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