]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_update.c
kes Implement 'MaxFullInterval' and start 'MaxDiffInterval' based on
[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];
337
338    memset(&pr, 0, sizeof(pr));
339    bstrncpy(pr.Name, val, sizeof(pr.Name));
340    if (!get_pool_dbr(ua, &pr, NT_("recyclepool"))) {
341       return;
342    }
343    /* pool = select_pool_resource(ua);  */
344    mr->RecyclePoolId = pr.PoolId;            /* get the PoolId */
345
346    db_lock(ua->db);
347    Mmsg(query, "UPDATE Media SET RecyclePoolId=%s WHERE MediaId=%s",
348       edit_int64(mr->RecyclePoolId, ed1), edit_int64(mr->MediaId, ed2));
349    if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
350       ua->error_msg("%s", db_strerror(ua->db));
351    } else {
352       ua->info_msg(_("New RecyclePool is: %s\n"), pr.Name);
353    }
354    db_unlock(ua->db);
355 }
356
357 /*
358  * Refresh the Volume information from the Pool record
359  */
360 static void update_vol_from_pool(UAContext *ua, MEDIA_DBR *mr)
361 {
362    POOL_DBR pr;
363
364    memset(&pr, 0, sizeof(pr));
365    pr.PoolId = mr->PoolId;
366    if (!db_get_pool_record(ua->jcr, ua->db, &pr) ||
367        !acl_access_ok(ua, Pool_ACL, pr.Name)) {
368       return;
369    }
370    set_pool_dbr_defaults_in_media_dbr(mr, &pr);
371    if (!db_update_media_defaults(ua->jcr, ua->db, mr)) {
372       ua->error_msg(_("Error updating Volume record: ERR=%s"), db_strerror(ua->db));
373    } else {
374       ua->info_msg(_("Volume defaults updated from \"%s\" Pool record.\n"),
375          pr.Name);
376    }
377 }
378
379 /*
380  * Refresh the Volume information from the Pool record
381  *   for all Volumes
382  */
383 static void update_all_vols_from_pool(UAContext *ua, const char *pool_name) 
384 {
385    POOL_DBR pr;
386    MEDIA_DBR mr;
387
388    memset(&pr, 0, sizeof(pr));
389    memset(&mr, 0, sizeof(mr));
390
391    bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
392    if (!get_pool_dbr(ua, &pr)) {
393       return;
394    }
395    set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
396    mr.PoolId = pr.PoolId;
397    if (!db_update_media_defaults(ua->jcr, ua->db, &mr)) {
398       ua->error_msg(_("Error updating Volume records: ERR=%s"), db_strerror(ua->db));
399    } else {
400       ua->info_msg(_("All Volume defaults updated from \"%s\" Pool record.\n"),
401          pr.Name);
402    }
403 }
404
405 static void update_all_vols(UAContext *ua)
406 {
407    int i, num_pools;
408    uint32_t *ids;
409    POOL_DBR pr;
410    MEDIA_DBR mr;
411
412    memset(&pr, 0, sizeof(pr));
413    memset(&mr, 0, sizeof(mr));
414    
415    if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
416       ua->error_msg(_("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
417       return;
418    }
419
420    for (i=0; i<num_pools; i++) {
421       pr.PoolId = ids[i];
422       if (!db_get_pool_record(ua->jcr, ua->db, &pr)) { /* ***FIXME*** use acl? */
423          ua->warning_msg(_("Updating all pools, but skipped PoolId=%d. ERR=%s\n"), db_strerror(ua->db));
424          continue;
425       }
426
427       set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
428       mr.PoolId = pr.PoolId;
429
430       if (!db_update_media_defaults(ua->jcr, ua->db, &mr)) {
431          ua->error_msg(_("Error updating Volume records: ERR=%s"), db_strerror(ua->db));
432       } else {
433          ua->info_msg(_("All Volume defaults updated from \"%s\" Pool record.\n"),
434             pr.Name);
435       }
436    }
437
438    free(ids);
439 }
440
441 static void update_volenabled(UAContext *ua, char *val, MEDIA_DBR *mr)
442 {
443    mr->Enabled = get_enabled(ua, val);
444    if (mr->Enabled < 0) {
445       return;
446    }
447    if (!db_update_media_record(ua->jcr, ua->db, mr)) {
448       ua->error_msg(_("Error updating media record Enabled: ERR=%s"), db_strerror(ua->db));
449    } else {
450       ua->info_msg(_("New Enabled is: %d\n"), mr->Enabled);
451    }
452 }
453
454
455
456 /*
457  * Update a media record -- allows you to change the
458  *  Volume status. E.g. if you want Bacula to stop
459  *  writing on the volume, set it to anything other
460  *  than Append.
461  */
462 static int update_volume(UAContext *ua)
463 {
464    MEDIA_DBR mr;
465    POOL *pool;
466    POOL_DBR pr;
467    POOLMEM *query;
468    char buf[1000];
469    char ed1[130];
470    bool done = false;
471    int i;
472    const char *kw[] = {
473       NT_("VolStatus"),                /* 0 */
474       NT_("VolRetention"),             /* 1 */
475       NT_("VolUse"),                   /* 2 */
476       NT_("MaxVolJobs"),               /* 3 */
477       NT_("MaxVolFiles"),              /* 4 */
478       NT_("MaxVolBytes"),              /* 5 */
479       NT_("Recycle"),                  /* 6 */
480       NT_("InChanger"),                /* 7 */
481       NT_("Slot"),                     /* 8 */
482       NT_("Pool"),                     /* 9 */
483       NT_("FromPool"),                 /* 10 */
484       NT_("AllFromPool"),              /* 11 !!! see below !!! */
485       NT_("Enabled"),                  /* 12 */
486       NT_("RecyclePool"),              /* 13 */
487       NULL };
488
489 #define AllFromPool 11               /* keep this updated with above */
490
491    for (i=0; kw[i]; i++) {
492       int j;
493       POOL_DBR pr;
494
495       if ((j=find_arg_with_value(ua, kw[i])) > 0) {
496          /* If all from pool don't select a media record */
497          if (i != AllFromPool && !select_media_dbr(ua, &mr)) {
498             return 0;
499          }
500          switch (i) {
501          case 0:
502             update_volstatus(ua, ua->argv[j], &mr);
503             break;
504          case 1:
505             update_volretention(ua, ua->argv[j], &mr);
506             break;
507          case 2:
508             update_voluseduration(ua, ua->argv[j], &mr);
509             break;
510          case 3:
511             update_volmaxjobs(ua, ua->argv[j], &mr);
512             break;
513          case 4:
514             update_volmaxfiles(ua, ua->argv[j], &mr);
515             break;
516          case 5:
517             update_volmaxbytes(ua, ua->argv[j], &mr);
518             break;
519          case 6:
520             update_volrecycle(ua, ua->argv[j], &mr);
521             break;
522          case 7:
523             update_volinchanger(ua, ua->argv[j], &mr);
524             break;
525          case 8:
526             update_volslot(ua, ua->argv[j], &mr);
527             break;
528          case 9:
529             memset(&pr, 0, sizeof(POOL_DBR));
530             pr.PoolId = mr.PoolId;
531             if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
532                ua->error_msg("%s", db_strerror(ua->db));
533                break;
534             }
535             update_vol_pool(ua, ua->argv[j], &mr, &pr);
536             break;
537          case 10:
538             update_vol_from_pool(ua, &mr);
539             return 1;
540          case 11:
541             update_all_vols_from_pool(ua, ua->argv[j]);
542             return 1;
543          case 12:
544             update_volenabled(ua, ua->argv[j], &mr);
545             break;
546          case 13:
547             update_vol_recyclepool(ua, ua->argv[j], &mr);
548             break;
549          }
550          done = true;
551       }
552    }
553
554    /* Allow user to simply update all volumes */
555    if (find_arg(ua, NT_("fromallpools")) > 0) {
556       update_all_vols(ua);
557       return 1;
558    }
559
560    for ( ; !done; ) {
561       start_prompt(ua, _("Parameters to modify:\n"));
562       add_prompt(ua, _("Volume Status"));              /* 0 */
563       add_prompt(ua, _("Volume Retention Period"));    /* 1 */
564       add_prompt(ua, _("Volume Use Duration"));        /* 2 */
565       add_prompt(ua, _("Maximum Volume Jobs"));        /* 3 */
566       add_prompt(ua, _("Maximum Volume Files"));       /* 4 */
567       add_prompt(ua, _("Maximum Volume Bytes"));       /* 5 */
568       add_prompt(ua, _("Recycle Flag"));               /* 6 */
569       add_prompt(ua, _("Slot"));                       /* 7 */
570       add_prompt(ua, _("InChanger Flag"));             /* 8 */
571       add_prompt(ua, _("Volume Files"));               /* 9 */
572       add_prompt(ua, _("Pool"));                       /* 10 */
573       add_prompt(ua, _("Volume from Pool"));           /* 11 */
574       add_prompt(ua, _("All Volumes from Pool"));      /* 12 */
575       add_prompt(ua, _("All Volumes from all Pools")); /* 13 */
576       add_prompt(ua, _("Enabled")),                    /* 14 */
577       add_prompt(ua, _("RecyclePool")),                /* 15 */
578       add_prompt(ua, _("Done"));                       /* 16 */
579       i = do_prompt(ua, "", _("Select parameter to modify"), NULL, 0);  
580
581       /* For All Volumes, All Volumes from Pool, and Done, we don't need
582            * a Volume record */
583       if ( i != 12 && i != 13 && i != 16) {
584          if (!select_media_dbr(ua, &mr)) {  /* Get Volume record */
585             return 0;
586          }
587          ua->info_msg(_("Updating Volume \"%s\"\n"), mr.VolumeName);
588       }
589       switch (i) {
590       case 0:                         /* Volume Status */
591          /* Modify Volume Status */
592          ua->info_msg(_("Current Volume status is: %s\n"), mr.VolStatus);
593          start_prompt(ua, _("Possible Values are:\n"));
594          add_prompt(ua, NT_("Append")); 
595          add_prompt(ua, NT_("Archive"));
596          add_prompt(ua, NT_("Disabled"));
597          add_prompt(ua, NT_("Full"));
598          add_prompt(ua, NT_("Used"));
599          add_prompt(ua, NT_("Cleaning"));
600          if (strcmp(mr.VolStatus, NT_("Purged")) == 0) {
601             add_prompt(ua, NT_("Recycle"));
602          }
603          add_prompt(ua, NT_("Read-Only"));
604          if (do_prompt(ua, "", _("Choose new Volume Status"), ua->cmd, sizeof(mr.VolStatus)) < 0) {
605             return 1;
606          }
607          update_volstatus(ua, ua->cmd, &mr);
608          break;
609       case 1:                         /* Retention */
610          ua->info_msg(_("Current retention period is: %s\n"),
611             edit_utime(mr.VolRetention, ed1, sizeof(ed1)));
612          if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
613             return 0;
614          }
615          update_volretention(ua, ua->cmd, &mr);
616          break;
617
618       case 2:                         /* Use Duration */
619          ua->info_msg(_("Current use duration is: %s\n"),
620             edit_utime(mr.VolUseDuration, ed1, sizeof(ed1)));
621          if (!get_cmd(ua, _("Enter Volume Use Duration: "))) {
622             return 0;
623          }
624          update_voluseduration(ua, ua->cmd, &mr);
625          break;
626
627       case 3:                         /* Max Jobs */
628          ua->info_msg(_("Current max jobs is: %u\n"), mr.MaxVolJobs);
629          if (!get_pint(ua, _("Enter new Maximum Jobs: "))) {
630             return 0;
631          }
632          update_volmaxjobs(ua, ua->cmd, &mr);
633          break;
634
635       case 4:                         /* Max Files */
636          ua->info_msg(_("Current max files is: %u\n"), mr.MaxVolFiles);
637          if (!get_pint(ua, _("Enter new Maximum Files: "))) {
638             return 0;
639          }
640          update_volmaxfiles(ua, ua->cmd, &mr);
641          break;
642
643       case 5:                         /* Max Bytes */
644          ua->info_msg(_("Current value is: %s\n"), edit_uint64(mr.MaxVolBytes, ed1));
645          if (!get_cmd(ua, _("Enter new Maximum Bytes: "))) {
646             return 0;
647          }
648          update_volmaxbytes(ua, ua->cmd, &mr);
649          break;
650
651
652       case 6:                         /* Recycle */
653          ua->info_msg(_("Current recycle flag is: %s\n"),
654             mr.Recycle==1?_("yes"):_("no"));
655          if (!get_yesno(ua, _("Enter new Recycle status: "))) {
656             return 0;
657          }
658          update_volrecycle(ua, ua->cmd, &mr);
659          break;
660
661       case 7:                         /* Slot */
662          ua->info_msg(_("Current Slot is: %d\n"), mr.Slot);
663          if (!get_pint(ua, _("Enter new Slot: "))) {
664             return 0;
665          }
666          update_volslot(ua, ua->cmd, &mr);
667          break;
668          
669       case 8:                         /* InChanger */
670          ua->info_msg(_("Current InChanger flag is: %d\n"), mr.InChanger);
671          bsnprintf(buf, sizeof(buf), _("Set InChanger flag for Volume \"%s\": yes/no: "),
672             mr.VolumeName);
673          if (!get_yesno(ua, buf)) {
674             return 0;
675          }
676          mr.InChanger = ua->pint32_val;
677          /*
678           * Make sure to use db_update... rather than doing this directly,
679           *   so that any Slot is handled correctly.
680           */
681          if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
682             ua->error_msg(_("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
683          } else {
684             ua->info_msg(_("New InChanger flag is: %d\n"), mr.InChanger);
685          }
686          break;
687
688
689       case 9:                         /* Volume Files */
690          int32_t VolFiles;
691          ua->warning_msg(_("Warning changing Volume Files can result\n"
692                         "in loss of data on your Volume\n\n"));
693          ua->info_msg(_("Current Volume Files is: %u\n"), mr.VolFiles);
694          if (!get_pint(ua, _("Enter new number of Files for Volume: "))) {
695             return 0;
696          }
697          VolFiles = ua->pint32_val;
698          if (VolFiles != (int)(mr.VolFiles + 1)) {
699             ua->warning_msg(_("Normally, you should only increase Volume Files by one!\n"));
700             if (!get_yesno(ua, _("Increase Volume Files? (yes/no): ")) || ua->pint32_val == 0) {
701                break;
702             }
703          }
704          query = get_pool_memory(PM_MESSAGE);
705          Mmsg(query, "UPDATE Media SET VolFiles=%u WHERE MediaId=%s",
706             VolFiles, edit_int64(mr.MediaId, ed1));
707          if (!db_sql_query(ua->db, query, NULL, NULL)) {
708             ua->error_msg("%s", db_strerror(ua->db));
709          } else {
710             ua->info_msg(_("New Volume Files is: %u\n"), VolFiles);
711          }
712          free_pool_memory(query);
713          break;
714
715       case 10:                        /* Volume's Pool */
716          memset(&pr, 0, sizeof(POOL_DBR));
717          pr.PoolId = mr.PoolId;
718          if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
719             ua->error_msg("%s", db_strerror(ua->db));
720             return 0;
721          }
722          ua->info_msg(_("Current Pool is: %s\n"), pr.Name);
723          if (!get_cmd(ua, _("Enter new Pool name: "))) {
724             return 0;
725          }
726          update_vol_pool(ua, ua->cmd, &mr, &pr);
727          return 1;
728
729       case 11:
730          update_vol_from_pool(ua, &mr);
731          return 1;
732       case 12:
733          pool = select_pool_resource(ua);
734          if (pool) {
735             update_all_vols_from_pool(ua, pool->name());
736          }
737          return 1;
738
739       case 13:
740          update_all_vols(ua);
741          return 1;
742
743       case 14:
744          ua->info_msg(_("Current Enabled is: %d\n"), mr.Enabled);
745          if (!get_cmd(ua, _("Enter new Enabled: "))) {
746             return 0;
747          }
748          if (strcasecmp(ua->cmd, "yes") == 0 || strcasecmp(ua->cmd, "true") == 0) {
749             mr.Enabled = 1;
750          } else if (strcasecmp(ua->cmd, "no") == 0 || strcasecmp(ua->cmd, "false") == 0) {
751             mr.Enabled = 0;
752          } else if (strcasecmp(ua->cmd, "archived") == 0) { 
753             mr.Enabled = 2;
754          } else {
755             mr.Enabled = atoi(ua->cmd);
756          }
757          update_volenabled(ua, ua->cmd, &mr);
758          break;
759
760       case 15:
761          memset(&pr, 0, sizeof(POOL_DBR));
762          pr.PoolId = mr.RecyclePoolId;
763          if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
764             ua->info_msg(_("Current RecyclePool is: %s\n"), pr.Name);
765          } else {
766             ua->warning_msg(_("No current RecyclePool\n"));
767          }
768          if (!get_cmd(ua, _("Enter new RecyclePool name: "))) {
769             return 0;
770          }
771          update_vol_recyclepool(ua, ua->cmd, &mr);
772          return 1;
773
774       default:                        /* Done or error */
775          ua->info_msg(_("Selection terminated.\n"));
776          return 1;
777       }
778    }
779    return 1;
780 }
781
782 /*
783  * Update pool record -- pull info from current POOL resource
784  */
785 static bool update_pool(UAContext *ua)
786 {
787    POOL_DBR  pr;
788    int id;
789    POOL *pool;
790    POOLMEM *query;
791    char ed1[50];
792
793    pool = get_pool_resource(ua);
794    if (!pool) {
795       return false;
796    }
797
798    memset(&pr, 0, sizeof(pr));
799    bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
800    if (!get_pool_dbr(ua, &pr)) {
801       return false;
802    }
803
804    set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE); /* update */
805    set_pooldbr_recyclepoolid(ua->jcr, ua->db, &pr, pool);
806
807    id = db_update_pool_record(ua->jcr, ua->db, &pr);
808    if (id <= 0) {
809       ua->error_msg(_("db_update_pool_record returned %d. ERR=%s\n"),
810          id, db_strerror(ua->db));
811    }
812    query = get_pool_memory(PM_MESSAGE);
813    Mmsg(query, list_pool, edit_int64(pr.PoolId, ed1));
814    db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST);
815    free_pool_memory(query);
816    ua->info_msg(_("Pool DB record updated from resource.\n"));
817    return true;
818 }
819
820 /*
821  * Update a Job record -- allows you to change the
822  *  date fields in a Job record. This helps when
823  *  providing migration from other vendors.
824  */
825 static bool update_job(UAContext *ua)
826 {
827    int i;
828    char ed1[50], ed2[50];
829    POOL_MEM cmd(PM_MESSAGE);
830    JOB_DBR jr;
831    CLIENT_DBR cr;
832    utime_t StartTime;
833    char *client_name = NULL;
834    char *start_time = NULL;
835    const char *kw[] = {
836       NT_("starttime"),                   /* 0 */
837       NT_("client"),                      /* 1 */
838       NULL };
839
840    Dmsg1(200, "cmd=%s\n", ua->cmd);
841    i = find_arg_with_value(ua, NT_("jobid"));
842    if (i < 0) {
843       ua->error_msg(_("Expect JobId keyword, not found.\n"));
844       return false;
845    }
846    memset(&jr, 0, sizeof(jr));
847    memset(&cr, 0, sizeof(cr));
848    jr.JobId = str_to_int64(ua->argv[i]);
849    if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
850       ua->error_msg("%s", db_strerror(ua->db));
851       return false;
852    }
853
854    for (i=0; kw[i]; i++) {
855       int j;
856       if ((j=find_arg_with_value(ua, kw[i])) >= 0) {
857          switch (i) {
858          case 0:                         /* start time */
859             start_time = ua->argv[j];
860             break;
861          case 1:                         /* Client name */
862             client_name = ua->argv[j];
863             break;
864          }
865       }
866    }
867    if (!client_name && !start_time) {
868       ua->error_msg(_("Neither Client nor StartTime specified.\n"));
869       return 0;
870    }
871    if (client_name) {
872       if (!get_client_dbr(ua, &cr)) {
873          return false;
874       }
875       jr.ClientId = cr.ClientId;
876    }
877    if (start_time) {
878       utime_t delta_start;
879
880       StartTime = str_to_utime(start_time);
881       if (StartTime == 0) {
882          ua->error_msg(_("Improper date format: %s\n"), ua->argv[i]);
883          return false;
884       }
885       delta_start = StartTime - jr.StartTime;
886       Dmsg3(200, "ST=%d jr.ST=%d delta=%d\n", (time_t)StartTime, 
887             (time_t)jr.StartTime, (time_t)delta_start);
888       jr.StartTime = (time_t)StartTime;
889       jr.SchedTime += (time_t)delta_start;
890       jr.EndTime += (time_t)delta_start;
891       jr.JobTDate += delta_start;
892       /* Convert to DB times */
893       bstrutime(jr.cStartTime, sizeof(jr.cStartTime), jr.StartTime);
894       bstrutime(jr.cSchedTime, sizeof(jr.cSchedTime), jr.SchedTime);
895       bstrutime(jr.cEndTime, sizeof(jr.cEndTime), jr.EndTime);
896    }
897    Mmsg(cmd, "UPDATE Job SET ClientId=%s,StartTime='%s',SchedTime='%s',"
898              "EndTime='%s',JobTDate=%s WHERE JobId=%s", 
899              edit_int64(jr.ClientId, ed1), 
900              jr.cStartTime,
901              jr.cSchedTime,
902              jr.cEndTime,
903              edit_uint64(jr.JobTDate, ed1), 
904              edit_int64(jr.JobId, ed2));
905    if (!db_sql_query(ua->db, cmd.c_str(), NULL, NULL)) {
906       ua->error_msg("%s", db_strerror(ua->db));
907       return false;
908    }
909    return true;
910 }