3 * Bacula Director -- Update command processing
4 * Split from ua_cmds.c March 2005
6 * Kern Sibbald, September MM
11 Bacula® - The Network Backup Solution
13 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
15 The main author of Bacula is Kern Sibbald, with contributions from
16 many others, a complete list can be found in the file AUTHORS.
17 This program is Free Software; you can redistribute it and/or
18 modify it under the terms of version two of the GNU General Public
19 License as published by the Free Software Foundation plus additions
20 that are listed in the file LICENSE.
22 This program is distributed in the hope that it will be useful, but
23 WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 General Public License for more details.
27 You should have received a copy of the GNU General Public License
28 along with this program; if not, write to the Free Software
29 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
32 Bacula® is a registered trademark of John Walker.
33 The licensor of Bacula is the Free Software Foundation Europe
34 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
35 Switzerland, email:ftf@fsfeurope.org.
41 /* Forward referenced functions */
42 static int update_volume(UAContext *ua);
43 static bool update_pool(UAContext *ua);
46 * Update a Pool Record in the database.
47 * It is always updated from the Resource record.
49 * update pool=<pool-name>
50 * updates pool from Pool resource
51 * update media pool=<pool-name> volume=<volume-name>
52 * changes pool info for volume
53 * update slots [scan=...]
54 * updates autochanger slots
56 int update_cmd(UAContext *ua, const char *cmd)
58 static const char *kw[] = {
60 NT_("volume"), /* 1 */
69 switch (find_arg_keyword(ua, kw)) {
84 start_prompt(ua, _("Update choice:\n"));
85 add_prompt(ua, _("Volume parameters"));
86 add_prompt(ua, _("Pool from resource"));
87 add_prompt(ua, _("Slots from autochanger"));
88 switch (do_prompt(ua, _("item"), _("Choose catalog item to update"), NULL, 0)) {
104 static void update_volstatus(UAContext *ua, const char *val, MEDIA_DBR *mr)
106 POOL_MEM query(PM_MESSAGE);
121 for (i=0; kw[i]; i++) {
122 if (strcasecmp(val, kw[i]) == 0) {
128 bsendmsg(ua, _("Invalid VolStatus specified: %s\n"), val);
131 bstrncpy(mr->VolStatus, kw[i], sizeof(mr->VolStatus));
132 Mmsg(query, "UPDATE Media SET VolStatus='%s' WHERE MediaId=%s",
133 mr->VolStatus, edit_int64(mr->MediaId,ed1));
134 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
135 bsendmsg(ua, "%s", db_strerror(ua->db));
137 bsendmsg(ua, _("New Volume status is: %s\n"), mr->VolStatus);
142 static void update_volretention(UAContext *ua, char *val, MEDIA_DBR *mr)
144 char ed1[150], ed2[50];
145 POOL_MEM query(PM_MESSAGE);
146 if (!duration_to_utime(val, &mr->VolRetention)) {
147 bsendmsg(ua, _("Invalid retention period specified: %s\n"), val);
150 Mmsg(query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%s",
151 edit_uint64(mr->VolRetention, ed1), edit_int64(mr->MediaId,ed2));
152 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
153 bsendmsg(ua, "%s", db_strerror(ua->db));
155 bsendmsg(ua, _("New retention period is: %s\n"),
156 edit_utime(mr->VolRetention, ed1, sizeof(ed1)));
160 static void update_voluseduration(UAContext *ua, char *val, MEDIA_DBR *mr)
162 char ed1[150], ed2[50];
163 POOL_MEM query(PM_MESSAGE);
165 if (!duration_to_utime(val, &mr->VolUseDuration)) {
166 bsendmsg(ua, _("Invalid use duration specified: %s\n"), val);
169 Mmsg(query, "UPDATE Media SET VolUseDuration=%s WHERE MediaId=%s",
170 edit_uint64(mr->VolUseDuration, ed1), edit_int64(mr->MediaId,ed2));
171 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
172 bsendmsg(ua, "%s", db_strerror(ua->db));
174 bsendmsg(ua, _("New use duration is: %s\n"),
175 edit_utime(mr->VolUseDuration, ed1, sizeof(ed1)));
179 static void update_volmaxjobs(UAContext *ua, char *val, MEDIA_DBR *mr)
181 POOL_MEM query(PM_MESSAGE);
183 Mmsg(query, "UPDATE Media SET MaxVolJobs=%s WHERE MediaId=%s",
184 val, edit_int64(mr->MediaId,ed1));
185 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
186 bsendmsg(ua, "%s", db_strerror(ua->db));
188 bsendmsg(ua, _("New max jobs is: %s\n"), val);
192 static void update_volmaxfiles(UAContext *ua, char *val, MEDIA_DBR *mr)
194 POOL_MEM query(PM_MESSAGE);
196 Mmsg(query, "UPDATE Media SET MaxVolFiles=%s WHERE MediaId=%s",
197 val, edit_int64(mr->MediaId, ed1));
198 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
199 bsendmsg(ua, "%s", db_strerror(ua->db));
201 bsendmsg(ua, _("New max files is: %s\n"), val);
205 static void update_volmaxbytes(UAContext *ua, char *val, MEDIA_DBR *mr)
208 char ed1[50], ed2[50];
209 POOL_MEM query(PM_MESSAGE);
211 if (!size_to_uint64(val, strlen(val), &maxbytes)) {
212 bsendmsg(ua, _("Invalid max. bytes specification: %s\n"), val);
215 Mmsg(query, "UPDATE Media SET MaxVolBytes=%s WHERE MediaId=%s",
216 edit_uint64(maxbytes, ed1), edit_int64(mr->MediaId, ed2));
217 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
218 bsendmsg(ua, "%s", db_strerror(ua->db));
220 bsendmsg(ua, _("New Max bytes is: %s\n"), edit_uint64(maxbytes, ed1));
224 static void update_volrecycle(UAContext *ua, char *val, MEDIA_DBR *mr)
229 POOL_MEM query(PM_MESSAGE);
230 if (!is_yesno(val, &recycle)) {
231 bsendmsg(ua, _("Invalid value. It must be yes or no.\n"));
234 Mmsg(query, "UPDATE Media SET Recycle=%d WHERE MediaId=%s",
235 recycle, edit_int64(mr->MediaId, ed1));
236 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
237 bsendmsg(ua, "%s", db_strerror(ua->db));
239 bsendmsg(ua, _("New Recycle flag is: %s\n"),
240 mr->Recycle==1?_("yes"):_("no"));
244 static void update_volinchanger(UAContext *ua, char *val, MEDIA_DBR *mr)
249 POOL_MEM query(PM_MESSAGE);
250 if (!is_yesno(val, &InChanger)) {
251 bsendmsg(ua, _("Invalid value. It must be yes or no.\n"));
254 Mmsg(query, "UPDATE Media SET InChanger=%d WHERE MediaId=%s",
255 InChanger, edit_int64(mr->MediaId, ed1));
256 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
257 bsendmsg(ua, "%s", db_strerror(ua->db));
259 bsendmsg(ua, _("New InChanger flag is: %s\n"),
260 mr->InChanger==1?_("yes"):_("no"));
265 static void update_volslot(UAContext *ua, char *val, MEDIA_DBR *mr)
269 memset(&pr, 0, sizeof(POOL_DBR));
270 pr.PoolId = mr->PoolId;
271 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
272 bsendmsg(ua, "%s", db_strerror(ua->db));
275 mr->Slot = atoi(val);
276 if (pr.MaxVols > 0 && mr->Slot > (int)pr.MaxVols) {
277 bsendmsg(ua, _("Invalid slot, it must be between 0 and MaxVols=%d\n"),
282 * Make sure to use db_update... rather than doing this directly,
283 * so that any Slot is handled correctly.
285 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
286 bsendmsg(ua, _("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
288 bsendmsg(ua, _("New Slot is: %d\n"), mr->Slot);
292 /* Modify the Pool in which this Volume is located */
293 static void update_vol_pool(UAContext *ua, char *val, MEDIA_DBR *mr, POOL_DBR *opr)
297 char ed1[50], ed2[50];
299 memset(&pr, 0, sizeof(pr));
300 bstrncpy(pr.Name, val, sizeof(pr.Name));
301 if (!get_pool_dbr(ua, &pr)) {
304 mr->PoolId = pr.PoolId; /* set new PoolId */
307 query = get_pool_memory(PM_MESSAGE);
309 Mmsg(query, "UPDATE Media SET PoolId=%s WHERE MediaId=%s",
310 edit_int64(mr->PoolId, ed1),
311 edit_int64(mr->MediaId, ed2));
312 if (!db_sql_query(ua->db, query, NULL, NULL)) {
313 bsendmsg(ua, "%s", db_strerror(ua->db));
315 bsendmsg(ua, _("New Pool is: %s\n"), pr.Name);
317 if (!db_update_pool_record(ua->jcr, ua->db, opr)) {
318 bsendmsg(ua, "%s", db_strerror(ua->db));
321 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
322 bsendmsg(ua, "%s", db_strerror(ua->db));
326 free_pool_memory(query);
330 * Refresh the Volume information from the Pool record
332 static void update_vol_from_pool(UAContext *ua, MEDIA_DBR *mr)
336 memset(&pr, 0, sizeof(pr));
337 pr.PoolId = mr->PoolId;
338 if (!db_get_pool_record(ua->jcr, ua->db, &pr) ||
339 !acl_access_ok(ua, Pool_ACL, pr.Name)) {
342 set_pool_dbr_defaults_in_media_dbr(mr, &pr);
343 if (!db_update_media_defaults(ua->jcr, ua->db, mr)) {
344 bsendmsg(ua, _("Error updating Volume record: ERR=%s"), db_strerror(ua->db));
346 bsendmsg(ua, _("Volume defaults updated from \"%s\" Pool record.\n"),
352 * Refresh the Volume information from the Pool record
355 static void update_all_vols_from_pool(UAContext *ua)
360 memset(&pr, 0, sizeof(pr));
361 memset(&mr, 0, sizeof(mr));
362 if (!get_pool_dbr(ua, &pr)) {
365 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
366 mr.PoolId = pr.PoolId;
367 if (!db_update_media_defaults(ua->jcr, ua->db, &mr)) {
368 bsendmsg(ua, _("Error updating Volume records: ERR=%s"), db_strerror(ua->db));
370 bsendmsg(ua, _("All Volume defaults updated from Pool record.\n"));
374 static void update_volenabled(UAContext *ua, char *val, MEDIA_DBR *mr)
376 mr->Enabled = get_enabled(ua, val);
377 if (mr->Enabled < 0) {
380 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
381 bsendmsg(ua, _("Error updating media record Enabled: ERR=%s"), db_strerror(ua->db));
383 bsendmsg(ua, _("New Enabled is: %d\n"), mr->Enabled);
390 * Update a media record -- allows you to change the
391 * Volume status. E.g. if you want Bacula to stop
392 * writing on the volume, set it to anything other
395 static int update_volume(UAContext *ua)
404 _("VolStatus"), /* 0 */
405 _("VolRetention"), /* 1 */
407 _("MaxVolJobs"), /* 3 */
408 _("MaxVolFiles"), /* 4 */
409 _("MaxVolBytes"), /* 5 */
410 _("Recycle"), /* 6 */
411 _("InChanger"), /* 7 */
414 _("FromPool"), /* 10 */
415 _("AllFromPool"), /* 11 !!! see below !!! */
416 _("Enabled"), /* 12 */
419 #define AllFromPool 11 /* keep this updated with above */
421 for (i=0; kw[i]; i++) {
424 if ((j=find_arg_with_value(ua, kw[i])) > 0) {
425 /* If all from pool don't select a media record */
426 if (i != AllFromPool && !select_media_dbr(ua, &mr)) {
431 update_volstatus(ua, ua->argv[j], &mr);
434 update_volretention(ua, ua->argv[j], &mr);
437 update_voluseduration(ua, ua->argv[j], &mr);
440 update_volmaxjobs(ua, ua->argv[j], &mr);
443 update_volmaxfiles(ua, ua->argv[j], &mr);
446 update_volmaxbytes(ua, ua->argv[j], &mr);
449 update_volrecycle(ua, ua->argv[j], &mr);
452 update_volinchanger(ua, ua->argv[j], &mr);
455 update_volslot(ua, ua->argv[j], &mr);
458 memset(&pr, 0, sizeof(POOL_DBR));
459 pr.PoolId = mr.PoolId;
460 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
461 bsendmsg(ua, "%s", db_strerror(ua->db));
464 update_vol_pool(ua, ua->argv[j], &mr, &pr);
467 update_vol_from_pool(ua, &mr);
470 update_all_vols_from_pool(ua);
473 update_volenabled(ua, ua->argv[j], &mr);
481 start_prompt(ua, _("Parameters to modify:\n"));
482 add_prompt(ua, _("Volume Status")); /* 0 */
483 add_prompt(ua, _("Volume Retention Period")); /* 1 */
484 add_prompt(ua, _("Volume Use Duration")); /* 2 */
485 add_prompt(ua, _("Maximum Volume Jobs")); /* 3 */
486 add_prompt(ua, _("Maximum Volume Files")); /* 4 */
487 add_prompt(ua, _("Maximum Volume Bytes")); /* 5 */
488 add_prompt(ua, _("Recycle Flag")); /* 6 */
489 add_prompt(ua, _("Slot")); /* 7 */
490 add_prompt(ua, _("InChanger Flag")); /* 8 */
491 add_prompt(ua, _("Volume Files")); /* 9 */
492 add_prompt(ua, _("Pool")); /* 10 */
493 add_prompt(ua, _("Volume from Pool")); /* 11 */
494 add_prompt(ua, _("All Volumes from Pool")); /* 12 */
495 add_prompt(ua, _("Enabled")), /* 13 */
496 add_prompt(ua, _("Done")); /* 14 */
497 i = do_prompt(ua, "", _("Select parameter to modify"), NULL, 0);
499 /* For All Volumes from Pool and Done, we don't need a Volume record */
500 if (i != 12 && i != 14) {
501 if (!select_media_dbr(ua, &mr)) { /* Get Volume record */
504 bsendmsg(ua, _("Updating Volume \"%s\"\n"), mr.VolumeName);
507 case 0: /* Volume Status */
508 /* Modify Volume Status */
509 bsendmsg(ua, _("Current Volume status is: %s\n"), mr.VolStatus);
510 start_prompt(ua, _("Possible Values are:\n"));
511 add_prompt(ua, NT_("Append"));
512 add_prompt(ua, NT_("Archive"));
513 add_prompt(ua, NT_("Disabled"));
514 add_prompt(ua, NT_("Full"));
515 add_prompt(ua, NT_("Used"));
516 add_prompt(ua, NT_("Cleaning"));
517 if (strcmp(mr.VolStatus, NT_("Purged")) == 0) {
518 add_prompt(ua, NT_("Recycle"));
520 add_prompt(ua, NT_("Read-Only"));
521 if (do_prompt(ua, "", _("Choose new Volume Status"), ua->cmd, sizeof(mr.VolStatus)) < 0) {
524 update_volstatus(ua, ua->cmd, &mr);
526 case 1: /* Retention */
527 bsendmsg(ua, _("Current retention period is: %s\n"),
528 edit_utime(mr.VolRetention, ed1, sizeof(ed1)));
529 if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
532 update_volretention(ua, ua->cmd, &mr);
535 case 2: /* Use Duration */
536 bsendmsg(ua, _("Current use duration is: %s\n"),
537 edit_utime(mr.VolUseDuration, ed1, sizeof(ed1)));
538 if (!get_cmd(ua, _("Enter Volume Use Duration: "))) {
541 update_voluseduration(ua, ua->cmd, &mr);
544 case 3: /* Max Jobs */
545 bsendmsg(ua, _("Current max jobs is: %u\n"), mr.MaxVolJobs);
546 if (!get_pint(ua, _("Enter new Maximum Jobs: "))) {
549 update_volmaxjobs(ua, ua->cmd, &mr);
552 case 4: /* Max Files */
553 bsendmsg(ua, _("Current max files is: %u\n"), mr.MaxVolFiles);
554 if (!get_pint(ua, _("Enter new Maximum Files: "))) {
557 update_volmaxfiles(ua, ua->cmd, &mr);
560 case 5: /* Max Bytes */
561 bsendmsg(ua, _("Current value is: %s\n"), edit_uint64(mr.MaxVolBytes, ed1));
562 if (!get_cmd(ua, _("Enter new Maximum Bytes: "))) {
565 update_volmaxbytes(ua, ua->cmd, &mr);
569 case 6: /* Recycle */
570 bsendmsg(ua, _("Current recycle flag is: %s\n"),
571 mr.Recycle==1?_("yes"):_("no"));
572 if (!get_yesno(ua, _("Enter new Recycle status: "))) {
575 update_volrecycle(ua, ua->cmd, &mr);
579 bsendmsg(ua, _("Current Slot is: %d\n"), mr.Slot);
580 if (!get_pint(ua, _("Enter new Slot: "))) {
583 update_volslot(ua, ua->cmd, &mr);
586 case 8: /* InChanger */
587 bsendmsg(ua, _("Current InChanger flag is: %d\n"), mr.InChanger);
588 if (!get_yesno(ua, _("Set InChanger flag? yes/no: "))) {
591 mr.InChanger = ua->pint32_val;
593 * Make sure to use db_update... rather than doing this directly,
594 * so that any Slot is handled correctly.
596 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
597 bsendmsg(ua, _("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
599 bsendmsg(ua, _("New InChanger flag is: %d\n"), mr.InChanger);
604 case 9: /* Volume Files */
606 bsendmsg(ua, _("Warning changing Volume Files can result\n"
607 "in loss of data on your Volume\n\n"));
608 bsendmsg(ua, _("Current Volume Files is: %u\n"), mr.VolFiles);
609 if (!get_pint(ua, _("Enter new number of Files for Volume: "))) {
612 VolFiles = ua->pint32_val;
613 if (VolFiles != (int)(mr.VolFiles + 1)) {
614 bsendmsg(ua, _("Normally, you should only increase Volume Files by one!\n"));
615 if (!get_yesno(ua, _("Continue? (yes/no): ")) || ua->pint32_val == 0) {
619 query = get_pool_memory(PM_MESSAGE);
620 Mmsg(query, "UPDATE Media SET VolFiles=%u WHERE MediaId=%s",
621 VolFiles, edit_int64(mr.MediaId, ed1));
622 if (!db_sql_query(ua->db, query, NULL, NULL)) {
623 bsendmsg(ua, "%s", db_strerror(ua->db));
625 bsendmsg(ua, _("New Volume Files is: %u\n"), VolFiles);
627 free_pool_memory(query);
630 case 10: /* Volume's Pool */
631 memset(&pr, 0, sizeof(POOL_DBR));
632 pr.PoolId = mr.PoolId;
633 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
634 bsendmsg(ua, "%s", db_strerror(ua->db));
637 bsendmsg(ua, _("Current Pool is: %s\n"), pr.Name);
638 if (!get_cmd(ua, _("Enter new Pool name: "))) {
641 update_vol_pool(ua, ua->cmd, &mr, &pr);
645 update_vol_from_pool(ua, &mr);
648 update_all_vols_from_pool(ua);
652 bsendmsg(ua, _("Current Enabled is: %d\n"), mr.Enabled);
653 if (!get_cmd(ua, _("Enter new Enabled: "))) {
656 if (strcasecmp(ua->cmd, "yes") == 0 || strcasecmp(ua->cmd, "true") == 0) {
658 } else if (strcasecmp(ua->cmd, "no") == 0 || strcasecmp(ua->cmd, "false") == 0) {
660 } else if (strcasecmp(ua->cmd, "archived") == 0) {
663 mr.Enabled = atoi(ua->cmd);
665 update_volenabled(ua, ua->cmd, &mr);
668 default: /* Done or error */
669 bsendmsg(ua, _("Selection terminated.\n"));
677 * Update pool record -- pull info from current POOL resource
679 static bool update_pool(UAContext *ua)
687 pool = get_pool_resource(ua);
692 memset(&pr, 0, sizeof(pr));
693 bstrncpy(pr.Name, pool->hdr.name, sizeof(pr.Name));
694 if (!get_pool_dbr(ua, &pr)) {
698 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE); /* update */
700 id = db_update_pool_record(ua->jcr, ua->db, &pr);
702 bsendmsg(ua, _("db_update_pool_record returned %d. ERR=%s\n"),
703 id, db_strerror(ua->db));
705 query = get_pool_memory(PM_MESSAGE);
706 Mmsg(query, list_pool, edit_int64(pr.PoolId, ed1));
707 db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST);
708 free_pool_memory(query);
709 bsendmsg(ua, _("Pool DB record updated from resource.\n"));