]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_dotcmds.c
Add error message to .bvfs_clear_cache command
[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    /* If we have the "all" option, we do a search on all defined fileset
549     * for this client
550     */
551    if (find_arg(ua, "all") > 0) {
552       edit_int64(jr.ClientId, ed1);
553       Mmsg(query, uar_sel_filesetid, ed1);
554       db_get_query_dbids(ua->jcr, ua->db, query, ids);
555    } else {
556       ids.num_ids = 1;
557       ids.DBId[0] = jr.FileSetId;
558    }
559
560    jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
561
562    /* Foreach different FileSet, we build a restore jobid list */
563    for (int i=0; i < ids.num_ids; i++) {
564       jr.FileSetId = ids.DBId[i];
565       if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &tempids)) {
566          return true;
567       }
568       jobids.add(tempids);
569    }
570
571    ua->send_msg("%s\n", jobids.list);
572    return true;
573 }
574
575 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
576 {
577    quit_cmd(ua, cmd);
578    return true;
579 }
580
581 static bool dot_help_cmd(UAContext *ua, const char *cmd)
582 {
583    qhelp_cmd(ua, cmd);
584    return true;
585 }
586
587 static bool getmsgscmd(UAContext *ua, const char *cmd)
588 {
589    if (console_msg_pending) {
590       do_messages(ua, cmd);
591    }
592    return 1;
593 }
594
595 #ifdef DEVELOPER
596 static void do_storage_cmd(UAContext *ua, STORE *store, const char *cmd)
597 {
598    BSOCK *sd;
599    JCR *jcr = ua->jcr;
600    USTORE lstore;
601    
602    lstore.store = store;
603    pm_strcpy(lstore.store_source, _("unknown source"));
604    set_wstorage(jcr, &lstore);
605    /* Try connecting for up to 15 seconds */
606    ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
607       store->name(), store->address, store->SDport);
608    if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
609       ua->error_msg(_("Failed to connect to Storage daemon.\n"));
610       return;
611    }
612    Dmsg0(120, _("Connected to storage daemon\n"));
613    sd = jcr->store_bsock;
614    sd->fsend("%s", cmd);
615    if (sd->recv() >= 0) {
616       ua->send_msg("%s", sd->msg);
617    }
618    sd->signal(BNET_TERMINATE);
619    sd->close();
620    jcr->store_bsock = NULL;
621    return;
622 }
623
624 static void do_client_cmd(UAContext *ua, CLIENT *client, const char *cmd)
625 {
626    BSOCK *fd;
627
628    /* Connect to File daemon */
629
630    ua->jcr->client = client;
631    /* Try to connect for 15 seconds */
632    ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
633       client->name(), client->address, client->FDport);
634    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
635       ua->error_msg(_("Failed to connect to Client.\n"));
636       return;
637    }
638    Dmsg0(120, "Connected to file daemon\n");
639    fd = ua->jcr->file_bsock;
640    fd->fsend("%s", cmd);
641    if (fd->recv() >= 0) {
642       ua->send_msg("%s", fd->msg);
643    }
644    fd->signal(BNET_TERMINATE);
645    fd->close();
646    ua->jcr->file_bsock = NULL;
647    return;
648 }
649
650 /*
651  *   .die (seg fault)
652  *   .dump (sm_dump)
653  *   .exit (no arg => .quit)
654  */
655 static bool admin_cmds(UAContext *ua, const char *cmd)
656 {
657    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
658    STORE *store=NULL;
659    CLIENT *client=NULL;
660    bool dir=false;
661    bool do_deadlock=false;
662    const char *remote_cmd;
663    int i;
664    JCR *jcr = NULL;
665    int a;
666    if (strncmp(ua->argk[0], ".die", 4) == 0) {
667       if (find_arg(ua, "deadlock") > 0) {
668          do_deadlock = true;
669          remote_cmd = ".die deadlock";
670       } else {
671          remote_cmd = ".die";
672       }
673    } else if (strncmp(ua->argk[0], ".dump", 5) == 0) {
674       remote_cmd = "sm_dump";
675    } else if (strncmp(ua->argk[0], ".exit", 5) == 0) {
676       remote_cmd = "exit";
677    } else {
678       ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
679       return true;
680    }
681    /* General debug? */
682    for (i=1; i<ua->argc; i++) {
683       if (strcasecmp(ua->argk[i], "dir") == 0 ||
684           strcasecmp(ua->argk[i], "director") == 0) {
685          dir = true;
686       }
687       if (strcasecmp(ua->argk[i], "client") == 0 ||
688           strcasecmp(ua->argk[i], "fd") == 0) {
689          client = NULL;
690          if (ua->argv[i]) {
691             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
692          }
693          if (!client) {
694             client = select_client_resource(ua);
695          }
696       }
697    
698       if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
699           strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
700           strcasecmp(ua->argk[i], NT_("sd")) == 0) {
701          store = NULL;
702          if (ua->argv[i]) {
703             store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
704          }
705          if (!store) {
706             store = get_storage_resource(ua, false/*no default*/);
707          }
708       }
709    }
710
711    if (!dir && !store && !client) {
712       /*
713        * We didn't find an appropriate keyword above, so
714        * prompt the user.
715        */
716       start_prompt(ua, _("Available daemons are: \n"));
717       add_prompt(ua, _("Director"));
718       add_prompt(ua, _("Storage"));
719       add_prompt(ua, _("Client"));
720       switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
721       case 0:                         /* Director */
722          dir=true;
723          break;
724       case 1:
725          store = get_storage_resource(ua, false/*no default*/);
726          break;
727       case 2:
728          client = select_client_resource(ua);
729          break;
730       default:
731          break;
732       }
733    }
734
735    if (store) {
736       do_storage_cmd(ua, store, remote_cmd);
737    }
738
739    if (client) {
740       do_client_cmd(ua, client, remote_cmd);
741    }
742
743    if (dir) {
744       if (strncmp(remote_cmd, ".die", 4) == 0) {
745          if (do_deadlock) {
746             ua->send_msg(_("The Director will generate a deadlock.\n"));
747             P(mutex); 
748             P(mutex);
749          }
750          ua->send_msg(_("The Director will segment fault.\n"));
751          a = jcr->JobId; /* ref NULL pointer */
752          jcr->JobId = 1000; /* another ref NULL pointer */
753          jcr->JobId = a;
754
755       } else if (strncmp(remote_cmd, ".dump", 5) == 0) {
756          sm_dump(false, true);
757       } else if (strncmp(remote_cmd, ".exit", 5) == 0) {
758          dot_quit_cmd(ua, cmd);
759       }
760    }
761
762    return true;
763 }
764
765 #else
766
767 /*
768  * Dummy routine for non-development version
769  */
770 static bool admin_cmds(UAContext *ua, const char *cmd)
771 {
772    ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
773    return true;
774 }
775
776 #endif
777
778 /* 
779  * Can use an argument to filter on JobType
780  * .jobs [type=B]
781  */
782 static bool jobscmd(UAContext *ua, const char *cmd)
783 {
784    JOB *job;
785    uint32_t type = 0;
786    int pos;
787    if ((pos = find_arg_with_value(ua, "type")) >= 0) {
788       type = ua->argv[pos][0];
789    }
790    LockRes();
791    foreach_res(job, R_JOB) {
792       if (!type || type == job->JobType) {
793          if (acl_access_ok(ua, Job_ACL, job->name())) {
794             ua->send_msg("%s\n", job->name());
795          }
796       }
797    }
798    UnlockRes();
799    return true;
800 }
801
802 static bool filesetscmd(UAContext *ua, const char *cmd)
803 {
804    FILESET *fs;
805    LockRes();
806    foreach_res(fs, R_FILESET) {
807       if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
808          ua->send_msg("%s\n", fs->name());
809       }
810    }
811    UnlockRes();
812    return true;
813 }
814
815 static bool catalogscmd(UAContext *ua, const char *cmd)
816 {
817    CAT *cat;
818    LockRes();
819    foreach_res(cat, R_CATALOG) {
820       if (acl_access_ok(ua, Catalog_ACL, cat->name())) {
821          ua->send_msg("%s\n", cat->name());
822       }
823    }
824    UnlockRes();
825    return true;
826 }
827
828 static bool clientscmd(UAContext *ua, const char *cmd)
829 {
830    CLIENT *client;       
831    LockRes();
832    foreach_res(client, R_CLIENT) {
833       if (acl_access_ok(ua, Client_ACL, client->name())) {
834          ua->send_msg("%s\n", client->name());
835       }
836    }
837    UnlockRes();
838    return true;
839 }
840
841 static bool msgscmd(UAContext *ua, const char *cmd)
842 {
843    MSGS *msgs = NULL;
844    LockRes();
845    foreach_res(msgs, R_MSGS) {
846       ua->send_msg("%s\n", msgs->name());
847    }
848    UnlockRes();
849    return true;
850 }
851
852 static bool poolscmd(UAContext *ua, const char *cmd)
853 {
854    POOL *pool;       
855    LockRes();
856    foreach_res(pool, R_POOL) {
857       if (acl_access_ok(ua, Pool_ACL, pool->name())) {
858          ua->send_msg("%s\n", pool->name());
859       }
860    }
861    UnlockRes();
862    return true;
863 }
864
865 static bool storagecmd(UAContext *ua, const char *cmd)
866 {
867    STORE *store;
868    LockRes();
869    foreach_res(store, R_STORAGE) {
870       if (acl_access_ok(ua, Storage_ACL, store->name())) {
871          ua->send_msg("%s\n", store->name());
872       }
873    }
874    UnlockRes();
875    return true;
876 }
877
878 static bool aopcmd(UAContext *ua, const char *cmd)
879 {
880    ua->send_msg("None\n");
881    ua->send_msg("Truncate\n");
882    return true;
883 }
884
885 static bool typescmd(UAContext *ua, const char *cmd)
886 {
887    ua->send_msg("Backup\n");
888    ua->send_msg("Restore\n");
889    ua->send_msg("Admin\n");
890    ua->send_msg("Verify\n");
891    ua->send_msg("Migrate\n");
892    ua->send_msg("Copy\n");
893    return true;
894 }
895
896 /*
897  * If this command is called, it tells the director that we
898  *  are a program that wants a sort of API, and hence,
899  *  we will probably suppress certain output, include more
900  *  error codes, and most of all send back a good number
901  *  of new signals that indicate whether or not the command
902  *  succeeded.
903  */
904 static bool api_cmd(UAContext *ua, const char *cmd)
905 {
906    if (ua->argc == 2) {
907       ua->api = atoi(ua->argk[1]);
908    } else {
909       ua->api = 1;
910    }
911    return true;
912 }
913
914 static int client_backups_handler(void *ctx, int num_field, char **row)
915 {
916    UAContext *ua = (UAContext *)ctx;
917    ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
918       row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
919    return 0;
920 }
921
922 /*
923  * Return the backups for this client 
924  *
925  *  .backups client=xxx fileset=yyy
926  *
927  */
928 static bool backupscmd(UAContext *ua, const char *cmd)
929 {
930    if (!open_client_db(ua)) {
931       return true;
932    }
933    if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 || 
934        strcmp(ua->argk[2], "fileset") != 0) {
935       return true;
936    }
937    if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
938        !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
939       ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
940       return true;
941    }
942    Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
943    if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
944       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
945       return true;
946    }
947    return true;
948 }
949
950 static int sql_handler(void *ctx, int num_field, char **row)
951 {
952    UAContext *ua = (UAContext *)ctx;
953    POOL_MEM rows(PM_MESSAGE);
954
955    /* Check for nonsense */
956    if (num_field == 0 || row == NULL || row[0] == NULL) {
957       return 0;                       /* nothing returned */
958    }
959    for (int i=0; num_field--; i++) {
960       if (i == 0) {
961          pm_strcpy(rows, NPRT(row[0]));
962       } else {
963          pm_strcat(rows, NPRT(row[i]));
964       }
965       pm_strcat(rows, "\t");
966    }
967    if (!rows.c_str() || !*rows.c_str()) {
968       ua->send_msg("\t");
969    } else {
970       ua->send_msg("%s", rows.c_str());
971    }
972    return 0;
973 }
974
975 static bool sql_cmd(UAContext *ua, const char *cmd)
976 {
977    int index;
978    if (!open_client_db(ua)) {
979       return true;
980    }
981    index = find_arg_with_value(ua, "query");
982    if (index < 0) {
983       ua->error_msg(_("query keyword not found.\n"));
984       return true;
985    }
986    if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
987       Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
988       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
989       return true;
990    }
991    return true;
992 }
993       
994 static int one_handler(void *ctx, int num_field, char **row)
995 {
996    UAContext *ua = (UAContext *)ctx;
997    ua->send_msg("%s\n", row[0]);
998    return 0;
999 }
1000
1001 static bool mediatypescmd(UAContext *ua, const char *cmd)
1002 {
1003    if (!open_client_db(ua)) {
1004       return true;
1005    }
1006    if (!db_sql_query(ua->db, 
1007                   "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
1008                   one_handler, (void *)ua)) 
1009    {
1010       ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
1011    }
1012    return true;
1013 }
1014
1015 static bool mediacmd(UAContext *ua, const char *cmd)
1016 {
1017    if (!open_client_db(ua)) {
1018       return true;
1019    }
1020    if (!db_sql_query(ua->db, 
1021                   "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
1022                   one_handler, (void *)ua)) 
1023    {
1024       ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
1025    }
1026    return true;
1027 }
1028
1029 static bool locationscmd(UAContext *ua, const char *cmd)
1030 {
1031    if (!open_client_db(ua)) {
1032       return true;
1033    }
1034    if (!db_sql_query(ua->db, 
1035                   "SELECT DISTINCT Location FROM Location ORDER BY Location",
1036                   one_handler, (void *)ua)) 
1037    {
1038       ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
1039    }
1040    return true;
1041 }
1042
1043 static bool levelscmd(UAContext *ua, const char *cmd)
1044 {
1045    int i;
1046    /* Note some levels are blank, which means none is needed */
1047    if (ua->argc == 1) {
1048       for (i=0; joblevels[i].level_name; i++) {
1049          if (joblevels[i].level_name[0] != ' ') {
1050             ua->send_msg("%s\n", joblevels[i].level_name);
1051          }
1052       }
1053    } else if (ua->argc == 2) {
1054       int jobtype = 0;
1055       /* Assume that first argument is the Job Type */
1056       for (i=0; jobtypes[i].type_name; i++) {
1057          if (strcasecmp(ua->argk[1], jobtypes[i].type_name) == 0) {
1058             jobtype = jobtypes[i].job_type;
1059             break;
1060          }
1061       }
1062       for (i=0; joblevels[i].level_name; i++) {
1063          if ((joblevels[i].job_type == jobtype) && (joblevels[i].level_name[0] != ' ')) {
1064             ua->send_msg("%s\n", joblevels[i].level_name);
1065          }
1066       }
1067    }
1068
1069    return true;
1070 }
1071
1072 static bool volstatuscmd(UAContext *ua, const char *cmd)
1073 {
1074    ua->send_msg("Append\n");
1075    ua->send_msg("Full\n");
1076    ua->send_msg("Used\n");
1077    ua->send_msg("Recycle\n");
1078    ua->send_msg("Purged\n");
1079    ua->send_msg("Cleaning\n");
1080    ua->send_msg("Error\n");
1081    return true;
1082 }
1083
1084 /*
1085  * Return default values for a job
1086  */
1087 static bool defaultscmd(UAContext *ua, const char *cmd)
1088 {
1089    JOB *job;
1090    CLIENT *client;
1091    STORE *storage;
1092    POOL *pool;
1093    char ed1[50];
1094
1095    if (ua->argc != 2 || !ua->argv[1]) {
1096       return true;
1097    }
1098
1099    /* Job defaults */   
1100    if (strcmp(ua->argk[1], "job") == 0) {
1101       if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
1102          return true;
1103       }
1104       job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
1105       if (job) {
1106          USTORE store;
1107          ua->send_msg("job=%s", job->name());
1108          ua->send_msg("pool=%s", job->pool->name());
1109          ua->send_msg("messages=%s", job->messages->name());
1110          ua->send_msg("client=%s", job->client->name());
1111          get_job_storage(&store, job, NULL);
1112          ua->send_msg("storage=%s", store.store->name());
1113          ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
1114          ua->send_msg("level=%s", level_to_str(job->JobLevel));
1115          ua->send_msg("type=%s", job_type_to_str(job->JobType));
1116          ua->send_msg("fileset=%s", job->fileset->name());
1117          ua->send_msg("enabled=%d", job->enabled);
1118          ua->send_msg("catalog=%s", job->client->catalog->name());
1119       }
1120    } 
1121    /* Client defaults */
1122    else if (strcmp(ua->argk[1], "client") == 0) {
1123       if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
1124          return true;   
1125       }
1126       client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
1127       if (client) {
1128          ua->send_msg("client=%s", client->name());
1129          ua->send_msg("address=%s", client->address);
1130          ua->send_msg("fdport=%d", client->FDport);
1131          ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
1132          ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
1133          ua->send_msg("autoprune=%d", client->AutoPrune);
1134          ua->send_msg("catalog=%s", client->catalog->name());
1135       }
1136    }
1137    /* Storage defaults */
1138    else if (strcmp(ua->argk[1], "storage") == 0) {
1139       if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
1140          return true;
1141       }
1142       storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
1143       DEVICE *device;
1144       if (storage) {
1145          ua->send_msg("storage=%s", storage->name());
1146          ua->send_msg("address=%s", storage->address);
1147          ua->send_msg("enabled=%d", storage->enabled);
1148          ua->send_msg("media_type=%s", storage->media_type);
1149          ua->send_msg("sdport=%d", storage->SDport);
1150          device = (DEVICE *)storage->device->first();
1151          ua->send_msg("device=%s", device->name());
1152          if (storage->device->size() > 1) {
1153             while ((device = (DEVICE *)storage->device->next())) {
1154                ua->send_msg(",%s", device->name());
1155             }
1156          }
1157       }
1158    }
1159    /* Pool defaults */
1160    else if (strcmp(ua->argk[1], "pool") == 0) {
1161       if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
1162          return true;
1163       }
1164       pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
1165       if (pool) {
1166          ua->send_msg("pool=%s", pool->name());
1167          ua->send_msg("pool_type=%s", pool->pool_type);
1168          ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
1169          ua->send_msg("use_volume_once=%d", pool->use_volume_once);
1170          ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
1171          ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
1172          ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
1173          ua->send_msg("max_volumes=%d", pool->max_volumes);
1174          ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
1175          ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
1176          ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
1177          ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
1178          ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
1179          ua->send_msg("auto_prune=%d", pool->AutoPrune);
1180          ua->send_msg("recycle=%d", pool->Recycle);
1181          ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1));
1182          ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1));
1183       }
1184    }
1185    return true;
1186 }