]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_update.c
kes Pass jcr to tls routines so debug messages can be handled better.
[bacula/bacula] / bacula / src / dird / ua_update.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 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 two of the GNU 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 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 John Walker.
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 -- Update command processing
31  *     Split from ua_cmds.c March 2005
32  *
33  *     Kern Sibbald, September MM
34  *
35  *   Version $Id$
36  */
37
38 #include "bacula.h"
39 #include "dird.h"
40
41 /* Forward referenced functions */
42 static int update_volume(UAContext *ua);
43 static bool update_pool(UAContext *ua);
44 static bool update_job(UAContext *ua);
45
46 /*
47  * Update a Pool Record in the database.
48  *  It is always updated from the Resource record.
49  *
50  *    update pool=<pool-name>
51  *         updates pool from Pool resource
52  *    update media pool=<pool-name> volume=<volume-name>
53  *         changes pool info for volume
54  *    update slots [scan=...]
55  *         updates autochanger slots
56  */
57 int update_cmd(UAContext *ua, const char *cmd)
58 {
59    static const char *kw[] = {
60       NT_("media"),  /* 0 */
61       NT_("volume"), /* 1 */
62       NT_("pool"),   /* 2 */
63       NT_("slots"),  /* 3 */
64       NT_("jobid"),  /* 4 */
65       NULL};
66
67    if (!open_client_db(ua)) {
68       return 1;
69    }
70
71    switch (find_arg_keyword(ua, kw)) {
72    case 0:
73    case 1:
74       update_volume(ua);
75       return 1;
76    case 2:
77       update_pool(ua);
78       return 1;
79    case 3:
80       update_slots(ua);
81       return 1;
82    case 4:
83       update_job(ua);
84       return 1;
85    default:
86       break;
87    }
88
89    start_prompt(ua, _("Update choice:\n"));
90    add_prompt(ua, _("Volume parameters"));
91    add_prompt(ua, _("Pool from resource"));
92    add_prompt(ua, _("Slots from autochanger"));
93    switch (do_prompt(ua, _("item"), _("Choose catalog item to update"), NULL, 0)) {
94    case 0:
95       update_volume(ua);
96       break;
97    case 1:
98       update_pool(ua);
99       break;
100    case 2:
101       update_slots(ua);
102       break;
103    default:
104       break;
105    }
106    return 1;
107 }
108
109 static void update_volstatus(UAContext *ua, const char *val, MEDIA_DBR *mr)
110 {
111    POOL_MEM query(PM_MESSAGE);
112    const char *kw[] = {
113       NT_("Append"),
114       NT_("Archive"),
115       NT_("Disabled"),
116       NT_("Full"),
117       NT_("Used"),
118       NT_("Cleaning"),
119       NT_("Recycle"),
120       NT_("Read-Only"),
121       NT_("Error"),
122       NULL};
123    bool found = false;
124    int i;
125
126    for (i=0; kw[i]; i++) {
127       if (strcasecmp(val, kw[i]) == 0) {
128          found = true;
129          break;
130       }
131    }
132    if (!found) {
133       ua->error_msg(_("Invalid VolStatus specified: %s\n"), val);
134    } else {
135       char ed1[50];
136       bstrncpy(mr->VolStatus, kw[i], sizeof(mr->VolStatus));
137       Mmsg(query, "UPDATE Media SET VolStatus='%s' WHERE MediaId=%s",
138          mr->VolStatus, edit_int64(mr->MediaId,ed1));
139       if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
140          ua->error_msg("%s", db_strerror(ua->db));
141       } else {
142          ua->info_msg(_("New Volume status is: %s\n"), mr->VolStatus);
143       }
144    }
145 }
146
147 static void update_volretention(UAContext *ua, char *val, MEDIA_DBR *mr)
148 {
149    char ed1[150], ed2[50];
150    POOL_MEM query(PM_MESSAGE);
151    if (!duration_to_utime(val, &mr->VolRetention)) {
152       ua->error_msg(_("Invalid retention period specified: %s\n"), val);
153       return;
154    }
155    Mmsg(query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%s",
156       edit_uint64(mr->VolRetention, ed1), edit_int64(mr->MediaId,ed2));
157    if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
158       ua->error_msg("%s", db_strerror(ua->db));
159    } else {
160       ua->info_msg(_("New retention period is: %s\n"),
161          edit_utime(mr->VolRetention, ed1, sizeof(ed1)));
162    }
163 }
164
165 static void update_voluseduration(UAContext *ua, char *val, MEDIA_DBR *mr)
166 {
167    char ed1[150], ed2[50];
168    POOL_MEM query(PM_MESSAGE);
169
170    if (!duration_to_utime(val, &mr->VolUseDuration)) {
171       ua->error_msg(_("Invalid use duration specified: %s\n"), val);
172       return;
173    }
174    Mmsg(query, "UPDATE Media SET VolUseDuration=%s WHERE MediaId=%s",
175       edit_uint64(mr->VolUseDuration, ed1), edit_int64(mr->MediaId,ed2));
176    if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
177       ua->error_msg("%s", db_strerror(ua->db));
178    } else {
179       ua->info_msg(_("New use duration is: %s\n"),
180          edit_utime(mr->VolUseDuration, ed1, sizeof(ed1)));
181    }
182 }
183
184 static void update_volmaxjobs(UAContext *ua, char *val, MEDIA_DBR *mr)
185 {
186    POOL_MEM query(PM_MESSAGE);
187    char ed1[50];
188    Mmsg(query, "UPDATE Media SET MaxVolJobs=%s WHERE MediaId=%s",
189       val, edit_int64(mr->MediaId,ed1));
190    if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
191       ua->error_msg("%s", db_strerror(ua->db));
192    } else {
193       ua->info_msg(_("New max jobs is: %s\n"), val);
194    }
195 }
196
197 static void update_volmaxfiles(UAContext *ua, char *val, MEDIA_DBR *mr)
198 {
199    POOL_MEM query(PM_MESSAGE);
200    char ed1[50];
201    Mmsg(query, "UPDATE Media SET MaxVolFiles=%s WHERE MediaId=%s",
202       val, edit_int64(mr->MediaId, ed1));
203    if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
204       ua->error_msg("%s", db_strerror(ua->db));
205    } else {
206       ua->info_msg(_("New max files is: %s\n"), val);
207    }
208 }
209
210 static void update_volmaxbytes(UAContext *ua, char *val, MEDIA_DBR *mr)
211 {
212    uint64_t maxbytes;
213    char ed1[50], ed2[50];
214    POOL_MEM query(PM_MESSAGE);
215
216    if (!size_to_uint64(val, strlen(val), &maxbytes)) {
217       ua->error_msg(_("Invalid max. bytes specification: %s\n"), val);
218       return;
219    }
220    Mmsg(query, "UPDATE Media SET MaxVolBytes=%s WHERE MediaId=%s",
221       edit_uint64(maxbytes, ed1), edit_int64(mr->MediaId, ed2));
222    if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
223       ua->error_msg("%s", db_strerror(ua->db));
224    } else {
225       ua->info_msg(_("New Max bytes is: %s\n"), edit_uint64(maxbytes, ed1));
226    }
227 }
228
229 static void update_volrecycle(UAContext *ua, char *val, MEDIA_DBR *mr)
230 {
231    int recycle;
232    char ed1[50];
233
234    POOL_MEM query(PM_MESSAGE);
235    if (!is_yesno(val, &recycle)) {
236       ua->error_msg(_("Invalid value. It must be yes or no.\n"));
237       return;
238    }
239    Mmsg(query, "UPDATE Media SET Recycle=%d WHERE MediaId=%s",
240       recycle, edit_int64(mr->MediaId, ed1));
241    if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
242       ua->error_msg("%s", db_strerror(ua->db));
243    } else {
244       ua->info_msg(_("New Recycle flag is: %s\n"),
245          recycle==1?_("yes"):_("no"));
246    }
247 }
248
249 static void update_volinchanger(UAContext *ua, char *val, MEDIA_DBR *mr)
250 {
251    int InChanger;
252    char ed1[50];
253
254    POOL_MEM query(PM_MESSAGE);
255    if (!is_yesno(val, &InChanger)) {
256       ua->error_msg(_("Invalid value. It must be yes or no.\n"));
257       return;
258    }
259    Mmsg(query, "UPDATE Media SET InChanger=%d WHERE MediaId=%s",
260       InChanger, edit_int64(mr->MediaId, ed1));
261    if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
262       ua->error_msg("%s", db_strerror(ua->db));
263    } else {
264       ua->info_msg(_("New InChanger flag is: %s\n"),
265          InChanger==1?_("yes"):_("no"));
266    }
267 }
268
269
270 static void update_volslot(UAContext *ua, char *val, MEDIA_DBR *mr)
271 {
272    POOL_DBR pr;
273
274    memset(&pr, 0, sizeof(POOL_DBR));
275    pr.PoolId = mr->PoolId;
276    if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
277       ua->error_msg("%s", db_strerror(ua->db));
278       return;
279    }
280    mr->Slot = atoi(val);
281    if (pr.MaxVols > 0 && mr->Slot > (int)pr.MaxVols) {
282       ua->error_msg(_("Invalid slot, it must be between 0 and MaxVols=%d\n"),
283          pr.MaxVols);
284       return;
285    }
286    /*
287     * Make sure to use db_update... rather than doing this directly,
288     *   so that any Slot is handled correctly.
289     */
290    if (!db_update_media_record(ua->jcr, ua->db, mr)) {
291       ua->error_msg(_("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
292    } else {
293       ua->info_msg(_("New Slot is: %d\n"), mr->Slot);
294    }
295 }
296
297 /* Modify the Pool in which this Volume is located */
298 void update_vol_pool(UAContext *ua, char *val, MEDIA_DBR *mr, POOL_DBR *opr)
299 {
300    POOL_DBR pr;
301    POOL_MEM query(PM_MESSAGE);
302    char ed1[50], ed2[50];
303
304    memset(&pr, 0, sizeof(pr));
305    bstrncpy(pr.Name, val, sizeof(pr.Name));
306    if (!get_pool_dbr(ua, &pr)) {
307       return;
308    }
309    mr->PoolId = pr.PoolId;            /* set new PoolId */
310    /*
311     */
312    db_lock(ua->db);
313    Mmsg(query, "UPDATE Media SET PoolId=%s WHERE MediaId=%s",
314       edit_int64(mr->PoolId, ed1), edit_int64(mr->MediaId, ed2));
315    if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
316       ua->error_msg("%s", db_strerror(ua->db));
317    } else {
318       ua->info_msg(_("New Pool is: %s\n"), pr.Name);
319       opr->NumVols--;
320       if (!db_update_pool_record(ua->jcr, ua->db, opr)) {
321          ua->error_msg("%s", db_strerror(ua->db));
322       }
323       pr.NumVols++;
324       if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
325          ua->error_msg("%s", db_strerror(ua->db));
326       }
327    }
328    db_unlock(ua->db);
329 }
330
331 /* Modify the RecyclePool of a Volume */
332 void update_vol_recyclepool(UAContext *ua, char *val, MEDIA_DBR *mr)
333 {
334    POOL_DBR pr;
335    POOL_MEM query(PM_MESSAGE);
336    char ed1[50], ed2[50], *poolname;
337
338    if(val && *val) { /* update volume recyclepool="Scratch" */
339      /* If a pool name is given, look up the PoolId */
340      memset(&pr, 0, sizeof(pr));
341      bstrncpy(pr.Name, val, sizeof(pr.Name));
342      if (!get_pool_dbr(ua, &pr, NT_("recyclepool"))) {
343         return;
344      }
345      /* pool = select_pool_resource(ua);  */
346      mr->RecyclePoolId = pr.PoolId;            /* get the PoolId */
347      poolname = pr.Name;
348
349   } else { /* update volume recyclepool="" */
350     /* If no pool name is given, set the PoolId to 0 (the default) */
351      mr->RecyclePoolId = 0;
352      poolname = _("*None*");
353   }
354
355    db_lock(ua->db);
356    Mmsg(query, "UPDATE Media SET RecyclePoolId=%s WHERE MediaId=%s",
357       edit_int64(mr->RecyclePoolId, ed1), edit_int64(mr->MediaId, ed2));
358    if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
359       ua->error_msg("%s", db_strerror(ua->db));
360    } else {
361       ua->info_msg(_("New RecyclePool is: %s\n"), poolname);
362    }
363    db_unlock(ua->db);
364 }
365
366 /*
367  * Refresh the Volume information from the Pool record
368  */
369 static void update_vol_from_pool(UAContext *ua, MEDIA_DBR *mr)
370 {
371    POOL_DBR pr;
372
373    memset(&pr, 0, sizeof(pr));
374    pr.PoolId = mr->PoolId;
375    if (!db_get_pool_record(ua->jcr, ua->db, &pr) ||
376        !acl_access_ok(ua, Pool_ACL, pr.Name)) {
377       return;
378    }
379    set_pool_dbr_defaults_in_media_dbr(mr, &pr);
380    if (!db_update_media_defaults(ua->jcr, ua->db, mr)) {
381       ua->error_msg(_("Error updating Volume record: ERR=%s"), db_strerror(ua->db));
382    } else {
383       ua->info_msg(_("Volume defaults updated from \"%s\" Pool record.\n"),
384          pr.Name);
385    }
386 }
387
388 /*
389  * Refresh the Volume information from the Pool record
390  *   for all Volumes
391  */
392 static void update_all_vols_from_pool(UAContext *ua, const char *pool_name) 
393 {
394    POOL_DBR pr;
395    MEDIA_DBR mr;
396
397    memset(&pr, 0, sizeof(pr));
398    memset(&mr, 0, sizeof(mr));
399
400    bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
401    if (!get_pool_dbr(ua, &pr)) {
402       return;
403    }
404    set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
405    mr.PoolId = pr.PoolId;
406    if (!db_update_media_defaults(ua->jcr, ua->db, &mr)) {
407       ua->error_msg(_("Error updating Volume records: ERR=%s"), db_strerror(ua->db));
408    } else {
409       ua->info_msg(_("All Volume defaults updated from \"%s\" Pool record.\n"),
410          pr.Name);
411    }
412 }
413
414 static void update_all_vols(UAContext *ua)
415 {
416    int i, num_pools;
417    uint32_t *ids;
418    POOL_DBR pr;
419    MEDIA_DBR mr;
420
421    memset(&pr, 0, sizeof(pr));
422    memset(&mr, 0, sizeof(mr));
423    
424    if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
425       ua->error_msg(_("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
426       return;
427    }
428
429    for (i=0; i<num_pools; i++) {
430       pr.PoolId = ids[i];
431       if (!db_get_pool_record(ua->jcr, ua->db, &pr)) { /* ***FIXME*** use acl? */
432          ua->warning_msg(_("Updating all pools, but skipped PoolId=%d. ERR=%s\n"), db_strerror(ua->db));
433          continue;
434       }
435
436       set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
437       mr.PoolId = pr.PoolId;
438
439       if (!db_update_media_defaults(ua->jcr, ua->db, &mr)) {
440          ua->error_msg(_("Error updating Volume records: ERR=%s"), db_strerror(ua->db));
441       } else {
442          ua->info_msg(_("All Volume defaults updated from \"%s\" Pool record.\n"),
443             pr.Name);
444       }
445    }
446
447    free(ids);
448 }
449
450 static void update_volenabled(UAContext *ua, char *val, MEDIA_DBR *mr)
451 {
452    mr->Enabled = get_enabled(ua, val);
453    if (mr->Enabled < 0) {
454       return;
455    }
456    if (!db_update_media_record(ua->jcr, ua->db, mr)) {
457       ua->error_msg(_("Error updating media record Enabled: ERR=%s"), db_strerror(ua->db));
458    } else {
459       ua->info_msg(_("New Enabled is: %d\n"), mr->Enabled);
460    }
461 }
462
463
464
465 /*
466  * Update a media record -- allows you to change the
467  *  Volume status. E.g. if you want Bacula to stop
468  *  writing on the volume, set it to anything other
469  *  than Append.
470  */
471 static int update_volume(UAContext *ua)
472 {
473    MEDIA_DBR mr;
474    POOL *pool;
475    POOL_DBR pr;
476    POOLMEM *query;
477    char buf[1000];
478    char ed1[130];
479    bool done = false;
480    int i;
481    const char *kw[] = {
482       NT_("VolStatus"),                /* 0 */
483       NT_("VolRetention"),             /* 1 */
484       NT_("VolUse"),                   /* 2 */
485       NT_("MaxVolJobs"),               /* 3 */
486       NT_("MaxVolFiles"),              /* 4 */
487       NT_("MaxVolBytes"),              /* 5 */
488       NT_("Recycle"),                  /* 6 */
489       NT_("InChanger"),                /* 7 */
490       NT_("Slot"),                     /* 8 */
491       NT_("Pool"),                     /* 9 */
492       NT_("FromPool"),                 /* 10 */
493       NT_("AllFromPool"),              /* 11 !!! see below !!! */
494       NT_("Enabled"),                  /* 12 */
495       NT_("RecyclePool"),              /* 13 */
496       NULL };
497
498 #define AllFromPool 11               /* keep this updated with above */
499
500    for (i=0; kw[i]; i++) {
501       int j;
502       POOL_DBR pr;
503
504       if ((j=find_arg_with_value(ua, kw[i])) > 0) {
505          /* If all from pool don't select a media record */
506          if (i != AllFromPool && !select_media_dbr(ua, &mr)) {
507             return 0;
508          }
509          switch (i) {
510          case 0:
511             update_volstatus(ua, ua->argv[j], &mr);
512             break;
513          case 1:
514             update_volretention(ua, ua->argv[j], &mr);
515             break;
516          case 2:
517             update_voluseduration(ua, ua->argv[j], &mr);
518             break;
519          case 3:
520             update_volmaxjobs(ua, ua->argv[j], &mr);
521             break;
522          case 4:
523             update_volmaxfiles(ua, ua->argv[j], &mr);
524             break;
525          case 5:
526             update_volmaxbytes(ua, ua->argv[j], &mr);
527             break;
528          case 6:
529             update_volrecycle(ua, ua->argv[j], &mr);
530             break;
531          case 7:
532             update_volinchanger(ua, ua->argv[j], &mr);
533             break;
534          case 8:
535             update_volslot(ua, ua->argv[j], &mr);
536             break;
537          case 9:
538             memset(&pr, 0, sizeof(POOL_DBR));
539             pr.PoolId = mr.PoolId;
540             if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
541                ua->error_msg("%s", db_strerror(ua->db));
542                break;
543             }
544             update_vol_pool(ua, ua->argv[j], &mr, &pr);
545             break;
546          case 10:
547             update_vol_from_pool(ua, &mr);
548             return 1;
549          case 11:
550             update_all_vols_from_pool(ua, ua->argv[j]);
551             return 1;
552          case 12:
553             update_volenabled(ua, ua->argv[j], &mr);
554             break;
555          case 13:
556             update_vol_recyclepool(ua, ua->argv[j], &mr);
557             break;
558          }
559          done = true;
560       }
561    }
562
563    /* Allow user to simply update all volumes */
564    if (find_arg(ua, NT_("fromallpools")) > 0) {
565       update_all_vols(ua);
566       return 1;
567    }
568
569    for ( ; !done; ) {
570       start_prompt(ua, _("Parameters to modify:\n"));
571       add_prompt(ua, _("Volume Status"));              /* 0 */
572       add_prompt(ua, _("Volume Retention Period"));    /* 1 */
573       add_prompt(ua, _("Volume Use Duration"));        /* 2 */
574       add_prompt(ua, _("Maximum Volume Jobs"));        /* 3 */
575       add_prompt(ua, _("Maximum Volume Files"));       /* 4 */
576       add_prompt(ua, _("Maximum Volume Bytes"));       /* 5 */
577       add_prompt(ua, _("Recycle Flag"));               /* 6 */
578       add_prompt(ua, _("Slot"));                       /* 7 */
579       add_prompt(ua, _("InChanger Flag"));             /* 8 */
580       add_prompt(ua, _("Volume Files"));               /* 9 */
581       add_prompt(ua, _("Pool"));                       /* 10 */
582       add_prompt(ua, _("Volume from Pool"));           /* 11 */
583       add_prompt(ua, _("All Volumes from Pool"));      /* 12 */
584       add_prompt(ua, _("All Volumes from all Pools")); /* 13 */
585       add_prompt(ua, _("Enabled")),                    /* 14 */
586       add_prompt(ua, _("RecyclePool")),                /* 15 */
587       add_prompt(ua, _("Done"));                       /* 16 */
588       i = do_prompt(ua, "", _("Select parameter to modify"), NULL, 0);  
589
590       /* For All Volumes, All Volumes from Pool, and Done, we don't need
591            * a Volume record */
592       if ( i != 12 && i != 13 && i != 16) {
593          if (!select_media_dbr(ua, &mr)) {  /* Get Volume record */
594             return 0;
595          }
596          ua->info_msg(_("Updating Volume \"%s\"\n"), mr.VolumeName);
597       }
598       switch (i) {
599       case 0:                         /* Volume Status */
600          /* Modify Volume Status */
601          ua->info_msg(_("Current Volume status is: %s\n"), mr.VolStatus);
602          start_prompt(ua, _("Possible Values are:\n"));
603          add_prompt(ua, NT_("Append")); 
604          add_prompt(ua, NT_("Archive"));
605          add_prompt(ua, NT_("Disabled"));
606          add_prompt(ua, NT_("Full"));
607          add_prompt(ua, NT_("Used"));
608          add_prompt(ua, NT_("Cleaning"));
609          if (strcmp(mr.VolStatus, NT_("Purged")) == 0) {
610             add_prompt(ua, NT_("Recycle"));
611          }
612          add_prompt(ua, NT_("Read-Only"));
613          if (do_prompt(ua, "", _("Choose new Volume Status"), ua->cmd, sizeof(mr.VolStatus)) < 0) {
614             return 1;
615          }
616          update_volstatus(ua, ua->cmd, &mr);
617          break;
618       case 1:                         /* Retention */
619          ua->info_msg(_("Current retention period is: %s\n"),
620             edit_utime(mr.VolRetention, ed1, sizeof(ed1)));
621          if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
622             return 0;
623          }
624          update_volretention(ua, ua->cmd, &mr);
625          break;
626
627       case 2:                         /* Use Duration */
628          ua->info_msg(_("Current use duration is: %s\n"),
629             edit_utime(mr.VolUseDuration, ed1, sizeof(ed1)));
630          if (!get_cmd(ua, _("Enter Volume Use Duration: "))) {
631             return 0;
632          }
633          update_voluseduration(ua, ua->cmd, &mr);
634          break;
635
636       case 3:                         /* Max Jobs */
637          ua->info_msg(_("Current max jobs is: %u\n"), mr.MaxVolJobs);
638          if (!get_pint(ua, _("Enter new Maximum Jobs: "))) {
639             return 0;
640          }
641          update_volmaxjobs(ua, ua->cmd, &mr);
642          break;
643
644       case 4:                         /* Max Files */
645          ua->info_msg(_("Current max files is: %u\n"), mr.MaxVolFiles);
646          if (!get_pint(ua, _("Enter new Maximum Files: "))) {
647             return 0;
648          }
649          update_volmaxfiles(ua, ua->cmd, &mr);
650          break;
651
652       case 5:                         /* Max Bytes */
653          ua->info_msg(_("Current value is: %s\n"), edit_uint64(mr.MaxVolBytes, ed1));
654          if (!get_cmd(ua, _("Enter new Maximum Bytes: "))) {
655             return 0;
656          }
657          update_volmaxbytes(ua, ua->cmd, &mr);
658          break;
659
660
661       case 6:                         /* Recycle */
662          ua->info_msg(_("Current recycle flag is: %s\n"),
663             mr.Recycle==1?_("yes"):_("no"));
664          if (!get_yesno(ua, _("Enter new Recycle status: "))) {
665             return 0;
666          }
667          update_volrecycle(ua, ua->cmd, &mr);
668          break;
669
670       case 7:                         /* Slot */
671          ua->info_msg(_("Current Slot is: %d\n"), mr.Slot);
672          if (!get_pint(ua, _("Enter new Slot: "))) {
673             return 0;
674          }
675          update_volslot(ua, ua->cmd, &mr);
676          break;
677          
678       case 8:                         /* InChanger */
679          ua->info_msg(_("Current InChanger flag is: %d\n"), mr.InChanger);
680          bsnprintf(buf, sizeof(buf), _("Set InChanger flag for Volume \"%s\": yes/no: "),
681             mr.VolumeName);
682          if (!get_yesno(ua, buf)) {
683             return 0;
684          }
685          mr.InChanger = ua->pint32_val;
686          /*
687           * Make sure to use db_update... rather than doing this directly,
688           *   so that any Slot is handled correctly.
689           */
690          if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
691             ua->error_msg(_("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
692          } else {
693             ua->info_msg(_("New InChanger flag is: %d\n"), mr.InChanger);
694          }
695          break;
696
697
698       case 9:                         /* Volume Files */
699          int32_t VolFiles;
700          ua->warning_msg(_("Warning changing Volume Files can result\n"
701                         "in loss of data on your Volume\n\n"));
702          ua->info_msg(_("Current Volume Files is: %u\n"), mr.VolFiles);
703          if (!get_pint(ua, _("Enter new number of Files for Volume: "))) {
704             return 0;
705          }
706          VolFiles = ua->pint32_val;
707          if (VolFiles != (int)(mr.VolFiles + 1)) {
708             ua->warning_msg(_("Normally, you should only increase Volume Files by one!\n"));
709             if (!get_yesno(ua, _("Increase Volume Files? (yes/no): ")) || ua->pint32_val == 0) {
710                break;
711             }
712          }
713          query = get_pool_memory(PM_MESSAGE);
714          Mmsg(query, "UPDATE Media SET VolFiles=%u WHERE MediaId=%s",
715             VolFiles, edit_int64(mr.MediaId, ed1));
716          if (!db_sql_query(ua->db, query, NULL, NULL)) {
717             ua->error_msg("%s", db_strerror(ua->db));
718          } else {
719             ua->info_msg(_("New Volume Files is: %u\n"), VolFiles);
720          }
721          free_pool_memory(query);
722          break;
723
724       case 10:                        /* Volume's Pool */
725          memset(&pr, 0, sizeof(POOL_DBR));
726          pr.PoolId = mr.PoolId;
727          if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
728             ua->error_msg("%s", db_strerror(ua->db));
729             return 0;
730          }
731          ua->info_msg(_("Current Pool is: %s\n"), pr.Name);
732          if (!get_cmd(ua, _("Enter new Pool name: "))) {
733             return 0;
734          }
735          update_vol_pool(ua, ua->cmd, &mr, &pr);
736          return 1;
737
738       case 11:
739          update_vol_from_pool(ua, &mr);
740          return 1;
741       case 12:
742          pool = select_pool_resource(ua);
743          if (pool) {
744             update_all_vols_from_pool(ua, pool->name());
745          }
746          return 1;
747
748       case 13:
749          update_all_vols(ua);
750          return 1;
751
752       case 14:
753          ua->info_msg(_("Current Enabled is: %d\n"), mr.Enabled);
754          if (!get_cmd(ua, _("Enter new Enabled: "))) {
755             return 0;
756          }
757          if (strcasecmp(ua->cmd, "yes") == 0 || strcasecmp(ua->cmd, "true") == 0) {
758             mr.Enabled = 1;
759          } else if (strcasecmp(ua->cmd, "no") == 0 || strcasecmp(ua->cmd, "false") == 0) {
760             mr.Enabled = 0;
761          } else if (strcasecmp(ua->cmd, "archived") == 0) { 
762             mr.Enabled = 2;
763          } else {
764             mr.Enabled = atoi(ua->cmd);
765          }
766          update_volenabled(ua, ua->cmd, &mr);
767          break;
768
769       case 15:
770          memset(&pr, 0, sizeof(POOL_DBR));
771          pr.PoolId = mr.RecyclePoolId;
772          if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
773             ua->info_msg(_("Current RecyclePool is: %s\n"), pr.Name);
774          } else {
775             ua->info_msg(_("No current RecyclePool\n"));
776          }
777          if (!select_pool_dbr(ua, &pr, NT_("recyclepool"))) {
778             return 0;
779          }
780          update_vol_recyclepool(ua, pr.Name, &mr);
781          return 1;
782
783       default:                        /* Done or error */
784          ua->info_msg(_("Selection terminated.\n"));
785          return 1;
786       }
787    }
788    return 1;
789 }
790
791 /*
792  * Update pool record -- pull info from current POOL resource
793  */
794 static bool update_pool(UAContext *ua)
795 {
796    POOL_DBR  pr;
797    int id;
798    POOL *pool;
799    POOLMEM *query;
800    char ed1[50];
801
802    pool = get_pool_resource(ua);
803    if (!pool) {
804       return false;
805    }
806
807    memset(&pr, 0, sizeof(pr));
808    bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
809    if (!get_pool_dbr(ua, &pr)) {
810       return false;
811    }
812
813    set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE); /* update */
814    set_pooldbr_recyclepoolid(ua->jcr, ua->db, &pr, pool);
815
816    id = db_update_pool_record(ua->jcr, ua->db, &pr);
817    if (id <= 0) {
818       ua->error_msg(_("db_update_pool_record returned %d. ERR=%s\n"),
819          id, db_strerror(ua->db));
820    }
821    query = get_pool_memory(PM_MESSAGE);
822    Mmsg(query, list_pool, edit_int64(pr.PoolId, ed1));
823    db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST);
824    free_pool_memory(query);
825    ua->info_msg(_("Pool DB record updated from resource.\n"));
826    return true;
827 }
828
829 /*
830  * Update a Job record -- allows you to change the
831  *  date fields in a Job record. This helps when
832  *  providing migration from other vendors.
833  */
834 static bool update_job(UAContext *ua)
835 {
836    int i;
837    char ed1[50], ed2[50];
838    POOL_MEM cmd(PM_MESSAGE);
839    JOB_DBR jr;
840    CLIENT_DBR cr;
841    utime_t StartTime;
842    char *client_name = NULL;
843    char *start_time = NULL;
844    const char *kw[] = {
845       NT_("starttime"),                   /* 0 */
846       NT_("client"),                      /* 1 */
847       NULL };
848
849    Dmsg1(200, "cmd=%s\n", ua->cmd);
850    i = find_arg_with_value(ua, NT_("jobid"));
851    if (i < 0) {
852       ua->error_msg(_("Expect JobId keyword, not found.\n"));
853       return false;
854    }
855    memset(&jr, 0, sizeof(jr));
856    memset(&cr, 0, sizeof(cr));
857    jr.JobId = str_to_int64(ua->argv[i]);
858    if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
859       ua->error_msg("%s", db_strerror(ua->db));
860       return false;
861    }
862
863    for (i=0; kw[i]; i++) {
864       int j;
865       if ((j=find_arg_with_value(ua, kw[i])) >= 0) {
866          switch (i) {
867          case 0:                         /* start time */
868             start_time = ua->argv[j];
869             break;
870          case 1:                         /* Client name */
871             client_name = ua->argv[j];
872             break;
873          }
874       }
875    }
876    if (!client_name && !start_time) {
877       ua->error_msg(_("Neither Client nor StartTime specified.\n"));
878       return 0;
879    }
880    if (client_name) {
881       if (!get_client_dbr(ua, &cr)) {
882          return false;
883       }
884       jr.ClientId = cr.ClientId;
885    }
886    if (start_time) {
887       utime_t delta_start;
888
889       StartTime = str_to_utime(start_time);
890       if (StartTime == 0) {
891          ua->error_msg(_("Improper date format: %s\n"), ua->argv[i]);
892          return false;
893       }
894       delta_start = StartTime - jr.StartTime;
895       Dmsg3(200, "ST=%d jr.ST=%d delta=%d\n", (time_t)StartTime, 
896             (time_t)jr.StartTime, (time_t)delta_start);
897       jr.StartTime = (time_t)StartTime;
898       jr.SchedTime += (time_t)delta_start;
899       jr.EndTime += (time_t)delta_start;
900       jr.JobTDate += delta_start;
901       /* Convert to DB times */
902       bstrutime(jr.cStartTime, sizeof(jr.cStartTime), jr.StartTime);
903       bstrutime(jr.cSchedTime, sizeof(jr.cSchedTime), jr.SchedTime);
904       bstrutime(jr.cEndTime, sizeof(jr.cEndTime), jr.EndTime);
905    }
906    Mmsg(cmd, "UPDATE Job SET ClientId=%s,StartTime='%s',SchedTime='%s',"
907              "EndTime='%s',JobTDate=%s WHERE JobId=%s", 
908              edit_int64(jr.ClientId, ed1), 
909              jr.cStartTime,
910              jr.cSchedTime,
911              jr.cEndTime,
912              edit_uint64(jr.JobTDate, ed1), 
913              edit_int64(jr.JobId, ed2));
914    if (!db_sql_query(ua->db, cmd.c_str(), NULL, NULL)) {
915       ua->error_msg("%s", db_strerror(ua->db));
916       return false;
917    }
918    return true;
919 }