]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_dotcmds.c
0e37efc6d11e39bd7d2b15e9295cd02fbccc60ff
[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  */
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 diecmd(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"),        diecmd,           NULL,       false},
89  { NT_(".exit"),       dot_quit_cmd,     NULL,       false},
90  { NT_(".filesets"),   filesetscmd,      NULL,       false},
91  { NT_(".help"),       dot_help_cmd,     NULL,       false},
92  { NT_(".jobs"),       jobscmd,          NULL,       true},
93  { NT_(".levels"),     levelscmd,        NULL,       false},
94  { NT_(".messages"),   getmsgscmd,       NULL,       false},
95  { NT_(".msgs"),       msgscmd,          NULL,       false},
96  { NT_(".pools"),      poolscmd,         NULL,       true},
97  { NT_(".quit"),       dot_quit_cmd,     NULL,       false},
98  { NT_(".sql"),        sql_cmd,          NULL,       false},
99  { NT_(".status"),     dot_status_cmd,   NULL,       false},
100  { NT_(".storage"),    storagecmd,       NULL,       true},
101  { NT_(".volstatus"),  volstatuscmd,     NULL,       true},
102  { NT_(".media"),      mediacmd,         NULL,       true},
103  { NT_(".mediatypes"), mediatypescmd,    NULL,       true},
104  { NT_(".locations"),  locationscmd,     NULL,       true},
105  { NT_(".actiononpurge"),aopcmd,         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 static bool aopcmd(UAContext *ua, const char *cmd)
590 {
591    ua->send_msg("None\n");
592    ua->send_msg("Truncate\n");
593    return true;
594 }
595
596 static bool typescmd(UAContext *ua, const char *cmd)
597 {
598    ua->send_msg("Backup\n");
599    ua->send_msg("Restore\n");
600    ua->send_msg("Admin\n");
601    ua->send_msg("Verify\n");
602    ua->send_msg("Migrate\n");
603    return true;
604 }
605
606 /*
607  * If this command is called, it tells the director that we
608  *  are a program that wants a sort of API, and hence,
609  *  we will probably suppress certain output, include more
610  *  error codes, and most of all send back a good number
611  *  of new signals that indicate whether or not the command
612  *  succeeded.
613  */
614 static bool api_cmd(UAContext *ua, const char *cmd)
615 {
616    if (ua->argc == 2) {
617       ua->api = atoi(ua->argk[1]);
618    } else {
619       ua->api = 1;
620    }
621    return true;
622 }
623
624 static int client_backups_handler(void *ctx, int num_field, char **row)
625 {
626    UAContext *ua = (UAContext *)ctx;
627    ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
628       row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
629    return 0;
630 }
631
632 /*
633  * Return the backups for this client 
634  *
635  *  .backups client=xxx fileset=yyy
636  *
637  */
638 static bool backupscmd(UAContext *ua, const char *cmd)
639 {
640    if (!open_client_db(ua)) {
641       return true;
642    }
643    if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 || 
644        strcmp(ua->argk[2], "fileset") != 0) {
645       return true;
646    }
647    if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
648        !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
649       ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
650       return true;
651    }
652    Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
653    if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
654       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
655       return true;
656    }
657    return true;
658 }
659
660 static int sql_handler(void *ctx, int num_field, char **row)
661 {
662    UAContext *ua = (UAContext *)ctx;
663    POOL_MEM rows(PM_MESSAGE);
664
665    /* Check for nonsense */
666    if (num_field == 0 || row == NULL || row[0] == NULL) {
667       return 0;                       /* nothing returned */
668    }
669    for (int i=0; num_field--; i++) {
670       if (i == 0) {
671          pm_strcpy(rows, NPRT(row[0]));
672       } else {
673          pm_strcat(rows, NPRT(row[i]));
674       }
675       pm_strcat(rows, "\t");
676    }
677    if (!rows.c_str() || !*rows.c_str()) {
678       ua->send_msg("\t");
679    } else {
680       ua->send_msg("%s", rows.c_str());
681    }
682    return 0;
683 }
684
685 static bool sql_cmd(UAContext *ua, const char *cmd)
686 {
687    int index;
688    if (!open_client_db(ua)) {
689       return true;
690    }
691    index = find_arg_with_value(ua, "query");
692    if (index < 0) {
693       ua->error_msg(_("query keyword not found.\n"));
694       return true;
695    }
696    if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
697       Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
698       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
699       return true;
700    }
701    return true;
702 }
703       
704 static int one_handler(void *ctx, int num_field, char **row)
705 {
706    UAContext *ua = (UAContext *)ctx;
707    ua->send_msg("%s\n", row[0]);
708    return 0;
709 }
710
711 static bool mediatypescmd(UAContext *ua, const char *cmd)
712 {
713    if (!open_client_db(ua)) {
714       return true;
715    }
716    if (!db_sql_query(ua->db, 
717                   "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
718                   one_handler, (void *)ua)) 
719    {
720       ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
721    }
722    return true;
723 }
724
725 static bool mediacmd(UAContext *ua, const char *cmd)
726 {
727    if (!open_client_db(ua)) {
728       return true;
729    }
730    if (!db_sql_query(ua->db, 
731                   "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
732                   one_handler, (void *)ua)) 
733    {
734       ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
735    }
736    return true;
737 }
738
739 static bool locationscmd(UAContext *ua, const char *cmd)
740 {
741    if (!open_client_db(ua)) {
742       return true;
743    }
744    if (!db_sql_query(ua->db, 
745                   "SELECT DISTINCT Location FROM Location ORDER BY Location",
746                   one_handler, (void *)ua)) 
747    {
748       ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
749    }
750    return true;
751 }
752
753 static bool levelscmd(UAContext *ua, const char *cmd)
754 {
755    ua->send_msg("Incremental\n");
756    ua->send_msg("Full\n");
757    ua->send_msg("Differential\n");
758    ua->send_msg("VirtualFull\n");
759    ua->send_msg("Catalog\n");
760    ua->send_msg("InitCatalog\n");
761    ua->send_msg("VolumeToCatalog\n");
762    return true;
763 }
764
765 static bool volstatuscmd(UAContext *ua, const char *cmd)
766 {
767    ua->send_msg("Append\n");
768    ua->send_msg("Full\n");
769    ua->send_msg("Used\n");
770    ua->send_msg("Recycle\n");
771    ua->send_msg("Purged\n");
772    ua->send_msg("Cleaning\n");
773    ua->send_msg("Error\n");
774    return true;
775 }
776
777 /*
778  * Return default values for a job
779  */
780 static bool defaultscmd(UAContext *ua, const char *cmd)
781 {
782    JOB *job;
783    CLIENT *client;
784    STORE *storage;
785    POOL *pool;
786    char ed1[50];
787
788    if (ua->argc != 2 || !ua->argv[1]) {
789       return true;
790    }
791
792    /* Job defaults */   
793    if (strcmp(ua->argk[1], "job") == 0) {
794       if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
795          return true;
796       }
797       job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
798       if (job) {
799          USTORE store;
800          ua->send_msg("job=%s", job->name());
801          ua->send_msg("pool=%s", job->pool->name());
802          ua->send_msg("messages=%s", job->messages->name());
803          ua->send_msg("client=%s", job->client->name());
804          get_job_storage(&store, job, NULL);
805          ua->send_msg("storage=%s", store.store->name());
806          ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
807          ua->send_msg("level=%s", level_to_str(job->JobLevel));
808          ua->send_msg("type=%s", job_type_to_str(job->JobType));
809          ua->send_msg("fileset=%s", job->fileset->name());
810          ua->send_msg("enabled=%d", job->enabled);
811          ua->send_msg("catalog=%s", job->client->catalog->name());
812       }
813    } 
814    /* Client defaults */
815    else if (strcmp(ua->argk[1], "client") == 0) {
816       if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
817          return true;   
818       }
819       client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
820       if (client) {
821          ua->send_msg("client=%s", client->name());
822          ua->send_msg("address=%s", client->address);
823          ua->send_msg("fdport=%d", client->FDport);
824          ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
825          ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
826          ua->send_msg("autoprune=%d", client->AutoPrune);
827          ua->send_msg("catalog=%s", client->catalog->name());
828       }
829    }
830    /* Storage defaults */
831    else if (strcmp(ua->argk[1], "storage") == 0) {
832       if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
833          return true;
834       }
835       storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
836       DEVICE *device;
837       if (storage) {
838          ua->send_msg("storage=%s", storage->name());
839          ua->send_msg("address=%s", storage->address);
840          ua->send_msg("enabled=%d", storage->enabled);
841          ua->send_msg("media_type=%s", storage->media_type);
842          ua->send_msg("sdport=%d", storage->SDport);
843          device = (DEVICE *)storage->device->first();
844          ua->send_msg("device=%s", device->name());
845          if (storage->device->size() > 1) {
846             while ((device = (DEVICE *)storage->device->next())) {
847                ua->send_msg(",%s", device->name());
848             }
849          }
850       }
851    }
852    /* Pool defaults */
853    else if (strcmp(ua->argk[1], "pool") == 0) {
854       if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
855          return true;
856       }
857       pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
858       if (pool) {
859          ua->send_msg("pool=%s", pool->name());
860          ua->send_msg("pool_type=%s", pool->pool_type);
861          ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
862          ua->send_msg("use_volume_once=%d", pool->use_volume_once);
863          ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
864          ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
865          ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
866          ua->send_msg("max_volumes=%d", pool->max_volumes);
867          ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
868          ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
869          ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
870          ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
871          ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
872          ua->send_msg("auto_prune=%d", pool->AutoPrune);
873          ua->send_msg("recycle=%d", pool->Recycle);
874          ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1));
875          ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1));
876       }
877    }
878    return true;
879 }