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