]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_dotcmds.c
Remove ifdeffing that turned off JS_Warning status -- must have been missed test...
[bacula/bacula] / bacula / src / dird / ua_dotcmds.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2011 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 three of the GNU Affero 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 Affero 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  */
39
40 #include "bacula.h"
41 #include "dird.h"
42 #include "cats/bvfs.h"
43 #include "findlib/find.h"
44
45 /* Imported variables */
46 extern struct s_jl joblevels[];
47 extern struct s_jt jobtypes[];
48
49 /* Imported functions */
50 extern void do_messages(UAContext *ua, const char *cmd);
51 extern int quit_cmd(UAContext *ua, const char *cmd);
52 extern int qhelp_cmd(UAContext *ua, const char *cmd);
53 extern bool dot_status_cmd(UAContext *ua, const char *cmd);
54
55
56 /* Forward referenced functions */
57 static bool admin_cmds(UAContext *ua, const char *cmd);
58 static bool jobscmd(UAContext *ua, const char *cmd);
59 static bool filesetscmd(UAContext *ua, const char *cmd);
60 static bool clientscmd(UAContext *ua, const char *cmd);
61 static bool msgscmd(UAContext *ua, const char *cmd);
62 static bool poolscmd(UAContext *ua, const char *cmd);
63 static bool storagecmd(UAContext *ua, const char *cmd);
64 static bool defaultscmd(UAContext *ua, const char *cmd);
65 static bool typescmd(UAContext *ua, const char *cmd);
66 static bool backupscmd(UAContext *ua, const char *cmd);
67 static bool levelscmd(UAContext *ua, const char *cmd);
68 static bool getmsgscmd(UAContext *ua, const char *cmd);
69 static bool volstatuscmd(UAContext *ua, const char *cmd);
70 static bool mediatypescmd(UAContext *ua, const char *cmd);
71 static bool locationscmd(UAContext *ua, const char *cmd);
72 static bool mediacmd(UAContext *ua, const char *cmd);
73 static bool aopcmd(UAContext *ua, const char *cmd);
74 static bool catalogscmd(UAContext *ua, const char *cmd);
75
76 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd);
77 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd);
78 static bool dot_bvfs_update(UAContext *ua, const char *cmd);
79 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd);
80 static bool dot_bvfs_versions(UAContext *ua, const char *cmd);
81 static bool dot_bvfs_restore(UAContext *ua, const char *cmd);
82 static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd);
83 static bool dot_bvfs_clear_cache(UAContext *ua, const char *cmd);
84
85 static bool api_cmd(UAContext *ua, const char *cmd);
86 static bool sql_cmd(UAContext *ua, const char *cmd);
87 static bool dot_quit_cmd(UAContext *ua, const char *cmd);
88 static bool dot_help_cmd(UAContext *ua, const char *cmd);
89 static int one_handler(void *ctx, int num_field, char **row);
90
91 struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help;const bool use_in_rs;};
92 static struct cmdstruct commands[] = { /* help */  /* can be used in runscript */
93  { NT_(".api"),        api_cmd,                  NULL,       false},
94  { NT_(".backups"),    backupscmd,               NULL,       false},
95  { NT_(".clients"),    clientscmd,               NULL,       true},
96  { NT_(".catalogs"),   catalogscmd,              NULL,       false},
97  { NT_(".defaults"),   defaultscmd,              NULL,       false},
98  { NT_(".die"),        admin_cmds,               NULL,       false},
99  { NT_(".dump"),       admin_cmds,               NULL,       false},
100  { NT_(".exit"),       admin_cmds,               NULL,       false},
101  { NT_(".filesets"),   filesetscmd,              NULL,       false},
102  { NT_(".help"),       dot_help_cmd,             NULL,       false},
103  { NT_(".jobs"),       jobscmd,                  NULL,       true},
104  { NT_(".levels"),     levelscmd,                NULL,       false},
105  { NT_(".messages"),   getmsgscmd,               NULL,       false},
106  { NT_(".msgs"),       msgscmd,                  NULL,       false},
107  { NT_(".pools"),      poolscmd,                 NULL,       true},
108  { NT_(".quit"),       dot_quit_cmd,             NULL,       false},
109  { NT_(".sql"),        sql_cmd,                  NULL,       false},
110  { NT_(".status"),     dot_status_cmd,           NULL,       false},
111  { NT_(".storage"),    storagecmd,               NULL,       true},
112  { NT_(".volstatus"),  volstatuscmd,             NULL,       true},
113  { NT_(".media"),      mediacmd,                 NULL,       true},
114  { NT_(".mediatypes"), mediatypescmd,            NULL,       true},
115  { NT_(".locations"),  locationscmd,             NULL,       true},
116  { NT_(".actiononpurge"),aopcmd,                 NULL,       true},
117  { NT_(".bvfs_lsdirs"), dot_bvfs_lsdirs,         NULL,       true},
118  { NT_(".bvfs_lsfiles"),dot_bvfs_lsfiles,        NULL,       true},
119  { NT_(".bvfs_update"), dot_bvfs_update,         NULL,       true},
120  { NT_(".bvfs_get_jobids"), dot_bvfs_get_jobids, NULL,       true},
121  { NT_(".bvfs_versions"), dot_bvfs_versions,     NULL,       true},
122  { NT_(".bvfs_restore"), dot_bvfs_restore,       NULL,       true},
123  { NT_(".bvfs_cleanup"), dot_bvfs_cleanup,       NULL,       true},
124  { NT_(".bvfs_clear_cache"),dot_bvfs_clear_cache,NULL,       false},
125  { NT_(".types"),      typescmd,                 NULL,       false}
126              };
127 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
128
129 /*
130  * Execute a command from the UA
131  */
132 bool do_a_dot_command(UAContext *ua) 
133 {
134    int i;
135    int len;
136    bool ok = false;
137    bool found = false;
138    BSOCK *user = ua->UA_sock;
139
140    Dmsg1(1400, "Dot command: %s\n", user->msg);
141    if (ua->argc == 0) {
142       return false;
143    }
144
145    len = strlen(ua->argk[0]);
146    if (len == 1) {
147       if (ua->api) user->signal(BNET_CMD_BEGIN);
148       if (ua->api) user->signal(BNET_CMD_OK);
149       return true;                    /* no op */
150    }
151    for (i=0; i<comsize; i++) {     /* search for command */
152       if (strncasecmp(ua->argk[0],  _(commands[i].key), len) == 0) {
153          /* Check if this command is authorized in RunScript */
154          if (ua->runscript && !commands[i].use_in_rs) {
155             ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
156             break;
157          }
158          bool gui = ua->gui;
159          /* Check if command permitted, but "quit" is always OK */
160          if (strcmp(ua->argk[0], NT_(".quit")) != 0 &&
161              !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
162             break;
163          }
164          Dmsg1(100, "Cmd: %s\n", ua->cmd);
165          ua->gui = true;
166          if (ua->api) user->signal(BNET_CMD_BEGIN);
167          ok = (*commands[i].func)(ua, ua->cmd);   /* go execute command */
168          if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
169          ua->gui = gui;
170          found = true;
171          break;
172       }
173    }
174    if (!found) {
175       ua->error_msg("%s%s", ua->argk[0], _(": is an invalid command.\n"));
176       ok = false;
177    }
178    return ok;
179 }
180
181 static bool dot_bvfs_update(UAContext *ua, const char *cmd)
182 {
183    if (!open_new_client_db(ua)) {
184       return 1;
185    }
186
187    int pos = find_arg_with_value(ua, "jobid");
188    if (pos != -1 && is_a_number_list(ua->argv[pos])) {
189       bvfs_update_path_hierarchy_cache(ua->jcr, ua->db, ua->argv[pos]);
190    } else {
191       /* update cache for all jobids */
192       bvfs_update_cache(ua->jcr, ua->db);
193    }
194    
195    close_db(ua);
196    return true;
197 }
198
199 static bool dot_bvfs_clear_cache(UAContext *ua, const char *cmd)
200 {
201    if (!open_new_client_db(ua)) {
202       return 1;
203    }
204
205    int pos = find_arg(ua, "yes");
206    if (pos != -1) {
207       Bvfs fs(ua->jcr, ua->db);
208       fs.clear_cache();
209       ua->info_msg("OK\n");
210    } 
211    close_db(ua);
212    return true;
213 }
214
215 static int bvfs_result_handler(void *ctx, int fields, char **row)
216 {
217    UAContext *ua = (UAContext *)ctx;
218    struct stat statp;
219    int32_t LinkFI;
220    char *fileid=row[BVFS_FileId];
221    char *lstat=row[BVFS_LStat];
222    char *jobid=row[BVFS_JobId];
223    
224    char empty[] = "A A A A A A A A A A A A A A";
225    char zero[] = "0";
226
227    /* We need to deal with non existant path */
228    if (!fileid || !is_a_number(fileid)) {
229       lstat = empty;
230       jobid = zero;
231       fileid = zero;
232    }
233
234    memset(&statp, 0, sizeof(struct stat));
235    decode_stat(lstat, &statp, sizeof(statp), &LinkFI);
236
237    Dmsg1(100, "type=%s\n", row[0]);
238    if (bvfs_is_dir(row)) {
239       char *path = bvfs_basename_dir(row[BVFS_Name]);
240       ua->send_msg("%s\t0\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], fileid,
241                    jobid, lstat, path);
242
243    } else if (bvfs_is_version(row)) {
244       ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
245                    row[BVFS_FilenameId], fileid, jobid,
246                    lstat, row[BVFS_Md5], row[BVFS_VolName], 
247                    row[BVFS_VolInchanger]);
248
249    } else if (bvfs_is_file(row)) {
250       ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
251                    row[BVFS_FilenameId], fileid, jobid,
252                    lstat, row[BVFS_Name]);
253    }
254
255    return 0;
256 }
257
258 static bool bvfs_parse_arg_version(UAContext *ua,
259                                    char **client,
260                                    DBId_t *fnid, 
261                                    bool *versions, 
262                                    bool *copies)
263 {
264    *fnid=0;
265    *client=NULL;
266    *versions=false;
267    *copies=false;
268
269    for (int i=1; i<ua->argc; i++) {
270       if (fnid && strcasecmp(ua->argk[i], NT_("fnid")) == 0) {
271          if (is_a_number(ua->argv[i])) {
272             *fnid = str_to_int64(ua->argv[i]);
273          }
274       }
275
276       if (strcasecmp(ua->argk[i], NT_("client")) == 0) {
277          *client = ua->argv[i];
278       }
279
280       if (copies && strcasecmp(ua->argk[i], NT_("copies")) == 0) {
281          *copies = true;
282       }
283
284       if (versions && strcasecmp(ua->argk[i], NT_("versions")) == 0) {
285          *versions = true;
286       }
287    }
288    return (*client && *fnid > 0);
289 }
290
291 static bool bvfs_parse_arg(UAContext *ua, 
292                            DBId_t *pathid, char **path, char **jobid,
293                            char **username,
294                            int *limit, int *offset)
295 {
296    *pathid=0;
297    *limit=2000;
298    *offset=0;
299    *path=NULL;
300    *jobid=NULL;
301    *username=NULL;
302
303    for (int i=1; i<ua->argc; i++) {
304       if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
305          if (is_a_number(ua->argv[i])) {
306             *pathid = str_to_int64(ua->argv[i]);
307          }
308       }
309
310       if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
311          *path = ua->argv[i];
312       }
313
314       if (strcasecmp(ua->argk[i], NT_("username")) == 0) {
315          *username = ua->argv[i];
316       }
317       
318       if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
319          if (is_a_number_list(ua->argv[i])) {
320             *jobid = ua->argv[i];
321          }
322       }
323
324       if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
325          if (is_a_number(ua->argv[i])) {
326             *limit = str_to_int64(ua->argv[i]);
327          }
328       }
329
330       if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
331          if (is_a_number(ua->argv[i])) {
332             *offset = str_to_int64(ua->argv[i]);
333          }
334       }
335    }
336
337    if (!((*pathid || *path) && *jobid)) {
338       return false;
339    }
340
341    if (!open_client_db(ua)) {
342       return false;
343    }
344
345    return true;
346 }
347
348 /* .bvfs_cleanup path=b2XXXXX
349  */
350 static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd)
351 {
352    int i;
353    if ((i = find_arg_with_value(ua, "path")) >= 0) {
354       open_client_db(ua);
355       Bvfs fs(ua->jcr, ua->db);
356       fs.drop_restore_list(ua->argv[i]);
357    }
358    return true;
359 }
360
361 /* .bvfs_restore path=b2XXXXX jobid=1,2 fileid=1,2 dirid=1,2 hardlink=1,2,3,4
362  */
363 static bool dot_bvfs_restore(UAContext *ua, const char *cmd)
364 {
365    DBId_t pathid=0;
366    int limit=2000, offset=0, i;
367    char *path=NULL, *jobid=NULL, *username=NULL;
368    char *empty = (char *)"";
369    char *fileid, *dirid, *hardlink;
370    fileid = dirid = hardlink = empty;
371
372    if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
373                        &limit, &offset))
374    {
375       ua->error_msg("Can't find jobid, pathid or path argument\n");
376       return true;              /* not enough param */
377    }
378
379    Bvfs fs(ua->jcr, ua->db);
380    fs.set_username(username);
381    fs.set_jobids(jobid);
382
383    if ((i = find_arg_with_value(ua, "fileid")) >= 0) {
384       fileid = ua->argv[i];
385    }
386    if ((i = find_arg_with_value(ua, "dirid")) >= 0) {
387       dirid = ua->argv[i];
388    }
389    if ((i = find_arg_with_value(ua, "hardlink")) >= 0) {
390       hardlink = ua->argv[i];
391    }
392
393    if (fs.compute_restore_list(fileid, dirid, hardlink, path)) {
394       ua->send_msg("OK\n");
395    } else {
396       ua->error_msg("Can't create restore list\n");
397    }
398    return true;
399 }
400
401 /* 
402  * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
403  * .bvfs_lsfiles jobid=1,2,3,4 path=/
404  */
405 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
406 {
407    DBId_t pathid=0;
408    int limit=2000, offset=0;
409    char *path=NULL, *jobid=NULL, *username=NULL;
410    char *pattern=NULL;
411    int i;
412
413    if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
414                        &limit, &offset))
415    {
416       ua->error_msg("Can't find jobid, pathid or path argument\n");
417       return true;              /* not enough param */
418    }
419    if ((i = find_arg_with_value(ua, "pattern")) >= 0) {
420       pattern = ua->argv[i];
421    }
422
423    Bvfs fs(ua->jcr, ua->db);
424    fs.set_username(username);
425    fs.set_jobids(jobid);   
426    fs.set_handler(bvfs_result_handler, ua);
427    fs.set_limit(limit);
428    if (pattern) {
429       fs.set_pattern(pattern);
430    }
431    if (pathid) {
432       fs.ch_dir(pathid);
433    } else {
434       fs.ch_dir(path);
435    }
436    
437    fs.set_offset(offset);
438
439    fs.ls_files();
440
441    return true;
442 }
443
444 /* 
445  * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
446  * .bvfs_lsdirs jobid=1,2,3,4 path=/
447  * .bvfs_lsdirs jobid=1,2,3,4 path=
448  */
449 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
450 {
451    DBId_t pathid=0;
452    int limit=2000, offset=0;
453    char *path=NULL, *jobid=NULL, *username=NULL;
454
455    if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
456                        &limit, &offset))
457    {
458       ua->error_msg("Can't find jobid, pathid or path argument\n");
459       return true;              /* not enough param */
460    }
461
462    Bvfs fs(ua->jcr, ua->db);
463    fs.set_username(username);
464    fs.set_jobids(jobid);   
465    fs.set_limit(limit);
466    fs.set_handler(bvfs_result_handler, ua);
467
468    if (pathid) {
469       fs.ch_dir(pathid);
470    } else {
471       fs.ch_dir(path);
472    }
473
474    fs.set_offset(offset);
475
476    fs.ls_special_dirs();
477    fs.ls_dirs();
478
479    return true;
480 }
481
482 /* 
483  * .bvfs_versions jobid=x fnid=10 pathid=10 copies versions
484  * (jobid isn't used)
485  */
486 static bool dot_bvfs_versions(UAContext *ua, const char *cmd)
487 {
488    DBId_t pathid=0, fnid=0;
489    int limit=2000, offset=0;
490    char *path=NULL, *jobid=NULL, *client=NULL, *username=NULL;
491    bool copies=false, versions=false;
492    if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
493                        &limit, &offset))
494    {
495       ua->error_msg("Can't find jobid, pathid or path argument\n");
496       return true;              /* not enough param */
497    }
498
499    if (!bvfs_parse_arg_version(ua, &client, &fnid, &versions, &copies))
500    {
501       ua->error_msg("Can't find client or fnid argument\n");
502       return true;              /* not enough param */
503    }
504
505    Bvfs fs(ua->jcr, ua->db);
506    fs.set_limit(limit);
507    fs.set_see_all_versions(versions);
508    fs.set_see_copies(copies);
509    fs.set_handler(bvfs_result_handler, ua);
510    fs.set_offset(offset);
511    fs.get_all_file_versions(pathid, fnid, client);
512
513    return true;
514 }
515
516 /* .bvfs_get_jobids jobid=1
517  *  -> returns needed jobids to restore
518  * .bvfs_get_jobids jobid=1 all
519  *  -> returns needed jobids to restore with all filesets a JobId=1 time
520  */
521 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd)
522 {
523    JOB_DBR jr;
524    db_list_ctx jobids, tempids;
525    int pos;
526    char ed1[50];
527    POOL_MEM query;
528    dbid_list ids;               /* Store all FileSetIds for this client */
529
530    if (!open_client_db(ua)) {
531       return true;
532    }
533
534    memset(&jr, 0, sizeof(JOB_DBR));
535    if ((pos = find_arg_with_value(ua, "jobid")) >= 0) {
536       jr.JobId = str_to_int64(ua->argv[pos]);
537    }
538
539    if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
540       ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"),
541                     ua->cmd, db_strerror(ua->db));
542       return true;
543    }
544
545    /* If we have the "all" option, we do a search on all defined fileset
546     * for this client
547     */
548    if (find_arg(ua, "all") > 0) {
549       edit_int64(jr.ClientId, ed1);
550       Mmsg(query, uar_sel_filesetid, ed1);
551       db_get_query_dbids(ua->jcr, ua->db, query, ids);
552    } else {
553       ids.num_ids = 1;
554       ids.DBId[0] = jr.FileSetId;
555    }
556
557    jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
558
559    /* Foreach different FileSet, we build a restore jobid list */
560    for (int i=0; i < ids.num_ids; i++) {
561       jr.FileSetId = ids.DBId[i];
562       if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &tempids)) {
563          return true;
564       }
565       jobids.add(tempids);
566    }
567
568    ua->send_msg("%s\n", jobids.list);
569    return true;
570 }
571
572 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
573 {
574    quit_cmd(ua, cmd);
575    return true;
576 }
577
578 static bool dot_help_cmd(UAContext *ua, const char *cmd)
579 {
580    qhelp_cmd(ua, cmd);
581    return true;
582 }
583
584 static bool getmsgscmd(UAContext *ua, const char *cmd)
585 {
586    if (console_msg_pending) {
587       do_messages(ua, cmd);
588    }
589    return 1;
590 }
591
592 #ifdef DEVELOPER
593 static void do_storage_cmd(UAContext *ua, STORE *store, const char *cmd)
594 {
595    BSOCK *sd;
596    JCR *jcr = ua->jcr;
597    USTORE lstore;
598    
599    lstore.store = store;
600    pm_strcpy(lstore.store_source, _("unknown source"));
601    set_wstorage(jcr, &lstore);
602    /* Try connecting for up to 15 seconds */
603    ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
604       store->name(), store->address, store->SDport);
605    if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
606       ua->error_msg(_("Failed to connect to Storage daemon.\n"));
607       return;
608    }
609    Dmsg0(120, _("Connected to storage daemon\n"));
610    sd = jcr->store_bsock;
611    sd->fsend("%s", cmd);
612    if (sd->recv() >= 0) {
613       ua->send_msg("%s", sd->msg);
614    }
615    sd->signal(BNET_TERMINATE);
616    sd->close();
617    jcr->store_bsock = NULL;
618    return;
619 }
620
621 static void do_client_cmd(UAContext *ua, CLIENT *client, const char *cmd)
622 {
623    BSOCK *fd;
624
625    /* Connect to File daemon */
626
627    ua->jcr->client = client;
628    /* Try to connect for 15 seconds */
629    ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
630       client->name(), client->address, client->FDport);
631    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
632       ua->error_msg(_("Failed to connect to Client.\n"));
633       return;
634    }
635    Dmsg0(120, "Connected to file daemon\n");
636    fd = ua->jcr->file_bsock;
637    fd->fsend("%s", cmd);
638    if (fd->recv() >= 0) {
639       ua->send_msg("%s", fd->msg);
640    }
641    fd->signal(BNET_TERMINATE);
642    fd->close();
643    ua->jcr->file_bsock = NULL;
644    return;
645 }
646
647 /*
648  *   .die (seg fault)
649  *   .dump (sm_dump)
650  *   .exit (no arg => .quit)
651  */
652 static bool admin_cmds(UAContext *ua, const char *cmd)
653 {
654    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
655    STORE *store=NULL;
656    CLIENT *client=NULL;
657    bool dir=false;
658    bool do_deadlock=false;
659    const char *remote_cmd;
660    int i;
661    JCR *jcr = NULL;
662    int a;
663    if (strncmp(ua->argk[0], ".die", 4) == 0) {
664       if (find_arg(ua, "deadlock") > 0) {
665          do_deadlock = true;
666          remote_cmd = ".die deadlock";
667       } else {
668          remote_cmd = ".die";
669       }
670    } else if (strncmp(ua->argk[0], ".dump", 5) == 0) {
671       remote_cmd = "sm_dump";
672    } else if (strncmp(ua->argk[0], ".exit", 5) == 0) {
673       remote_cmd = "exit";
674    } else {
675       ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
676       return true;
677    }
678    /* General debug? */
679    for (i=1; i<ua->argc; i++) {
680       if (strcasecmp(ua->argk[i], "dir") == 0 ||
681           strcasecmp(ua->argk[i], "director") == 0) {
682          dir = true;
683       }
684       if (strcasecmp(ua->argk[i], "client") == 0 ||
685           strcasecmp(ua->argk[i], "fd") == 0) {
686          client = NULL;
687          if (ua->argv[i]) {
688             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
689          }
690          if (!client) {
691             client = select_client_resource(ua);
692          }
693       }
694    
695       if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
696           strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
697           strcasecmp(ua->argk[i], NT_("sd")) == 0) {
698          store = NULL;
699          if (ua->argv[i]) {
700             store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
701          }
702          if (!store) {
703             store = get_storage_resource(ua, false/*no default*/);
704          }
705       }
706    }
707
708    if (!dir && !store && !client) {
709       /*
710        * We didn't find an appropriate keyword above, so
711        * prompt the user.
712        */
713       start_prompt(ua, _("Available daemons are: \n"));
714       add_prompt(ua, _("Director"));
715       add_prompt(ua, _("Storage"));
716       add_prompt(ua, _("Client"));
717       switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
718       case 0:                         /* Director */
719          dir=true;
720          break;
721       case 1:
722          store = get_storage_resource(ua, false/*no default*/);
723          break;
724       case 2:
725          client = select_client_resource(ua);
726          break;
727       default:
728          break;
729       }
730    }
731
732    if (store) {
733       do_storage_cmd(ua, store, remote_cmd);
734    }
735
736    if (client) {
737       do_client_cmd(ua, client, remote_cmd);
738    }
739
740    if (dir) {
741       if (strncmp(remote_cmd, ".die", 4) == 0) {
742          if (do_deadlock) {
743             ua->send_msg(_("The Director will generate a deadlock.\n"));
744             P(mutex); 
745             P(mutex);
746          }
747          ua->send_msg(_("The Director will segment fault.\n"));
748          a = jcr->JobId; /* ref NULL pointer */
749          jcr->JobId = 1000; /* another ref NULL pointer */
750          jcr->JobId = a;
751
752       } else if (strncmp(remote_cmd, ".dump", 5) == 0) {
753          sm_dump(false, true);
754       } else if (strncmp(remote_cmd, ".exit", 5) == 0) {
755          dot_quit_cmd(ua, cmd);
756       }
757    }
758
759    return true;
760 }
761
762 #else
763
764 /*
765  * Dummy routine for non-development version
766  */
767 static bool admin_cmds(UAContext *ua, const char *cmd)
768 {
769    ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
770    return true;
771 }
772
773 #endif
774
775 /* 
776  * Can use an argument to filter on JobType
777  * .jobs [type=B]
778  */
779 static bool jobscmd(UAContext *ua, const char *cmd)
780 {
781    JOB *job;
782    uint32_t type = 0;
783    int pos;
784    if ((pos = find_arg_with_value(ua, "type")) >= 0) {
785       type = ua->argv[pos][0];
786    }
787    LockRes();
788    foreach_res(job, R_JOB) {
789       if (!type || type == job->JobType) {
790          if (acl_access_ok(ua, Job_ACL, job->name())) {
791             ua->send_msg("%s\n", job->name());
792          }
793       }
794    }
795    UnlockRes();
796    return true;
797 }
798
799 static bool filesetscmd(UAContext *ua, const char *cmd)
800 {
801    FILESET *fs;
802    LockRes();
803    foreach_res(fs, R_FILESET) {
804       if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
805          ua->send_msg("%s\n", fs->name());
806       }
807    }
808    UnlockRes();
809    return true;
810 }
811
812 static bool catalogscmd(UAContext *ua, const char *cmd)
813 {
814    CAT *cat;
815    LockRes();
816    foreach_res(cat, R_CATALOG) {
817       if (acl_access_ok(ua, Catalog_ACL, cat->name())) {
818          ua->send_msg("%s\n", cat->name());
819       }
820    }
821    UnlockRes();
822    return true;
823 }
824
825 static bool clientscmd(UAContext *ua, const char *cmd)
826 {
827    CLIENT *client;       
828    LockRes();
829    foreach_res(client, R_CLIENT) {
830       if (acl_access_ok(ua, Client_ACL, client->name())) {
831          ua->send_msg("%s\n", client->name());
832       }
833    }
834    UnlockRes();
835    return true;
836 }
837
838 static bool msgscmd(UAContext *ua, const char *cmd)
839 {
840    MSGS *msgs = NULL;
841    LockRes();
842    foreach_res(msgs, R_MSGS) {
843       ua->send_msg("%s\n", msgs->name());
844    }
845    UnlockRes();
846    return true;
847 }
848
849 static bool poolscmd(UAContext *ua, const char *cmd)
850 {
851    POOL *pool;       
852    LockRes();
853    foreach_res(pool, R_POOL) {
854       if (acl_access_ok(ua, Pool_ACL, pool->name())) {
855          ua->send_msg("%s\n", pool->name());
856       }
857    }
858    UnlockRes();
859    return true;
860 }
861
862 static bool storagecmd(UAContext *ua, const char *cmd)
863 {
864    STORE *store;
865    LockRes();
866    foreach_res(store, R_STORAGE) {
867       if (acl_access_ok(ua, Storage_ACL, store->name())) {
868          ua->send_msg("%s\n", store->name());
869       }
870    }
871    UnlockRes();
872    return true;
873 }
874
875 static bool aopcmd(UAContext *ua, const char *cmd)
876 {
877    ua->send_msg("None\n");
878    ua->send_msg("Truncate\n");
879    return true;
880 }
881
882 static bool typescmd(UAContext *ua, const char *cmd)
883 {
884    ua->send_msg("Backup\n");
885    ua->send_msg("Restore\n");
886    ua->send_msg("Admin\n");
887    ua->send_msg("Verify\n");
888    ua->send_msg("Migrate\n");
889    ua->send_msg("Copy\n");
890    return true;
891 }
892
893 /*
894  * If this command is called, it tells the director that we
895  *  are a program that wants a sort of API, and hence,
896  *  we will probably suppress certain output, include more
897  *  error codes, and most of all send back a good number
898  *  of new signals that indicate whether or not the command
899  *  succeeded.
900  */
901 static bool api_cmd(UAContext *ua, const char *cmd)
902 {
903    if (ua->argc == 2) {
904       ua->api = atoi(ua->argk[1]);
905    } else {
906       ua->api = 1;
907    }
908    return true;
909 }
910
911 static int client_backups_handler(void *ctx, int num_field, char **row)
912 {
913    UAContext *ua = (UAContext *)ctx;
914    ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
915       row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
916    return 0;
917 }
918
919 /*
920  * Return the backups for this client 
921  *
922  *  .backups client=xxx fileset=yyy
923  *
924  */
925 static bool backupscmd(UAContext *ua, const char *cmd)
926 {
927    if (!open_client_db(ua)) {
928       return true;
929    }
930    if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 || 
931        strcmp(ua->argk[2], "fileset") != 0) {
932       return true;
933    }
934    if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
935        !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
936       ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
937       return true;
938    }
939    Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
940    if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
941       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
942       return true;
943    }
944    return true;
945 }
946
947 static int sql_handler(void *ctx, int num_field, char **row)
948 {
949    UAContext *ua = (UAContext *)ctx;
950    POOL_MEM rows(PM_MESSAGE);
951
952    /* Check for nonsense */
953    if (num_field == 0 || row == NULL || row[0] == NULL) {
954       return 0;                       /* nothing returned */
955    }
956    for (int i=0; num_field--; i++) {
957       if (i == 0) {
958          pm_strcpy(rows, NPRT(row[0]));
959       } else {
960          pm_strcat(rows, NPRT(row[i]));
961       }
962       pm_strcat(rows, "\t");
963    }
964    if (!rows.c_str() || !*rows.c_str()) {
965       ua->send_msg("\t");
966    } else {
967       ua->send_msg("%s", rows.c_str());
968    }
969    return 0;
970 }
971
972 static bool sql_cmd(UAContext *ua, const char *cmd)
973 {
974    int index;
975    if (!open_client_db(ua)) {
976       return true;
977    }
978    index = find_arg_with_value(ua, "query");
979    if (index < 0) {
980       ua->error_msg(_("query keyword not found.\n"));
981       return true;
982    }
983    if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
984       Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
985       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
986       return true;
987    }
988    return true;
989 }
990       
991 static int one_handler(void *ctx, int num_field, char **row)
992 {
993    UAContext *ua = (UAContext *)ctx;
994    ua->send_msg("%s\n", row[0]);
995    return 0;
996 }
997
998 static bool mediatypescmd(UAContext *ua, const char *cmd)
999 {
1000    if (!open_client_db(ua)) {
1001       return true;
1002    }
1003    if (!db_sql_query(ua->db, 
1004                   "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
1005                   one_handler, (void *)ua)) 
1006    {
1007       ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
1008    }
1009    return true;
1010 }
1011
1012 static bool mediacmd(UAContext *ua, const char *cmd)
1013 {
1014    if (!open_client_db(ua)) {
1015       return true;
1016    }
1017    if (!db_sql_query(ua->db, 
1018                   "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
1019                   one_handler, (void *)ua)) 
1020    {
1021       ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
1022    }
1023    return true;
1024 }
1025
1026 static bool locationscmd(UAContext *ua, const char *cmd)
1027 {
1028    if (!open_client_db(ua)) {
1029       return true;
1030    }
1031    if (!db_sql_query(ua->db, 
1032                   "SELECT DISTINCT Location FROM Location ORDER BY Location",
1033                   one_handler, (void *)ua)) 
1034    {
1035       ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
1036    }
1037    return true;
1038 }
1039
1040 static bool levelscmd(UAContext *ua, const char *cmd)
1041 {
1042    int i;
1043    /* Note some levels are blank, which means none is needed */
1044    if (ua->argc == 1) {
1045       for (i=0; joblevels[i].level_name; i++) {
1046          if (joblevels[i].level_name[0] != ' ') {
1047             ua->send_msg("%s\n", joblevels[i].level_name);
1048          }
1049       }
1050    } else if (ua->argc == 2) {
1051       int jobtype = 0;
1052       /* Assume that first argument is the Job Type */
1053       for (i=0; jobtypes[i].type_name; i++) {
1054          if (strcasecmp(ua->argk[1], jobtypes[i].type_name) == 0) {
1055             jobtype = jobtypes[i].job_type;
1056             break;
1057          }
1058       }
1059       for (i=0; joblevels[i].level_name; i++) {
1060          if ((joblevels[i].job_type == jobtype) && (joblevels[i].level_name[0] != ' ')) {
1061             ua->send_msg("%s\n", joblevels[i].level_name);
1062          }
1063       }
1064    }
1065
1066    return true;
1067 }
1068
1069 static bool volstatuscmd(UAContext *ua, const char *cmd)
1070 {
1071    ua->send_msg("Append\n");
1072    ua->send_msg("Full\n");
1073    ua->send_msg("Used\n");
1074    ua->send_msg("Recycle\n");
1075    ua->send_msg("Purged\n");
1076    ua->send_msg("Cleaning\n");
1077    ua->send_msg("Error\n");
1078    return true;
1079 }
1080
1081 /*
1082  * Return default values for a job
1083  */
1084 static bool defaultscmd(UAContext *ua, const char *cmd)
1085 {
1086    JOB *job;
1087    CLIENT *client;
1088    STORE *storage;
1089    POOL *pool;
1090    char ed1[50];
1091
1092    if (ua->argc != 2 || !ua->argv[1]) {
1093       return true;
1094    }
1095
1096    /* Job defaults */   
1097    if (strcmp(ua->argk[1], "job") == 0) {
1098       if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
1099          return true;
1100       }
1101       job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
1102       if (job) {
1103          USTORE store;
1104          ua->send_msg("job=%s", job->name());
1105          ua->send_msg("pool=%s", job->pool->name());
1106          ua->send_msg("messages=%s", job->messages->name());
1107          ua->send_msg("client=%s", job->client->name());
1108          get_job_storage(&store, job, NULL);
1109          ua->send_msg("storage=%s", store.store->name());
1110          ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
1111          ua->send_msg("level=%s", level_to_str(job->JobLevel));
1112          ua->send_msg("type=%s", job_type_to_str(job->JobType));
1113          ua->send_msg("fileset=%s", job->fileset->name());
1114          ua->send_msg("enabled=%d", job->enabled);
1115          ua->send_msg("catalog=%s", job->client->catalog->name());
1116       }
1117    } 
1118    /* Client defaults */
1119    else if (strcmp(ua->argk[1], "client") == 0) {
1120       if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
1121          return true;   
1122       }
1123       client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
1124       if (client) {
1125          ua->send_msg("client=%s", client->name());
1126          ua->send_msg("address=%s", client->address);
1127          ua->send_msg("fdport=%d", client->FDport);
1128          ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
1129          ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
1130          ua->send_msg("autoprune=%d", client->AutoPrune);
1131          ua->send_msg("catalog=%s", client->catalog->name());
1132       }
1133    }
1134    /* Storage defaults */
1135    else if (strcmp(ua->argk[1], "storage") == 0) {
1136       if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
1137          return true;
1138       }
1139       storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
1140       DEVICE *device;
1141       if (storage) {
1142          ua->send_msg("storage=%s", storage->name());
1143          ua->send_msg("address=%s", storage->address);
1144          ua->send_msg("enabled=%d", storage->enabled);
1145          ua->send_msg("media_type=%s", storage->media_type);
1146          ua->send_msg("sdport=%d", storage->SDport);
1147          device = (DEVICE *)storage->device->first();
1148          ua->send_msg("device=%s", device->name());
1149          if (storage->device->size() > 1) {
1150             while ((device = (DEVICE *)storage->device->next())) {
1151                ua->send_msg(",%s", device->name());
1152             }
1153          }
1154       }
1155    }
1156    /* Pool defaults */
1157    else if (strcmp(ua->argk[1], "pool") == 0) {
1158       if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
1159          return true;
1160       }
1161       pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
1162       if (pool) {
1163          ua->send_msg("pool=%s", pool->name());
1164          ua->send_msg("pool_type=%s", pool->pool_type);
1165          ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
1166          ua->send_msg("use_volume_once=%d", pool->use_volume_once);
1167          ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
1168          ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
1169          ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
1170          ua->send_msg("max_volumes=%d", pool->max_volumes);
1171          ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
1172          ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
1173          ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
1174          ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
1175          ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
1176          ua->send_msg("auto_prune=%d", pool->AutoPrune);
1177          ua->send_msg("recycle=%d", pool->Recycle);
1178          ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1));
1179          ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1));
1180       }
1181    }
1182    return true;
1183 }