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