]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_dotcmds.c
Add .actiononpurge command
[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 static bool aopcmd(UAContext *ua, const char *cmd);
73
74 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd);
75 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd);
76 static bool dot_bvfs_update(UAContext *ua, const char *cmd);
77
78 static bool api_cmd(UAContext *ua, const char *cmd);
79 static bool sql_cmd(UAContext *ua, const char *cmd);
80 static bool dot_quit_cmd(UAContext *ua, const char *cmd);
81 static bool dot_help_cmd(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_(".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
170    if (!open_client_db(ua)) {
171       return 1;
172    }
173
174    int pos = find_arg_with_value(ua, "jobid");
175    if (pos != -1 && is_a_number_list(ua->argv[pos])) {
176       POOL_MEM jobids;
177       pm_strcpy(jobids, ua->argv[pos]);
178       bvfs_update_path_hierarchy_cache(ua->jcr, ua->db, jobids.c_str());
179    } else {
180       /* update cache for all jobids */
181       bvfs_update_cache(ua->jcr, ua->db);
182    }
183    return true;
184 }
185
186 static int bvfs_result_handler(void *ctx, int fields, char **row)
187 {
188    UAContext *ua = (UAContext *)ctx;
189    struct stat statp;
190    int32_t LinkFI;
191    const char *fileid;
192    char *lstat;
193    char empty[] = "A A A A A A A A A A A A A A";
194
195    lstat = (row[BVFS_LStat] && row[BVFS_LStat][0])?row[BVFS_LStat]:empty;
196    fileid = (row[BVFS_FileId] && row[BVFS_FileId][0])?row[BVFS_FileId]:"0";
197
198    memset(&statp, 0, sizeof(struct stat));
199    decode_stat(lstat, &statp, &LinkFI);
200
201    Dmsg1(0, "type=%s\n", row[0]);
202    if (bvfs_is_dir(row)) {
203       char *path = bvfs_basename_dir(row[BVFS_Name]);
204       ua->send_msg("%s\t0\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], fileid,
205                    row[BVFS_JobId], row[BVFS_LStat], path);
206
207    } else if (bvfs_is_file(row)) {
208       ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
209                    row[BVFS_FilenameId], fileid, row[BVFS_JobId],
210                    row[BVFS_LStat], row[BVFS_Name]);
211    }
212
213    return 0;
214 }
215
216 static bool bvfs_parse_arg(UAContext *ua, 
217                            DBId_t *pathid, char **path, char **jobid,
218                            int *limit, int *offset)
219 {
220    *pathid=0;
221    *limit=2000;
222    *offset=0;
223    *path=NULL;
224    *jobid=NULL;
225
226    for (int i=1; i<ua->argc; i++) {
227       if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
228          if (is_a_number(ua->argv[i])) {
229             *pathid = str_to_int64(ua->argv[i]);
230          }
231       }
232       if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
233          *path = ua->argv[i];
234       }
235       
236       if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
237          if (is_a_number_list(ua->argv[i])) {
238             *jobid = ua->argv[i];
239          }
240       }
241
242       if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
243          if (is_a_number(ua->argv[i])) {
244             *limit = str_to_int64(ua->argv[i]);
245          }
246       }
247
248       if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
249          if (is_a_number(ua->argv[i])) {
250             *offset = str_to_int64(ua->argv[i]);
251          }
252       }
253    }
254
255    if (!((*pathid || *path) && *jobid)) {
256       return false;
257    }
258
259    if (!open_client_db(ua)) {
260       return false;
261    }
262
263    return true;
264 }
265
266 /* 
267  * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
268  * .bvfs_lsfiles jobid=1,2,3,4 path=/
269  */
270 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
271 {
272    DBId_t pathid=0;
273    int limit=2000, offset=0;
274    char *path=NULL, *jobid=NULL;
275
276    if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
277                        &limit, &offset))
278    {
279       ua->error_msg("Can't find jobid, pathid or path argument\n");
280       return true;              /* not enough param */
281    }
282
283    Bvfs fs(ua->jcr, ua->db);
284    fs.set_jobids(jobid);   
285    fs.set_handler(bvfs_result_handler, ua);
286    fs.set_limit(limit);
287
288    if (pathid) {
289       fs.ch_dir(pathid);
290    } else {
291       fs.ch_dir(path);
292    }
293
294    fs.set_offset(offset);
295
296    fs.ls_files();
297
298    return true;
299 }
300
301 /* 
302  * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
303  * .bvfs_lsdirs jobid=1,2,3,4 path=/
304  * .bvfs_lsdirs jobid=1,2,3,4 path=
305  */
306 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
307 {
308    DBId_t pathid=0;
309    int limit=2000, offset=0;
310    char *path=NULL, *jobid=NULL;
311
312    if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
313                        &limit, &offset))
314    {
315       ua->error_msg("Can't find jobid, pathid or path argument\n");
316       return true;              /* not enough param */
317    }
318
319    Bvfs fs(ua->jcr, ua->db);
320    fs.set_jobids(jobid);   
321    fs.set_limit(limit);
322    fs.set_handler(bvfs_result_handler, ua);
323
324    if (pathid) {
325       fs.ch_dir(pathid);
326    } else {
327       fs.ch_dir(path);
328    }
329
330    fs.set_offset(offset);
331
332    fs.ls_special_dirs();
333    fs.ls_dirs();
334
335    return true;
336 }
337
338 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
339 {
340    quit_cmd(ua, cmd);
341    return true;
342 }
343
344 static bool dot_help_cmd(UAContext *ua, const char *cmd)
345 {
346    qhelp_cmd(ua, cmd);
347    return true;
348 }
349
350 static bool getmsgscmd(UAContext *ua, const char *cmd)
351 {
352    if (console_msg_pending) {
353       do_messages(ua, cmd);
354    }
355    return 1;
356 }
357
358 #ifdef DEVELOPER
359 static void do_storage_die(UAContext *ua, STORE *store)
360 {
361    BSOCK *sd;
362    JCR *jcr = ua->jcr;
363    USTORE lstore;
364    
365    lstore.store = store;
366    pm_strcpy(lstore.store_source, _("unknown source"));
367    set_wstorage(jcr, &lstore);
368    /* Try connecting for up to 15 seconds */
369    ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
370       store->name(), store->address, store->SDport);
371    if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
372       ua->error_msg(_("Failed to connect to Storage daemon.\n"));
373       return;
374    }
375    Dmsg0(120, _("Connected to storage daemon\n"));
376    sd = jcr->store_bsock;
377    sd->fsend(".die");
378    if (sd->recv() >= 0) {
379       ua->send_msg("%s", sd->msg);
380    }
381    sd->signal(BNET_TERMINATE);
382    sd->close();
383    jcr->store_bsock = NULL;
384    return;
385 }
386
387 static void do_client_die(UAContext *ua, CLIENT *client)
388 {
389    BSOCK *fd;
390
391    /* Connect to File daemon */
392
393    ua->jcr->client = client;
394    /* Try to connect for 15 seconds */
395    ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
396       client->name(), client->address, client->FDport);
397    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
398       ua->error_msg(_("Failed to connect to Client.\n"));
399       return;
400    }
401    Dmsg0(120, "Connected to file daemon\n");
402    fd = ua->jcr->file_bsock;
403    fd->fsend(".die");
404    if (fd->recv() >= 0) {
405       ua->send_msg("%s", fd->msg);
406    }
407    fd->signal(BNET_TERMINATE);
408    fd->close();
409    ua->jcr->file_bsock = NULL;
410    return;
411 }
412
413 /*
414  * Create segmentation fault
415  */
416 static bool diecmd(UAContext *ua, const char *cmd)
417 {
418    STORE *store;
419    CLIENT *client;
420    int i;
421    JCR *jcr = NULL;
422    int a;
423
424    Dmsg1(120, "diecmd:%s:\n", cmd);
425
426    /* General debug? */
427    for (i=1; i<ua->argc; i++) {
428       if (strcasecmp(ua->argk[i], "dir") == 0 ||
429           strcasecmp(ua->argk[i], "director") == 0) {
430          ua->send_msg(_("The Director will segment fault.\n"));
431          a = jcr->JobId; /* ref NULL pointer */
432          jcr->JobId = 1000; /* another ref NULL pointer */
433          return 1;
434       }
435       if (strcasecmp(ua->argk[i], "client") == 0 ||
436           strcasecmp(ua->argk[i], "fd") == 0) {
437          client = NULL;
438          if (ua->argv[i]) {
439             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
440             if (client) {
441                do_client_die(ua, client);
442                return 1;
443             }
444          }
445          client = select_client_resource(ua);
446          if (client) {
447             do_client_die(ua, client);
448             return 1;
449          }
450       }
451
452       if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
453           strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
454           strcasecmp(ua->argk[i], NT_("sd")) == 0) {
455          store = NULL;
456          if (ua->argv[i]) {
457             store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
458             if (store) {
459                do_storage_die(ua, store);
460                return 1;
461             }
462          }
463          store = get_storage_resource(ua, false/*no default*/);
464          if (store) {
465             do_storage_die(ua, store);
466             return 1;
467          }
468       }
469    }
470    /*
471     * We didn't find an appropriate keyword above, so
472     * prompt the user.
473     */
474    start_prompt(ua, _("Available daemons are: \n"));
475    add_prompt(ua, _("Director"));
476    add_prompt(ua, _("Storage"));
477    add_prompt(ua, _("Client"));
478    switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
479    case 0:                         /* Director */
480       ua->send_msg(_("The Director will segment fault.\n"));
481       a = jcr->JobId; /* ref NULL pointer */
482       jcr->JobId = 1000; /* another ref NULL pointer */
483       break;
484    case 1:
485       store = get_storage_resource(ua, false/*no default*/);
486       if (store) {
487          do_storage_die(ua, store);
488       }
489       break;
490    case 2:
491       client = select_client_resource(ua);
492       if (client) {
493          do_client_die(ua, client);
494       }
495       break;
496    default:
497       break;
498    }
499    return true;
500 }
501
502 #else
503
504 /*
505  * Dummy routine for non-development version
506  */
507 static bool diecmd(UAContext *ua, const char *cmd)
508 {
509    return true;
510 }
511
512 #endif
513
514 static bool jobscmd(UAContext *ua, const char *cmd)
515 {
516    JOB *job;
517    LockRes();
518    foreach_res(job, R_JOB) {
519       if (acl_access_ok(ua, Job_ACL, job->name())) {
520          ua->send_msg("%s\n", job->name());
521       }
522    }
523    UnlockRes();
524    return true;
525 }
526
527 static bool filesetscmd(UAContext *ua, const char *cmd)
528 {
529    FILESET *fs;
530    LockRes();
531    foreach_res(fs, R_FILESET) {
532       if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
533          ua->send_msg("%s\n", fs->name());
534       }
535    }
536    UnlockRes();
537    return true;
538 }
539
540 static bool clientscmd(UAContext *ua, const char *cmd)
541 {
542    CLIENT *client;       
543    LockRes();
544    foreach_res(client, R_CLIENT) {
545       if (acl_access_ok(ua, Client_ACL, client->name())) {
546          ua->send_msg("%s\n", client->name());
547       }
548    }
549    UnlockRes();
550    return true;
551 }
552
553 static bool msgscmd(UAContext *ua, const char *cmd)
554 {
555    MSGS *msgs = NULL;
556    LockRes();
557    foreach_res(msgs, R_MSGS) {
558       ua->send_msg("%s\n", msgs->name());
559    }
560    UnlockRes();
561    return true;
562 }
563
564 static bool poolscmd(UAContext *ua, const char *cmd)
565 {
566    POOL *pool;       
567    LockRes();
568    foreach_res(pool, R_POOL) {
569       if (acl_access_ok(ua, Pool_ACL, pool->name())) {
570          ua->send_msg("%s\n", pool->name());
571       }
572    }
573    UnlockRes();
574    return true;
575 }
576
577 static bool storagecmd(UAContext *ua, const char *cmd)
578 {
579    STORE *store;
580    LockRes();
581    foreach_res(store, R_STORAGE) {
582       if (acl_access_ok(ua, Storage_ACL, store->name())) {
583          ua->send_msg("%s\n", store->name());
584       }
585    }
586    UnlockRes();
587    return true;
588 }
589
590 static bool aopcmd(UAContext *ua, const char *cmd)
591 {
592    ua->send_msg("None\n");
593    ua->send_msg("Truncate\n");
594    return true;
595 }
596
597 static bool typescmd(UAContext *ua, const char *cmd)
598 {
599    ua->send_msg("Backup\n");
600    ua->send_msg("Restore\n");
601    ua->send_msg("Admin\n");
602    ua->send_msg("Verify\n");
603    ua->send_msg("Migrate\n");
604    return true;
605 }
606
607 /*
608  * If this command is called, it tells the director that we
609  *  are a program that wants a sort of API, and hence,
610  *  we will probably suppress certain output, include more
611  *  error codes, and most of all send back a good number
612  *  of new signals that indicate whether or not the command
613  *  succeeded.
614  */
615 static bool api_cmd(UAContext *ua, const char *cmd)
616 {
617    if (ua->argc == 2) {
618       ua->api = atoi(ua->argk[1]);
619    } else {
620       ua->api = 1;
621    }
622    return true;
623 }
624
625 static int client_backups_handler(void *ctx, int num_field, char **row)
626 {
627    UAContext *ua = (UAContext *)ctx;
628    ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
629       row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
630    return 0;
631 }
632
633 /*
634  * Return the backups for this client 
635  *
636  *  .backups client=xxx fileset=yyy
637  *
638  */
639 static bool backupscmd(UAContext *ua, const char *cmd)
640 {
641    if (!open_client_db(ua)) {
642       return true;
643    }
644    if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 || 
645        strcmp(ua->argk[2], "fileset") != 0) {
646       return true;
647    }
648    if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
649        !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
650       ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
651       return true;
652    }
653    Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
654    if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
655       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
656       return true;
657    }
658    return true;
659 }
660
661 static int sql_handler(void *ctx, int num_field, char **row)
662 {
663    UAContext *ua = (UAContext *)ctx;
664    POOL_MEM rows(PM_MESSAGE);
665
666    /* Check for nonsense */
667    if (num_field == 0 || row == NULL || row[0] == NULL) {
668       return 0;                       /* nothing returned */
669    }
670    for (int i=0; num_field--; i++) {
671       if (i == 0) {
672          pm_strcpy(rows, NPRT(row[0]));
673       } else {
674          pm_strcat(rows, NPRT(row[i]));
675       }
676       pm_strcat(rows, "\t");
677    }
678    if (!rows.c_str() || !*rows.c_str()) {
679       ua->send_msg("\t");
680    } else {
681       ua->send_msg("%s", rows.c_str());
682    }
683    return 0;
684 }
685
686 static bool sql_cmd(UAContext *ua, const char *cmd)
687 {
688    int index;
689    if (!open_client_db(ua)) {
690       return true;
691    }
692    index = find_arg_with_value(ua, "query");
693    if (index < 0) {
694       ua->error_msg(_("query keyword not found.\n"));
695       return true;
696    }
697    if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
698       Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
699       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
700       return true;
701    }
702    return true;
703 }
704       
705 static int one_handler(void *ctx, int num_field, char **row)
706 {
707    UAContext *ua = (UAContext *)ctx;
708    ua->send_msg("%s\n", row[0]);
709    return 0;
710 }
711
712 static bool mediatypescmd(UAContext *ua, const char *cmd)
713 {
714    if (!open_client_db(ua)) {
715       return true;
716    }
717    if (!db_sql_query(ua->db, 
718                   "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
719                   one_handler, (void *)ua)) 
720    {
721       ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
722    }
723    return true;
724 }
725
726 static bool mediacmd(UAContext *ua, const char *cmd)
727 {
728    if (!open_client_db(ua)) {
729       return true;
730    }
731    if (!db_sql_query(ua->db, 
732                   "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
733                   one_handler, (void *)ua)) 
734    {
735       ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
736    }
737    return true;
738 }
739
740 static bool locationscmd(UAContext *ua, const char *cmd)
741 {
742    if (!open_client_db(ua)) {
743       return true;
744    }
745    if (!db_sql_query(ua->db, 
746                   "SELECT DISTINCT Location FROM Location ORDER BY Location",
747                   one_handler, (void *)ua)) 
748    {
749       ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
750    }
751    return true;
752 }
753
754 static bool levelscmd(UAContext *ua, const char *cmd)
755 {
756    ua->send_msg("Incremental\n");
757    ua->send_msg("Full\n");
758    ua->send_msg("Differential\n");
759    ua->send_msg("VirtualFull\n");
760    ua->send_msg("Catalog\n");
761    ua->send_msg("InitCatalog\n");
762    ua->send_msg("VolumeToCatalog\n");
763    return true;
764 }
765
766 static bool volstatuscmd(UAContext *ua, const char *cmd)
767 {
768    ua->send_msg("Append\n");
769    ua->send_msg("Full\n");
770    ua->send_msg("Used\n");
771    ua->send_msg("Recycle\n");
772    ua->send_msg("Purged\n");
773    ua->send_msg("Cleaning\n");
774    ua->send_msg("Error\n");
775    return true;
776 }
777
778 /*
779  * Return default values for a job
780  */
781 static bool defaultscmd(UAContext *ua, const char *cmd)
782 {
783    JOB *job;
784    CLIENT *client;
785    STORE *storage;
786    POOL *pool;
787    char ed1[50];
788
789    if (ua->argc != 2 || !ua->argv[1]) {
790       return true;
791    }
792
793    /* Job defaults */   
794    if (strcmp(ua->argk[1], "job") == 0) {
795       if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
796          return true;
797       }
798       job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
799       if (job) {
800          USTORE store;
801          ua->send_msg("job=%s", job->name());
802          ua->send_msg("pool=%s", job->pool->name());
803          ua->send_msg("messages=%s", job->messages->name());
804          ua->send_msg("client=%s", job->client->name());
805          get_job_storage(&store, job, NULL);
806          ua->send_msg("storage=%s", store.store->name());
807          ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
808          ua->send_msg("level=%s", level_to_str(job->JobLevel));
809          ua->send_msg("type=%s", job_type_to_str(job->JobType));
810          ua->send_msg("fileset=%s", job->fileset->name());
811          ua->send_msg("enabled=%d", job->enabled);
812          ua->send_msg("catalog=%s", job->client->catalog->name());
813       }
814    } 
815    /* Client defaults */
816    else if (strcmp(ua->argk[1], "client") == 0) {
817       if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
818          return true;   
819       }
820       client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
821       if (client) {
822          ua->send_msg("client=%s", client->name());
823          ua->send_msg("address=%s", client->address);
824          ua->send_msg("fdport=%d", client->FDport);
825          ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
826          ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
827          ua->send_msg("autoprune=%d", client->AutoPrune);
828          ua->send_msg("catalog=%s", client->catalog->name());
829       }
830    }
831    /* Storage defaults */
832    else if (strcmp(ua->argk[1], "storage") == 0) {
833       if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
834          return true;
835       }
836       storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
837       DEVICE *device;
838       if (storage) {
839          ua->send_msg("storage=%s", storage->name());
840          ua->send_msg("address=%s", storage->address);
841          ua->send_msg("enabled=%d", storage->enabled);
842          ua->send_msg("media_type=%s", storage->media_type);
843          ua->send_msg("sdport=%d", storage->SDport);
844          device = (DEVICE *)storage->device->first();
845          ua->send_msg("device=%s", device->name());
846          if (storage->device->size() > 1) {
847             while ((device = (DEVICE *)storage->device->next())) {
848                ua->send_msg(",%s", device->name());
849             }
850          }
851       }
852    }
853    /* Pool defaults */
854    else if (strcmp(ua->argk[1], "pool") == 0) {
855       if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
856          return true;
857       }
858       pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
859       if (pool) {
860          ua->send_msg("pool=%s", pool->name());
861          ua->send_msg("pool_type=%s", pool->pool_type);
862          ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
863          ua->send_msg("use_volume_once=%d", pool->use_volume_once);
864          ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
865          ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
866          ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
867          ua->send_msg("max_volumes=%d", pool->max_volumes);
868          ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
869          ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
870          ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
871          ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
872          ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
873          ua->send_msg("auto_prune=%d", pool->AutoPrune);
874          ua->send_msg("recycle=%d", pool->Recycle);
875       }
876    }
877    return true;
878 }