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