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