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