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