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