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 and included
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, const char *pool_name)
394 memset(&pr, 0, sizeof(pr));
395 memset(&mr, 0, sizeof(mr));
397 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
398 if (!get_pool_dbr(ua, &pr)) {
401 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
402 mr.PoolId = pr.PoolId;
403 if (!db_update_media_defaults(ua->jcr, ua->db, &mr)) {
404 ua->error_msg(_("Error updating Volume records: ERR=%s"), db_strerror(ua->db));
406 ua->info_msg(_("All Volume defaults updated from \"%s\" Pool record.\n"),
411 static void update_volenabled(UAContext *ua, char *val, MEDIA_DBR *mr)
413 mr->Enabled = get_enabled(ua, val);
414 if (mr->Enabled < 0) {
417 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
418 ua->error_msg(_("Error updating media record Enabled: ERR=%s"), db_strerror(ua->db));
420 ua->info_msg(_("New Enabled is: %d\n"), mr->Enabled);
427 * Update a media record -- allows you to change the
428 * Volume status. E.g. if you want Bacula to stop
429 * writing on the volume, set it to anything other
432 static int update_volume(UAContext *ua)
442 NT_("VolStatus"), /* 0 */
443 NT_("VolRetention"), /* 1 */
444 NT_("VolUse"), /* 2 */
445 NT_("MaxVolJobs"), /* 3 */
446 NT_("MaxVolFiles"), /* 4 */
447 NT_("MaxVolBytes"), /* 5 */
448 NT_("Recycle"), /* 6 */
449 NT_("InChanger"), /* 7 */
452 NT_("FromPool"), /* 10 */
453 NT_("AllFromPool"), /* 11 !!! see below !!! */
454 NT_("Enabled"), /* 12 */
455 NT_("RecyclePool"), /* 13 */
458 #define AllFromPool 11 /* keep this updated with above */
460 for (i=0; kw[i]; i++) {
463 if ((j=find_arg_with_value(ua, kw[i])) > 0) {
464 /* If all from pool don't select a media record */
465 if (i != AllFromPool && !select_media_dbr(ua, &mr)) {
470 update_volstatus(ua, ua->argv[j], &mr);
473 update_volretention(ua, ua->argv[j], &mr);
476 update_voluseduration(ua, ua->argv[j], &mr);
479 update_volmaxjobs(ua, ua->argv[j], &mr);
482 update_volmaxfiles(ua, ua->argv[j], &mr);
485 update_volmaxbytes(ua, ua->argv[j], &mr);
488 update_volrecycle(ua, ua->argv[j], &mr);
491 update_volinchanger(ua, ua->argv[j], &mr);
494 update_volslot(ua, ua->argv[j], &mr);
497 memset(&pr, 0, sizeof(POOL_DBR));
498 pr.PoolId = mr.PoolId;
499 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
500 ua->error_msg("%s", db_strerror(ua->db));
503 update_vol_pool(ua, ua->argv[j], &mr, &pr);
506 update_vol_from_pool(ua, &mr);
509 update_all_vols_from_pool(ua, ua->argv[j]);
512 update_volenabled(ua, ua->argv[j], &mr);
515 update_vol_recyclepool(ua, ua->argv[j], &mr);
523 start_prompt(ua, _("Parameters to modify:\n"));
524 add_prompt(ua, _("Volume Status")); /* 0 */
525 add_prompt(ua, _("Volume Retention Period")); /* 1 */
526 add_prompt(ua, _("Volume Use Duration")); /* 2 */
527 add_prompt(ua, _("Maximum Volume Jobs")); /* 3 */
528 add_prompt(ua, _("Maximum Volume Files")); /* 4 */
529 add_prompt(ua, _("Maximum Volume Bytes")); /* 5 */
530 add_prompt(ua, _("Recycle Flag")); /* 6 */
531 add_prompt(ua, _("Slot")); /* 7 */
532 add_prompt(ua, _("InChanger Flag")); /* 8 */
533 add_prompt(ua, _("Volume Files")); /* 9 */
534 add_prompt(ua, _("Pool")); /* 10 */
535 add_prompt(ua, _("Volume from Pool")); /* 11 */
536 add_prompt(ua, _("All Volumes from Pool")); /* 12 */
537 add_prompt(ua, _("Enabled")), /* 13 */
538 add_prompt(ua, _("RecyclePool")), /* 14 */
539 add_prompt(ua, _("Done")); /* 15 */
540 i = do_prompt(ua, "", _("Select parameter to modify"), NULL, 0);
542 /* For All Volumes from Pool and Done, we don't need a Volume record */
543 if (i != 12 && i != 15) {
544 if (!select_media_dbr(ua, &mr)) { /* Get Volume record */
547 ua->info_msg(_("Updating Volume \"%s\"\n"), mr.VolumeName);
550 case 0: /* Volume Status */
551 /* Modify Volume Status */
552 ua->info_msg(_("Current Volume status is: %s\n"), mr.VolStatus);
553 start_prompt(ua, _("Possible Values are:\n"));
554 add_prompt(ua, NT_("Append"));
555 add_prompt(ua, NT_("Archive"));
556 add_prompt(ua, NT_("Disabled"));
557 add_prompt(ua, NT_("Full"));
558 add_prompt(ua, NT_("Used"));
559 add_prompt(ua, NT_("Cleaning"));
560 if (strcmp(mr.VolStatus, NT_("Purged")) == 0) {
561 add_prompt(ua, NT_("Recycle"));
563 add_prompt(ua, NT_("Read-Only"));
564 if (do_prompt(ua, "", _("Choose new Volume Status"), ua->cmd, sizeof(mr.VolStatus)) < 0) {
567 update_volstatus(ua, ua->cmd, &mr);
569 case 1: /* Retention */
570 ua->info_msg(_("Current retention period is: %s\n"),
571 edit_utime(mr.VolRetention, ed1, sizeof(ed1)));
572 if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
575 update_volretention(ua, ua->cmd, &mr);
578 case 2: /* Use Duration */
579 ua->info_msg(_("Current use duration is: %s\n"),
580 edit_utime(mr.VolUseDuration, ed1, sizeof(ed1)));
581 if (!get_cmd(ua, _("Enter Volume Use Duration: "))) {
584 update_voluseduration(ua, ua->cmd, &mr);
587 case 3: /* Max Jobs */
588 ua->info_msg(_("Current max jobs is: %u\n"), mr.MaxVolJobs);
589 if (!get_pint(ua, _("Enter new Maximum Jobs: "))) {
592 update_volmaxjobs(ua, ua->cmd, &mr);
595 case 4: /* Max Files */
596 ua->info_msg(_("Current max files is: %u\n"), mr.MaxVolFiles);
597 if (!get_pint(ua, _("Enter new Maximum Files: "))) {
600 update_volmaxfiles(ua, ua->cmd, &mr);
603 case 5: /* Max Bytes */
604 ua->info_msg(_("Current value is: %s\n"), edit_uint64(mr.MaxVolBytes, ed1));
605 if (!get_cmd(ua, _("Enter new Maximum Bytes: "))) {
608 update_volmaxbytes(ua, ua->cmd, &mr);
612 case 6: /* Recycle */
613 ua->info_msg(_("Current recycle flag is: %s\n"),
614 mr.Recycle==1?_("yes"):_("no"));
615 if (!get_yesno(ua, _("Enter new Recycle status: "))) {
618 update_volrecycle(ua, ua->cmd, &mr);
622 ua->info_msg(_("Current Slot is: %d\n"), mr.Slot);
623 if (!get_pint(ua, _("Enter new Slot: "))) {
626 update_volslot(ua, ua->cmd, &mr);
629 case 8: /* InChanger */
630 ua->info_msg(_("Current InChanger flag is: %d\n"), mr.InChanger);
631 if (!get_yesno(ua, _("Set InChanger flag? yes/no: "))) {
634 mr.InChanger = ua->pint32_val;
636 * Make sure to use db_update... rather than doing this directly,
637 * so that any Slot is handled correctly.
639 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
640 ua->error_msg(_("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
642 ua->info_msg(_("New InChanger flag is: %d\n"), mr.InChanger);
647 case 9: /* Volume Files */
649 ua->warning_msg(_("Warning changing Volume Files can result\n"
650 "in loss of data on your Volume\n\n"));
651 ua->info_msg(_("Current Volume Files is: %u\n"), mr.VolFiles);
652 if (!get_pint(ua, _("Enter new number of Files for Volume: "))) {
655 VolFiles = ua->pint32_val;
656 if (VolFiles != (int)(mr.VolFiles + 1)) {
657 ua->warning_msg(_("Normally, you should only increase Volume Files by one!\n"));
658 if (!get_yesno(ua, _("Continue? (yes/no): ")) || ua->pint32_val == 0) {
662 query = get_pool_memory(PM_MESSAGE);
663 Mmsg(query, "UPDATE Media SET VolFiles=%u WHERE MediaId=%s",
664 VolFiles, edit_int64(mr.MediaId, ed1));
665 if (!db_sql_query(ua->db, query, NULL, NULL)) {
666 ua->error_msg("%s", db_strerror(ua->db));
668 ua->info_msg(_("New Volume Files is: %u\n"), VolFiles);
670 free_pool_memory(query);
673 case 10: /* Volume's Pool */
674 memset(&pr, 0, sizeof(POOL_DBR));
675 pr.PoolId = mr.PoolId;
676 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
677 ua->error_msg("%s", db_strerror(ua->db));
680 ua->info_msg(_("Current Pool is: %s\n"), pr.Name);
681 if (!get_cmd(ua, _("Enter new Pool name: "))) {
684 update_vol_pool(ua, ua->cmd, &mr, &pr);
688 update_vol_from_pool(ua, &mr);
691 pool = select_pool_resource(ua);
693 update_all_vols_from_pool(ua, pool->name());
698 ua->info_msg(_("Current Enabled is: %d\n"), mr.Enabled);
699 if (!get_cmd(ua, _("Enter new Enabled: "))) {
702 if (strcasecmp(ua->cmd, "yes") == 0 || strcasecmp(ua->cmd, "true") == 0) {
704 } else if (strcasecmp(ua->cmd, "no") == 0 || strcasecmp(ua->cmd, "false") == 0) {
706 } else if (strcasecmp(ua->cmd, "archived") == 0) {
709 mr.Enabled = atoi(ua->cmd);
711 update_volenabled(ua, ua->cmd, &mr);
715 memset(&pr, 0, sizeof(POOL_DBR));
716 pr.PoolId = mr.RecyclePoolId;
717 if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
718 ua->info_msg(_("Current RecyclePool is: %s\n"), pr.Name);
720 ua->warning_msg(_("No current RecyclePool\n"));
722 if (!get_cmd(ua, _("Enter new RecyclePool name: "))) {
725 update_vol_recyclepool(ua, ua->cmd, &mr);
728 default: /* Done or error */
729 ua->info_msg(_("Selection terminated.\n"));
737 * Update pool record -- pull info from current POOL resource
739 static bool update_pool(UAContext *ua)
747 pool = get_pool_resource(ua);
752 memset(&pr, 0, sizeof(pr));
753 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
754 if (!get_pool_dbr(ua, &pr)) {
758 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE); /* update */
759 set_pooldbr_recyclepoolid(ua->jcr, ua->db, &pr, pool);
761 id = db_update_pool_record(ua->jcr, ua->db, &pr);
763 ua->error_msg(_("db_update_pool_record returned %d. ERR=%s\n"),
764 id, db_strerror(ua->db));
766 query = get_pool_memory(PM_MESSAGE);
767 Mmsg(query, list_pool, edit_int64(pr.PoolId, ed1));
768 db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST);
769 free_pool_memory(query);
770 ua->info_msg(_("Pool DB record updated from resource.\n"));
775 * Update a Job record -- allows you to change the
776 * date fields in a Job record. This helps when
777 * providing migration from other vendors.
779 static bool update_job(UAContext *ua)
782 char ed1[50], ed2[50];
783 POOL_MEM cmd(PM_MESSAGE);
787 char *client_name = NULL;
788 char *start_time = NULL;
790 NT_("starttime"), /* 0 */
791 NT_("client"), /* 1 */
794 Dmsg1(200, "cmd=%s\n", ua->cmd);
795 i = find_arg_with_value(ua, NT_("jobid"));
797 ua->error_msg(_("Expect JobId keyword, not found.\n"));
800 memset(&jr, 0, sizeof(jr));
801 memset(&cr, 0, sizeof(cr));
802 jr.JobId = str_to_int64(ua->argv[i]);
803 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
804 ua->error_msg("%s", db_strerror(ua->db));
808 for (i=0; kw[i]; i++) {
810 if ((j=find_arg_with_value(ua, kw[i])) >= 0) {
812 case 0: /* start time */
813 start_time = ua->argv[j];
815 case 1: /* Client name */
816 client_name = ua->argv[j];
821 if (!client_name && !start_time) {
822 ua->error_msg(_("Neither Client nor StartTime specified.\n"));
826 if (!get_client_dbr(ua, &cr)) {
829 jr.ClientId = cr.ClientId;
834 StartTime = str_to_utime(start_time);
835 if (StartTime == 0) {
836 ua->error_msg(_("Improper date format: %s\n"), ua->argv[i]);
839 delta_start = StartTime - jr.StartTime;
840 Dmsg3(200, "ST=%d jr.ST=%d delta=%d\n", (time_t)StartTime,
841 (time_t)jr.StartTime, (time_t)delta_start);
842 jr.StartTime = (time_t)StartTime;
843 jr.SchedTime += (time_t)delta_start;
844 jr.EndTime += (time_t)delta_start;
845 jr.JobTDate += delta_start;
846 /* Convert to DB times */
847 bstrutime(jr.cStartTime, sizeof(jr.cStartTime), jr.StartTime);
848 bstrutime(jr.cSchedTime, sizeof(jr.cSchedTime), jr.SchedTime);
849 bstrutime(jr.cEndTime, sizeof(jr.cEndTime), jr.EndTime);
851 Mmsg(cmd, "UPDATE Job SET ClientId=%s,StartTime='%s',SchedTime='%s',"
852 "EndTime='%s',JobTDate=%s WHERE JobId=%s",
853 edit_int64(jr.ClientId, ed1),
857 edit_uint64(jr.JobTDate, ed1),
858 edit_int64(jr.JobId, ed2));
859 if (!db_sql_query(ua->db, cmd.c_str(), NULL, NULL)) {
860 ua->error_msg("%s", db_strerror(ua->db));