]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_dotcmds.c
677447c96767d34bc9c7892148559baf349c789a
[bacula/bacula] / bacula / src / dird / ua_dotcmds.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2009 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  *   Bacula Director -- User Agent Commands
31  *     These are "dot" commands, i.e. commands preceded
32  *        by a period. These commands are meant to be used
33  *        by a program, so there is no prompting, and the
34  *        returned results are (supposed to be) predictable.
35  *
36  *     Kern Sibbald, April MMII
37  *
38  *   Version $Id$
39  */
40
41 #include "bacula.h"
42 #include "dird.h"
43 #include "cats/bvfs.h"
44 #include "findlib/find.h"
45
46 /* Imported variables */
47
48 /* Imported functions */
49 extern void do_messages(UAContext *ua, const char *cmd);
50 extern int quit_cmd(UAContext *ua, const char *cmd);
51 extern int qhelp_cmd(UAContext *ua, const char *cmd);
52 extern bool dot_status_cmd(UAContext *ua, const char *cmd);
53
54
55 /* Forward referenced functions */
56 static bool diecmd(UAContext *ua, const char *cmd);
57 static bool jobscmd(UAContext *ua, const char *cmd);
58 static bool filesetscmd(UAContext *ua, const char *cmd);
59 static bool clientscmd(UAContext *ua, const char *cmd);
60 static bool msgscmd(UAContext *ua, const char *cmd);
61 static bool poolscmd(UAContext *ua, const char *cmd);
62 static bool storagecmd(UAContext *ua, const char *cmd);
63 static bool defaultscmd(UAContext *ua, const char *cmd);
64 static bool typescmd(UAContext *ua, const char *cmd);
65 static bool backupscmd(UAContext *ua, const char *cmd);
66 static bool levelscmd(UAContext *ua, const char *cmd);
67 static bool getmsgscmd(UAContext *ua, const char *cmd);
68 static bool volstatuscmd(UAContext *ua, const char *cmd);
69 static bool mediatypescmd(UAContext *ua, const char *cmd);
70 static bool locationscmd(UAContext *ua, const char *cmd);
71 static bool mediacmd(UAContext *ua, const char *cmd);
72
73 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd);
74 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd);
75 static bool dot_bvfs_update(UAContext *ua, const char *cmd);
76
77 static bool api_cmd(UAContext *ua, const char *cmd);
78 static bool sql_cmd(UAContext *ua, const char *cmd);
79 static bool dot_quit_cmd(UAContext *ua, const char *cmd);
80 static bool dot_help_cmd(UAContext *ua, const char *cmd);
81 static bool helpscmd(UAContext *ua, const char *cmd);
82
83 struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help;const bool use_in_rs;};
84 static struct cmdstruct commands[] = { /* help */  /* can be used in runscript */
85  { NT_(".api"),        api_cmd,          NULL,       false},
86  { NT_(".backups"),    backupscmd,       NULL,       false},
87  { NT_(".clients"),    clientscmd,       NULL,       true},
88  { NT_(".defaults"),   defaultscmd,      NULL,       false},
89  { NT_(".die"),        diecmd,           NULL,       false},
90  { NT_(".exit"),       dot_quit_cmd,     NULL,       false},
91  { NT_(".filesets"),   filesetscmd,      NULL,       false},
92  { NT_(".help"),       dot_help_cmd,     NULL,       false},
93  { NT_(".jobs"),       jobscmd,          NULL,       true},
94  { NT_(".levels"),     levelscmd,        NULL,       false},
95  { NT_(".messages"),   getmsgscmd,       NULL,       false},
96  { NT_(".msgs"),       msgscmd,          NULL,       false},
97  { NT_(".pools"),      poolscmd,         NULL,       true},
98  { NT_(".quit"),       dot_quit_cmd,     NULL,       false},
99  { NT_(".sql"),        sql_cmd,          NULL,       false},
100  { NT_(".status"),     dot_status_cmd,   NULL,       false},
101  { NT_(".storage"),    storagecmd,       NULL,       true},
102  { NT_(".volstatus"),  volstatuscmd,     NULL,       true},
103  { NT_(".media"),      mediacmd,         NULL,       true},
104  { NT_(".mediatypes"), mediatypescmd,    NULL,       true},
105  { NT_(".locations"),  locationscmd,     NULL,       true},
106  { NT_(".bvfs_lsdirs"), dot_bvfs_lsdirs, NULL,       true},
107  { NT_(".bvfs_lsfiles"),dot_bvfs_lsfiles,NULL,       true},
108  { NT_(".bvfs_update"), dot_bvfs_update, NULL,       true},
109  { NT_(".types"),      typescmd,         NULL,       false} 
110              };
111 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
112
113 /*
114  * Execute a command from the UA
115  */
116 bool do_a_dot_command(UAContext *ua) 
117 {
118    int i;
119    int len;
120    bool ok = false;
121    bool found = false;
122    BSOCK *user = ua->UA_sock;
123
124    Dmsg1(1400, "Dot command: %s\n", user->msg);
125    if (ua->argc == 0) {
126       return false;
127    }
128
129    len = strlen(ua->argk[0]);
130    if (len == 1) {
131       if (ua->api) user->signal(BNET_CMD_BEGIN);
132       if (ua->api) user->signal(BNET_CMD_OK);
133       return true;                    /* no op */
134    }
135    for (i=0; i<comsize; i++) {     /* search for command */
136       if (strncasecmp(ua->argk[0],  _(commands[i].key), len) == 0) {
137          /* Check if this command is authorized in RunScript */
138          if (ua->runscript && !commands[i].use_in_rs) {
139             ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
140             break;
141          }
142          bool gui = ua->gui;
143          /* Check if command permitted, but "quit" is always OK */
144          if (strcmp(ua->argk[0], NT_(".quit")) != 0 &&
145              !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
146             break;
147          }
148          Dmsg1(100, "Cmd: %s\n", ua->cmd);
149          ua->gui = true;
150          if (ua->api) user->signal(BNET_CMD_BEGIN);
151          ok = (*commands[i].func)(ua, ua->cmd);   /* go execute command */
152          if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
153          ua->gui = gui;
154          found = true;
155          break;
156       }
157    }
158    if (!found) {
159       pm_strcat(user->msg, _(": is an invalid command.\n"));
160       ua->error_msg("%s", user->msg);
161       ok = false;
162    }
163    return ok;
164 }
165
166 static bool dot_bvfs_update(UAContext *ua, const char *cmd)
167 {
168
169    if (!open_client_db(ua)) {
170       return 1;
171    }
172
173    int pos = find_arg_with_value(ua, "jobid");
174    if (pos != -1 && is_a_number_list(ua->argv[pos])) {
175       POOL_MEM jobids;
176       pm_strcpy(jobids, ua->argv[pos]);
177       bvfs_update_path_hierarchy_cache(ua->jcr, ua->db, jobids.c_str());
178    } else {
179       /* update cache for all jobids */
180       bvfs_update_cache(ua->jcr, ua->db);
181    }
182    return true;
183 }
184
185 static int bvfs_result_handler(void *ctx, int fields, char **row)
186 {
187    UAContext *ua = (UAContext *)ctx;
188    struct stat statp;
189    int32_t LinkFI;
190    const char *fileid;
191    char *lstat;
192    char empty[] = "A A A A A A A A A A A A A A";
193
194    lstat = (row[BVFS_LStat] && row[BVFS_LStat][0])?row[BVFS_LStat]:empty;
195    fileid = (row[BVFS_FileId] && row[BVFS_FileId][0])?row[BVFS_FileId]:"0";
196
197    memset(&statp, 0, sizeof(struct stat));
198    decode_stat(lstat, &statp, &LinkFI);
199
200    Dmsg1(0, "type=%s\n", row[0]);
201    if (bvfs_is_dir(row)) {
202       char *path = bvfs_basename_dir(row[BVFS_Name]);
203       ua->send_msg("%s\t0\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], fileid,
204                    row[BVFS_JobId], row[BVFS_LStat], path);
205
206    } else if (bvfs_is_file(row)) {
207       ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
208                    row[BVFS_FilenameId], fileid, row[BVFS_JobId],
209                    row[BVFS_LStat], row[BVFS_Name]);
210    }
211
212    return 0;
213 }
214
215 static bool bvfs_parse_arg(UAContext *ua, 
216                            DBId_t *pathid, char **path, char **jobid,
217                            int *limit, int *offset)
218 {
219    *pathid=0;
220    *limit=2000;
221    *offset=0;
222    *path=NULL;
223    *jobid=NULL;
224
225    for (int i=1; i<ua->argc; i++) {
226       if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
227          if (is_a_number(ua->argv[i])) {
228             *pathid = str_to_int64(ua->argv[i]);
229          }
230       }
231       if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
232          *path = ua->argv[i];
233       }
234       
235       if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
236          if (is_a_number_list(ua->argv[i])) {
237             *jobid = ua->argv[i];
238          }
239       }
240
241       if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
242          if (is_a_number(ua->argv[i])) {
243             *limit = str_to_int64(ua->argv[i]);
244          }
245       }
246
247       if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
248          if (is_a_number(ua->argv[i])) {
249             *offset = str_to_int64(ua->argv[i]);
250          }
251       }
252    }
253
254    if (!((*pathid || *path) && *jobid)) {
255       return false;
256    }
257
258    if (!open_client_db(ua)) {
259       return false;
260    }
261
262    return true;
263 }
264
265 /* 
266  * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
267  * .bvfs_lsfiles jobid=1,2,3,4 path=/
268  */
269 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
270 {
271    DBId_t pathid=0;
272    int limit=2000, offset=0;
273    char *path=NULL, *jobid=NULL;
274
275    if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
276                        &limit, &offset))
277    {
278       ua->error_msg("Can't find jobid, pathid or path argument\n");
279       return true;              /* not enough param */
280    }
281
282    Bvfs fs(ua->jcr, ua->db);
283    fs.set_jobids(jobid);   
284    fs.set_handler(bvfs_result_handler, ua);
285    fs.set_limit(limit);
286
287    if (pathid) {
288       fs.ch_dir(pathid);
289    } else {
290       fs.ch_dir(path);
291    }
292
293    fs.set_offset(offset);
294
295    fs.ls_files();
296
297    return true;
298 }
299
300 /* 
301  * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
302  * .bvfs_lsdirs jobid=1,2,3,4 path=/
303  * .bvfs_lsdirs jobid=1,2,3,4 path=
304  */
305 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
306 {
307    DBId_t pathid=0;
308    int limit=2000, offset=0;
309    char *path=NULL, *jobid=NULL;
310
311    if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
312                        &limit, &offset))
313    {
314       ua->error_msg("Can't find jobid, pathid or path argument\n");
315       return true;              /* not enough param */
316    }
317
318    Bvfs fs(ua->jcr, ua->db);
319    fs.set_jobids(jobid);   
320    fs.set_limit(limit);
321    fs.set_handler(bvfs_result_handler, ua);
322
323    if (pathid) {
324       fs.ch_dir(pathid);
325    } else {
326       fs.ch_dir(path);
327    }
328
329    fs.set_offset(offset);
330
331    fs.ls_special_dirs();
332    fs.ls_dirs();
333
334    return true;
335 }
336
337 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
338 {
339    quit_cmd(ua, cmd);
340    return true;
341 }
342
343 static bool dot_help_cmd(UAContext *ua, const char *cmd)
344 {
345    qhelp_cmd(ua, cmd);
346    return true;
347 }
348
349 static bool getmsgscmd(UAContext *ua, const char *cmd)
350 {
351    if (console_msg_pending) {
352       do_messages(ua, cmd);
353    }
354    return 1;
355 }
356
357 #ifdef DEVELOPER
358 static void do_storage_die(UAContext *ua, STORE *store)
359 {
360    BSOCK *sd;
361    JCR *jcr = ua->jcr;
362    USTORE lstore;
363    
364    lstore.store = store;
365    pm_strcpy(lstore.store_source, _("unknown source"));
366    set_wstorage(jcr, &lstore);
367    /* Try connecting for up to 15 seconds */
368    ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
369       store->name(), store->address, store->SDport);
370    if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
371       ua->error_msg(_("Failed to connect to Storage daemon.\n"));
372       return;
373    }
374    Dmsg0(120, _("Connected to storage daemon\n"));
375    sd = jcr->store_bsock;
376    sd->fsend(".die");
377    if (sd->recv() >= 0) {
378       ua->send_msg("%s", sd->msg);
379    }
380    sd->signal(BNET_TERMINATE);
381    sd->close();
382    jcr->store_bsock = NULL;
383    return;
384 }
385
386 static void do_client_die(UAContext *ua, CLIENT *client)
387 {
388    BSOCK *fd;
389
390    /* Connect to File daemon */
391
392    ua->jcr->client = client;
393    /* Try to connect for 15 seconds */
394    ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
395       client->name(), client->address, client->FDport);
396    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
397       ua->error_msg(_("Failed to connect to Client.\n"));
398       return;
399    }
400    Dmsg0(120, "Connected to file daemon\n");
401    fd = ua->jcr->file_bsock;
402    fd->fsend(".die");
403    if (fd->recv() >= 0) {
404       ua->send_msg("%s", fd->msg);
405    }
406    fd->signal(BNET_TERMINATE);
407    fd->close();
408    ua->jcr->file_bsock = NULL;
409    return;
410 }
411
412 /*
413  * Create segmentation fault
414  */
415 static bool diecmd(UAContext *ua, const char *cmd)
416 {
417    STORE *store;
418    CLIENT *client;
419    int i;
420    JCR *jcr = NULL;
421    int a;
422
423    Dmsg1(120, "diecmd:%s:\n", cmd);
424
425    /* General debug? */
426    for (i=1; i<ua->argc; i++) {
427       if (strcasecmp(ua->argk[i], "dir") == 0 ||
428           strcasecmp(ua->argk[i], "director") == 0) {
429          ua->send_msg(_("The Director will segment fault.\n"));
430          a = jcr->JobId; /* ref NULL pointer */
431          jcr->JobId = 1000; /* another ref NULL pointer */
432          return 1;
433       }
434       if (strcasecmp(ua->argk[i], "client") == 0 ||
435           strcasecmp(ua->argk[i], "fd") == 0) {
436          client = NULL;
437          if (ua->argv[i]) {
438             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
439             if (client) {
440                do_client_die(ua, client);
441                return 1;
442             }
443          }
444          client = select_client_resource(ua);
445          if (client) {
446             do_client_die(ua, client);
447             return 1;
448          }
449       }
450
451       if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
452           strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
453           strcasecmp(ua->argk[i], NT_("sd")) == 0) {
454          store = NULL;
455          if (ua->argv[i]) {
456             store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
457             if (store) {
458                do_storage_die(ua, store);
459                return 1;
460             }
461          }
462          store = get_storage_resource(ua, false/*no default*/);
463          if (store) {
464             do_storage_die(ua, store);
465             return 1;
466          }
467       }
468    }
469    /*
470     * We didn't find an appropriate keyword above, so
471     * prompt the user.
472     */
473    start_prompt(ua, _("Available daemons are: \n"));
474    add_prompt(ua, _("Director"));
475    add_prompt(ua, _("Storage"));
476    add_prompt(ua, _("Client"));
477    switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
478    case 0:                         /* Director */
479       ua->send_msg(_("The Director will segment fault.\n"));
480       a = jcr->JobId; /* ref NULL pointer */
481       jcr->JobId = 1000; /* another ref NULL pointer */
482       break;
483    case 1:
484       store = get_storage_resource(ua, false/*no default*/);
485       if (store) {
486          do_storage_die(ua, store);
487       }
488       break;
489    case 2:
490       client = select_client_resource(ua);
491       if (client) {
492          do_client_die(ua, client);
493       }
494       break;
495    default:
496       break;
497    }
498    return true;
499 }
500
501 #else
502
503 /*
504  * Dummy routine for non-development version
505  */
506 static bool diecmd(UAContext *ua, const char *cmd)
507 {
508    return true;
509 }
510
511 #endif
512
513 static bool jobscmd(UAContext *ua, const char *cmd)
514 {
515    JOB *job;
516    LockRes();
517    foreach_res(job, R_JOB) {
518       if (acl_access_ok(ua, Job_ACL, job->name())) {
519          ua->send_msg("%s\n", job->name());
520       }
521    }
522    UnlockRes();
523    return true;
524 }
525
526 static bool filesetscmd(UAContext *ua, const char *cmd)
527 {
528    FILESET *fs;
529    LockRes();
530    foreach_res(fs, R_FILESET) {
531       if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
532          ua->send_msg("%s\n", fs->name());
533       }
534    }
535    UnlockRes();
536    return true;
537 }
538
539 static bool clientscmd(UAContext *ua, const char *cmd)
540 {
541    CLIENT *client;       
542    LockRes();
543    foreach_res(client, R_CLIENT) {
544       if (acl_access_ok(ua, Client_ACL, client->name())) {
545          ua->send_msg("%s\n", client->name());
546       }
547    }
548    UnlockRes();
549    return true;
550 }
551
552 static bool msgscmd(UAContext *ua, const char *cmd)
553 {
554    MSGS *msgs = NULL;
555    LockRes();
556    foreach_res(msgs, R_MSGS) {
557       ua->send_msg("%s\n", msgs->name());
558    }
559    UnlockRes();
560    return true;
561 }
562
563 static bool poolscmd(UAContext *ua, const char *cmd)
564 {
565    POOL *pool;       
566    LockRes();
567    foreach_res(pool, R_POOL) {
568       if (acl_access_ok(ua, Pool_ACL, pool->name())) {
569          ua->send_msg("%s\n", pool->name());
570       }
571    }
572    UnlockRes();
573    return true;
574 }
575
576 static bool storagecmd(UAContext *ua, const char *cmd)
577 {
578    STORE *store;
579    LockRes();
580    foreach_res(store, R_STORAGE) {
581       if (acl_access_ok(ua, Storage_ACL, store->name())) {
582          ua->send_msg("%s\n", store->name());
583       }
584    }
585    UnlockRes();
586    return true;
587 }
588
589
590 static bool typescmd(UAContext *ua, const char *cmd)
591 {
592    ua->send_msg("Backup\n");
593    ua->send_msg("Restore\n");
594    ua->send_msg("Admin\n");
595    ua->send_msg("Verify\n");
596    ua->send_msg("Migrate\n");
597    return true;
598 }
599
600
601 /*
602  * If this command is called, it tells the director that we
603  *  are a program that wants a sort of API, and hence,
604  *  we will probably suppress certain output, include more
605  *  error codes, and most of all send back a good number
606  *  of new signals that indicate whether or not the command
607  *  succeeded.
608  */
609 static bool api_cmd(UAContext *ua, const char *cmd)
610 {
611    if (ua->argc == 2) {
612       ua->api = atoi(ua->argk[1]);
613    } else {
614       ua->api = 1;
615    }
616    return true;
617 }
618
619 static int client_backups_handler(void *ctx, int num_field, char **row)
620 {
621    UAContext *ua = (UAContext *)ctx;
622    ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
623       row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
624    return 0;
625 }
626
627 /*
628  * Return the backups for this client 
629  *
630  *  .backups client=xxx fileset=yyy
631  *
632  */
633 static bool backupscmd(UAContext *ua, const char *cmd)
634 {
635    if (!open_client_db(ua)) {
636       return true;
637    }
638    if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 || 
639        strcmp(ua->argk[2], "fileset") != 0) {
640       return true;
641    }
642    if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
643        !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
644       ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
645       return true;
646    }
647    Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
648    if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
649       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
650       return true;
651    }
652    return true;
653 }
654
655 static int sql_handler(void *ctx, int num_field, char **row)
656 {
657    UAContext *ua = (UAContext *)ctx;
658    POOL_MEM rows(PM_MESSAGE);
659
660    /* Check for nonsense */
661    if (num_field == 0 || row == NULL || row[0] == NULL) {
662       return 0;                       /* nothing returned */
663    }
664    for (int i=0; num_field--; i++) {
665       if (i == 0) {
666          pm_strcpy(rows, NPRT(row[0]));
667       } else {
668          pm_strcat(rows, NPRT(row[i]));
669       }
670       pm_strcat(rows, "\t");
671    }
672    if (!rows.c_str() || !*rows.c_str()) {
673       ua->send_msg("\t");
674    } else {
675       ua->send_msg("%s", rows.c_str());
676    }
677    return 0;
678 }
679
680 static bool sql_cmd(UAContext *ua, const char *cmd)
681 {
682    int index;
683    if (!open_client_db(ua)) {
684       return true;
685    }
686    index = find_arg_with_value(ua, "query");
687    if (index < 0) {
688       ua->error_msg(_("query keyword not found.\n"));
689       return true;
690    }
691    if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
692       Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
693       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
694       return true;
695    }
696    return true;
697 }
698       
699 static int one_handler(void *ctx, int num_field, char **row)
700 {
701    UAContext *ua = (UAContext *)ctx;
702    ua->send_msg("%s\n", row[0]);
703    return 0;
704 }
705
706 static bool mediatypescmd(UAContext *ua, const char *cmd)
707 {
708    if (!open_client_db(ua)) {
709       return true;
710    }
711    if (!db_sql_query(ua->db, 
712                   "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
713                   one_handler, (void *)ua)) 
714    {
715       ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
716    }
717    return true;
718 }
719
720 static bool mediacmd(UAContext *ua, const char *cmd)
721 {
722    if (!open_client_db(ua)) {
723       return true;
724    }
725    if (!db_sql_query(ua->db, 
726                   "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
727                   one_handler, (void *)ua)) 
728    {
729       ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
730    }
731    return true;
732 }
733
734 static bool locationscmd(UAContext *ua, const char *cmd)
735 {
736    if (!open_client_db(ua)) {
737       return true;
738    }
739    if (!db_sql_query(ua->db, 
740                   "SELECT DISTINCT Location FROM Location ORDER BY Location",
741                   one_handler, (void *)ua)) 
742    {
743       ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
744    }
745    return true;
746 }
747
748 static bool levelscmd(UAContext *ua, const char *cmd)
749 {
750    ua->send_msg("Incremental\n");
751    ua->send_msg("Full\n");
752    ua->send_msg("Differential\n");
753    ua->send_msg("VirtualFull\n");
754    ua->send_msg("Catalog\n");
755    ua->send_msg("InitCatalog\n");
756    ua->send_msg("VolumeToCatalog\n");
757    return true;
758 }
759
760 static bool volstatuscmd(UAContext *ua, const char *cmd)
761 {
762    ua->send_msg("Append\n");
763    ua->send_msg("Full\n");
764    ua->send_msg("Used\n");
765    ua->send_msg("Recycle\n");
766    ua->send_msg("Purged\n");
767    ua->send_msg("Cleaning\n");
768    ua->send_msg("Error\n");
769    return true;
770 }
771
772 /*
773  * Return default values for a job
774  */
775 static bool defaultscmd(UAContext *ua, const char *cmd)
776 {
777    JOB *job;
778    CLIENT *client;
779    STORE *storage;
780    POOL *pool;
781    char ed1[50];
782
783    if (ua->argc != 2 || !ua->argv[1]) {
784       return true;
785    }
786
787    /* Job defaults */   
788    if (strcmp(ua->argk[1], "job") == 0) {
789       if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
790          return true;
791       }
792       job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
793       if (job) {
794          USTORE store;
795          ua->send_msg("job=%s", job->name());
796          ua->send_msg("pool=%s", job->pool->name());
797          ua->send_msg("messages=%s", job->messages->name());
798          ua->send_msg("client=%s", job->client->name());
799          get_job_storage(&store, job, NULL);
800          ua->send_msg("storage=%s", store.store->name());
801          ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
802          ua->send_msg("level=%s", level_to_str(job->JobLevel));
803          ua->send_msg("type=%s", job_type_to_str(job->JobType));
804          ua->send_msg("fileset=%s", job->fileset->name());
805          ua->send_msg("enabled=%d", job->enabled);
806          ua->send_msg("catalog=%s", job->client->catalog->name());
807       }
808    } 
809    /* Client defaults */
810    else if (strcmp(ua->argk[1], "client") == 0) {
811       if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
812          return true;   
813       }
814       client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
815       if (client) {
816          ua->send_msg("client=%s", client->name());
817          ua->send_msg("address=%s", client->address);
818          ua->send_msg("fdport=%d", client->FDport);
819          ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
820          ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
821          ua->send_msg("autoprune=%d", client->AutoPrune);
822          ua->send_msg("catalog=%s", client->catalog->name());
823       }
824    }
825    /* Storage defaults */
826    else if (strcmp(ua->argk[1], "storage") == 0) {
827       if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
828          return true;
829       }
830       storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
831       DEVICE *device;
832       if (storage) {
833          ua->send_msg("storage=%s", storage->name());
834          ua->send_msg("address=%s", storage->address);
835          ua->send_msg("enabled=%d", storage->enabled);
836          ua->send_msg("media_type=%s", storage->media_type);
837          ua->send_msg("sdport=%d", storage->SDport);
838          device = (DEVICE *)storage->device->first();
839          ua->send_msg("device=%s", device->name());
840          if (storage->device->size() > 1) {
841             while ((device = (DEVICE *)storage->device->next())) {
842                ua->send_msg(",%s", device->name());
843             }
844          }
845       }
846    }
847    /* Pool defaults */
848    else if (strcmp(ua->argk[1], "pool") == 0) {
849       if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
850          return true;
851       }
852       pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
853       if (pool) {
854          ua->send_msg("pool=%s", pool->name());
855          ua->send_msg("pool_type=%s", pool->pool_type);
856          ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
857          ua->send_msg("use_volume_once=%d", pool->use_volume_once);
858          ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
859          ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
860          ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
861          ua->send_msg("max_volumes=%d", pool->max_volumes);
862          ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
863          ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
864          ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
865          ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
866          ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
867          ua->send_msg("auto_prune=%d", pool->AutoPrune);
868          ua->send_msg("recycle=%d", pool->Recycle);
869       }
870    }
871    return true;
872 }