]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_cmds.c
Pool + label cleanups from bug reports
[bacula/bacula] / bacula / src / dird / ua_cmds.c
1 /*
2  *
3  *   Bacula Director -- User Agent Commands
4  *
5  *     Kern Sibbald, September MM
6  *
7  *   Version $Id$
8  */
9
10 /*
11    Copyright (C) 2000-2004 Kern Sibbald and John Walker
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of
16    the License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public
24    License along with this program; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "dird.h"
32
33 /* Imported subroutines */
34
35 /* Imported variables */
36 extern int r_first;
37 extern int r_last;
38 extern struct s_res resources[];
39 extern char my_name[];
40 extern jobq_t job_queue;              /* job queue */
41
42
43 extern char *list_pool;
44
45 /* Imported functions */
46 extern int status_cmd(UAContext *ua, const char *cmd);
47 extern int list_cmd(UAContext *ua, const char *cmd);
48 extern int llist_cmd(UAContext *ua, const char *cmd);
49 extern int show_cmd(UAContext *ua, const char *cmd);
50 extern int messagescmd(UAContext *ua, const char *cmd);
51 extern int autodisplay_cmd(UAContext *ua, const char *cmd);
52 extern int gui_cmd(UAContext *ua, const char *cmd);
53 extern int sqlquerycmd(UAContext *ua, const char *cmd);
54 extern int querycmd(UAContext *ua, const char *cmd);
55 extern int run_cmd(UAContext *ua, const char *cmd);
56 extern int retentioncmd(UAContext *ua, const char *cmd);
57 extern int prunecmd(UAContext *ua, const char *cmd);
58 extern int purgecmd(UAContext *ua, const char *cmd);
59 extern int restore_cmd(UAContext *ua, const char *cmd);
60 extern int label_cmd(UAContext *ua, const char *cmd);
61 extern int relabel_cmd(UAContext *ua, const char *cmd);
62 extern int update_slots(UAContext *ua);  /* ua_label.c */
63
64 /* Forward referenced functions */
65 static int add_cmd(UAContext *ua, const char *cmd);  
66 static int create_cmd(UAContext *ua, const char *cmd); 
67 static int cancel_cmd(UAContext *ua, const char *cmd); 
68 static int setdebug_cmd(UAContext *ua, const char *cmd);
69 static int trace_cmd(UAContext *ua, const char *cmd);
70 static int var_cmd(UAContext *ua, const char *cmd);
71 static int estimate_cmd(UAContext *ua, const char *cmd);
72 static int help_cmd(UAContext *ua, const char *cmd);
73 static int delete_cmd(UAContext *ua, const char *cmd);
74 static int use_cmd(UAContext *ua, const char *cmd);
75 static int unmount_cmd(UAContext *ua, const char *cmd);
76 static int version_cmd(UAContext *ua, const char *cmd);
77 static int automount_cmd(UAContext *ua, const char *cmd);
78 static int time_cmd(UAContext *ua, const char *cmd);
79 static int reload_cmd(UAContext *ua, const char *cmd);
80 static int update_volume(UAContext *ua);
81 static int update_pool(UAContext *ua);
82 static int delete_volume(UAContext *ua);
83 static int delete_pool(UAContext *ua);
84 static int delete_job(UAContext *ua);
85 static int mount_cmd(UAContext *ua, const char *cmd);
86 static int release_cmd(UAContext *ua, const char *cmd);
87 static int update_cmd(UAContext *ua, const char *cmd);
88 static int wait_cmd(UAContext *ua, const char *cmd);
89 static int setip_cmd(UAContext *ua, const char *cmd);
90
91 int quit_cmd(UAContext *ua, const char *cmd);
92
93
94 struct cmdstruct { const char *key; int (*func)(UAContext *ua, const char *cmd); const char *help; }; 
95 static struct cmdstruct commands[] = {
96  { N_("add"),        add_cmd,         _("add media to a pool")},
97  { N_("autodisplay"), autodisplay_cmd, _("autodisplay [on/off] -- console messages")},
98  { N_("automount"),   automount_cmd,  _("automount [on/off] -- after label")},
99  { N_("cancel"),     cancel_cmd,    _("cancel job=nnn -- cancel a job")},
100  { N_("create"),     create_cmd,    _("create DB Pool from resource")},  
101  { N_("delete"),     delete_cmd,    _("delete [pool=<pool-name> | media volume=<volume-name>]")},    
102  { N_("estimate"),   estimate_cmd,  _("performs FileSet estimate, listing gives full listing")},
103  { N_("exit"),       quit_cmd,      _("exit = quit")},
104  { N_("gui"),        gui_cmd,       _("gui [on/off] -- non-interactive gui mode")},
105  { N_("help"),       help_cmd,      _("print this command")},
106  { N_("list"),       list_cmd,      _("list [pools | jobs | jobtotals | media <pool> | files jobid=<nn>]; from catalog")},
107  { N_("label"),      label_cmd,     _("label a tape")},
108  { N_("llist"),      llist_cmd,     _("full or long list like list command")},
109  { N_("messages"),   messagescmd,   _("messages")},
110  { N_("mount"),      mount_cmd,     _("mount <storage-name>")},
111  { N_("prune"),      prunecmd,      _("prune expired records from catalog")},
112  { N_("purge"),      purgecmd,      _("purge records from catalog")},
113  { N_("quit"),       quit_cmd,      _("quit")},
114  { N_("query"),      querycmd,      _("query catalog")},
115  { N_("restore"),    restore_cmd,   _("restore files")},
116  { N_("relabel"),    relabel_cmd,   _("relabel a tape")},
117  { N_("release"),    release_cmd,   _("release <storage-name>")},
118  { N_("reload"),     reload_cmd,    _("reload conf file")},
119  { N_("run"),        run_cmd,       _("run <job-name>")},
120  { N_("status"),     status_cmd,    _("status [storage | client]=<name>")},
121  { N_("setdebug"),   setdebug_cmd,  _("sets debug level")},
122  { N_("setip"),      setip_cmd,     _("sets new client address -- if authorized")},
123  { N_("show"),       show_cmd,      _("show (resource records) [jobs | pools | ... | all]")},
124  { N_("sqlquery"),   sqlquerycmd,   _("use SQL to query catalog")}, 
125  { N_("time"),       time_cmd,      _("print current time")},
126  { N_("trace"),      trace_cmd,     _("turn on/off trace to file")},
127  { N_("unmount"),    unmount_cmd,   _("unmount <storage-name>")},
128  { N_("update"),     update_cmd,    _("update Volume or Pool")},
129  { N_("use"),        use_cmd,       _("use catalog xxx")},
130  { N_("var"),        var_cmd,       _("does variable expansion")},
131  { N_("version"),    version_cmd,   _("print Director version")},
132  { N_("wait"),       wait_cmd,      _("wait until no jobs are running")},
133              };
134 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
135
136 /*
137  * Execute a command from the UA
138  */
139 int do_a_command(UAContext *ua, const char *cmd)
140 {
141    unsigned int i;
142    int len, stat;
143    bool found = false;
144
145    stat = 1;
146
147    Dmsg1(200, "Command: %s\n", ua->UA_sock->msg);
148    if (ua->argc == 0) {
149       return 1;
150    }
151
152    len = strlen(ua->argk[0]);
153    for (i=0; i<comsize; i++) {     /* search for command */
154       if (strncasecmp(ua->argk[0],  _(commands[i].key), len) == 0) {
155          if (!acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
156             break;
157          }
158          stat = (*commands[i].func)(ua, cmd);   /* go execute command */
159          found = true;
160          break;
161       }
162    }
163    if (!found) {
164       bnet_fsend(ua->UA_sock, _("%s: is an illegal command.\n"), ua->argk[0]);
165    }
166    return stat;
167 }
168
169 /*
170  * This is a common routine used to stuff the Pool DB record defaults
171  *   into the Media DB record just before creating a media (Volume) 
172  *   record.
173  */
174 void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr)
175 {
176    mr->PoolId = pr->PoolId;
177    bstrncpy(mr->VolStatus, "Append", sizeof(mr->VolStatus));
178    mr->Recycle = pr->Recycle;
179    mr->VolRetention = pr->VolRetention;
180    mr->VolUseDuration = pr->VolUseDuration;
181    mr->MaxVolJobs = pr->MaxVolJobs;
182    mr->MaxVolFiles = pr->MaxVolFiles;
183    mr->MaxVolBytes = pr->MaxVolBytes;
184 }
185
186
187 /*
188  *  Add Volumes to an existing Pool
189  */
190 static int add_cmd(UAContext *ua, const char *cmd) 
191 {
192    POOL_DBR pr;
193    MEDIA_DBR mr;
194    int num, i, max, startnum;
195    int first_id = 0;
196    char name[MAX_NAME_LENGTH];
197    STORE *store;
198    int Slot = 0, InChanger = 0;
199
200    bsendmsg(ua, _(
201 "You probably don't want to be using this command since it\n"
202 "creates database records without labeling the Volumes.\n"
203 "You probably want to use the \"label\" command.\n\n"));
204
205    if (!open_db(ua)) {
206       return 1;
207    }
208
209    memset(&pr, 0, sizeof(pr));
210    memset(&mr, 0, sizeof(mr));
211
212    if (!get_pool_dbr(ua, &pr)) {
213       return 1;
214    }
215
216    Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
217       pr.MaxVols, pr.PoolType);
218
219    while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
220       bsendmsg(ua, _("Pool already has maximum volumes = %d\n"), pr.MaxVols);
221       for (;;) {
222          if (!get_pint(ua, _("Enter new maximum (zero for unlimited): "))) {
223             return 1;
224          }
225          pr.MaxVols = ua->pint32_val;
226       }
227    }
228
229    /* Get media type */
230    if ((store = get_storage_resource(ua, 0)) != NULL) {
231       bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
232    } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
233       return 1;
234    }
235       
236    if (pr.MaxVols == 0) {
237       max = 1000;
238    } else {
239       max = pr.MaxVols - pr.NumVols;
240    }
241    for (;;) {
242       char buf[100]; 
243       bsnprintf(buf, sizeof(buf), _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
244       if (!get_pint(ua, buf)) {
245          return 1;
246       }
247       num = ua->pint32_val;
248       if (num < 0 || num > max) {
249          bsendmsg(ua, _("The number must be between 0 and %d\n"), max);
250          continue;
251       }
252       break;
253    }
254 getVolName:
255    if (num == 0) {
256       if (!get_cmd(ua, _("Enter Volume name: "))) {
257          return 1;
258       }
259    } else {
260       if (!get_cmd(ua, _("Enter base volume name: "))) {
261          return 1;
262       }
263    }
264    /* Don't allow | in Volume name because it is the volume separator character */
265    if (!is_volume_name_legal(ua, ua->cmd)) {
266       goto getVolName;
267    }
268    if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
269       bsendmsg(ua, _("Volume name too long.\n"));
270       goto getVolName;
271    }
272    if (strlen(ua->cmd) == 0) {
273       bsendmsg(ua, _("Volume name must be at least one character long.\n"));
274       goto getVolName;
275    }
276
277    bstrncpy(name, ua->cmd, sizeof(name));
278    if (num > 0) {
279       strcat(name, "%04d");
280
281       for (;;) {
282          if (!get_pint(ua, _("Enter the starting number: "))) {
283             return 1;
284          }
285          startnum = ua->pint32_val;
286          if (startnum < 1) {
287             bsendmsg(ua, _("Start number must be greater than zero.\n"));
288             continue;
289          }
290          break;
291       }
292    } else {
293       startnum = 1;
294       num = 1;
295    }
296
297    if (store && store->autochanger) {
298       if (!get_pint(ua, _("Enter slot (0 for none): "))) {
299          return 1;
300       }
301       Slot = ua->pint32_val;
302       if (!get_yesno(ua, _("InChanger? yes/no: "))) {
303          return 1;
304       }
305       InChanger = ua->pint32_val;
306    }
307            
308    set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
309    for (i=startnum; i < num+startnum; i++) { 
310       bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
311       mr.Slot = Slot++;
312       mr.InChanger = InChanger;
313       Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
314       if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
315          bsendmsg(ua, "%s", db_strerror(ua->db));
316          return 1;
317       }
318       if (i == startnum) {
319          first_id = mr.PoolId;
320       }
321    }
322    pr.NumVols += num;
323    Dmsg0(200, "Update pool record.\n"); 
324    if (db_update_pool_record(ua->jcr, ua->db, &pr) != 1) {
325       bsendmsg(ua, "%s", db_strerror(ua->db));
326       return 1;
327    }
328    bsendmsg(ua, _("%d Volumes created in pool %s\n"), num, pr.Name);
329
330    return 1;
331 }
332
333 /*
334  * Turn auto mount on/off  
335  * 
336  *  automount on 
337  *  automount off
338  */
339 int automount_cmd(UAContext *ua, const char *cmd)
340 {
341    char *onoff;
342
343    if (ua->argc != 2) {
344       if (!get_cmd(ua, _("Turn on or off? "))) {
345             return 1;
346       }
347       onoff = ua->cmd;
348    } else {
349       onoff = ua->argk[1];
350    }
351
352    ua->automount = (strcasecmp(onoff, _("off")) == 0) ? 0 : 1;
353    return 1; 
354 }
355
356
357 /*
358  * Cancel a job
359  */
360 static int cancel_cmd(UAContext *ua, const char *cmd)
361 {
362    int i, ret;
363    int njobs = 0;
364    JCR *jcr = NULL;
365    char JobName[MAX_NAME_LENGTH];
366
367    if (!open_db(ua)) {
368       return 1;
369    }
370
371    for (i=1; i<ua->argc; i++) {
372       if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
373          uint32_t JobId;
374          if (!ua->argv[i]) {
375             break;
376          }
377          JobId = str_to_int64(ua->argv[i]);
378          if (!(jcr=get_jcr_by_id(JobId))) {
379             bsendmsg(ua, _("JobId %d is not running.\n"),  JobId);
380             return 1;
381          }
382          break;
383       } else if (strcasecmp(ua->argk[i], _("job")) == 0) {
384          if (!ua->argv[i]) {
385             break;
386          }
387          if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
388             bsendmsg(ua, _("Job %s is not running.\n"), ua->argv[i]);
389             return 1;
390          }
391          break;
392       }
393    }
394    /* If we still do not have a jcr,
395     *   throw up a list and ask the user to select one.
396     */
397    if (!jcr) {
398       /* Count Jobs running */
399       lock_jcr_chain();
400       foreach_jcr(jcr) {
401          if (jcr->JobId == 0) {      /* this is us */
402             free_locked_jcr(jcr);
403             continue;
404          }
405          free_locked_jcr(jcr);
406          njobs++;
407       }
408       unlock_jcr_chain();
409
410       if (njobs == 0) {
411          bsendmsg(ua, _("No Jobs running.\n"));
412          return 1;
413       }
414       start_prompt(ua, _("Select Job:\n"));
415       lock_jcr_chain();
416       foreach_jcr(jcr) {
417          if (jcr->JobId == 0) {      /* this is us */
418             free_locked_jcr(jcr);
419             continue;
420          }
421          add_prompt(ua, jcr->Job);
422          free_locked_jcr(jcr);
423       }
424       unlock_jcr_chain();
425
426       if (do_prompt(ua, _("Job"),  _("Choose Job to cancel"), JobName, sizeof(JobName)) < 0) {
427          return 1;
428       }
429       if (njobs == 1) {
430          if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) {
431             return 1;
432          }
433       }
434       /* NOTE! This increments the ref_count */
435       jcr = get_jcr_by_full_name(JobName);
436       if (!jcr) {
437          bsendmsg(ua, _("Job %s not found.\n"), JobName);
438          return 1;
439       }
440    }
441
442    ret = cancel_job(ua, jcr);
443    free_jcr(jcr);
444
445    return ret;
446 }
447
448 /*
449  * This is a common routine to create or update a
450  *   Pool DB base record from a Pool Resource. We handle
451  *   the setting of MaxVols and NumVols slightly differently
452  *   depending on if we are creating the Pool or we are
453  *   simply bringing it into agreement with the resource (updage).
454  */
455 static void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
456 {
457    strcpy(pr->PoolType, pool->pool_type);
458    if (op == POOL_OP_CREATE) {
459       pr->MaxVols = pool->max_volumes;
460       pr->NumVols = 0;
461    } else {          /* update pool */
462       if (pr->MaxVols != pool->max_volumes) {
463          pr->MaxVols = pool->max_volumes;
464       }
465       if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
466          pr->MaxVols = pr->NumVols;
467       }
468    }
469    pr->UseOnce = pool->use_volume_once;
470    pr->UseCatalog = pool->use_catalog;
471    pr->AcceptAnyVolume = pool->accept_any_volume;
472    pr->Recycle = pool->Recycle;
473    pr->VolRetention = pool->VolRetention;
474    pr->VolUseDuration = pool->VolUseDuration;
475    pr->MaxVolJobs = pool->MaxVolJobs;
476    pr->MaxVolFiles = pool->MaxVolFiles;
477    pr->MaxVolBytes = pool->MaxVolBytes;
478    pr->AutoPrune = pool->AutoPrune;
479    pr->Recycle = pool->Recycle;
480    if (pool->label_format) {
481       strcpy(pr->LabelFormat, pool->label_format);
482    } else {
483       strcpy(pr->LabelFormat, "*");    /* none */
484    }
485 }
486
487
488 /*
489  * Create a pool record from a given Pool resource
490  *   Also called from backup.c
491  * Returns: -1  on error
492  *           0  record already exists
493  *           1  record created
494  */
495
496 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
497 {
498    POOL_DBR  pr;
499
500    memset(&pr, 0, sizeof(POOL_DBR));
501
502    strcpy(pr.Name, pool->hdr.name);
503
504    if (db_get_pool_record(jcr, db, &pr)) {
505       /* Pool Exists */
506       if (op == POOL_OP_UPDATE) {  /* update request */
507          set_pooldbr_from_poolres(&pr, pool, op);
508          db_update_pool_record(jcr, db, &pr);
509       }
510       return 0;                       /* exists */
511    }
512
513    set_pooldbr_from_poolres(&pr, pool, op);
514
515    if (!db_create_pool_record(jcr, db, &pr)) {
516       return -1;                      /* error */
517    }
518    return 1;
519 }
520
521
522
523 /*
524  * Create a Pool Record in the database.
525  *  It is always created from the Resource record.
526  */
527 static int create_cmd(UAContext *ua, const char *cmd) 
528 {
529    POOL *pool;
530
531    if (!open_db(ua)) {
532       return 1;
533    }
534
535    pool = get_pool_resource(ua);
536    if (!pool) {
537       return 1;
538    }
539
540    switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
541    case 0:
542       bsendmsg(ua, _("Error: Pool %s already exists.\n"
543                "Use update to change it.\n"), pool->hdr.name);
544       break;
545
546    case -1:
547       bsendmsg(ua, "%s", db_strerror(ua->db));
548       break;
549
550    default:
551      break;
552    }
553    bsendmsg(ua, _("Pool %s created.\n"), pool->hdr.name);
554    return 1;
555 }
556
557
558 /*
559  * Set a new address in a Client resource. We do this only
560  *  if the Console name is the same as the Client name 
561  *  and the Console can access the client.
562  */
563 static int setip_cmd(UAContext *ua, const char *cmd) 
564 {
565    CLIENT *client;
566    if (!ua->cons || !acl_access_ok(ua, Client_ACL, ua->cons->hdr.name)) {
567       bsendmsg(ua, _("Illegal command from this console.\n"));
568       return 1;
569    }
570    LockRes();
571    client = (CLIENT *)GetResWithName(R_CLIENT, ua->cons->hdr.name);
572
573    if (!client) {
574       bsendmsg(ua, _("Client \"%s\" not found.\n"), ua->cons->hdr.name);
575       goto get_out;
576    }
577    if (client->address) {
578       free(client->address);
579    }
580    client->address = bstrdup(inet_ntoa(ua->UA_sock->client_addr.sin_addr));
581    bsendmsg(ua, _("Client \"%s\" address set to %s\n"),
582             client->hdr.name, client->address);
583 get_out:
584    UnlockRes();
585    return 1;
586 }
587
588
589 /*
590  * Update a Pool Record in the database.
591  *  It is always updated from the Resource record.
592  *
593  *    update pool=<pool-name>
594  *         updates pool from Pool resource
595  *    update media pool=<pool-name> volume=<volume-name>
596  *         changes pool info for volume
597  *    update slots [scan=...]
598  *         updates autochanger slots
599  */
600 static int update_cmd(UAContext *ua, const char *cmd) 
601 {
602    static const char *kw[] = {
603       N_("media"),  /* 0 */
604       N_("volume"), /* 1 */
605       N_("pool"),   /* 2 */
606       N_("slots"),  /* 3 */
607       NULL};
608
609    if (!open_db(ua)) {
610       return 1;
611    }
612
613    switch (find_arg_keyword(ua, kw)) {
614    case 0:
615    case 1:
616       update_volume(ua);
617       return 1;
618    case 2:
619       update_pool(ua);
620       return 1;
621    case 3:
622       update_slots(ua);
623       return 1;
624    default:
625       break;
626    }
627     
628    start_prompt(ua, _("Update choice:\n"));
629    add_prompt(ua, _("Volume parameters"));
630    add_prompt(ua, _("Pool from resource"));
631    add_prompt(ua, _("Slots from autochanger"));
632    switch (do_prompt(ua, _("item"), _("Choose catalog item to update"), NULL, 0)) {
633    case 0:
634       update_volume(ua);
635       break;
636    case 1:
637       update_pool(ua);
638       break;
639    case 2:
640       update_slots(ua);
641       break;
642    default:
643       break;
644    }
645    return 1;
646 }
647
648 static void update_volstatus(UAContext *ua, const char *val, MEDIA_DBR *mr)
649 {
650    POOLMEM *query = get_pool_memory(PM_MESSAGE);
651    const char *kw[] = {
652       "Append",
653       "Archive",
654       "Disabled",
655       "Full",
656       "Used", 
657       "Cleaning", 
658       "Recycle",
659       "Read-Only",
660       NULL};
661    bool found = false;
662    int i;
663
664    for (i=0; kw[i]; i++) {
665       if (strcasecmp(val, kw[i]) == 0) {
666          found = true;
667          break;
668       }
669    }
670    if (!found) {
671       bsendmsg(ua, _("Invalid VolStatus specified: %s\n"), val);
672    } else {
673       bstrncpy(mr->VolStatus, kw[i], sizeof(mr->VolStatus));
674       Mmsg(&query, "UPDATE Media SET VolStatus='%s' WHERE MediaId=%u",
675          mr->VolStatus, mr->MediaId);
676       if (!db_sql_query(ua->db, query, NULL, NULL)) {  
677          bsendmsg(ua, "%s", db_strerror(ua->db));
678       } else {
679          bsendmsg(ua, _("New Volume status is: %s\n"), mr->VolStatus);
680       }
681    }
682    free_pool_memory(query);
683 }
684
685 static void update_volretention(UAContext *ua, char *val, MEDIA_DBR *mr)
686 {
687    char ed1[50];
688    POOLMEM *query;
689    if (!duration_to_utime(val, &mr->VolRetention)) {
690       bsendmsg(ua, _("Invalid retention period specified: %s\n"), val);
691       return;
692    }
693    query = get_pool_memory(PM_MESSAGE);
694    Mmsg(&query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%u",
695       edit_uint64(mr->VolRetention, ed1), mr->MediaId);
696    if (!db_sql_query(ua->db, query, NULL, NULL)) {  
697       bsendmsg(ua, "%s", db_strerror(ua->db));
698    } else {
699       bsendmsg(ua, _("New retention seconds is: %s\n"),
700          edit_utime(mr->VolRetention, ed1));
701    }
702    free_pool_memory(query);
703 }
704
705 static void update_voluseduration(UAContext *ua, char *val, MEDIA_DBR *mr)
706 {
707    char ed1[50];
708    POOLMEM *query;
709
710    if (!duration_to_utime(val, &mr->VolUseDuration)) {
711       bsendmsg(ua, _("Invalid use duration specified: %s\n"), val);
712       return;
713    }
714    query = get_pool_memory(PM_MESSAGE);
715    Mmsg(&query, "UPDATE Media SET VolUseDuration=%s WHERE MediaId=%u",
716       edit_uint64(mr->VolUseDuration, ed1), mr->MediaId);
717    if (!db_sql_query(ua->db, query, NULL, NULL)) {  
718       bsendmsg(ua, "%s", db_strerror(ua->db));
719    } else {
720       bsendmsg(ua, _("New use duration is: %s\n"),
721          edit_utime(mr->VolUseDuration, ed1));
722    }
723    free_pool_memory(query);
724 }
725
726 static void update_volmaxjobs(UAContext *ua, char *val, MEDIA_DBR *mr)
727 {
728    POOLMEM *query = get_pool_memory(PM_MESSAGE);
729    Mmsg(&query, "UPDATE Media SET MaxVolJobs=%s WHERE MediaId=%u",
730       val, mr->MediaId);
731    if (!db_sql_query(ua->db, query, NULL, NULL)) {  
732       bsendmsg(ua, "%s", db_strerror(ua->db));
733    } else {
734       bsendmsg(ua, _("New max jobs is: %s\n"), val);
735    }
736    free_pool_memory(query);
737 }
738
739 static void update_volmaxfiles(UAContext *ua, char *val, MEDIA_DBR *mr)
740 {
741    POOLMEM *query = get_pool_memory(PM_MESSAGE);
742    Mmsg(&query, "UPDATE Media SET MaxVolFiles=%s WHERE MediaId=%u",
743       val, mr->MediaId);
744    if (!db_sql_query(ua->db, query, NULL, NULL)) {  
745       bsendmsg(ua, "%s", db_strerror(ua->db));
746    } else {
747       bsendmsg(ua, _("New max files is: %s\n"), val);
748    }
749    free_pool_memory(query);
750 }
751
752 static void update_volmaxbytes(UAContext *ua, char *val, MEDIA_DBR *mr)
753 {
754    uint64_t maxbytes;
755    char ed1[50];
756    POOLMEM *query;
757
758    if (!size_to_uint64(val, strlen(val), &maxbytes)) {
759       bsendmsg(ua, _("Invalid max. bytes specification: %s\n"), val);
760       return;
761    } 
762    query = get_pool_memory(PM_MESSAGE);
763    Mmsg(&query, "UPDATE Media SET MaxVolBytes=%s WHERE MediaId=%u",
764       edit_uint64(maxbytes, ed1), mr->MediaId);
765    if (!db_sql_query(ua->db, query, NULL, NULL)) {  
766       bsendmsg(ua, "%s", db_strerror(ua->db));
767    } else {
768       bsendmsg(ua, _("New Max bytes is: %s\n"), edit_uint64(maxbytes, ed1));
769    }
770    free_pool_memory(query);
771 }
772
773 static void update_volrecycle(UAContext *ua, char *val, MEDIA_DBR *mr)
774 {
775    int recycle;
776    POOLMEM *query;
777    if (strcasecmp(val, _("yes")) == 0) {
778       recycle = 1;
779    } else if (strcasecmp(val, _("no")) == 0) {
780       recycle = 0;
781    } else {
782       bsendmsg(ua, _("Invalid value. It must by yes or no.\n"));
783       return;
784    }
785    query = get_pool_memory(PM_MESSAGE);
786    Mmsg(&query, "UPDATE Media SET Recycle=%d WHERE MediaId=%u",
787       recycle, mr->MediaId);
788    if (!db_sql_query(ua->db, query, NULL, NULL)) {  
789       bsendmsg(ua, "%s", db_strerror(ua->db));
790    } else {       
791       bsendmsg(ua, _("New Recycle flag is: %s\n"),
792          mr->Recycle==1?_("yes"):_("no"));
793    }
794    free_pool_memory(query);
795 }
796
797 /* Modify the Pool in which this Volume is located */
798 static void update_vol_pool(UAContext *ua, char *val, MEDIA_DBR *mr, POOL_DBR *opr)
799 {
800    POOL_DBR pr;
801    POOLMEM *query;
802
803    memset(&pr, 0, sizeof(pr));
804    bstrncpy(pr.Name, val, sizeof(pr.Name));
805    if (!get_pool_dbr(ua, &pr)) {
806       return;
807    }
808    mr->PoolId = pr.PoolId;            /* set new PoolId */
809    /*
810     */
811    query = get_pool_memory(PM_MESSAGE);
812    db_lock(ua->db);
813    Mmsg(&query, "UPDATE Media SET PoolId=%d WHERE MediaId=%u",
814       mr->PoolId, mr->MediaId);
815    if (!db_sql_query(ua->db, query, NULL, NULL)) {  
816       bsendmsg(ua, "%s", db_strerror(ua->db));
817    } else {       
818       bsendmsg(ua, _("New Pool is: %s\n"), pr.Name);
819       opr->NumVols--;
820       if (!db_update_pool_record(ua->jcr, ua->db, opr)) {
821          bsendmsg(ua, "%s", db_strerror(ua->db));
822       }
823       pr.NumVols++;
824       if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
825          bsendmsg(ua, "%s", db_strerror(ua->db));
826       }
827       db_make_inchanger_unique(ua->jcr, ua->db, mr);
828    }
829    db_unlock(ua->db);
830    free_pool_memory(query);
831 }
832
833 /*
834  * Refresh the Volume information from the Pool record
835  */
836 static void update_volfrompool(UAContext *ua, MEDIA_DBR *mr)
837 {
838    POOL_DBR pr;
839    char VolStatus[50];
840
841    memset(&pr, 0, sizeof(pr));
842    pr.PoolId = mr->PoolId;
843    if (!get_pool_dbr(ua, &pr)) {
844       return;
845    }
846    bstrncpy(VolStatus, mr->VolStatus, sizeof(VolStatus));
847    set_pool_dbr_defaults_in_media_dbr(mr, &pr);
848    bstrncpy(mr->VolStatus, VolStatus, sizeof(mr->VolStatus));
849    if (!db_update_media_record(ua->jcr, ua->db, mr)) {
850       bsendmsg(ua, _("Error updating Volume record: ERR=%s"), db_strerror(ua->db));
851    } else {
852       bsendmsg(ua, _("Volume defaults updated from Pool record.\n"));
853    }
854 }
855
856 /*
857  * Update a media record -- allows you to change the
858  *  Volume status. E.g. if you want Bacula to stop
859  *  writing on the volume, set it to anything other
860  *  than Append.
861  */              
862 static int update_volume(UAContext *ua)
863 {
864    MEDIA_DBR mr;
865    POOL_DBR pr;
866    POOLMEM *query;
867    char ed1[30];
868    bool done = false;
869    const char *kw[] = {
870       N_("VolStatus"),                /* 0 */
871       N_("VolRetention"),             /* 1 */
872       N_("VolUse"),                   /* 2 */
873       N_("MaxVolJobs"),               /* 3 */
874       N_("MaxVolFiles"),              /* 4 */
875       N_("MaxVolBytes"),              /* 5 */
876       N_("Recycle"),                  /* 6 */
877       N_("Pool"),                     /* 7 */
878       N_("FromPool"),                 /* 8 */
879       NULL };
880
881    for (int i=0; kw[i]; i++) {
882       int j;
883       POOL_DBR pr;
884       if ((j=find_arg_with_value(ua, kw[i])) > 0) {
885          if (!select_media_dbr(ua, &mr)) {
886             return 0;
887          }
888          switch (i) {
889          case 0:
890             update_volstatus(ua, ua->argv[j], &mr);
891             break;
892          case 1:
893             update_volretention(ua, ua->argv[j], &mr);
894             break;
895          case 2:
896             update_voluseduration(ua, ua->argv[j], &mr);
897             break;
898          case 3:
899             update_volmaxjobs(ua, ua->argv[j], &mr);
900             break;
901          case 4:
902             update_volmaxfiles(ua, ua->argv[j], &mr);
903             break;
904          case 5:
905             update_volmaxbytes(ua, ua->argv[j], &mr);
906             break;
907          case 6:
908             update_volrecycle(ua, ua->argv[j], &mr);
909             break;
910          case 7:
911             memset(&pr, 0, sizeof(POOL_DBR));
912             pr.PoolId = mr.PoolId;
913             if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
914                bsendmsg(ua, "%s", db_strerror(ua->db));
915                break;
916             }
917             update_vol_pool(ua, ua->argv[j], &mr, &pr);
918             break;
919          case 8:
920             update_volfrompool(ua, &mr);
921             break;
922          }
923          done = true;
924       }
925    }
926
927    for ( ; !done; ) {
928       if (!select_media_dbr(ua, &mr)) {
929          return 0;
930       }
931       bsendmsg(ua, _("Updating Volume \"%s\"\n"), mr.VolumeName);
932       start_prompt(ua, _("Parameters to modify:\n"));
933       add_prompt(ua, _("Volume Status"));
934       add_prompt(ua, _("Volume Retention Period"));
935       add_prompt(ua, _("Volume Use Duration"));
936       add_prompt(ua, _("Maximum Volume Jobs"));
937       add_prompt(ua, _("Maximum Volume Files"));
938       add_prompt(ua, _("Maximum Volume Bytes"));
939       add_prompt(ua, _("Recycle Flag"));
940       add_prompt(ua, _("Slot"));
941       add_prompt(ua, _("InChanger Flag"));
942       add_prompt(ua, _("Volume Files"));
943       add_prompt(ua, _("Pool"));
944       add_prompt(ua, _("Done"));
945       switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
946       case 0:                         /* Volume Status */
947          /* Modify Volume Status */
948          bsendmsg(ua, _("Current Volume status is: %s\n"), mr.VolStatus);
949          start_prompt(ua, _("Possible Values are:\n"));
950          add_prompt(ua, "Append");      /* Better not translate these as */
951          add_prompt(ua, "Archive");     /* They are known in the database code */
952          add_prompt(ua, "Disabled");
953          add_prompt(ua, "Full");
954          add_prompt(ua, "Used");
955          add_prompt(ua, "Cleaning");
956          if (strcmp(mr.VolStatus, "Purged") == 0) {
957             add_prompt(ua, "Recycle");
958          }
959          add_prompt(ua, "Read-Only");
960          if (do_prompt(ua, "", _("Choose new Volume Status"), ua->cmd, sizeof(mr.VolStatus)) < 0) {
961             return 1;
962          }
963          update_volstatus(ua, ua->cmd, &mr);
964          break;
965       case 1:                         /* Retention */
966          bsendmsg(ua, _("Current retention seconds is: %s\n"),
967             edit_utime(mr.VolRetention, ed1));
968          if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
969             return 0;
970          }
971          update_volretention(ua, ua->cmd, &mr);
972          break;
973
974       case 2:                         /* Use Duration */
975          bsendmsg(ua, _("Current use duration is: %s\n"),
976             edit_utime(mr.VolUseDuration, ed1));
977          if (!get_cmd(ua, _("Enter Volume Use Duration: "))) {
978             return 0;
979          }
980          update_voluseduration(ua, ua->cmd, &mr);
981          break;
982
983       case 3:                         /* Max Jobs */
984          bsendmsg(ua, _("Current max jobs is: %u\n"), mr.MaxVolJobs);
985          if (!get_pint(ua, _("Enter new Maximum Jobs: "))) {
986             return 0;
987          }
988          update_volmaxjobs(ua, ua->cmd, &mr);
989          break;
990
991       case 4:                         /* Max Files */
992          bsendmsg(ua, _("Current max files is: %u\n"), mr.MaxVolFiles);
993          if (!get_pint(ua, _("Enter new Maximum Files: "))) {
994             return 0;
995          }
996          update_volmaxfiles(ua, ua->cmd, &mr);
997          break;
998
999       case 5:                         /* Max Bytes */
1000          bsendmsg(ua, _("Current value is: %s\n"), edit_uint64(mr.MaxVolBytes, ed1));
1001          if (!get_cmd(ua, _("Enter new Maximum Bytes: "))) {
1002             return 0;
1003          }
1004          update_volmaxbytes(ua, ua->cmd, &mr);
1005          break;
1006
1007
1008       case 6:                         /* Recycle */
1009          bsendmsg(ua, _("Current recycle flag is: %s\n"),
1010             mr.Recycle==1?_("yes"):_("no"));
1011          if (!get_yesno(ua, _("Enter new Recycle status: "))) {
1012             return 0;
1013          }
1014          update_volrecycle(ua, ua->cmd, &mr);
1015          break;
1016
1017       case 7:                         /* Slot */
1018          int Slot;
1019
1020          memset(&pr, 0, sizeof(POOL_DBR));
1021          pr.PoolId = mr.PoolId;
1022          if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
1023             bsendmsg(ua, "%s", db_strerror(ua->db));
1024             return 0;
1025          }
1026          bsendmsg(ua, _("Current Slot is: %d\n"), mr.Slot);
1027          if (!get_pint(ua, _("Enter new Slot: "))) {
1028             return 0;
1029          }
1030          Slot = ua->pint32_val;
1031          if (pr.MaxVols > 0 && Slot > (int)pr.MaxVols) {
1032             bsendmsg(ua, _("Invalid slot, it must be between 0 and %d\n"),
1033                pr.MaxVols);
1034             break;
1035          }
1036          mr.Slot = Slot;
1037          /*
1038           * Make sure to use db_update... rather than doing this directly,
1039           *   so that any Slot is handled correctly. 
1040           */
1041          if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
1042             bsendmsg(ua, _("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
1043          } else {
1044             bsendmsg(ua, _("New Slot is: %d\n"), mr.Slot);
1045          }
1046          break;
1047
1048       case 8:                         /* InChanger */
1049          bsendmsg(ua, _("Current InChanger flag is: %d\n"), mr.InChanger);
1050          if (!get_yesno(ua, _("Set InChanger flag? yes/no: "))) {
1051             return 0;
1052          }
1053          mr.InChanger = ua->pint32_val;
1054          /*
1055           * Make sure to use db_update... rather than doing this directly,
1056           *   so that any Slot is handled correctly. 
1057           */
1058          if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
1059             bsendmsg(ua, _("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
1060          } else {
1061             bsendmsg(ua, _("New InChanger flag is: %d\n"), mr.InChanger);
1062          }
1063          break;
1064
1065
1066       case 9:                         /* Volume Files */
1067          int32_t VolFiles;
1068          bsendmsg(ua, _("Warning changing Volume Files can result\n"
1069                         "in loss of data on your Volume\n\n"));
1070          bsendmsg(ua, _("Current Volume Files is: %u\n"), mr.VolFiles);
1071          if (!get_pint(ua, _("Enter new number of Files for Volume: "))) {
1072             return 0;
1073          }
1074          VolFiles = ua->pint32_val;
1075          if (VolFiles != (int)(mr.VolFiles + 1)) {
1076             bsendmsg(ua, _("Normally, you should only increase Volume Files by one!\n"));
1077             if (!get_yesno(ua, _("Continue? (yes/no): ")) || ua->pint32_val == 0) {
1078                break;
1079             }
1080          }
1081          query = get_pool_memory(PM_MESSAGE);
1082          Mmsg(&query, "UPDATE Media SET VolFiles=%u WHERE MediaId=%u",
1083             VolFiles, mr.MediaId);
1084          if (!db_sql_query(ua->db, query, NULL, NULL)) {  
1085             bsendmsg(ua, "%s", db_strerror(ua->db));
1086          } else {
1087             bsendmsg(ua, _("New Volume Files is: %u\n"), VolFiles);
1088          }
1089          free_pool_memory(query);
1090          break;
1091
1092       case 10:                        /* Volume's Pool */
1093          memset(&pr, 0, sizeof(POOL_DBR));
1094          pr.PoolId = mr.PoolId;
1095          if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
1096             bsendmsg(ua, "%s", db_strerror(ua->db));
1097             return 0;
1098          }
1099          bsendmsg(ua, _("Current Pool is: %s\n"), pr.Name);
1100          if (!get_cmd(ua, _("Enter new Pool name: "))) {
1101             return 0;
1102          }
1103          update_vol_pool(ua, ua->cmd, &mr, &pr);
1104          return 1;
1105
1106       default:                        /* Done or error */
1107          bsendmsg(ua, "Selection done.\n");
1108          return 1;
1109       }
1110    }
1111    return 1;
1112 }
1113
1114 /* 
1115  * Update pool record -- pull info from current POOL resource
1116  */
1117 static int update_pool(UAContext *ua)
1118 {
1119    POOL_DBR  pr;
1120    int id;
1121    POOL *pool;
1122    POOLMEM *query;       
1123    
1124    pool = get_pool_resource(ua);
1125    if (!pool) {
1126       return 0;
1127    }
1128
1129    memset(&pr, 0, sizeof(pr));
1130    strcpy(pr.Name, pool->hdr.name);
1131    if (!get_pool_dbr(ua, &pr)) {
1132       return 0;
1133    }
1134
1135    set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE); /* update */
1136
1137    id = db_update_pool_record(ua->jcr, ua->db, &pr);
1138    if (id <= 0) {
1139       bsendmsg(ua, _("db_update_pool_record returned %d. ERR=%s\n"),
1140          id, db_strerror(ua->db));
1141    }
1142    query = get_pool_memory(PM_MESSAGE);
1143    Mmsg(&query, list_pool, pr.PoolId);
1144    db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST);
1145    free_pool_memory(query);
1146    bsendmsg(ua, _("Pool DB record updated from resource.\n"));
1147    return 1;
1148 }
1149
1150
1151 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
1152 {
1153    BSOCK *sd;
1154
1155    ua->jcr->store = store;
1156    /* Try connecting for up to 15 seconds */
1157    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"), 
1158       store->hdr.name, store->address, store->SDport);
1159    if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
1160       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1161       return;
1162    }
1163    Dmsg0(120, _("Connected to storage daemon\n"));
1164    sd = ua->jcr->store_bsock;
1165    bnet_fsend(sd, "setdebug=%d trace=%d\n", level, trace_flag);
1166    if (bnet_recv(sd) >= 0) {
1167       bsendmsg(ua, "%s", sd->msg);
1168    }
1169    bnet_sig(sd, BNET_TERMINATE);
1170    bnet_close(sd);
1171    ua->jcr->store_bsock = NULL;
1172    return;  
1173 }
1174    
1175 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int trace_flag)
1176 {
1177    BSOCK *fd;
1178
1179    /* Connect to File daemon */
1180
1181    ua->jcr->client = client;
1182    /* Try to connect for 15 seconds */
1183    bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"), 
1184       client->hdr.name, client->address, client->FDport);
1185    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
1186       bsendmsg(ua, _("Failed to connect to Client.\n"));
1187       return;
1188    }
1189    Dmsg0(120, "Connected to file daemon\n");
1190    fd = ua->jcr->file_bsock;
1191    bnet_fsend(fd, "setdebug=%d trace=%d\n", level, trace_flag);
1192    if (bnet_recv(fd) >= 0) {
1193       bsendmsg(ua, "%s", fd->msg);
1194    }
1195    bnet_sig(fd, BNET_TERMINATE);
1196    bnet_close(fd);
1197    ua->jcr->file_bsock = NULL;
1198    return;  
1199 }
1200
1201
1202 static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
1203 {
1204    STORE *store, **unique_store;
1205    CLIENT *client, **unique_client;
1206    int i, j, found;
1207
1208    /* Director */
1209    debug_level = level;
1210
1211    /* Count Storage items */
1212    LockRes();
1213    store = NULL;
1214    for (i=0; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); i++)
1215       { }
1216    unique_store = (STORE **) malloc(i * sizeof(STORE));
1217    /* Find Unique Storage address/port */         
1218    store = (STORE *)GetNextRes(R_STORAGE, NULL);
1219    i = 0;
1220    unique_store[i++] = store;
1221    while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
1222       found = 0;
1223       for (j=0; j<i; j++) {
1224          if (strcmp(unique_store[j]->address, store->address) == 0 &&
1225              unique_store[j]->SDport == store->SDport) {
1226             found = 1;
1227             break;
1228          }
1229       }
1230       if (!found) {
1231          unique_store[i++] = store;
1232          Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
1233       }
1234    }
1235    UnlockRes();
1236
1237    /* Call each unique Storage daemon */
1238    for (j=0; j<i; j++) {
1239       do_storage_setdebug(ua, unique_store[j], level, trace_flag);
1240    }
1241    free(unique_store);
1242
1243    /* Count Client items */
1244    LockRes();
1245    client = NULL;
1246    for (i=0; (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)); i++)
1247       { }
1248    unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
1249    /* Find Unique Client address/port */         
1250    client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
1251    i = 0;
1252    unique_client[i++] = client;
1253    while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
1254       found = 0;
1255       for (j=0; j<i; j++) {
1256          if (strcmp(unique_client[j]->address, client->address) == 0 &&
1257              unique_client[j]->FDport == client->FDport) {
1258             found = 1;
1259             break;
1260          }
1261       }
1262       if (!found) {
1263          unique_client[i++] = client;
1264          Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
1265       }
1266    }
1267    UnlockRes();
1268
1269    /* Call each unique File daemon */
1270    for (j=0; j<i; j++) {
1271       do_client_setdebug(ua, unique_client[j], level, trace_flag);
1272    }
1273    free(unique_client);
1274 }
1275
1276 /*
1277  * setdebug level=nn all trace=1/0
1278  */
1279 static int setdebug_cmd(UAContext *ua, const char *cmd)
1280 {
1281    STORE *store;
1282    CLIENT *client;
1283    int level;
1284    int trace_flag = -1;
1285    int i;
1286
1287    if (!open_db(ua)) {
1288       return 1;
1289    }
1290    Dmsg1(120, "setdebug:%s:\n", cmd);
1291
1292    level = -1;
1293    i = find_arg_with_value(ua, _("level"));
1294    if (i >= 0) {
1295       level = atoi(ua->argv[i]);
1296    }
1297    if (level < 0) {
1298       if (!get_pint(ua, _("Enter new debug level: "))) {
1299          return 1;
1300       }
1301       level = ua->pint32_val;
1302    }
1303
1304    /* Look for trace flag. -1 => not change */
1305    i = find_arg_with_value(ua, _("trace"));
1306    if (i >= 0) {
1307       trace_flag = atoi(ua->argv[i]);
1308       if (trace_flag > 0) {
1309          trace_flag = 1;
1310       }
1311    }
1312
1313    /* General debug? */
1314    for (i=1; i<ua->argc; i++) {
1315       if (strcasecmp(ua->argk[i], _("all")) == 0) {
1316          do_all_setdebug(ua, level, trace_flag);
1317          return 1;
1318       }
1319       if (strcasecmp(ua->argk[i], _("dir")) == 0 ||
1320           strcasecmp(ua->argk[i], _("director")) == 0) {
1321          debug_level = level;
1322          set_trace(trace_flag);
1323          return 1;
1324       }
1325       if (strcasecmp(ua->argk[i], _("client")) == 0 ||
1326           strcasecmp(ua->argk[i], _("fd")) == 0) {
1327          client = NULL;
1328          if (ua->argv[i]) {
1329             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
1330             if (client) {
1331                do_client_setdebug(ua, client, level, trace_flag);
1332                return 1;
1333             }
1334          }
1335          client = select_client_resource(ua);   
1336          if (client) {
1337             do_client_setdebug(ua, client, level, trace_flag);
1338             return 1;
1339          }
1340       }
1341
1342       if (strcasecmp(ua->argk[i], _("store")) == 0 ||
1343           strcasecmp(ua->argk[i], _("storage")) == 0 ||
1344           strcasecmp(ua->argk[i], _("sd")) == 0) {
1345          store = NULL;
1346          if (ua->argv[i]) {
1347             store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
1348             if (store) {
1349                do_storage_setdebug(ua, store, level, trace_flag);
1350                return 1;
1351             }
1352          }
1353          store = get_storage_resource(ua, 0);
1354          if (store) {
1355             do_storage_setdebug(ua, store, level, trace_flag);
1356             return 1;
1357          }
1358       }
1359    } 
1360    /*
1361     * We didn't find an appropriate keyword above, so
1362     * prompt the user.
1363     */
1364    start_prompt(ua, _("Available daemons are: \n"));
1365    add_prompt(ua, _("Director"));
1366    add_prompt(ua, _("Storage"));
1367    add_prompt(ua, _("Client"));
1368    add_prompt(ua, _("All"));
1369    switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
1370    case 0:                         /* Director */
1371       debug_level = level;
1372       set_trace(trace_flag);
1373       break;
1374    case 1:
1375       store = get_storage_resource(ua, 0);
1376       if (store) {
1377          do_storage_setdebug(ua, store, level, trace_flag);
1378       }
1379       break;
1380    case 2:
1381       client = select_client_resource(ua);
1382       if (client) {
1383          do_client_setdebug(ua, client, level, trace_flag);
1384       }
1385       break;
1386    case 3:
1387       do_all_setdebug(ua, level, trace_flag);
1388       break;
1389    default:
1390       break;
1391    }
1392    return 1;
1393 }
1394
1395 /*
1396  * Turn debug tracing to file on/off
1397  */
1398 static int trace_cmd(UAContext *ua, const char *cmd)
1399 {
1400    char *onoff;
1401
1402    if (ua->argc != 2) {
1403       if (!get_cmd(ua, _("Turn on or off? "))) {
1404             return 1;
1405       }
1406       onoff = ua->cmd;
1407    } else {
1408       onoff = ua->argk[1];
1409    }
1410
1411    set_trace((strcasecmp(onoff, _("off")) == 0) ? false : true);
1412    return 1; 
1413
1414 }
1415
1416 static int var_cmd(UAContext *ua, const char *cmd)
1417 {
1418    POOLMEM *val = get_pool_memory(PM_FNAME);
1419    char *var;
1420
1421    if (!open_db(ua)) {
1422       return 1;
1423    }
1424    for (var=ua->cmd; *var != ' '; ) {    /* skip command */
1425       var++;
1426    }
1427    while (*var == ' ') {                 /* skip spaces */
1428       var++;
1429    }
1430    Dmsg1(100, "Var=%s:\n", var);
1431    variable_expansion(ua->jcr, var, &val);  
1432    bsendmsg(ua, "%s\n", val);
1433    free_pool_memory(val);
1434    return 1;
1435 }
1436
1437 static int estimate_cmd(UAContext *ua, const char *cmd)
1438 {
1439    JOB *job = NULL;
1440    CLIENT *client = NULL;
1441    FILESET *fileset = NULL;
1442    FILESET_DBR fsr;
1443    int listing = 0;
1444    char since[MAXSTRING];
1445    JCR *jcr = ua->jcr;
1446
1447    jcr->JobLevel = L_FULL;
1448    for (int i=1; i<ua->argc; i++) {
1449       if (strcasecmp(ua->argk[i], _("client")) == 0 ||
1450           strcasecmp(ua->argk[i], _("fd")) == 0) {
1451          if (ua->argv[i]) {
1452             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
1453             continue;
1454          }
1455       }
1456       if (strcasecmp(ua->argk[i], _("job")) == 0) {
1457          if (ua->argv[i]) {
1458             job = (JOB *)GetResWithName(R_JOB, ua->argv[i]);
1459             continue;
1460          }
1461       }
1462       if (strcasecmp(ua->argk[i], _("fileset")) == 0) {
1463          if (ua->argv[i]) {
1464             fileset = (FILESET *)GetResWithName(R_FILESET, ua->argv[i]);
1465             continue;
1466          }
1467       }
1468       if (strcasecmp(ua->argk[i], _("listing")) == 0) {
1469          listing = 1;
1470          continue;
1471       }
1472       if (strcasecmp(ua->argk[i], _("level")) == 0) {
1473          if (!get_level_from_name(ua->jcr, ua->argv[i])) {
1474             bsendmsg(ua, _("Level %s not valid.\n"), ua->argv[i]);
1475          }
1476          continue;
1477       }
1478    } 
1479    if (!job && !(client && fileset)) {
1480       if (!(job = select_job_resource(ua))) {
1481          return 1;
1482       }
1483    }
1484    if (!job) {
1485       job = (JOB *)GetResWithName(R_JOB, ua->argk[1]);
1486       if (!job) {
1487          bsendmsg(ua, _("No job specified.\n"));
1488          return 1;
1489       }
1490    }
1491    if (!client) {
1492       client = job->client;
1493    }
1494    if (!fileset) {
1495       fileset = job->fileset;
1496    }
1497    jcr->client = client;
1498    jcr->fileset = fileset;
1499    close_db(ua);
1500    ua->catalog = client->catalog;
1501
1502    if (!open_db(ua)) {
1503       return 1;
1504    }
1505
1506    jcr->job = job;
1507    jcr->JobType = JT_BACKUP;
1508    init_jcr_job_record(jcr);
1509
1510    if (!get_or_create_client_record(jcr)) {
1511       return 1;
1512    }
1513    if (!get_or_create_fileset_record(jcr, &fsr)) {
1514       return 1;
1515    }
1516    
1517    get_level_since_time(ua->jcr, since, sizeof(since));
1518
1519    bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"),
1520       job->client->hdr.name, job->client->address, job->client->FDport);
1521    if (!connect_to_file_daemon(jcr, 1, 15, 0)) {
1522       bsendmsg(ua, _("Failed to connect to Client.\n"));
1523       return 1;
1524    }
1525
1526    if (!send_include_list(jcr)) {
1527       bsendmsg(ua, _("Error sending include list.\n"));
1528       goto bail_out;
1529    }
1530
1531    if (!send_exclude_list(jcr)) {
1532       bsendmsg(ua, _("Error sending exclude list.\n"));
1533       goto bail_out;
1534    }
1535
1536    if (!send_level_command(jcr)) {
1537       goto bail_out;
1538    }
1539
1540    bnet_fsend(jcr->file_bsock, "estimate listing=%d\n", listing);
1541    while (bnet_recv(jcr->file_bsock) >= 0) {
1542       bsendmsg(ua, "%s", jcr->file_bsock->msg);
1543    }
1544
1545 bail_out:
1546    if (jcr->file_bsock) {
1547       bnet_sig(jcr->file_bsock, BNET_TERMINATE);
1548       bnet_close(jcr->file_bsock);
1549       jcr->file_bsock = NULL;
1550    }
1551    return 1;
1552 }
1553
1554
1555 /*
1556  * print time
1557  */
1558 static int time_cmd(UAContext *ua, const char *cmd)
1559 {
1560    char sdt[50];
1561    time_t ttime = time(NULL);
1562    struct tm tm;
1563    localtime_r(&ttime, &tm);
1564    strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1565    bsendmsg(ua, "%s\n", sdt);
1566    return 1;
1567 }
1568
1569 /*
1570  * reload the conf file
1571  */
1572 extern "C" void reload_config(int sig);
1573
1574 static int reload_cmd(UAContext *ua, const char *cmd)
1575 {
1576    reload_config(1);   
1577    return 1;
1578 }
1579
1580
1581
1582 /*
1583  * Delete Pool records (should purge Media with it).
1584  *
1585  *  delete pool=<pool-name>
1586  *  delete volume pool=<pool-name> volume=<name>
1587  *  delete job jobid=xxx
1588  */
1589 static int delete_cmd(UAContext *ua, const char *cmd)
1590 {
1591    static const char *keywords[] = {
1592       N_("volume"),
1593       N_("pool"),
1594       N_("job"),
1595       N_("jobid"),
1596       NULL};
1597
1598    if (!open_db(ua)) {
1599       return 1;
1600    }
1601
1602    switch (find_arg_keyword(ua, keywords)) {      
1603    case 0:
1604       delete_volume(ua);     
1605       return 1;
1606    case 1:
1607       delete_pool(ua);
1608       return 1;
1609    case 2:
1610    case 3:
1611       int i;
1612       while ((i=find_arg(ua, _("jobid"))) > 0) {
1613          delete_job(ua);
1614          *ua->argk[i] = 0;         /* zap keyword already visited */
1615       }
1616       return 1;
1617    default:
1618       break;
1619    }
1620
1621    bsendmsg(ua, _(
1622 "In general it is not a good idea to delete either a\n"
1623 "Pool or a Volume since they may contain data.\n\n"));
1624
1625    switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1626    case 0:
1627       delete_volume(ua);
1628       break;
1629    case 1:
1630       delete_pool(ua);
1631       break;
1632    case 2:
1633       delete_job(ua);
1634       return 1;
1635    default:
1636       bsendmsg(ua, _("Nothing done.\n"));
1637       break;
1638    }
1639    return 1;
1640 }
1641
1642 static int delete_job(UAContext *ua)
1643 {
1644    POOLMEM *query = get_pool_memory(PM_MESSAGE);
1645    JobId_t JobId;
1646
1647    int i = find_arg_with_value(ua, _("jobid"));
1648    if (i >= 0) {
1649       JobId = str_to_int64(ua->argv[i]);
1650    } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
1651       return 0;
1652    } else {
1653       JobId = ua->pint32_val; 
1654    }
1655    Mmsg(&query, "DELETE FROM Job WHERE JobId=%u", JobId);
1656    db_sql_query(ua->db, query, NULL, (void *)NULL);
1657    Mmsg(&query, "DELETE FROM File WHERE JobId=%u", JobId);
1658    db_sql_query(ua->db, query, NULL, (void *)NULL);
1659    Mmsg(&query, "DELETE FROM JobMedia WHERE JobId=%u", JobId);
1660    db_sql_query(ua->db, query, NULL, (void *)NULL);
1661    free_pool_memory(query);
1662    bsendmsg(ua, _("Job %u and associated records deleted from the catalog.\n"), JobId);
1663    return 1;
1664 }
1665
1666 /*
1667  * Delete media records from database -- dangerous 
1668  */
1669 static int delete_volume(UAContext *ua)
1670 {
1671    MEDIA_DBR mr;
1672
1673    if (!select_media_dbr(ua, &mr)) {
1674       return 1;
1675    }
1676    bsendmsg(ua, _("\nThis command will delete volume %s\n"
1677       "and all Jobs saved on that volume from the Catalog\n"),
1678       mr.VolumeName);
1679
1680    if (!get_yesno(ua, _("Are you sure you want to delete this Volume? (yes/no): "))) {
1681       return 1;
1682    }
1683    if (ua->pint32_val) {
1684       db_delete_media_record(ua->jcr, ua->db, &mr);
1685    }
1686    return 1;
1687 }
1688
1689 /*
1690  * Delete a pool record from the database -- dangerous   
1691  */
1692 static int delete_pool(UAContext *ua)
1693 {
1694    POOL_DBR  pr;
1695    
1696    memset(&pr, 0, sizeof(pr));
1697
1698    if (!get_pool_dbr(ua, &pr)) {
1699       return 1;
1700    }
1701    if (!get_yesno(ua, _("Are you sure you want to delete this Pool? (yes/no): "))) {
1702       return 1;
1703    }
1704    if (ua->pint32_val) {
1705       db_delete_pool_record(ua->jcr, ua->db, &pr);
1706    }
1707    return 1;
1708 }
1709
1710
1711 static void do_mount_cmd(UAContext *ua, const char *command)
1712 {
1713    STORE *store;
1714    BSOCK *sd;
1715    char dev_name[MAX_NAME_LENGTH];
1716
1717
1718    if (!open_db(ua)) {
1719       return;
1720    }
1721    Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1722
1723    store = get_storage_resource(ua, 1);
1724    if (!store) {
1725       return;
1726    }
1727
1728    Dmsg2(120, "Found storage, MediaType=%s DevName=%s\n",
1729       store->media_type, store->dev_name);
1730
1731    ua->jcr->store = store;
1732    if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
1733       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1734       return;
1735    }
1736    sd = ua->jcr->store_bsock;
1737    strcpy(dev_name, store->dev_name);
1738    bash_spaces(dev_name);
1739    bnet_fsend(sd, "%s %s", command, dev_name);
1740    while (bnet_recv(sd) >= 0) {
1741       bsendmsg(ua, "%s", sd->msg);
1742    }
1743    bnet_sig(sd, BNET_TERMINATE);
1744    bnet_close(sd);
1745    ua->jcr->store_bsock = NULL;
1746 }
1747
1748 /*
1749  * mount [storage | device] <name>
1750  */
1751 static int mount_cmd(UAContext *ua, const char *cmd)
1752 {
1753    do_mount_cmd(ua, "mount");          /* mount */
1754    return 1;
1755 }
1756
1757
1758 /*
1759  * unmount [storage | device] <name>
1760  */
1761 static int unmount_cmd(UAContext *ua, const char *cmd)
1762 {
1763    do_mount_cmd(ua, "unmount");          /* unmount */
1764    return 1;
1765 }
1766
1767
1768 /*
1769  * release [storage | device] <name>
1770  */
1771 static int release_cmd(UAContext *ua, const char *cmd)
1772 {
1773    do_mount_cmd(ua, "release");          /* release */
1774    return 1;
1775 }
1776
1777
1778 /*
1779  * Switch databases
1780  *   use catalog=<name>
1781  */
1782 static int use_cmd(UAContext *ua, const char *cmd)
1783 {
1784    CAT *oldcatalog, *catalog;
1785
1786
1787    close_db(ua);                      /* close any previously open db */
1788    oldcatalog = ua->catalog;
1789
1790    if (!(catalog = get_catalog_resource(ua))) {
1791       ua->catalog = oldcatalog;
1792    } else {
1793       ua->catalog = catalog;
1794    }
1795    if (open_db(ua)) {
1796       bsendmsg(ua, _("Using Catalog name=%s DB=%s\n"),
1797          ua->catalog->hdr.name, ua->catalog->db_name);
1798    }
1799    return 1;
1800 }
1801
1802 int quit_cmd(UAContext *ua, const char *cmd) 
1803 {
1804    ua->quit = TRUE;
1805    return 1;
1806 }
1807
1808 /*
1809  * Wait until no job is running 
1810  */
1811 int wait_cmd(UAContext *ua, const char *cmd) 
1812 {
1813    JCR *jcr;
1814    bmicrosleep(0, 200000);            /* let job actually start */
1815    for (bool running=true; running; ) {
1816       running = false;
1817       lock_jcr_chain();
1818       foreach_jcr(jcr) {
1819          if (jcr->JobId != 0) {
1820             running = true;
1821             free_locked_jcr(jcr);
1822             break;
1823          }
1824          free_locked_jcr(jcr);
1825       }
1826       unlock_jcr_chain();
1827       if (running) {
1828          bmicrosleep(1, 0);
1829       }
1830    }
1831    return 1;
1832 }
1833
1834
1835 static int help_cmd(UAContext *ua, const char *cmd)
1836 {
1837    unsigned int i;
1838
1839    bsendmsg(ua, _("  Command    Description\n  =======    ===========\n"));
1840    for (i=0; i<comsize; i++) {
1841       bsendmsg(ua, _("  %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1842    }
1843    bsendmsg(ua, _("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1844    return 1;
1845 }
1846
1847 static int version_cmd(UAContext *ua, const char *cmd)
1848 {
1849    bsendmsg(ua, "%s Version: " VERSION " (" BDATE ")\n", my_name);
1850    return 1;
1851 }
1852
1853
1854 /* A bit brain damaged in that if the user has not done
1855  * a "use catalog xxx" command, we simply find the first
1856  * catalog resource and open it.
1857  */
1858 int open_db(UAContext *ua)
1859 {
1860    if (ua->db) {
1861       return 1;
1862    }
1863    if (!ua->catalog) {
1864       LockRes();
1865       ua->catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
1866       UnlockRes();
1867       if (!ua->catalog) {    
1868          bsendmsg(ua, _("Could not find a Catalog resource\n"));
1869          return 0;
1870       } else {
1871          bsendmsg(ua, _("Using default Catalog name=%s DB=%s\n"), 
1872             ua->catalog->hdr.name, ua->catalog->db_name);
1873       }
1874    }
1875
1876    ua->jcr->catalog = ua->catalog;
1877
1878    Dmsg0(150, "Open database\n");
1879    ua->db = db_init_database(ua->jcr, ua->catalog->db_name, ua->catalog->db_user,
1880                              ua->catalog->db_password, ua->catalog->db_address,
1881                              ua->catalog->db_port, ua->catalog->db_socket);
1882    if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
1883       bsendmsg(ua, _("Could not open database \"%s\".\n"),
1884                  ua->catalog->db_name);
1885       if (ua->db) {
1886          bsendmsg(ua, "%s", db_strerror(ua->db));
1887       }
1888       close_db(ua);
1889       return 0;
1890    }
1891    ua->jcr->db = ua->db;
1892    Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
1893    return 1;
1894 }
1895
1896 void close_db(UAContext *ua)
1897 {
1898    if (ua->db) {
1899       db_close_database(ua->jcr, ua->db);
1900       ua->db = NULL;
1901       if (ua->jcr) {
1902          ua->jcr->db = NULL;
1903       }
1904    }
1905 }