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