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);
120 for (i=0; kw[i]; i++) {
121 if (strcasecmp(val, kw[i]) == 0) {
127 bsendmsg(ua, _("Invalid VolStatus specified: %s\n"), val);
130 bstrncpy(mr->VolStatus, kw[i], sizeof(mr->VolStatus));
131 Mmsg(query, "UPDATE Media SET VolStatus='%s' WHERE MediaId=%s",
132 mr->VolStatus, edit_int64(mr->MediaId,ed1));
133 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
134 bsendmsg(ua, "%s", db_strerror(ua->db));
136 bsendmsg(ua, _("New Volume status is: %s\n"), mr->VolStatus);
141 static void update_volretention(UAContext *ua, char *val, MEDIA_DBR *mr)
143 char ed1[150], ed2[50];
144 POOL_MEM query(PM_MESSAGE);
145 if (!duration_to_utime(val, &mr->VolRetention)) {
146 bsendmsg(ua, _("Invalid retention period specified: %s\n"), val);
149 Mmsg(query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%s",
150 edit_uint64(mr->VolRetention, ed1), edit_int64(mr->MediaId,ed2));
151 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
152 bsendmsg(ua, "%s", db_strerror(ua->db));
154 bsendmsg(ua, _("New retention period is: %s\n"),
155 edit_utime(mr->VolRetention, ed1, sizeof(ed1)));
159 static void update_voluseduration(UAContext *ua, char *val, MEDIA_DBR *mr)
161 char ed1[150], ed2[50];
162 POOL_MEM query(PM_MESSAGE);
164 if (!duration_to_utime(val, &mr->VolUseDuration)) {
165 bsendmsg(ua, _("Invalid use duration specified: %s\n"), val);
168 Mmsg(query, "UPDATE Media SET VolUseDuration=%s WHERE MediaId=%s",
169 edit_uint64(mr->VolUseDuration, ed1), edit_int64(mr->MediaId,ed2));
170 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
171 bsendmsg(ua, "%s", db_strerror(ua->db));
173 bsendmsg(ua, _("New use duration is: %s\n"),
174 edit_utime(mr->VolUseDuration, ed1, sizeof(ed1)));
178 static void update_volmaxjobs(UAContext *ua, char *val, MEDIA_DBR *mr)
180 POOL_MEM query(PM_MESSAGE);
182 Mmsg(query, "UPDATE Media SET MaxVolJobs=%s WHERE MediaId=%s",
183 val, edit_int64(mr->MediaId,ed1));
184 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
185 bsendmsg(ua, "%s", db_strerror(ua->db));
187 bsendmsg(ua, _("New max jobs is: %s\n"), val);
191 static void update_volmaxfiles(UAContext *ua, char *val, MEDIA_DBR *mr)
193 POOL_MEM query(PM_MESSAGE);
195 Mmsg(query, "UPDATE Media SET MaxVolFiles=%s WHERE MediaId=%s",
196 val, edit_int64(mr->MediaId, ed1));
197 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
198 bsendmsg(ua, "%s", db_strerror(ua->db));
200 bsendmsg(ua, _("New max files is: %s\n"), val);
204 static void update_volmaxbytes(UAContext *ua, char *val, MEDIA_DBR *mr)
207 char ed1[50], ed2[50];
208 POOL_MEM query(PM_MESSAGE);
210 if (!size_to_uint64(val, strlen(val), &maxbytes)) {
211 bsendmsg(ua, _("Invalid max. bytes specification: %s\n"), val);
214 Mmsg(query, "UPDATE Media SET MaxVolBytes=%s WHERE MediaId=%s",
215 edit_uint64(maxbytes, ed1), edit_int64(mr->MediaId, ed2));
216 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
217 bsendmsg(ua, "%s", db_strerror(ua->db));
219 bsendmsg(ua, _("New Max bytes is: %s\n"), edit_uint64(maxbytes, ed1));
223 static void update_volrecycle(UAContext *ua, char *val, MEDIA_DBR *mr)
228 POOL_MEM query(PM_MESSAGE);
229 if (!is_yesno(val, &recycle)) {
230 bsendmsg(ua, _("Invalid value. It must be yes or no.\n"));
233 Mmsg(query, "UPDATE Media SET Recycle=%d WHERE MediaId=%s",
234 recycle, edit_int64(mr->MediaId, ed1));
235 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
236 bsendmsg(ua, "%s", db_strerror(ua->db));
238 bsendmsg(ua, _("New Recycle flag is: %s\n"),
239 mr->Recycle==1?_("yes"):_("no"));
243 static void update_volinchanger(UAContext *ua, char *val, MEDIA_DBR *mr)
248 POOL_MEM query(PM_MESSAGE);
249 if (!is_yesno(val, &InChanger)) {
250 bsendmsg(ua, _("Invalid value. It must be yes or no.\n"));
253 Mmsg(query, "UPDATE Media SET InChanger=%d WHERE MediaId=%s",
254 InChanger, edit_int64(mr->MediaId, ed1));
255 if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
256 bsendmsg(ua, "%s", db_strerror(ua->db));
258 bsendmsg(ua, _("New InChanger flag is: %s\n"),
259 mr->InChanger==1?_("yes"):_("no"));
264 static void update_volslot(UAContext *ua, char *val, MEDIA_DBR *mr)
268 memset(&pr, 0, sizeof(POOL_DBR));
269 pr.PoolId = mr->PoolId;
270 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
271 bsendmsg(ua, "%s", db_strerror(ua->db));
274 mr->Slot = atoi(val);
275 if (pr.MaxVols > 0 && mr->Slot > (int)pr.MaxVols) {
276 bsendmsg(ua, _("Invalid slot, it must be between 0 and MaxVols=%d\n"),
281 * Make sure to use db_update... rather than doing this directly,
282 * so that any Slot is handled correctly.
284 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
285 bsendmsg(ua, _("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
287 bsendmsg(ua, _("New Slot is: %d\n"), mr->Slot);
291 /* Modify the Pool in which this Volume is located */
292 static void update_vol_pool(UAContext *ua, char *val, MEDIA_DBR *mr, POOL_DBR *opr)
296 char ed1[50], ed2[50];
298 memset(&pr, 0, sizeof(pr));
299 bstrncpy(pr.Name, val, sizeof(pr.Name));
300 if (!get_pool_dbr(ua, &pr)) {
303 mr->PoolId = pr.PoolId; /* set new PoolId */
306 query = get_pool_memory(PM_MESSAGE);
308 Mmsg(query, "UPDATE Media SET PoolId=%s WHERE MediaId=%s",
309 edit_int64(mr->PoolId, ed1),
310 edit_int64(mr->MediaId, ed2));
311 if (!db_sql_query(ua->db, query, NULL, NULL)) {
312 bsendmsg(ua, "%s", db_strerror(ua->db));
314 bsendmsg(ua, _("New Pool is: %s\n"), pr.Name);
316 if (!db_update_pool_record(ua->jcr, ua->db, opr)) {
317 bsendmsg(ua, "%s", db_strerror(ua->db));
320 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
321 bsendmsg(ua, "%s", db_strerror(ua->db));
325 free_pool_memory(query);
329 * Refresh the Volume information from the Pool record
331 static void update_vol_from_pool(UAContext *ua, MEDIA_DBR *mr)
335 memset(&pr, 0, sizeof(pr));
336 pr.PoolId = mr->PoolId;
337 if (!db_get_pool_record(ua->jcr, ua->db, &pr) ||
338 !acl_access_ok(ua, Pool_ACL, pr.Name)) {
341 set_pool_dbr_defaults_in_media_dbr(mr, &pr);
342 if (!db_update_media_defaults(ua->jcr, ua->db, mr)) {
343 bsendmsg(ua, _("Error updating Volume record: ERR=%s"), db_strerror(ua->db));
345 bsendmsg(ua, _("Volume defaults updated from \"%s\" Pool record.\n"),
351 * Refresh the Volume information from the Pool record
354 static void update_all_vols_from_pool(UAContext *ua)
359 memset(&pr, 0, sizeof(pr));
360 memset(&mr, 0, sizeof(mr));
361 if (!get_pool_dbr(ua, &pr)) {
364 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
365 mr.PoolId = pr.PoolId;
366 if (!db_update_media_defaults(ua->jcr, ua->db, &mr)) {
367 bsendmsg(ua, _("Error updating Volume records: ERR=%s"), db_strerror(ua->db));
369 bsendmsg(ua, _("All Volume defaults updated from Pool record.\n"));
373 static void update_volenabled(UAContext *ua, char *val, MEDIA_DBR *mr)
375 mr->Enabled = get_enabled(ua, val);
376 if (mr->Enabled < 0) {
379 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
380 bsendmsg(ua, _("Error updating media record Enabled: ERR=%s"), db_strerror(ua->db));
382 bsendmsg(ua, _("New Enabled is: %d\n"), mr->Enabled);
389 * Update a media record -- allows you to change the
390 * Volume status. E.g. if you want Bacula to stop
391 * writing on the volume, set it to anything other
394 static int update_volume(UAContext *ua)
403 _("VolStatus"), /* 0 */
404 _("VolRetention"), /* 1 */
406 _("MaxVolJobs"), /* 3 */
407 _("MaxVolFiles"), /* 4 */
408 _("MaxVolBytes"), /* 5 */
409 _("Recycle"), /* 6 */
410 _("InChanger"), /* 7 */
413 _("FromPool"), /* 10 */
414 _("AllFromPool"), /* 11 !!! see below !!! */
415 _("Enabled"), /* 12 */
418 #define AllFromPool 11 /* keep this updated with above */
420 for (i=0; kw[i]; i++) {
423 if ((j=find_arg_with_value(ua, kw[i])) > 0) {
424 /* If all from pool don't select a media record */
425 if (i != AllFromPool && !select_media_dbr(ua, &mr)) {
430 update_volstatus(ua, ua->argv[j], &mr);
433 update_volretention(ua, ua->argv[j], &mr);
436 update_voluseduration(ua, ua->argv[j], &mr);
439 update_volmaxjobs(ua, ua->argv[j], &mr);
442 update_volmaxfiles(ua, ua->argv[j], &mr);
445 update_volmaxbytes(ua, ua->argv[j], &mr);
448 update_volrecycle(ua, ua->argv[j], &mr);
451 update_volinchanger(ua, ua->argv[j], &mr);
454 update_volslot(ua, ua->argv[j], &mr);
457 memset(&pr, 0, sizeof(POOL_DBR));
458 pr.PoolId = mr.PoolId;
459 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
460 bsendmsg(ua, "%s", db_strerror(ua->db));
463 update_vol_pool(ua, ua->argv[j], &mr, &pr);
466 update_vol_from_pool(ua, &mr);
469 update_all_vols_from_pool(ua);
472 update_volenabled(ua, ua->argv[j], &mr);
480 start_prompt(ua, _("Parameters to modify:\n"));
481 add_prompt(ua, _("Volume Status")); /* 0 */
482 add_prompt(ua, _("Volume Retention Period")); /* 1 */
483 add_prompt(ua, _("Volume Use Duration")); /* 2 */
484 add_prompt(ua, _("Maximum Volume Jobs")); /* 3 */
485 add_prompt(ua, _("Maximum Volume Files")); /* 4 */
486 add_prompt(ua, _("Maximum Volume Bytes")); /* 5 */
487 add_prompt(ua, _("Recycle Flag")); /* 6 */
488 add_prompt(ua, _("Slot")); /* 7 */
489 add_prompt(ua, _("InChanger Flag")); /* 8 */
490 add_prompt(ua, _("Volume Files")); /* 9 */
491 add_prompt(ua, _("Pool")); /* 10 */
492 add_prompt(ua, _("Volume from Pool")); /* 11 */
493 add_prompt(ua, _("All Volumes from Pool")); /* 12 */
494 add_prompt(ua, _("Enabled")), /* 13 */
495 add_prompt(ua, _("Done")); /* 14 */
496 i = do_prompt(ua, "", _("Select parameter to modify"), NULL, 0);
498 /* For All Volumes from Pool and Done, we don't need a Volume record */
499 if (i != 12 && i != 14) {
500 if (!select_media_dbr(ua, &mr)) { /* Get Volume record */
503 bsendmsg(ua, _("Updating Volume \"%s\"\n"), mr.VolumeName);
506 case 0: /* Volume Status */
507 /* Modify Volume Status */
508 bsendmsg(ua, _("Current Volume status is: %s\n"), mr.VolStatus);
509 start_prompt(ua, _("Possible Values are:\n"));
510 add_prompt(ua, NT_("Append"));
511 add_prompt(ua, NT_("Archive"));
512 add_prompt(ua, NT_("Disabled"));
513 add_prompt(ua, NT_("Full"));
514 add_prompt(ua, NT_("Used"));
515 add_prompt(ua, NT_("Cleaning"));
516 if (strcmp(mr.VolStatus, NT_("Purged")) == 0) {
517 add_prompt(ua, NT_("Recycle"));
519 add_prompt(ua, NT_("Read-Only"));
520 if (do_prompt(ua, "", _("Choose new Volume Status"), ua->cmd, sizeof(mr.VolStatus)) < 0) {
523 update_volstatus(ua, ua->cmd, &mr);
525 case 1: /* Retention */
526 bsendmsg(ua, _("Current retention period is: %s\n"),
527 edit_utime(mr.VolRetention, ed1, sizeof(ed1)));
528 if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
531 update_volretention(ua, ua->cmd, &mr);
534 case 2: /* Use Duration */
535 bsendmsg(ua, _("Current use duration is: %s\n"),
536 edit_utime(mr.VolUseDuration, ed1, sizeof(ed1)));
537 if (!get_cmd(ua, _("Enter Volume Use Duration: "))) {
540 update_voluseduration(ua, ua->cmd, &mr);
543 case 3: /* Max Jobs */
544 bsendmsg(ua, _("Current max jobs is: %u\n"), mr.MaxVolJobs);
545 if (!get_pint(ua, _("Enter new Maximum Jobs: "))) {
548 update_volmaxjobs(ua, ua->cmd, &mr);
551 case 4: /* Max Files */
552 bsendmsg(ua, _("Current max files is: %u\n"), mr.MaxVolFiles);
553 if (!get_pint(ua, _("Enter new Maximum Files: "))) {
556 update_volmaxfiles(ua, ua->cmd, &mr);
559 case 5: /* Max Bytes */
560 bsendmsg(ua, _("Current value is: %s\n"), edit_uint64(mr.MaxVolBytes, ed1));
561 if (!get_cmd(ua, _("Enter new Maximum Bytes: "))) {
564 update_volmaxbytes(ua, ua->cmd, &mr);
568 case 6: /* Recycle */
569 bsendmsg(ua, _("Current recycle flag is: %s\n"),
570 mr.Recycle==1?_("yes"):_("no"));
571 if (!get_yesno(ua, _("Enter new Recycle status: "))) {
574 update_volrecycle(ua, ua->cmd, &mr);
578 bsendmsg(ua, _("Current Slot is: %d\n"), mr.Slot);
579 if (!get_pint(ua, _("Enter new Slot: "))) {
582 update_volslot(ua, ua->cmd, &mr);
585 case 8: /* InChanger */
586 bsendmsg(ua, _("Current InChanger flag is: %d\n"), mr.InChanger);
587 if (!get_yesno(ua, _("Set InChanger flag? yes/no: "))) {
590 mr.InChanger = ua->pint32_val;
592 * Make sure to use db_update... rather than doing this directly,
593 * so that any Slot is handled correctly.
595 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
596 bsendmsg(ua, _("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
598 bsendmsg(ua, _("New InChanger flag is: %d\n"), mr.InChanger);
603 case 9: /* Volume Files */
605 bsendmsg(ua, _("Warning changing Volume Files can result\n"
606 "in loss of data on your Volume\n\n"));
607 bsendmsg(ua, _("Current Volume Files is: %u\n"), mr.VolFiles);
608 if (!get_pint(ua, _("Enter new number of Files for Volume: "))) {
611 VolFiles = ua->pint32_val;
612 if (VolFiles != (int)(mr.VolFiles + 1)) {
613 bsendmsg(ua, _("Normally, you should only increase Volume Files by one!\n"));
614 if (!get_yesno(ua, _("Continue? (yes/no): ")) || ua->pint32_val == 0) {
618 query = get_pool_memory(PM_MESSAGE);
619 Mmsg(query, "UPDATE Media SET VolFiles=%u WHERE MediaId=%s",
620 VolFiles, edit_int64(mr.MediaId, ed1));
621 if (!db_sql_query(ua->db, query, NULL, NULL)) {
622 bsendmsg(ua, "%s", db_strerror(ua->db));
624 bsendmsg(ua, _("New Volume Files is: %u\n"), VolFiles);
626 free_pool_memory(query);
629 case 10: /* Volume's Pool */
630 memset(&pr, 0, sizeof(POOL_DBR));
631 pr.PoolId = mr.PoolId;
632 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
633 bsendmsg(ua, "%s", db_strerror(ua->db));
636 bsendmsg(ua, _("Current Pool is: %s\n"), pr.Name);
637 if (!get_cmd(ua, _("Enter new Pool name: "))) {
640 update_vol_pool(ua, ua->cmd, &mr, &pr);
644 update_vol_from_pool(ua, &mr);
647 update_all_vols_from_pool(ua);
651 bsendmsg(ua, _("Current Enabled is: %d\n"), mr.Enabled);
652 if (!get_cmd(ua, _("Enter new Enabled: "))) {
655 if (strcasecmp(ua->cmd, "yes") == 0 || strcasecmp(ua->cmd, "true") == 0) {
657 } else if (strcasecmp(ua->cmd, "no") == 0 || strcasecmp(ua->cmd, "false") == 0) {
659 } else if (strcasecmp(ua->cmd, "archived") == 0) {
662 mr.Enabled = atoi(ua->cmd);
664 update_volenabled(ua, ua->cmd, &mr);
667 default: /* Done or error */
668 bsendmsg(ua, _("Selection terminated.\n"));
676 * Update pool record -- pull info from current POOL resource
678 static bool update_pool(UAContext *ua)
686 pool = get_pool_resource(ua);
691 memset(&pr, 0, sizeof(pr));
692 bstrncpy(pr.Name, pool->hdr.name, sizeof(pr.Name));
693 if (!get_pool_dbr(ua, &pr)) {
697 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE); /* update */
699 id = db_update_pool_record(ua->jcr, ua->db, &pr);
701 bsendmsg(ua, _("db_update_pool_record returned %d. ERR=%s\n"),
702 id, db_strerror(ua->db));
704 query = get_pool_memory(PM_MESSAGE);
705 Mmsg(query, list_pool, edit_int64(pr.PoolId, ed1));
706 db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST);
707 free_pool_memory(query);
708 bsendmsg(ua, _("Pool DB record updated from resource.\n"));