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