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