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);
122 for (i=0; kw[i]; i++) {
123 if (strcasecmp(val, kw[i]) == 0) {
129 bsendmsg(ua, _("Invalid VolStatus specified: %s\n"), val);
132 bstrncpy(mr->VolStatus, kw[i], sizeof(mr->VolStatus));
133 Mmsg(query, "UPDATE Media SET VolStatus='%s' WHERE MediaId=%s",
134 mr->VolStatus, edit_int64(mr->MediaId,ed1));
135 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
136 bsendmsg(ua, "%s", db_strerror(ua->db));
138 bsendmsg(ua, _("New Volume status is: %s\n"), mr->VolStatus);
143 static void update_volretention(UAContext *ua, char *val, MEDIA_DBR *mr)
145 char ed1[150], ed2[50];
146 POOL_MEM query(PM_MESSAGE);
147 if (!duration_to_utime(val, &mr->VolRetention)) {
148 bsendmsg(ua, _("Invalid retention period specified: %s\n"), val);
151 Mmsg(query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%s",
152 edit_uint64(mr->VolRetention, ed1), edit_int64(mr->MediaId,ed2));
153 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
154 bsendmsg(ua, "%s", db_strerror(ua->db));
156 bsendmsg(ua, _("New retention period is: %s\n"),
157 edit_utime(mr->VolRetention, ed1, sizeof(ed1)));
161 static void update_voluseduration(UAContext *ua, char *val, MEDIA_DBR *mr)
163 char ed1[150], ed2[50];
164 POOL_MEM query(PM_MESSAGE);
166 if (!duration_to_utime(val, &mr->VolUseDuration)) {
167 bsendmsg(ua, _("Invalid use duration specified: %s\n"), val);
170 Mmsg(query, "UPDATE Media SET VolUseDuration=%s WHERE MediaId=%s",
171 edit_uint64(mr->VolUseDuration, ed1), edit_int64(mr->MediaId,ed2));
172 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
173 bsendmsg(ua, "%s", db_strerror(ua->db));
175 bsendmsg(ua, _("New use duration is: %s\n"),
176 edit_utime(mr->VolUseDuration, ed1, sizeof(ed1)));
180 static void update_volmaxjobs(UAContext *ua, char *val, MEDIA_DBR *mr)
182 POOL_MEM query(PM_MESSAGE);
184 Mmsg(query, "UPDATE Media SET MaxVolJobs=%s WHERE MediaId=%s",
185 val, edit_int64(mr->MediaId,ed1));
186 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
187 bsendmsg(ua, "%s", db_strerror(ua->db));
189 bsendmsg(ua, _("New max jobs is: %s\n"), val);
193 static void update_volmaxfiles(UAContext *ua, char *val, MEDIA_DBR *mr)
195 POOL_MEM query(PM_MESSAGE);
197 Mmsg(query, "UPDATE Media SET MaxVolFiles=%s WHERE MediaId=%s",
198 val, edit_int64(mr->MediaId, ed1));
199 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
200 bsendmsg(ua, "%s", db_strerror(ua->db));
202 bsendmsg(ua, _("New max files is: %s\n"), val);
206 static void update_volmaxbytes(UAContext *ua, char *val, MEDIA_DBR *mr)
209 char ed1[50], ed2[50];
210 POOL_MEM query(PM_MESSAGE);
212 if (!size_to_uint64(val, strlen(val), &maxbytes)) {
213 bsendmsg(ua, _("Invalid max. bytes specification: %s\n"), val);
216 Mmsg(query, "UPDATE Media SET MaxVolBytes=%s WHERE MediaId=%s",
217 edit_uint64(maxbytes, ed1), edit_int64(mr->MediaId, ed2));
218 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
219 bsendmsg(ua, "%s", db_strerror(ua->db));
221 bsendmsg(ua, _("New Max bytes is: %s\n"), edit_uint64(maxbytes, ed1));
225 static void update_volrecycle(UAContext *ua, char *val, MEDIA_DBR *mr)
230 POOL_MEM query(PM_MESSAGE);
231 if (!is_yesno(val, &recycle)) {
232 bsendmsg(ua, _("Invalid value. It must be yes or no.\n"));
235 Mmsg(query, "UPDATE Media SET Recycle=%d WHERE MediaId=%s",
236 recycle, edit_int64(mr->MediaId, ed1));
237 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
238 bsendmsg(ua, "%s", db_strerror(ua->db));
240 bsendmsg(ua, _("New Recycle flag is: %s\n"),
241 mr->Recycle==1?_("yes"):_("no"));
245 static void update_volinchanger(UAContext *ua, char *val, MEDIA_DBR *mr)
250 POOL_MEM query(PM_MESSAGE);
251 if (!is_yesno(val, &InChanger)) {
252 bsendmsg(ua, _("Invalid value. It must be yes or no.\n"));
255 Mmsg(query, "UPDATE Media SET InChanger=%d WHERE MediaId=%s",
256 InChanger, edit_int64(mr->MediaId, ed1));
257 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
258 bsendmsg(ua, "%s", db_strerror(ua->db));
260 bsendmsg(ua, _("New InChanger flag is: %s\n"),
261 mr->InChanger==1?_("yes"):_("no"));
266 static void update_volslot(UAContext *ua, char *val, MEDIA_DBR *mr)
270 memset(&pr, 0, sizeof(POOL_DBR));
271 pr.PoolId = mr->PoolId;
272 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
273 bsendmsg(ua, "%s", db_strerror(ua->db));
276 mr->Slot = atoi(val);
277 if (pr.MaxVols > 0 && mr->Slot > (int)pr.MaxVols) {
278 bsendmsg(ua, _("Invalid slot, it must be between 0 and MaxVols=%d\n"),
283 * Make sure to use db_update... rather than doing this directly,
284 * so that any Slot is handled correctly.
286 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
287 bsendmsg(ua, _("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
289 bsendmsg(ua, _("New Slot is: %d\n"), mr->Slot);
293 /* Modify the Pool in which this Volume is located */
294 static void update_vol_pool(UAContext *ua, char *val, MEDIA_DBR *mr, POOL_DBR *opr)
298 char ed1[50], ed2[50];
300 memset(&pr, 0, sizeof(pr));
301 bstrncpy(pr.Name, val, sizeof(pr.Name));
302 if (!get_pool_dbr(ua, &pr)) {
305 mr->PoolId = pr.PoolId; /* set new PoolId */
308 query = get_pool_memory(PM_MESSAGE);
310 Mmsg(query, "UPDATE Media SET PoolId=%s WHERE MediaId=%s",
311 edit_int64(mr->PoolId, ed1),
312 edit_int64(mr->MediaId, ed2));
313 if (!db_sql_query(ua->db, query, NULL, NULL)) {
314 bsendmsg(ua, "%s", db_strerror(ua->db));
316 bsendmsg(ua, _("New Pool is: %s\n"), pr.Name);
318 if (!db_update_pool_record(ua->jcr, ua->db, opr)) {
319 bsendmsg(ua, "%s", db_strerror(ua->db));
322 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
323 bsendmsg(ua, "%s", db_strerror(ua->db));
327 free_pool_memory(query);
331 * Refresh the Volume information from the Pool record
333 static void update_vol_from_pool(UAContext *ua, MEDIA_DBR *mr)
337 memset(&pr, 0, sizeof(pr));
338 pr.PoolId = mr->PoolId;
339 if (!db_get_pool_record(ua->jcr, ua->db, &pr) ||
340 !acl_access_ok(ua, Pool_ACL, pr.Name)) {
343 set_pool_dbr_defaults_in_media_dbr(mr, &pr);
344 if (!db_update_media_defaults(ua->jcr, ua->db, mr)) {
345 bsendmsg(ua, _("Error updating Volume record: ERR=%s"), db_strerror(ua->db));
347 bsendmsg(ua, _("Volume defaults updated from \"%s\" Pool record.\n"),
353 * Refresh the Volume information from the Pool record
356 static void update_all_vols_from_pool(UAContext *ua)
361 memset(&pr, 0, sizeof(pr));
362 memset(&mr, 0, sizeof(mr));
363 if (!get_pool_dbr(ua, &pr)) {
366 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
367 mr.PoolId = pr.PoolId;
368 if (!db_update_media_defaults(ua->jcr, ua->db, &mr)) {
369 bsendmsg(ua, _("Error updating Volume records: ERR=%s"), db_strerror(ua->db));
371 bsendmsg(ua, _("All Volume defaults updated from Pool record.\n"));
375 static void update_volenabled(UAContext *ua, char *val, MEDIA_DBR *mr)
377 mr->Enabled = get_enabled(ua, val);
378 if (mr->Enabled < 0) {
381 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
382 bsendmsg(ua, _("Error updating media record Enabled: ERR=%s"), db_strerror(ua->db));
384 bsendmsg(ua, _("New Enabled is: %d\n"), mr->Enabled);
391 * Update a media record -- allows you to change the
392 * Volume status. E.g. if you want Bacula to stop
393 * writing on the volume, set it to anything other
396 static int update_volume(UAContext *ua)
405 _("VolStatus"), /* 0 */
406 _("VolRetention"), /* 1 */
408 _("MaxVolJobs"), /* 3 */
409 _("MaxVolFiles"), /* 4 */
410 _("MaxVolBytes"), /* 5 */
411 _("Recycle"), /* 6 */
412 _("InChanger"), /* 7 */
415 _("FromPool"), /* 10 */
416 _("AllFromPool"), /* 11 !!! see below !!! */
417 _("Enabled"), /* 12 */
420 #define AllFromPool 11 /* keep this updated with above */
422 for (i=0; kw[i]; i++) {
425 if ((j=find_arg_with_value(ua, kw[i])) > 0) {
426 /* If all from pool don't select a media record */
427 if (i != AllFromPool && !select_media_dbr(ua, &mr)) {
432 update_volstatus(ua, ua->argv[j], &mr);
435 update_volretention(ua, ua->argv[j], &mr);
438 update_voluseduration(ua, ua->argv[j], &mr);
441 update_volmaxjobs(ua, ua->argv[j], &mr);
444 update_volmaxfiles(ua, ua->argv[j], &mr);
447 update_volmaxbytes(ua, ua->argv[j], &mr);
450 update_volrecycle(ua, ua->argv[j], &mr);
453 update_volinchanger(ua, ua->argv[j], &mr);
456 update_volslot(ua, ua->argv[j], &mr);
459 memset(&pr, 0, sizeof(POOL_DBR));
460 pr.PoolId = mr.PoolId;
461 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
462 bsendmsg(ua, "%s", db_strerror(ua->db));
465 update_vol_pool(ua, ua->argv[j], &mr, &pr);
468 update_vol_from_pool(ua, &mr);
471 update_all_vols_from_pool(ua);
474 update_volenabled(ua, ua->argv[j], &mr);
482 start_prompt(ua, _("Parameters to modify:\n"));
483 add_prompt(ua, _("Volume Status")); /* 0 */
484 add_prompt(ua, _("Volume Retention Period")); /* 1 */
485 add_prompt(ua, _("Volume Use Duration")); /* 2 */
486 add_prompt(ua, _("Maximum Volume Jobs")); /* 3 */
487 add_prompt(ua, _("Maximum Volume Files")); /* 4 */
488 add_prompt(ua, _("Maximum Volume Bytes")); /* 5 */
489 add_prompt(ua, _("Recycle Flag")); /* 6 */
490 add_prompt(ua, _("Slot")); /* 7 */
491 add_prompt(ua, _("InChanger Flag")); /* 8 */
492 add_prompt(ua, _("Volume Files")); /* 9 */
493 add_prompt(ua, _("Pool")); /* 10 */
494 add_prompt(ua, _("Volume from Pool")); /* 11 */
495 add_prompt(ua, _("All Volumes from Pool")); /* 12 */
496 add_prompt(ua, _("Enabled")), /* 13 */
497 add_prompt(ua, _("Done")); /* 14 */
498 i = do_prompt(ua, "", _("Select parameter to modify"), NULL, 0);
500 /* For All Volumes from Pool and Done, we don't need a Volume record */
501 if (i != 12 && i != 14) {
502 if (!select_media_dbr(ua, &mr)) { /* Get Volume record */
505 bsendmsg(ua, _("Updating Volume \"%s\"\n"), mr.VolumeName);
508 case 0: /* Volume Status */
509 /* Modify Volume Status */
510 bsendmsg(ua, _("Current Volume status is: %s\n"), mr.VolStatus);
511 start_prompt(ua, _("Possible Values are:\n"));
512 add_prompt(ua, NT_("Append"));
513 add_prompt(ua, NT_("Archive"));
514 add_prompt(ua, NT_("Disabled"));
515 add_prompt(ua, NT_("Full"));
516 add_prompt(ua, NT_("Used"));
517 add_prompt(ua, NT_("Cleaning"));
518 if (strcmp(mr.VolStatus, NT_("Purged")) == 0) {
519 add_prompt(ua, NT_("Recycle"));
521 add_prompt(ua, NT_("Read-Only"));
522 if (do_prompt(ua, "", _("Choose new Volume Status"), ua->cmd, sizeof(mr.VolStatus)) < 0) {
525 update_volstatus(ua, ua->cmd, &mr);
527 case 1: /* Retention */
528 bsendmsg(ua, _("Current retention period is: %s\n"),
529 edit_utime(mr.VolRetention, ed1, sizeof(ed1)));
530 if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
533 update_volretention(ua, ua->cmd, &mr);
536 case 2: /* Use Duration */
537 bsendmsg(ua, _("Current use duration is: %s\n"),
538 edit_utime(mr.VolUseDuration, ed1, sizeof(ed1)));
539 if (!get_cmd(ua, _("Enter Volume Use Duration: "))) {
542 update_voluseduration(ua, ua->cmd, &mr);
545 case 3: /* Max Jobs */
546 bsendmsg(ua, _("Current max jobs is: %u\n"), mr.MaxVolJobs);
547 if (!get_pint(ua, _("Enter new Maximum Jobs: "))) {
550 update_volmaxjobs(ua, ua->cmd, &mr);
553 case 4: /* Max Files */
554 bsendmsg(ua, _("Current max files is: %u\n"), mr.MaxVolFiles);
555 if (!get_pint(ua, _("Enter new Maximum Files: "))) {
558 update_volmaxfiles(ua, ua->cmd, &mr);
561 case 5: /* Max Bytes */
562 bsendmsg(ua, _("Current value is: %s\n"), edit_uint64(mr.MaxVolBytes, ed1));
563 if (!get_cmd(ua, _("Enter new Maximum Bytes: "))) {
566 update_volmaxbytes(ua, ua->cmd, &mr);
570 case 6: /* Recycle */
571 bsendmsg(ua, _("Current recycle flag is: %s\n"),
572 mr.Recycle==1?_("yes"):_("no"));
573 if (!get_yesno(ua, _("Enter new Recycle status: "))) {
576 update_volrecycle(ua, ua->cmd, &mr);
580 bsendmsg(ua, _("Current Slot is: %d\n"), mr.Slot);
581 if (!get_pint(ua, _("Enter new Slot: "))) {
584 update_volslot(ua, ua->cmd, &mr);
587 case 8: /* InChanger */
588 bsendmsg(ua, _("Current InChanger flag is: %d\n"), mr.InChanger);
589 if (!get_yesno(ua, _("Set InChanger flag? yes/no: "))) {
592 mr.InChanger = ua->pint32_val;
594 * Make sure to use db_update... rather than doing this directly,
595 * so that any Slot is handled correctly.
597 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
598 bsendmsg(ua, _("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
600 bsendmsg(ua, _("New InChanger flag is: %d\n"), mr.InChanger);
605 case 9: /* Volume Files */
607 bsendmsg(ua, _("Warning changing Volume Files can result\n"
608 "in loss of data on your Volume\n\n"));
609 bsendmsg(ua, _("Current Volume Files is: %u\n"), mr.VolFiles);
610 if (!get_pint(ua, _("Enter new number of Files for Volume: "))) {
613 VolFiles = ua->pint32_val;
614 if (VolFiles != (int)(mr.VolFiles + 1)) {
615 bsendmsg(ua, _("Normally, you should only increase Volume Files by one!\n"));
616 if (!get_yesno(ua, _("Continue? (yes/no): ")) || ua->pint32_val == 0) {
620 query = get_pool_memory(PM_MESSAGE);
621 Mmsg(query, "UPDATE Media SET VolFiles=%u WHERE MediaId=%s",
622 VolFiles, edit_int64(mr.MediaId, ed1));
623 if (!db_sql_query(ua->db, query, NULL, NULL)) {
624 bsendmsg(ua, "%s", db_strerror(ua->db));
626 bsendmsg(ua, _("New Volume Files is: %u\n"), VolFiles);
628 free_pool_memory(query);
631 case 10: /* Volume's Pool */
632 memset(&pr, 0, sizeof(POOL_DBR));
633 pr.PoolId = mr.PoolId;
634 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
635 bsendmsg(ua, "%s", db_strerror(ua->db));
638 bsendmsg(ua, _("Current Pool is: %s\n"), pr.Name);
639 if (!get_cmd(ua, _("Enter new Pool name: "))) {
642 update_vol_pool(ua, ua->cmd, &mr, &pr);
646 update_vol_from_pool(ua, &mr);
649 update_all_vols_from_pool(ua);
653 bsendmsg(ua, _("Current Enabled is: %d\n"), mr.Enabled);
654 if (!get_cmd(ua, _("Enter new Enabled: "))) {
657 if (strcasecmp(ua->cmd, "yes") == 0 || strcasecmp(ua->cmd, "true") == 0) {
659 } else if (strcasecmp(ua->cmd, "no") == 0 || strcasecmp(ua->cmd, "false") == 0) {
661 } else if (strcasecmp(ua->cmd, "archived") == 0) {
664 mr.Enabled = atoi(ua->cmd);
666 update_volenabled(ua, ua->cmd, &mr);
669 default: /* Done or error */
670 bsendmsg(ua, _("Selection terminated.\n"));
678 * Update pool record -- pull info from current POOL resource
680 static bool update_pool(UAContext *ua)
688 pool = get_pool_resource(ua);
693 memset(&pr, 0, sizeof(pr));
694 bstrncpy(pr.Name, pool->hdr.name, sizeof(pr.Name));
695 if (!get_pool_dbr(ua, &pr)) {
699 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE); /* update */
701 id = db_update_pool_record(ua->jcr, ua->db, &pr);
703 bsendmsg(ua, _("db_update_pool_record returned %d. ERR=%s\n"),
704 id, db_strerror(ua->db));
706 query = get_pool_memory(PM_MESSAGE);
707 Mmsg(query, list_pool, edit_int64(pr.PoolId, ed1));
708 db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST);
709 free_pool_memory(query);
710 bsendmsg(ua, _("Pool DB record updated from resource.\n"));