2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
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 plus additions
11 that are listed in the file LICENSE.
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.
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
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.
30 * Bacula Director -- Update command processing
31 * Split from ua_cmds.c March 2005
33 * Kern Sibbald, September MM
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);
47 * Update a Pool Record in the database.
48 * It is always updated from the Resource record.
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
57 int update_cmd(UAContext *ua, const char *cmd)
59 static const char *kw[] = {
61 NT_("volume"), /* 1 */
67 if (!open_client_db(ua)) {
71 switch (find_arg_keyword(ua, kw)) {
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)) {
109 static void update_volstatus(UAContext *ua, const char *val, MEDIA_DBR *mr)
111 POOL_MEM query(PM_MESSAGE);
126 for (i=0; kw[i]; i++) {
127 if (strcasecmp(val, kw[i]) == 0) {
133 ua->error_msg(_("Invalid VolStatus specified: %s\n"), val);
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));
142 ua->info_msg(_("New Volume status is: %s\n"), mr->VolStatus);
147 static void update_volretention(UAContext *ua, char *val, MEDIA_DBR *mr)
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);
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));
160 ua->info_msg(_("New retention period is: %s\n"),
161 edit_utime(mr->VolRetention, ed1, sizeof(ed1)));
165 static void update_voluseduration(UAContext *ua, char *val, MEDIA_DBR *mr)
167 char ed1[150], ed2[50];
168 POOL_MEM query(PM_MESSAGE);
170 if (!duration_to_utime(val, &mr->VolUseDuration)) {
171 ua->error_msg(_("Invalid use duration specified: %s\n"), val);
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));
179 ua->info_msg(_("New use duration is: %s\n"),
180 edit_utime(mr->VolUseDuration, ed1, sizeof(ed1)));
184 static void update_volmaxjobs(UAContext *ua, char *val, MEDIA_DBR *mr)
186 POOL_MEM query(PM_MESSAGE);
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));
193 ua->info_msg(_("New max jobs is: %s\n"), val);
197 static void update_volmaxfiles(UAContext *ua, char *val, MEDIA_DBR *mr)
199 POOL_MEM query(PM_MESSAGE);
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));
206 ua->info_msg(_("New max files is: %s\n"), val);
210 static void update_volmaxbytes(UAContext *ua, char *val, MEDIA_DBR *mr)
213 char ed1[50], ed2[50];
214 POOL_MEM query(PM_MESSAGE);
216 if (!size_to_uint64(val, strlen(val), &maxbytes)) {
217 ua->error_msg(_("Invalid max. bytes specification: %s\n"), val);
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));
225 ua->info_msg(_("New Max bytes is: %s\n"), edit_uint64(maxbytes, ed1));
229 static void update_volrecycle(UAContext *ua, char *val, MEDIA_DBR *mr)
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"));
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));
244 ua->info_msg(_("New Recycle flag is: %s\n"),
245 mr->Recycle==1?_("yes"):_("no"));
249 static void update_volinchanger(UAContext *ua, char *val, MEDIA_DBR *mr)
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"));
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));
264 ua->info_msg(_("New InChanger flag is: %s\n"),
265 mr->InChanger==1?_("yes"):_("no"));
270 static void update_volslot(UAContext *ua, char *val, MEDIA_DBR *mr)
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));
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"),
287 * Make sure to use db_update... rather than doing this directly,
288 * so that any Slot is handled correctly.
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));
293 ua->info_msg(_("New Slot is: %d\n"), mr->Slot);
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)
302 char ed1[50], ed2[50];
304 memset(&pr, 0, sizeof(pr));
305 bstrncpy(pr.Name, val, sizeof(pr.Name));
306 if (!get_pool_dbr(ua, &pr)) {
309 mr->PoolId = pr.PoolId; /* set new PoolId */
312 query = get_pool_memory(PM_MESSAGE);
314 Mmsg(query, "UPDATE Media SET PoolId=%s WHERE MediaId=%s",
315 edit_int64(mr->PoolId, ed1),
316 edit_int64(mr->MediaId, ed2));
317 if (!db_sql_query(ua->db, query, NULL, NULL)) {
318 ua->error_msg("%s", db_strerror(ua->db));
320 ua->info_msg(_("New Pool is: %s\n"), pr.Name);
322 if (!db_update_pool_record(ua->jcr, ua->db, opr)) {
323 ua->error_msg("%s", db_strerror(ua->db));
326 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
327 ua->error_msg("%s", db_strerror(ua->db));
331 free_pool_memory(query);
334 /* Modify the RecyclePool of a Volume */
335 void update_vol_recyclepool(UAContext *ua, char *val, MEDIA_DBR *mr)
339 char ed1[50], ed2[50];
341 memset(&pr, 0, sizeof(pr));
342 bstrncpy(pr.Name, val, sizeof(pr.Name));
343 if (!get_pool_dbr(ua, &pr, NT_("recyclepool"))) {
346 /* pool = select_pool_resource(ua); */
347 mr->RecyclePoolId = pr.PoolId; /* get the PoolId */
349 query = get_pool_memory(PM_MESSAGE);
351 Mmsg(query, "UPDATE Media SET RecyclePoolId=%s WHERE MediaId=%s",
352 edit_int64(mr->RecyclePoolId, ed1),
353 edit_int64(mr->MediaId, ed2));
354 if (!db_sql_query(ua->db, query, NULL, NULL)) {
355 ua->error_msg("%s", db_strerror(ua->db));
357 ua->info_msg(_("New RecyclePool is: %s\n"), pr.Name);
360 free_pool_memory(query);
364 * Refresh the Volume information from the Pool record
366 static void update_vol_from_pool(UAContext *ua, MEDIA_DBR *mr)
370 memset(&pr, 0, sizeof(pr));
371 pr.PoolId = mr->PoolId;
372 if (!db_get_pool_record(ua->jcr, ua->db, &pr) ||
373 !acl_access_ok(ua, Pool_ACL, pr.Name)) {
376 set_pool_dbr_defaults_in_media_dbr(mr, &pr);
377 if (!db_update_media_defaults(ua->jcr, ua->db, mr)) {
378 ua->error_msg(_("Error updating Volume record: ERR=%s"), db_strerror(ua->db));
380 ua->info_msg(_("Volume defaults updated from \"%s\" Pool record.\n"),
386 * Refresh the Volume information from the Pool record
389 static void update_all_vols_from_pool(UAContext *ua)
394 memset(&pr, 0, sizeof(pr));
395 memset(&mr, 0, sizeof(mr));
396 if (!get_pool_dbr(ua, &pr)) {
399 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
400 mr.PoolId = pr.PoolId;
401 if (!db_update_media_defaults(ua->jcr, ua->db, &mr)) {
402 ua->error_msg(_("Error updating Volume records: ERR=%s"), db_strerror(ua->db));
404 ua->info_msg(_("All Volume defaults updated from Pool record.\n"));
408 static void update_volenabled(UAContext *ua, char *val, MEDIA_DBR *mr)
410 mr->Enabled = get_enabled(ua, val);
411 if (mr->Enabled < 0) {
414 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
415 ua->error_msg(_("Error updating media record Enabled: ERR=%s"), db_strerror(ua->db));
417 ua->info_msg(_("New Enabled is: %d\n"), mr->Enabled);
424 * Update a media record -- allows you to change the
425 * Volume status. E.g. if you want Bacula to stop
426 * writing on the volume, set it to anything other
429 static int update_volume(UAContext *ua)
438 NT_("VolStatus"), /* 0 */
439 NT_("VolRetention"), /* 1 */
440 NT_("VolUse"), /* 2 */
441 NT_("MaxVolJobs"), /* 3 */
442 NT_("MaxVolFiles"), /* 4 */
443 NT_("MaxVolBytes"), /* 5 */
444 NT_("Recycle"), /* 6 */
445 NT_("InChanger"), /* 7 */
448 NT_("FromPool"), /* 10 */
449 NT_("AllFromPool"), /* 11 !!! see below !!! */
450 NT_("Enabled"), /* 12 */
451 NT_("RecyclePool"), /* 13 */
454 #define AllFromPool 11 /* keep this updated with above */
456 for (i=0; kw[i]; i++) {
459 if ((j=find_arg_with_value(ua, kw[i])) > 0) {
460 /* If all from pool don't select a media record */
461 if (i != AllFromPool && !select_media_dbr(ua, &mr)) {
466 update_volstatus(ua, ua->argv[j], &mr);
469 update_volretention(ua, ua->argv[j], &mr);
472 update_voluseduration(ua, ua->argv[j], &mr);
475 update_volmaxjobs(ua, ua->argv[j], &mr);
478 update_volmaxfiles(ua, ua->argv[j], &mr);
481 update_volmaxbytes(ua, ua->argv[j], &mr);
484 update_volrecycle(ua, ua->argv[j], &mr);
487 update_volinchanger(ua, ua->argv[j], &mr);
490 update_volslot(ua, ua->argv[j], &mr);
493 memset(&pr, 0, sizeof(POOL_DBR));
494 pr.PoolId = mr.PoolId;
495 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
496 ua->error_msg("%s", db_strerror(ua->db));
499 update_vol_pool(ua, ua->argv[j], &mr, &pr);
502 update_vol_from_pool(ua, &mr);
505 update_all_vols_from_pool(ua);
508 update_volenabled(ua, ua->argv[j], &mr);
511 update_vol_recyclepool(ua, ua->argv[j], &mr);
519 start_prompt(ua, _("Parameters to modify:\n"));
520 add_prompt(ua, _("Volume Status")); /* 0 */
521 add_prompt(ua, _("Volume Retention Period")); /* 1 */
522 add_prompt(ua, _("Volume Use Duration")); /* 2 */
523 add_prompt(ua, _("Maximum Volume Jobs")); /* 3 */
524 add_prompt(ua, _("Maximum Volume Files")); /* 4 */
525 add_prompt(ua, _("Maximum Volume Bytes")); /* 5 */
526 add_prompt(ua, _("Recycle Flag")); /* 6 */
527 add_prompt(ua, _("Slot")); /* 7 */
528 add_prompt(ua, _("InChanger Flag")); /* 8 */
529 add_prompt(ua, _("Volume Files")); /* 9 */
530 add_prompt(ua, _("Pool")); /* 10 */
531 add_prompt(ua, _("Volume from Pool")); /* 11 */
532 add_prompt(ua, _("All Volumes from Pool")); /* 12 */
533 add_prompt(ua, _("Enabled")), /* 13 */
534 add_prompt(ua, _("RecyclePool")), /* 14 */
535 add_prompt(ua, _("Done")); /* 15 */
536 i = do_prompt(ua, "", _("Select parameter to modify"), NULL, 0);
538 /* For All Volumes from Pool and Done, we don't need a Volume record */
539 if (i != 12 && i != 15) {
540 if (!select_media_dbr(ua, &mr)) { /* Get Volume record */
543 ua->info_msg(_("Updating Volume \"%s\"\n"), mr.VolumeName);
546 case 0: /* Volume Status */
547 /* Modify Volume Status */
548 ua->info_msg(_("Current Volume status is: %s\n"), mr.VolStatus);
549 start_prompt(ua, _("Possible Values are:\n"));
550 add_prompt(ua, NT_("Append"));
551 add_prompt(ua, NT_("Archive"));
552 add_prompt(ua, NT_("Disabled"));
553 add_prompt(ua, NT_("Full"));
554 add_prompt(ua, NT_("Used"));
555 add_prompt(ua, NT_("Cleaning"));
556 if (strcmp(mr.VolStatus, NT_("Purged")) == 0) {
557 add_prompt(ua, NT_("Recycle"));
559 add_prompt(ua, NT_("Read-Only"));
560 if (do_prompt(ua, "", _("Choose new Volume Status"), ua->cmd, sizeof(mr.VolStatus)) < 0) {
563 update_volstatus(ua, ua->cmd, &mr);
565 case 1: /* Retention */
566 ua->info_msg(_("Current retention period is: %s\n"),
567 edit_utime(mr.VolRetention, ed1, sizeof(ed1)));
568 if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
571 update_volretention(ua, ua->cmd, &mr);
574 case 2: /* Use Duration */
575 ua->info_msg(_("Current use duration is: %s\n"),
576 edit_utime(mr.VolUseDuration, ed1, sizeof(ed1)));
577 if (!get_cmd(ua, _("Enter Volume Use Duration: "))) {
580 update_voluseduration(ua, ua->cmd, &mr);
583 case 3: /* Max Jobs */
584 ua->info_msg(_("Current max jobs is: %u\n"), mr.MaxVolJobs);
585 if (!get_pint(ua, _("Enter new Maximum Jobs: "))) {
588 update_volmaxjobs(ua, ua->cmd, &mr);
591 case 4: /* Max Files */
592 ua->info_msg(_("Current max files is: %u\n"), mr.MaxVolFiles);
593 if (!get_pint(ua, _("Enter new Maximum Files: "))) {
596 update_volmaxfiles(ua, ua->cmd, &mr);
599 case 5: /* Max Bytes */
600 ua->info_msg(_("Current value is: %s\n"), edit_uint64(mr.MaxVolBytes, ed1));
601 if (!get_cmd(ua, _("Enter new Maximum Bytes: "))) {
604 update_volmaxbytes(ua, ua->cmd, &mr);
608 case 6: /* Recycle */
609 ua->info_msg(_("Current recycle flag is: %s\n"),
610 mr.Recycle==1?_("yes"):_("no"));
611 if (!get_yesno(ua, _("Enter new Recycle status: "))) {
614 update_volrecycle(ua, ua->cmd, &mr);
618 ua->info_msg(_("Current Slot is: %d\n"), mr.Slot);
619 if (!get_pint(ua, _("Enter new Slot: "))) {
622 update_volslot(ua, ua->cmd, &mr);
625 case 8: /* InChanger */
626 ua->info_msg(_("Current InChanger flag is: %d\n"), mr.InChanger);
627 if (!get_yesno(ua, _("Set InChanger flag? yes/no: "))) {
630 mr.InChanger = ua->pint32_val;
632 * Make sure to use db_update... rather than doing this directly,
633 * so that any Slot is handled correctly.
635 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
636 ua->error_msg(_("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
638 ua->info_msg(_("New InChanger flag is: %d\n"), mr.InChanger);
643 case 9: /* Volume Files */
645 ua->warning_msg(_("Warning changing Volume Files can result\n"
646 "in loss of data on your Volume\n\n"));
647 ua->info_msg(_("Current Volume Files is: %u\n"), mr.VolFiles);
648 if (!get_pint(ua, _("Enter new number of Files for Volume: "))) {
651 VolFiles = ua->pint32_val;
652 if (VolFiles != (int)(mr.VolFiles + 1)) {
653 ua->warning_msg(_("Normally, you should only increase Volume Files by one!\n"));
654 if (!get_yesno(ua, _("Continue? (yes/no): ")) || ua->pint32_val == 0) {
658 query = get_pool_memory(PM_MESSAGE);
659 Mmsg(query, "UPDATE Media SET VolFiles=%u WHERE MediaId=%s",
660 VolFiles, edit_int64(mr.MediaId, ed1));
661 if (!db_sql_query(ua->db, query, NULL, NULL)) {
662 ua->error_msg("%s", db_strerror(ua->db));
664 ua->info_msg(_("New Volume Files is: %u\n"), VolFiles);
666 free_pool_memory(query);
669 case 10: /* Volume's Pool */
670 memset(&pr, 0, sizeof(POOL_DBR));
671 pr.PoolId = mr.PoolId;
672 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
673 ua->error_msg("%s", db_strerror(ua->db));
676 ua->info_msg(_("Current Pool is: %s\n"), pr.Name);
677 if (!get_cmd(ua, _("Enter new Pool name: "))) {
680 update_vol_pool(ua, ua->cmd, &mr, &pr);
684 update_vol_from_pool(ua, &mr);
687 update_all_vols_from_pool(ua);
691 ua->info_msg(_("Current Enabled is: %d\n"), mr.Enabled);
692 if (!get_cmd(ua, _("Enter new Enabled: "))) {
695 if (strcasecmp(ua->cmd, "yes") == 0 || strcasecmp(ua->cmd, "true") == 0) {
697 } else if (strcasecmp(ua->cmd, "no") == 0 || strcasecmp(ua->cmd, "false") == 0) {
699 } else if (strcasecmp(ua->cmd, "archived") == 0) {
702 mr.Enabled = atoi(ua->cmd);
704 update_volenabled(ua, ua->cmd, &mr);
708 memset(&pr, 0, sizeof(POOL_DBR));
709 pr.PoolId = mr.RecyclePoolId;
710 if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
711 ua->info_msg(_("Current RecyclePool is: %s\n"), pr.Name);
713 ua->warning_msg(_("No current RecyclePool\n"));
715 if (!get_cmd(ua, _("Enter new RecyclePool name: "))) {
718 update_vol_recyclepool(ua, ua->cmd, &mr);
721 default: /* Done or error */
722 ua->info_msg(_("Selection terminated.\n"));
730 * Update pool record -- pull info from current POOL resource
732 static bool update_pool(UAContext *ua)
740 pool = get_pool_resource(ua);
745 memset(&pr, 0, sizeof(pr));
746 bstrncpy(pr.Name, pool->hdr.name, sizeof(pr.Name));
747 if (!get_pool_dbr(ua, &pr)) {
751 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE); /* update */
752 set_pooldbr_recyclepoolid(ua->jcr, ua->db, &pr, pool);
754 id = db_update_pool_record(ua->jcr, ua->db, &pr);
756 ua->error_msg(_("db_update_pool_record returned %d. ERR=%s\n"),
757 id, db_strerror(ua->db));
759 query = get_pool_memory(PM_MESSAGE);
760 Mmsg(query, list_pool, edit_int64(pr.PoolId, ed1));
761 db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST);
762 free_pool_memory(query);
763 ua->info_msg(_("Pool DB record updated from resource.\n"));
768 * Update a Job record -- allows you to change the
769 * date fields in a Job record. This helps when
770 * providing migration from other vendors.
772 static bool update_job(UAContext *ua)
777 NT_("StartTime"), /* 0 */
781 for (i=0; kw[i]; i++) {
783 if ((j=find_arg_with_value(ua, kw[i])) > 0) {