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);
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 */
65 if (!open_client_db(ua)) {
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 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);
329 /* Modify the RecyclePool of a Volume */
330 void update_vol_recyclepool(UAContext *ua, char *val, MEDIA_DBR *mr)
334 char ed1[50], ed2[50];
336 memset(&pr, 0, sizeof(pr));
337 bstrncpy(pr.Name, val, sizeof(pr.Name));
338 if (!get_pool_dbr(ua, &pr, NT_("recyclepool"))) {
341 /* pool = select_pool_resource(ua); */
342 mr->RecyclePoolId = pr.PoolId; /* get the PoolId */
344 query = get_pool_memory(PM_MESSAGE);
346 Mmsg(query, "UPDATE Media SET RecyclePoolId=%s WHERE MediaId=%s",
347 edit_int64(mr->RecyclePoolId, ed1),
348 edit_int64(mr->MediaId, ed2));
349 if (!db_sql_query(ua->db, query, NULL, NULL)) {
350 bsendmsg(ua, "%s", db_strerror(ua->db));
352 bsendmsg(ua, _("New RecyclePool is: %s\n"), pr.Name);
355 free_pool_memory(query);
359 * Refresh the Volume information from the Pool record
361 static void update_vol_from_pool(UAContext *ua, MEDIA_DBR *mr)
365 memset(&pr, 0, sizeof(pr));
366 pr.PoolId = mr->PoolId;
367 if (!db_get_pool_record(ua->jcr, ua->db, &pr) ||
368 !acl_access_ok(ua, Pool_ACL, pr.Name)) {
371 set_pool_dbr_defaults_in_media_dbr(mr, &pr);
372 if (!db_update_media_defaults(ua->jcr, ua->db, mr)) {
373 bsendmsg(ua, _("Error updating Volume record: ERR=%s"), db_strerror(ua->db));
375 bsendmsg(ua, _("Volume defaults updated from \"%s\" Pool record.\n"),
381 * Refresh the Volume information from the Pool record
384 static void update_all_vols_from_pool(UAContext *ua)
389 memset(&pr, 0, sizeof(pr));
390 memset(&mr, 0, sizeof(mr));
391 if (!get_pool_dbr(ua, &pr)) {
394 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
395 mr.PoolId = pr.PoolId;
396 if (!db_update_media_defaults(ua->jcr, ua->db, &mr)) {
397 bsendmsg(ua, _("Error updating Volume records: ERR=%s"), db_strerror(ua->db));
399 bsendmsg(ua, _("All Volume defaults updated from Pool record.\n"));
403 static void update_volenabled(UAContext *ua, char *val, MEDIA_DBR *mr)
405 mr->Enabled = get_enabled(ua, val);
406 if (mr->Enabled < 0) {
409 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
410 bsendmsg(ua, _("Error updating media record Enabled: ERR=%s"), db_strerror(ua->db));
412 bsendmsg(ua, _("New Enabled is: %d\n"), mr->Enabled);
419 * Update a media record -- allows you to change the
420 * Volume status. E.g. if you want Bacula to stop
421 * writing on the volume, set it to anything other
424 static int update_volume(UAContext *ua)
433 _("VolStatus"), /* 0 */
434 _("VolRetention"), /* 1 */
436 _("MaxVolJobs"), /* 3 */
437 _("MaxVolFiles"), /* 4 */
438 _("MaxVolBytes"), /* 5 */
439 _("Recycle"), /* 6 */
440 _("InChanger"), /* 7 */
443 _("FromPool"), /* 10 */
444 _("AllFromPool"), /* 11 !!! see below !!! */
445 _("Enabled"), /* 12 */
446 _("RecyclePool"), /* 13 */
449 #define AllFromPool 11 /* keep this updated with above */
451 for (i=0; kw[i]; i++) {
454 if ((j=find_arg_with_value(ua, kw[i])) > 0) {
455 /* If all from pool don't select a media record */
456 if (i != AllFromPool && !select_media_dbr(ua, &mr)) {
461 update_volstatus(ua, ua->argv[j], &mr);
464 update_volretention(ua, ua->argv[j], &mr);
467 update_voluseduration(ua, ua->argv[j], &mr);
470 update_volmaxjobs(ua, ua->argv[j], &mr);
473 update_volmaxfiles(ua, ua->argv[j], &mr);
476 update_volmaxbytes(ua, ua->argv[j], &mr);
479 update_volrecycle(ua, ua->argv[j], &mr);
482 update_volinchanger(ua, ua->argv[j], &mr);
485 update_volslot(ua, ua->argv[j], &mr);
488 memset(&pr, 0, sizeof(POOL_DBR));
489 pr.PoolId = mr.PoolId;
490 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
491 bsendmsg(ua, "%s", db_strerror(ua->db));
494 update_vol_pool(ua, ua->argv[j], &mr, &pr);
497 update_vol_from_pool(ua, &mr);
500 update_all_vols_from_pool(ua);
503 update_volenabled(ua, ua->argv[j], &mr);
506 update_vol_recyclepool(ua, ua->argv[j], &mr);
514 start_prompt(ua, _("Parameters to modify:\n"));
515 add_prompt(ua, _("Volume Status")); /* 0 */
516 add_prompt(ua, _("Volume Retention Period")); /* 1 */
517 add_prompt(ua, _("Volume Use Duration")); /* 2 */
518 add_prompt(ua, _("Maximum Volume Jobs")); /* 3 */
519 add_prompt(ua, _("Maximum Volume Files")); /* 4 */
520 add_prompt(ua, _("Maximum Volume Bytes")); /* 5 */
521 add_prompt(ua, _("Recycle Flag")); /* 6 */
522 add_prompt(ua, _("Slot")); /* 7 */
523 add_prompt(ua, _("InChanger Flag")); /* 8 */
524 add_prompt(ua, _("Volume Files")); /* 9 */
525 add_prompt(ua, _("Pool")); /* 10 */
526 add_prompt(ua, _("Volume from Pool")); /* 11 */
527 add_prompt(ua, _("All Volumes from Pool")); /* 12 */
528 add_prompt(ua, _("Enabled")), /* 13 */
529 add_prompt(ua, _("RecyclePool")), /* 14 */
530 add_prompt(ua, _("Done")); /* 15 */
531 i = do_prompt(ua, "", _("Select parameter to modify"), NULL, 0);
533 /* For All Volumes from Pool and Done, we don't need a Volume record */
534 if (i != 12 && i != 15) {
535 if (!select_media_dbr(ua, &mr)) { /* Get Volume record */
538 bsendmsg(ua, _("Updating Volume \"%s\"\n"), mr.VolumeName);
541 case 0: /* Volume Status */
542 /* Modify Volume Status */
543 bsendmsg(ua, _("Current Volume status is: %s\n"), mr.VolStatus);
544 start_prompt(ua, _("Possible Values are:\n"));
545 add_prompt(ua, NT_("Append"));
546 add_prompt(ua, NT_("Archive"));
547 add_prompt(ua, NT_("Disabled"));
548 add_prompt(ua, NT_("Full"));
549 add_prompt(ua, NT_("Used"));
550 add_prompt(ua, NT_("Cleaning"));
551 if (strcmp(mr.VolStatus, NT_("Purged")) == 0) {
552 add_prompt(ua, NT_("Recycle"));
554 add_prompt(ua, NT_("Read-Only"));
555 if (do_prompt(ua, "", _("Choose new Volume Status"), ua->cmd, sizeof(mr.VolStatus)) < 0) {
558 update_volstatus(ua, ua->cmd, &mr);
560 case 1: /* Retention */
561 bsendmsg(ua, _("Current retention period is: %s\n"),
562 edit_utime(mr.VolRetention, ed1, sizeof(ed1)));
563 if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
566 update_volretention(ua, ua->cmd, &mr);
569 case 2: /* Use Duration */
570 bsendmsg(ua, _("Current use duration is: %s\n"),
571 edit_utime(mr.VolUseDuration, ed1, sizeof(ed1)));
572 if (!get_cmd(ua, _("Enter Volume Use Duration: "))) {
575 update_voluseduration(ua, ua->cmd, &mr);
578 case 3: /* Max Jobs */
579 bsendmsg(ua, _("Current max jobs is: %u\n"), mr.MaxVolJobs);
580 if (!get_pint(ua, _("Enter new Maximum Jobs: "))) {
583 update_volmaxjobs(ua, ua->cmd, &mr);
586 case 4: /* Max Files */
587 bsendmsg(ua, _("Current max files is: %u\n"), mr.MaxVolFiles);
588 if (!get_pint(ua, _("Enter new Maximum Files: "))) {
591 update_volmaxfiles(ua, ua->cmd, &mr);
594 case 5: /* Max Bytes */
595 bsendmsg(ua, _("Current value is: %s\n"), edit_uint64(mr.MaxVolBytes, ed1));
596 if (!get_cmd(ua, _("Enter new Maximum Bytes: "))) {
599 update_volmaxbytes(ua, ua->cmd, &mr);
603 case 6: /* Recycle */
604 bsendmsg(ua, _("Current recycle flag is: %s\n"),
605 mr.Recycle==1?_("yes"):_("no"));
606 if (!get_yesno(ua, _("Enter new Recycle status: "))) {
609 update_volrecycle(ua, ua->cmd, &mr);
613 bsendmsg(ua, _("Current Slot is: %d\n"), mr.Slot);
614 if (!get_pint(ua, _("Enter new Slot: "))) {
617 update_volslot(ua, ua->cmd, &mr);
620 case 8: /* InChanger */
621 bsendmsg(ua, _("Current InChanger flag is: %d\n"), mr.InChanger);
622 if (!get_yesno(ua, _("Set InChanger flag? yes/no: "))) {
625 mr.InChanger = ua->pint32_val;
627 * Make sure to use db_update... rather than doing this directly,
628 * so that any Slot is handled correctly.
630 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
631 bsendmsg(ua, _("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
633 bsendmsg(ua, _("New InChanger flag is: %d\n"), mr.InChanger);
638 case 9: /* Volume Files */
640 bsendmsg(ua, _("Warning changing Volume Files can result\n"
641 "in loss of data on your Volume\n\n"));
642 bsendmsg(ua, _("Current Volume Files is: %u\n"), mr.VolFiles);
643 if (!get_pint(ua, _("Enter new number of Files for Volume: "))) {
646 VolFiles = ua->pint32_val;
647 if (VolFiles != (int)(mr.VolFiles + 1)) {
648 bsendmsg(ua, _("Normally, you should only increase Volume Files by one!\n"));
649 if (!get_yesno(ua, _("Continue? (yes/no): ")) || ua->pint32_val == 0) {
653 query = get_pool_memory(PM_MESSAGE);
654 Mmsg(query, "UPDATE Media SET VolFiles=%u WHERE MediaId=%s",
655 VolFiles, edit_int64(mr.MediaId, ed1));
656 if (!db_sql_query(ua->db, query, NULL, NULL)) {
657 bsendmsg(ua, "%s", db_strerror(ua->db));
659 bsendmsg(ua, _("New Volume Files is: %u\n"), VolFiles);
661 free_pool_memory(query);
664 case 10: /* Volume's Pool */
665 memset(&pr, 0, sizeof(POOL_DBR));
666 pr.PoolId = mr.PoolId;
667 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
668 bsendmsg(ua, "%s", db_strerror(ua->db));
671 bsendmsg(ua, _("Current Pool is: %s\n"), pr.Name);
672 if (!get_cmd(ua, _("Enter new Pool name: "))) {
675 update_vol_pool(ua, ua->cmd, &mr, &pr);
679 update_vol_from_pool(ua, &mr);
682 update_all_vols_from_pool(ua);
686 bsendmsg(ua, _("Current Enabled is: %d\n"), mr.Enabled);
687 if (!get_cmd(ua, _("Enter new Enabled: "))) {
690 if (strcasecmp(ua->cmd, "yes") == 0 || strcasecmp(ua->cmd, "true") == 0) {
692 } else if (strcasecmp(ua->cmd, "no") == 0 || strcasecmp(ua->cmd, "false") == 0) {
694 } else if (strcasecmp(ua->cmd, "archived") == 0) {
697 mr.Enabled = atoi(ua->cmd);
699 update_volenabled(ua, ua->cmd, &mr);
703 memset(&pr, 0, sizeof(POOL_DBR));
704 pr.PoolId = mr.RecyclePoolId;
705 if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
706 bsendmsg(ua, _("Current RecyclePool is: %s\n"), pr.Name);
708 bsendmsg(ua, _("No current RecyclePool\n"));
710 if (!get_cmd(ua, _("Enter new RecyclePool name: "))) {
713 update_vol_recyclepool(ua, ua->cmd, &mr);
716 default: /* Done or error */
717 bsendmsg(ua, _("Selection terminated.\n"));
725 * Update pool record -- pull info from current POOL resource
727 static bool update_pool(UAContext *ua)
735 pool = get_pool_resource(ua);
740 memset(&pr, 0, sizeof(pr));
741 bstrncpy(pr.Name, pool->hdr.name, sizeof(pr.Name));
742 if (!get_pool_dbr(ua, &pr)) {
746 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE); /* update */
747 set_pooldbr_recyclepoolid(ua->jcr, ua->db, &pr, pool);
749 id = db_update_pool_record(ua->jcr, ua->db, &pr);
751 bsendmsg(ua, _("db_update_pool_record returned %d. ERR=%s\n"),
752 id, db_strerror(ua->db));
754 query = get_pool_memory(PM_MESSAGE);
755 Mmsg(query, list_pool, edit_int64(pr.PoolId, ed1));
756 db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST);
757 free_pool_memory(query);
758 bsendmsg(ua, _("Pool DB record updated from resource.\n"));