1 /* BAREOS® - Backup Archiving REcovery Open Sourced
2
3 Copyright (C) 2001-2012 Free Software Foundation Europe e.V.
4 Copyright (C) 2011-2016 Planets Communications B.V.
5 Copyright (C) 2013-2019 Bareos GmbH & Co. KG
6
7 This program is Free Software; you can redistribute it and/or
8 modify it under the terms of version three of the GNU Affero General Public
9 License as published by the Free Software Foundation and included
10 in the file LICENSE.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.
21 */
22 /*
23 * Kern Sibbald, December MMI
24 */
25 /**
26 * @file
27 * BAREOS Director -- Run Command
28 */
29 #include "include/bareos.h"
30 #include "dird.h"
31 #include "dird/jcr_private.h"
32 #include "dird/job.h"
33 #include "dird/migration.h"
34 #include "dird/storage.h"
35 #include "dird/ua_db.h"
36 #include "dird/ua_input.h"
37 #include "dird/ua_select.h"
38 #include "dird/ua_run.h"
39 #include "lib/breg.h"
40 #include "lib/berrno.h"
41 #include "lib/edit.h"
42 #include "lib/keyword_table_s.h"
43
44 namespace directordaemon {
45
46 /* Forward referenced subroutines */
47 static void SelectJobLevel(UaContext* ua, JobControlRecord* jcr);
48 static bool DisplayJobParameters(UaContext* ua,
49 JobControlRecord* jcr,
50 RunContext& rc);
51 static void SelectWhereRegexp(UaContext* ua, JobControlRecord* jcr);
52 static bool ScanCommandLineArguments(UaContext* ua, RunContext& rc);
53 static bool ResetRestoreContext(UaContext* ua,
54 JobControlRecord* jcr,
55 RunContext& rc);
56 static int ModifyJobParameters(UaContext* ua,
57 JobControlRecord* jcr,
58 RunContext& rc);
59
60 /* Imported variables */
61 extern struct s_kw ReplaceOptions[];
62
63 /**
64 * Rerun a job by jobid. Lookup the job data and rerun the job with that data.
65 *
66 * Returns: false on error
67 * true if OK
68 */
reRunJob(UaContext * ua,JobId_t JobId,bool yes,utime_t now)69 static inline bool reRunJob(UaContext* ua, JobId_t JobId, bool yes, utime_t now)
70 {
71 JobDbRecord jr;
72 char dt[MAX_TIME_LENGTH];
73 PoolMem cmdline(PM_MESSAGE);
74
75 jr.JobId = JobId;
76 ua->SendMsg("rerunning jobid %d\n", jr.JobId);
77 if (!ua->db->GetJobRecord(ua->jcr, &jr)) {
78 Jmsg(ua->jcr, M_WARNING, 0,
79 _("Error getting Job record for Job rerun: ERR=%s"),
80 ua->db->strerror());
81 goto bail_out;
82 }
83
84 /*
85 * Only perform rerun on JobTypes where it makes sense.
86 */
87 switch (jr.JobType) {
88 case JT_BACKUP:
89 case JT_COPY:
90 case JT_MIGRATE:
91 break;
92 default:
93 return true;
94 }
95
96 if (jr.JobLevel == L_NONE) {
97 Mmsg(cmdline, "run job=\"%s\"", jr.Name);
98 } else {
99 Mmsg(cmdline, "run job=\"%s\" level=\"%s\"", jr.Name,
100 JobLevelToString(jr.JobLevel));
101 }
102 PmStrcpy(ua->cmd, cmdline);
103
104 if (jr.ClientId) {
105 ClientDbRecord cr;
106
107 cr.ClientId = jr.ClientId;
108 if (!ua->db->GetClientRecord(ua->jcr, &cr)) {
109 Jmsg(ua->jcr, M_WARNING, 0,
110 _("Error getting Client record for Job rerun: ERR=%s"),
111 ua->db->strerror());
112 goto bail_out;
113 }
114 Mmsg(cmdline, " client=\"%s\"", cr.Name);
115 PmStrcat(ua->cmd, cmdline);
116 }
117
118 if (jr.PoolId) {
119 PoolDbRecord pr;
120
121 pr.PoolId = jr.PoolId;
122 if (!ua->db->GetPoolRecord(ua->jcr, &pr)) {
123 Jmsg(ua->jcr, M_WARNING, 0,
124 _("Error getting Pool record for Job rerun: ERR=%s"),
125 ua->db->strerror());
126 goto bail_out;
127 }
128
129 /*
130 * Source pool.
131 */
132 switch (jr.JobType) {
133 case JT_COPY:
134 case JT_MIGRATE: {
135 JobResource* job = NULL;
136
137 job = ua->GetJobResWithName(jr.Name, false);
138 if (job) {
139 Mmsg(cmdline, " pool=\"%s\"", job->pool->resource_name_);
140 PmStrcat(ua->cmd, cmdline);
141 }
142 break;
143 }
144 case JT_BACKUP:
145 switch (jr.JobLevel) {
146 case L_VIRTUAL_FULL: {
147 JobResource* job = NULL;
148
149 job = ua->GetJobResWithName(jr.Name, false);
150 if (job) {
151 Mmsg(cmdline, " pool=\"%s\"", job->pool->resource_name_);
152 PmStrcat(ua->cmd, cmdline);
153 }
154 break;
155 }
156 default:
157 Mmsg(cmdline, " pool=\"%s\"", pr.Name);
158 PmStrcat(ua->cmd, cmdline);
159 break;
160 }
161 }
162
163 /*
164 * Next pool.
165 */
166 switch (jr.JobType) {
167 case JT_COPY:
168 case JT_MIGRATE:
169 Mmsg(cmdline, " nextpool=\"%s\"", pr.Name);
170 PmStrcat(ua->cmd, cmdline);
171 break;
172 case JT_BACKUP:
173 switch (jr.JobLevel) {
174 case L_VIRTUAL_FULL:
175 Mmsg(cmdline, " nextpool=\"%s\"", pr.Name);
176 PmStrcat(ua->cmd, cmdline);
177
178 break;
179 default:
180 break;
181 }
182 break;
183 }
184 }
185
186 if (jr.FileSetId) {
187 FileSetDbRecord fs;
188
189 fs.FileSetId = jr.FileSetId;
190 if (!ua->db->GetFilesetRecord(ua->jcr, &fs)) {
191 Jmsg(ua->jcr, M_WARNING, 0,
192 _("Error getting FileSet record for Job rerun: ERR=%s"),
193 ua->db->strerror());
194 goto bail_out;
195 }
196 Mmsg(cmdline, " fileset=\"%s\"", fs.FileSet);
197 PmStrcat(ua->cmd, cmdline);
198 }
199
200 bstrutime(dt, sizeof(dt), now);
201 Mmsg(cmdline, " when=\"%s\"", dt);
202 PmStrcat(ua->cmd, cmdline);
203
204 if (yes) { PmStrcat(ua->cmd, " yes"); }
205
206 Dmsg1(100, "rerun cmdline=%s\n", ua->cmd);
207
208 ParseUaArgs(ua);
209 return RunCmd(ua, ua->cmd);
210
211 bail_out:
212 return false;
213 }
214
215 /**
216 * Rerun a job selection.
217 *
218 * Returns: 0 on error
219 * 1 if OK
220 */
reRunCmd(UaContext * ua,const char * cmd)221 bool reRunCmd(UaContext* ua, const char* cmd)
222 {
223 int i, j, d, h, s, u;
224 int days = 0;
225 int hours = 0;
226 int since_jobid = 0;
227 int until_jobid = 0;
228 JobId_t JobId;
229 dbid_list ids;
230 PoolMem query(PM_MESSAGE);
231 utime_t now;
232 time_t schedtime;
233 char dt[MAX_TIME_LENGTH];
234 char ed1[50];
235 char ed2[50];
236 bool yes = false; /* Was "yes" given on cmdline*/
237 bool timeframe = false; /* Should the selection happen based on timeframe? */
238 bool since_jobid_given = false; /* Was since_jobid given? */
239 bool until_jobid_given = false; /* Was until_jobid given? */
240 const int secs_in_day = 86400;
241 const int secs_in_hour = 3600;
242
243 if (!OpenClientDb(ua)) { return true; }
244
245 now = (utime_t)time(NULL);
246
247 /*
248 * Determine what cmdline arguments are given.
249 */
250 j = FindArgWithValue(ua, NT_("jobid"));
251 d = FindArgWithValue(ua, NT_("days"));
252 h = FindArgWithValue(ua, NT_("hours"));
253 s = FindArgWithValue(ua, NT_("since_jobid"));
254 u = FindArgWithValue(ua, NT_("until_jobid"));
255
256 if (s > 0) {
257 since_jobid = str_to_int64(ua->argv[s]);
258 since_jobid_given = true;
259 }
260
261 if (u > 0) {
262 until_jobid = str_to_int64(ua->argv[u]);
263 until_jobid_given = true;
264 }
265
266 if (d > 0 || h > 0) { timeframe = true; }
267
268 if (FindArg(ua, NT_("yes")) > 0) { yes = true; }
269
270 if (j < 0 && !timeframe && !since_jobid_given) {
271 ua->SendMsg("Please specify jobid, since_jobid, hours or days\n");
272 goto bail_out;
273 }
274
275 if (j >= 0 && since_jobid_given) {
276 ua->SendMsg(
277 "Please specify either jobid or since_jobid (and optionally "
278 "until_jobid)\n");
279 goto bail_out;
280 }
281
282 if (j >= 0 && timeframe) {
283 ua->SendMsg("Please specify either jobid or timeframe\n");
284 goto bail_out;
285 }
286
287 if (timeframe || since_jobid_given) {
288 schedtime = now;
289 if (d > 0) {
290 days = str_to_int64(ua->argv[d]);
291 schedtime = now - secs_in_day * days; /* Days in the past */
292 }
293 if (h > 0) {
294 hours = str_to_int64(ua->argv[h]);
295 schedtime = now - secs_in_hour * hours; /* Hours in the past */
296 }
297
298 /*
299 * Job Query Start
300 */
301 bstrutime(dt, sizeof(dt), schedtime);
302
303 if (since_jobid_given) {
304 if (until_jobid_given) {
305 Mmsg(query,
306 "SELECT JobId FROM Job WHERE JobStatus = 'f' AND JobId >= %s AND "
307 "JobId <= %s ORDER BY JobId",
308 edit_int64(since_jobid, ed1), edit_int64(until_jobid, ed2));
309 } else {
310 Mmsg(query,
311 "SELECT JobId FROM Job WHERE JobStatus = 'f' AND JobId >= %s "
312 "ORDER BY JobId",
313 edit_int64(since_jobid, ed1));
314 }
315
316 } else {
317 Mmsg(query,
318 "SELECT JobId FROM Job WHERE JobStatus = 'f' AND SchedTime > '%s' "
319 "ORDER BY JobId",
320 dt);
321 }
322
323 ua->db->GetQueryDbids(ua->jcr, query, ids);
324
325 ua->SendMsg("The following ids were selected for rerun:\n");
326 for (i = 0; i < ids.num_ids; i++) {
327 if (i > 0) {
328 ua->SendMsg(",%d", ids.DBId[i]);
329 } else {
330 ua->SendMsg("%d", ids.DBId[i]);
331 }
332 }
333 ua->SendMsg("\n");
334
335 if (!yes && (!GetYesno(ua, _("rerun these jobids? (yes/no): ")) ||
336 !ua->pint32_val)) {
337 goto bail_out;
338 }
339 /*
340 * Job Query End
341 */
342
343 /*
344 * Loop over all selected JobIds.
345 */
346 for (i = 0; i < ids.num_ids; i++) {
347 JobId = ids.DBId[i];
348 if (!reRunJob(ua, JobId, yes, now)) { goto bail_out; }
349 }
350 } else {
351 JobId = str_to_int64(ua->argv[j]);
352 if (!reRunJob(ua, JobId, yes, now)) { goto bail_out; }
353 }
354
355 return true;
356
357 bail_out:
358 return false;
359 }
360
361 /**
362 * For Backup and Verify Jobs
363 * run [job=]<job-name> level=<level-name>
364 *
365 * For Restore Jobs
366 * run <job-name>
367 *
368 * Returns: 0 on error
369 * JobId if OK
370 *
371 */
DoRunCmd(UaContext * ua,const char * cmd)372 int DoRunCmd(UaContext* ua, const char* cmd)
373 {
374 JobControlRecord* jcr = NULL;
375 RunContext rc;
376 int status, length;
377 bool valid_response;
378 bool do_pool_overrides = true;
379
380 if (!OpenClientDb(ua)) { return 0; }
381
382 if (!ScanCommandLineArguments(ua, rc)) { return 0; }
383
384 if (FindArg(ua, NT_("fdcalled")) > 0) {
385 jcr->file_bsock = ua->UA_sock->clone();
386 ua->quit = true;
387 }
388
389 /*
390 * Create JobControlRecord to run job. NOTE!!! after this point, FreeJcr()
391 * before returning.
392 */
393 if (!jcr) {
394 jcr = NewDirectorJcr();
395 SetJcrDefaults(jcr, rc.job);
396 jcr->impl->unlink_bsr =
397 ua->jcr->impl->unlink_bsr; /* copy unlink flag from caller */
398 ua->jcr->impl->unlink_bsr = false;
399 }
400
401 /*
402 * Transfer JobIds to new restore Job
403 */
404 if (ua->jcr->JobIds) {
405 jcr->JobIds = ua->jcr->JobIds;
406 ua->jcr->JobIds = NULL;
407 }
408
409 /*
410 * Transfer selected restore tree to new restore Job
411 */
412 if (ua->jcr->impl->restore_tree_root) {
413 jcr->impl->restore_tree_root = ua->jcr->impl->restore_tree_root;
414 ua->jcr->impl->restore_tree_root = NULL;
415 }
416
417 try_again:
418 if (!ResetRestoreContext(ua, jcr, rc)) { goto bail_out; }
419
420 /*
421 * Run without prompting?
422 */
423 if (ua->batch || FindArg(ua, NT_("yes")) > 0) { goto start_job; }
424
425 /*
426 * When doing interactive runs perform the pool level overrides
427 * early this way the user doesn't get nasty surprisses when
428 * a level override changes the pool the data will be saved to
429 * later. We only want to do these overrides once so we use
430 * a tracking boolean do_pool_overrides to see if we still
431 * need to do this (e.g. we pass by here multiple times when
432 * the user interactivly changes options.
433 */
434 if (do_pool_overrides) {
435 switch (jcr->getJobType()) {
436 case JT_BACKUP:
437 if (!jcr->is_JobLevel(L_VIRTUAL_FULL)) { ApplyPoolOverrides(jcr); }
438 break;
439 default:
440 break;
441 }
442 do_pool_overrides = false;
443 }
444
445 /*
446 * Prompt User to see if all run job parameters are correct, and
447 * allow him to modify them.
448 */
449 if (!DisplayJobParameters(ua, jcr, rc)) { goto bail_out; }
450
451 /*
452 * Prompt User until we have a valid response.
453 */
454 do {
455 if (!GetCmd(ua, _("OK to run? (yes/mod/no): "))) { goto bail_out; }
456
457 /*
458 * Empty line equals yes, anything other we compare
459 * the cmdline for the length of the given input unless
460 * its mod or .mod where we compare only the keyword
461 * and a space as it can be followed by a full cmdline
462 * with new cmdline arguments that need to be parsed.
463 */
464 valid_response = false;
465 length = strlen(ua->cmd);
466 if (ua->cmd[0] == 0 || bstrncasecmp(ua->cmd, ".mod ", MIN(length, 5)) ||
467 bstrncasecmp(ua->cmd, "mod ", MIN(length, 4)) ||
468 bstrncasecmp(ua->cmd, NT_("yes"), length) ||
469 bstrncasecmp(ua->cmd, _("yes"), length) ||
470 bstrncasecmp(ua->cmd, NT_("no"), length) ||
471 bstrncasecmp(ua->cmd, _("no"), length)) {
472 valid_response = true;
473 }
474
475 if (!valid_response) {
476 ua->WarningMsg(_("Illegal response %s\n"), ua->cmd);
477 }
478 } while (!valid_response);
479
480 /*
481 * See if the .mod or mod has arguments.
482 */
483 if (bstrncasecmp(ua->cmd, ".mod ", 5) ||
484 (bstrncasecmp(ua->cmd, "mod ", 4) && strlen(ua->cmd) > 6)) {
485 ParseUaArgs(ua);
486 rc.mod = true;
487 if (!ScanCommandLineArguments(ua, rc)) { return 0; }
488 goto try_again;
489 }
490
491 /*
492 * Allow the user to modify the settings
493 */
494 status = ModifyJobParameters(ua, jcr, rc);
495 switch (status) {
496 case 0:
497 goto try_again;
498 case 1:
499 break;
500 case -1:
501 goto bail_out;
502 }
503
504 /*
505 * For interactive runs we set IgnoreLevelPoolOverrides as we already
506 * performed the actual overrrides.
507 */
508 jcr->impl->IgnoreLevelPoolOverides = true;
509
510 if (ua->cmd[0] == 0 || bstrncasecmp(ua->cmd, NT_("yes"), strlen(ua->cmd)) ||
511 bstrncasecmp(ua->cmd, _("yes"), strlen(ua->cmd))) {
512 JobId_t JobId;
513 Dmsg1(800, "Calling RunJob job=%x\n", jcr->impl->res.job);
514
515 start_job:
516 Dmsg3(100, "JobId=%u using pool %s priority=%d\n", (int)jcr->JobId,
517 jcr->impl->res.pool->resource_name_, jcr->JobPriority);
518 Dmsg1(900, "Running a job; its spool_data = %d\n", jcr->impl->spool_data);
519
520 JobId = RunJob(jcr);
521
522 Dmsg4(100, "JobId=%u NewJobId=%d using pool %s priority=%d\n",
523 (int)jcr->JobId, JobId, jcr->impl->res.pool->resource_name_,
524 jcr->JobPriority);
525
526 FreeJcr(jcr); /* release jcr */
527
528 if (JobId == 0) {
529 ua->ErrorMsg(_("Job failed.\n"));
530 } else {
531 char ed1[50];
532 ua->send->ObjectStart("run");
533 ua->send->ObjectKeyValue("jobid", edit_int64(JobId, ed1),
534 _("Job queued. JobId=%s\n"));
535 ua->send->ObjectEnd("run");
536 }
537
538 return JobId;
539 }
540
541 bail_out:
542 ua->SendMsg(_("Job not run.\n"));
543 FreeJcr(jcr);
544
545 return 0; /* do not run */
546 }
547
RunCmd(UaContext * ua,const char * cmd)548 bool RunCmd(UaContext* ua, const char* cmd)
549 {
550 return (DoRunCmd(ua, ua->cmd) != 0);
551 }
552
ModifyJobParameters(UaContext * ua,JobControlRecord * jcr,RunContext & rc)553 int ModifyJobParameters(UaContext* ua, JobControlRecord* jcr, RunContext& rc)
554 {
555 int opt;
556
557 /*
558 * At user request modify parameters of job to be run.
559 */
560 if (ua->cmd[0] != 0 && bstrncasecmp(ua->cmd, _("mod"), strlen(ua->cmd))) {
561 StartPrompt(ua, _("Parameters to modify:\n"));
562
563 AddPrompt(ua, _("Level")); /* 0 */
564 AddPrompt(ua, _("Storage")); /* 1 */
565 AddPrompt(ua, _("Job")); /* 2 */
566 AddPrompt(ua, _("FileSet")); /* 3 */
567 if (jcr->is_JobType(JT_RESTORE)) {
568 AddPrompt(ua, _("Restore Client")); /* 4 */
569 } else {
570 AddPrompt(ua, _("Client")); /* 4 */
571 }
572 AddPrompt(ua, _("Backup Format")); /* 5 */
573 AddPrompt(ua, _("When")); /* 6 */
574 AddPrompt(ua, _("Priority")); /* 7 */
575 if (jcr->is_JobType(JT_BACKUP) || jcr->is_JobType(JT_COPY) ||
576 jcr->is_JobType(JT_MIGRATE) || jcr->is_JobType(JT_VERIFY)) {
577 AddPrompt(ua, _("Pool")); /* 8 */
578 if (jcr->is_JobType(JT_MIGRATE) || jcr->is_JobType(JT_COPY) ||
579 (jcr->is_JobType(JT_BACKUP) &&
580 jcr->is_JobLevel(L_VIRTUAL_FULL))) { /* NextPool */
581 AddPrompt(ua, _("NextPool")); /* 9 */
582 if (jcr->is_JobType(JT_BACKUP)) {
583 AddPrompt(ua, _("Plugin Options")); /* 10 */
584 }
585 } else if (jcr->is_JobType(JT_VERIFY)) {
586 AddPrompt(ua, _("Verify Job")); /* 9 */
587 } else if (jcr->is_JobType(JT_BACKUP)) {
588 AddPrompt(ua, _("Plugin Options")); /* 9 */
589 }
590 } else if (jcr->is_JobType(JT_RESTORE)) {
591 AddPrompt(ua, _("Bootstrap")); /* 8 */
592 AddPrompt(ua, _("Where")); /* 9 */
593 AddPrompt(ua, _("File Relocation")); /* 10 */
594 AddPrompt(ua, _("Replace")); /* 11 */
595 AddPrompt(ua, _("JobId")); /* 12 */
596 AddPrompt(ua, _("Plugin Options")); /* 13 */
597 }
598
599 switch (DoPrompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
600 case 0:
601 /* Level */
602 SelectJobLevel(ua, jcr);
603 switch (jcr->getJobType()) {
604 case JT_BACKUP:
605 if (!rc.pool_override && !jcr->is_JobLevel(L_VIRTUAL_FULL)) {
606 ApplyPoolOverrides(jcr, true);
607 rc.pool = jcr->impl->res.pool;
608 rc.level_override = true;
609 }
610 break;
611 default:
612 break;
613 }
614 goto try_again;
615 case 1:
616 /* Storage */
617 rc.store->store = select_storage_resource(ua);
618 if (rc.store->store) {
619 PmStrcpy(rc.store->store_source, _("user selection"));
620 SetRwstorage(jcr, rc.store);
621 goto try_again;
622 }
623 break;
624 case 2:
625 /* Job */
626 rc.job = select_job_resource(ua);
627 if (rc.job) {
628 jcr->impl->res.job = rc.job;
629 SetJcrDefaults(jcr, rc.job);
630 goto try_again;
631 }
632 break;
633 case 3:
634 /* FileSet */
635 rc.fileset = select_fileset_resource(ua);
636 if (rc.fileset) {
637 jcr->impl->res.fileset = rc.fileset;
638 goto try_again;
639 }
640 break;
641 case 4:
642 /* Client */
643 rc.client = select_client_resource(ua);
644 if (rc.client) {
645 jcr->impl->res.client = rc.client;
646 goto try_again;
647 }
648 break;
649 case 5:
650 /* Backup Format */
651 if (GetCmd(ua, _("Please enter Backup Format: "))) {
652 if (jcr->impl->backup_format) {
653 free(jcr->impl->backup_format);
654 jcr->impl->backup_format = NULL;
655 }
656 jcr->impl->backup_format = strdup(ua->cmd);
657 goto try_again;
658 }
659 break;
660 case 6:
661 /* When */
662 if (GetCmd(ua, _("Please enter desired start time as YYYY-MM-DD "
663 "HH:MM:SS (return for now): "))) {
664 if (ua->cmd[0] == 0) {
665 jcr->sched_time = time(NULL);
666 } else {
667 jcr->sched_time = StrToUtime(ua->cmd);
668 if (jcr->sched_time == 0) {
669 ua->SendMsg(_("Invalid time, using current time.\n"));
670 jcr->sched_time = time(NULL);
671 }
672 }
673 goto try_again;
674 }
675 break;
676 case 7:
677 /* Priority */
678 if (GetPint(ua, _("Enter new Priority: "))) {
679 if (!ua->pint32_val) {
680 ua->SendMsg(_("Priority must be a positive integer.\n"));
681 } else {
682 jcr->JobPriority = ua->pint32_val;
683 }
684 goto try_again;
685 }
686 break;
687 case 8:
688 /* Pool or Bootstrap depending on JobType */
689 if (jcr->is_JobType(JT_BACKUP) || jcr->is_JobType(JT_COPY) ||
690 jcr->is_JobType(JT_MIGRATE) ||
691 jcr->is_JobType(JT_VERIFY)) { /* Pool */
692 rc.pool = select_pool_resource(ua);
693 if (rc.pool) {
694 jcr->impl->res.pool = rc.pool;
695 rc.level_override = false;
696 rc.pool_override = true;
697 Dmsg1(100, "Set new pool=%s\n",
698 jcr->impl->res.pool->resource_name_);
699 goto try_again;
700 }
701 } else {
702 /* Bootstrap */
703 if (GetCmd(ua, _("Please enter the Bootstrap file name: "))) {
704 if (jcr->RestoreBootstrap) {
705 free(jcr->RestoreBootstrap);
706 jcr->RestoreBootstrap = NULL;
707 }
708 if (ua->cmd[0] != 0) {
709 FILE* fd;
710
711 jcr->RestoreBootstrap = strdup(ua->cmd);
712 fd = fopen(jcr->RestoreBootstrap, "rb");
713 if (!fd) {
714 BErrNo be;
715 ua->SendMsg(_("Warning cannot open %s: ERR=%s\n"),
716 jcr->RestoreBootstrap, be.bstrerror());
717 free(jcr->RestoreBootstrap);
718 jcr->RestoreBootstrap = NULL;
719 } else {
720 fclose(fd);
721 }
722 }
723 goto try_again;
724 }
725 }
726 break;
727 case 9:
728 /* NextPool/Verify Job/Where/Plugin Options depending on JobType */
729 if (jcr->is_JobType(JT_MIGRATE) || jcr->is_JobType(JT_COPY) ||
730 (jcr->is_JobType(JT_BACKUP) &&
731 jcr->is_JobLevel(L_VIRTUAL_FULL))) { /* NextPool */
732 rc.next_pool = select_pool_resource(ua);
733 if (rc.next_pool) {
734 jcr->impl->res.next_pool = rc.next_pool;
735 Dmsg1(100, "Set new next_pool=%s\n",
736 jcr->impl->res.next_pool->resource_name_);
737 goto try_again;
738 }
739 } else if (jcr->is_JobType(JT_VERIFY)) { /* Verify Job */
740 rc.verify_job = select_job_resource(ua);
741 if (rc.verify_job) { jcr->impl->res.verify_job = rc.verify_job; }
742 goto try_again;
743 } else if (jcr->is_JobType(JT_RESTORE)) { /* Where */
744 if (GetCmd(ua, _("Please enter the full path prefix for restore (/ "
745 "for none): "))) {
746 if (jcr->RegexWhere) { /* cannot use regexwhere and where */
747 free(jcr->RegexWhere);
748 jcr->RegexWhere = NULL;
749 }
750 if (jcr->where) {
751 free(jcr->where);
752 jcr->where = NULL;
753 }
754 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
755 ua->cmd[0] = 0;
756 }
757 jcr->where = strdup(ua->cmd);
758 goto try_again;
759 }
760 } else { /* Plugin Options */
761 if (GetCmd(ua, _("Please enter Plugin Options string: "))) {
762 if (jcr->impl->plugin_options) {
763 free(jcr->impl->plugin_options);
764 jcr->impl->plugin_options = NULL;
765 }
766 jcr->impl->plugin_options = strdup(ua->cmd);
767 goto try_again;
768 }
769 }
770 break;
771 case 10:
772 /* File relocation/Plugin Options depending on JobType */
773 if (jcr->is_JobType(JT_RESTORE)) {
774 SelectWhereRegexp(ua, jcr);
775 goto try_again;
776 } else if (jcr->is_JobType(JT_BACKUP)) {
777 if (GetCmd(ua, _("Please enter Plugin Options string: "))) {
778 if (jcr->impl->plugin_options) {
779 free(jcr->impl->plugin_options);
780 jcr->impl->plugin_options = NULL;
781 }
782 jcr->impl->plugin_options = strdup(ua->cmd);
783 goto try_again;
784 }
785 }
786 break;
787 case 11:
788 /* Replace */
789 StartPrompt(ua, _("Replace:\n"));
790 for (int i = 0; ReplaceOptions[i].name; i++) {
791 AddPrompt(ua, ReplaceOptions[i].name);
792 }
793 opt = DoPrompt(ua, "", _("Select replace option"), NULL, 0);
794 if (opt >= 0) {
795 rc.replace = ReplaceOptions[opt].name;
796 jcr->impl->replace = ReplaceOptions[opt].token;
797 }
798 goto try_again;
799 case 12:
800 /* JobId */
801 rc.jid = NULL; /* force reprompt */
802 jcr->impl->RestoreJobId = 0;
803 if (jcr->RestoreBootstrap) {
804 ua->SendMsg(
805 _("You must set the bootstrap file to NULL to be able to specify "
806 "a JobId.\n"));
807 }
808 goto try_again;
809 case 13:
810 /* Plugin Options */
811 if (GetCmd(ua, _("Please enter Plugin Options string: "))) {
812 if (jcr->impl->plugin_options) {
813 free(jcr->impl->plugin_options);
814 jcr->impl->plugin_options = NULL;
815 }
816 jcr->impl->plugin_options = strdup(ua->cmd);
817 goto try_again;
818 }
819 break;
820 case -1: /* error or cancel */
821 goto bail_out;
822 default:
823 goto try_again;
824 }
825 goto bail_out;
826 }
827 return 1;
828
829 bail_out:
830 return -1;
831
832 try_again:
833 return 0;
834 }
835
836 /**
837 * Reset the restore context.
838 * This subroutine can be called multiple times, so it must keep any prior
839 * settings.
840 */
ResetRestoreContext(UaContext * ua,JobControlRecord * jcr,RunContext & rc)841 static bool ResetRestoreContext(UaContext* ua,
842 JobControlRecord* jcr,
843 RunContext& rc)
844 {
845 jcr->impl->res.verify_job = rc.verify_job;
846 jcr->impl->res.previous_job = rc.previous_job;
847 jcr->impl->res.pool = rc.pool;
848 jcr->impl->res.next_pool = rc.next_pool;
849
850 /*
851 * See if an explicit pool override was performed.
852 * If so set the pool_source to command line and
853 * set the IgnoreLevelPoolOverides so any level Pool
854 * overrides are ignored.
855 */
856 if (rc.pool_name) {
857 PmStrcpy(jcr->impl->res.pool_source, _("command line"));
858 jcr->impl->IgnoreLevelPoolOverides = true;
859 } else if (!rc.level_override &&
860 jcr->impl->res.pool != jcr->impl->res.job->pool) {
861 PmStrcpy(jcr->impl->res.pool_source, _("user input"));
862 }
863 SetRwstorage(jcr, rc.store);
864
865 if (rc.next_pool_name) {
866 PmStrcpy(jcr->impl->res.npool_source, _("command line"));
867 jcr->impl->res.run_next_pool_override = true;
868 } else if (jcr->impl->res.next_pool != jcr->impl->res.pool->NextPool) {
869 PmStrcpy(jcr->impl->res.npool_source, _("user input"));
870 jcr->impl->res.run_next_pool_override = true;
871 }
872
873 jcr->impl->res.client = rc.client;
874 if (jcr->impl->res.client) {
875 PmStrcpy(jcr->client_name, rc.client->resource_name_);
876 }
877 jcr->impl->res.fileset = rc.fileset;
878 jcr->impl->ExpectedFiles = rc.files;
879
880 if (rc.catalog) {
881 jcr->impl->res.catalog = rc.catalog;
882 PmStrcpy(jcr->impl->res.catalog_source, _("user input"));
883 }
884
885 PmStrcpy(jcr->comment, rc.comment);
886
887 if (rc.where) {
888 if (jcr->where) { free(jcr->where); }
889 jcr->where = strdup(rc.where);
890 rc.where = NULL;
891 }
892
893 if (rc.regexwhere) {
894 if (jcr->RegexWhere) { free(jcr->RegexWhere); }
895 jcr->RegexWhere = strdup(rc.regexwhere);
896 rc.regexwhere = NULL;
897 }
898
899 if (rc.when) {
900 jcr->sched_time = StrToUtime(rc.when);
901 if (jcr->sched_time == 0) {
902 ua->SendMsg(_("Invalid time, using current time.\n"));
903 jcr->sched_time = time(NULL);
904 }
905 rc.when = NULL;
906 }
907
908 if (rc.bootstrap) {
909 if (jcr->RestoreBootstrap) { free(jcr->RestoreBootstrap); }
910 jcr->RestoreBootstrap = strdup(rc.bootstrap);
911 rc.bootstrap = NULL;
912 }
913
914 if (rc.plugin_options) {
915 if (jcr->impl->plugin_options) { free(jcr->impl->plugin_options); }
916 jcr->impl->plugin_options = strdup(rc.plugin_options);
917 rc.plugin_options = NULL;
918 }
919
920 if (rc.replace) {
921 jcr->impl->replace = 0;
922 for (int i = 0; ReplaceOptions[i].name; i++) {
923 if (Bstrcasecmp(rc.replace, ReplaceOptions[i].name)) {
924 jcr->impl->replace = ReplaceOptions[i].token;
925 }
926 }
927 if (!jcr->impl->replace) {
928 ua->SendMsg(_("Invalid replace option: %s\n"), rc.replace);
929 return false;
930 }
931 } else if (rc.job->replace) {
932 jcr->impl->replace = rc.job->replace;
933 } else {
934 jcr->impl->replace = REPLACE_ALWAYS;
935 }
936 rc.replace = NULL;
937
938 if (rc.Priority) {
939 jcr->JobPriority = rc.Priority;
940 rc.Priority = 0;
941 }
942
943 if (rc.since) {
944 if (!jcr->stime) { jcr->stime = GetPoolMemory(PM_MESSAGE); }
945 PmStrcpy(jcr->stime, rc.since);
946 rc.since = NULL;
947 }
948
949 if (rc.cloned) {
950 jcr->impl->cloned = rc.cloned;
951 rc.cloned = false;
952 }
953
954 /*
955 * If pool changed, update migration write storage
956 */
957 if (jcr->is_JobType(JT_MIGRATE) || jcr->is_JobType(JT_COPY) ||
958 (jcr->is_JobType(JT_BACKUP) && jcr->is_JobLevel(L_VIRTUAL_FULL))) {
959 if (!SetMigrationWstorage(jcr, rc.pool, rc.next_pool,
960 _("Storage from Run NextPool override"))) {
961 return false;
962 }
963 }
964 rc.replace = ReplaceOptions[0].name;
965 for (int i = 0; ReplaceOptions[i].name; i++) {
966 if (ReplaceOptions[i].token == jcr->impl->replace) {
967 rc.replace = ReplaceOptions[i].name;
968 }
969 }
970
971 if (rc.level_name) {
972 if (!GetLevelFromName(jcr, rc.level_name)) {
973 ua->SendMsg(_("Level \"%s\" not valid.\n"), rc.level_name);
974 return false;
975 }
976 rc.level_name = NULL;
977 }
978
979 if (rc.jid) {
980 if (jcr->is_JobType(JT_BACKUP) && jcr->is_JobLevel(L_VIRTUAL_FULL)) {
981 if (!jcr->impl->vf_jobids) {
982 jcr->impl->vf_jobids = GetPoolMemory(PM_MESSAGE);
983 }
984 PmStrcpy(jcr->impl->vf_jobids, rc.jid);
985 } else {
986 /*
987 * Note, this is also MigrateJobId and a VerifyJobId
988 */
989 jcr->impl->RestoreJobId = str_to_int64(rc.jid);
990 }
991 rc.jid = NULL;
992 }
993
994 if (rc.backup_format) {
995 if (jcr->impl->backup_format) { free(jcr->impl->backup_format); }
996 jcr->impl->backup_format = strdup(rc.backup_format);
997 rc.backup_format = NULL;
998 }
999
1000 /*
1001 * Some options are not available through the menu
1002 * TODO: Add an advanced menu?
1003 */
1004 if (rc.spool_data_set) { jcr->impl->spool_data = rc.spool_data; }
1005
1006 if (rc.accurate_set) { jcr->accurate = rc.accurate; }
1007
1008 /*
1009 * Used by migration jobs that can have the same name,
1010 * but can run at the same time
1011 */
1012 if (rc.ignoreduplicatecheck_set) {
1013 jcr->impl->IgnoreDuplicateJobChecking = rc.ignoreduplicatecheck;
1014 }
1015
1016 return true;
1017 }
1018
SelectWhereRegexp(UaContext * ua,JobControlRecord * jcr)1019 static void SelectWhereRegexp(UaContext* ua, JobControlRecord* jcr)
1020 {
1021 alist* regs;
1022 char *strip_prefix, *add_prefix, *add_suffix, *rwhere;
1023 strip_prefix = add_suffix = rwhere = add_prefix = NULL;
1024
1025 try_again_reg:
1026 ua->SendMsg(_("strip_prefix=%s add_prefix=%s add_suffix=%s\n"),
1027 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix));
1028
1029 StartPrompt(ua, _("This will replace your current Where value\n"));
1030 AddPrompt(ua, _("Strip prefix")); /* 0 */
1031 AddPrompt(ua, _("Add prefix")); /* 1 */
1032 AddPrompt(ua, _("Add file suffix")); /* 2 */
1033 AddPrompt(ua, _("Enter a regexp")); /* 3 */
1034 AddPrompt(ua, _("Test filename manipulation")); /* 4 */
1035 AddPrompt(ua, _("Use this ?")); /* 5 */
1036
1037 switch (DoPrompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
1038 case 0:
1039 /* Strip prefix */
1040 if (GetCmd(ua, _("Please enter the path prefix to strip: "))) {
1041 if (strip_prefix) free(strip_prefix);
1042 strip_prefix = strdup(ua->cmd);
1043 }
1044 goto try_again_reg;
1045 case 1:
1046 /* Add prefix */
1047 if (GetCmd(ua, _("Please enter the path prefix to add (/ for none): "))) {
1048 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
1049 ua->cmd[0] = 0;
1050 }
1051
1052 if (add_prefix) free(add_prefix);
1053 add_prefix = strdup(ua->cmd);
1054 }
1055 goto try_again_reg;
1056 case 2:
1057 /* Add suffix */
1058 if (GetCmd(ua, _("Please enter the file suffix to add: "))) {
1059 if (add_suffix) free(add_suffix);
1060 add_suffix = strdup(ua->cmd);
1061 }
1062 goto try_again_reg;
1063 case 3:
1064 /* Add rwhere */
1065 if (GetCmd(ua, _("Please enter a valid regexp (!from!to!): "))) {
1066 if (rwhere) free(rwhere);
1067 rwhere = strdup(ua->cmd);
1068 }
1069 goto try_again_reg;
1070 case 4:
1071 /* Test regexp */
1072 char* result;
1073 char* regexp;
1074
1075 if (rwhere && rwhere[0] != '\0') {
1076 regs = get_bregexps(rwhere);
1077 ua->SendMsg(_("regexwhere=%s\n"), NPRT(rwhere));
1078 } else {
1079 int len =
1080 BregexpGetBuildWhereSize(strip_prefix, add_prefix, add_suffix);
1081 regexp = (char*)malloc(len * sizeof(char));
1082 bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix);
1083 regs = get_bregexps(regexp);
1084 ua->SendMsg(
1085 _("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"),
1086 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix),
1087 NPRT(regexp));
1088
1089 free(regexp);
1090 }
1091
1092 if (!regs) {
1093 ua->SendMsg(_("Cannot use your regexp\n"));
1094 goto try_again_reg;
1095 }
1096 ua->SendMsg(_("Enter a period (.) to stop this test\n"));
1097 while (GetCmd(ua, _("Please enter filename to test: "))) {
1098 ApplyBregexps(ua->cmd, regs, &result);
1099 ua->SendMsg(_("%s -> %s\n"), ua->cmd, result);
1100 }
1101 FreeBregexps(regs);
1102 delete regs;
1103 goto try_again_reg;
1104 case 5:
1105 /* OK */
1106 break;
1107 case -1: /* error or cancel */
1108 goto bail_out_reg;
1109 default:
1110 goto try_again_reg;
1111 }
1112
1113 /* replace the existing where */
1114 if (jcr->where) {
1115 free(jcr->where);
1116 jcr->where = NULL;
1117 }
1118
1119 /* replace the existing regexwhere */
1120 if (jcr->RegexWhere) {
1121 free(jcr->RegexWhere);
1122 jcr->RegexWhere = NULL;
1123 }
1124
1125 if (rwhere) {
1126 jcr->RegexWhere = strdup(rwhere);
1127 } else if (strip_prefix || add_prefix || add_suffix) {
1128 int len = BregexpGetBuildWhereSize(strip_prefix, add_prefix, add_suffix);
1129 jcr->RegexWhere = (char*)malloc(len * sizeof(char));
1130 bregexp_build_where(jcr->RegexWhere, len, strip_prefix, add_prefix,
1131 add_suffix);
1132 }
1133
1134 regs = get_bregexps(jcr->RegexWhere);
1135 if (regs) {
1136 FreeBregexps(regs);
1137 delete regs;
1138 } else {
1139 if (jcr->RegexWhere) {
1140 free(jcr->RegexWhere);
1141 jcr->RegexWhere = NULL;
1142 }
1143 ua->SendMsg(_("Cannot use your regexp.\n"));
1144 }
1145
1146 bail_out_reg:
1147 if (strip_prefix) { free(strip_prefix); }
1148 if (add_prefix) { free(add_prefix); }
1149 if (add_suffix) { free(add_suffix); }
1150 if (rwhere) { free(rwhere); }
1151 }
1152
SelectJobLevel(UaContext * ua,JobControlRecord * jcr)1153 static void SelectJobLevel(UaContext* ua, JobControlRecord* jcr)
1154 {
1155 if (jcr->is_JobType(JT_BACKUP)) {
1156 StartPrompt(ua, _("Levels:\n"));
1157 // AddPrompt(ua, _("Base"));
1158 AddPrompt(ua, _("Full"));
1159 AddPrompt(ua, _("Incremental"));
1160 AddPrompt(ua, _("Differential"));
1161 AddPrompt(ua, _("Since"));
1162 AddPrompt(ua, _("VirtualFull"));
1163 switch (DoPrompt(ua, "", _("Select level"), NULL, 0)) {
1164 // case 0:
1165 // jcr->JobLevel = L_BASE;
1166 // break;
1167 case 0:
1168 jcr->setJobLevel(L_FULL);
1169 break;
1170 case 1:
1171 jcr->setJobLevel(L_INCREMENTAL);
1172 break;
1173 case 2:
1174 jcr->setJobLevel(L_DIFFERENTIAL);
1175 break;
1176 case 3:
1177 jcr->setJobLevel(L_SINCE);
1178 break;
1179 case 4:
1180 jcr->setJobLevel(L_VIRTUAL_FULL);
1181 break;
1182 default:
1183 break;
1184 }
1185 } else if (jcr->is_JobType(JT_VERIFY)) {
1186 StartPrompt(ua, _("Levels:\n"));
1187 AddPrompt(ua, _("Initialize Catalog"));
1188 AddPrompt(ua, _("Verify Catalog"));
1189 AddPrompt(ua, _("Verify Volume to Catalog"));
1190 AddPrompt(ua, _("Verify Disk to Catalog"));
1191 AddPrompt(ua, _("Verify Volume Data (not yet implemented)"));
1192 switch (DoPrompt(ua, "", _("Select level"), NULL, 0)) {
1193 case 0:
1194 jcr->setJobLevel(L_VERIFY_INIT);
1195 break;
1196 case 1:
1197 jcr->setJobLevel(L_VERIFY_CATALOG);
1198 break;
1199 case 2:
1200 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
1201 break;
1202 case 3:
1203 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
1204 break;
1205 case 4:
1206 jcr->setJobLevel(L_VERIFY_DATA);
1207 break;
1208 default:
1209 break;
1210 }
1211 } else {
1212 ua->WarningMsg(
1213 _("Level not appropriate for this Job. Cannot be changed.\n"));
1214 }
1215 return;
1216 }
1217
DisplayJobParameters(UaContext * ua,JobControlRecord * jcr,RunContext & rc)1218 static bool DisplayJobParameters(UaContext* ua,
1219 JobControlRecord* jcr,
1220 RunContext& rc)
1221 {
1222 char ec1[30];
1223 JobResource* job = rc.job;
1224 char dt[MAX_TIME_LENGTH];
1225 const char* verify_list = rc.verify_list;
1226
1227 Dmsg1(800, "JobType=%c\n", jcr->getJobType());
1228 switch (jcr->getJobType()) {
1229 case JT_ADMIN:
1230 if (ua->api) {
1231 ua->signal(BNET_RUN_CMD);
1232 ua->SendMsg(
1233 "Type: Admin\n"
1234 "Title: Run Admin Job\n"
1235 "JobName: %s\n"
1236 "FileSet: %s\n"
1237 "Client: %s\n"
1238 "Storage: %s\n"
1239 "When: %s\n"
1240 "Priority: %d\n",
1241 job->resource_name_, jcr->impl->res.fileset->resource_name_,
1242 NPRT(jcr->impl->res.client->resource_name_),
1243 jcr->impl->res.write_storage
1244 ? jcr->impl->res.write_storage->resource_name_
1245 : _("*None*"),
1246 bstrutime(dt, sizeof(dt), jcr->sched_time), jcr->JobPriority);
1247 } else {
1248 ua->SendMsg(
1249 _("Run Admin Job\n"
1250 "JobName: %s\n"
1251 "FileSet: %s\n"
1252 "Client: %s\n"
1253 "Storage: %s\n"
1254 "When: %s\n"
1255 "Priority: %d\n"),
1256 job->resource_name_, jcr->impl->res.fileset->resource_name_,
1257 NPRT(jcr->impl->res.client->resource_name_),
1258 jcr->impl->res.write_storage
1259 ? jcr->impl->res.write_storage->resource_name_
1260 : _("*None*"),
1261 bstrutime(dt, sizeof(dt), jcr->sched_time), jcr->JobPriority);
1262 }
1263 jcr->setJobLevel(L_FULL);
1264 break;
1265 case JT_ARCHIVE:
1266 if (ua->api) {
1267 ua->signal(BNET_RUN_CMD);
1268 ua->SendMsg(
1269 "Type: Archive\n"
1270 "Title: Run Archive Job\n"
1271 "JobName: %s\n"
1272 "FileSet: %s\n"
1273 "Client: %s\n"
1274 "Storage: %s\n"
1275 "When: %s\n"
1276 "Priority: %d\n",
1277 job->resource_name_, jcr->impl->res.fileset->resource_name_,
1278 NPRT(jcr->impl->res.client->resource_name_),
1279 jcr->impl->res.write_storage
1280 ? jcr->impl->res.write_storage->resource_name_
1281 : _("*None*"),
1282 bstrutime(dt, sizeof(dt), jcr->sched_time), jcr->JobPriority);
1283 } else {
1284 ua->SendMsg(
1285 _("Run Archive Job\n"
1286 "JobName: %s\n"
1287 "FileSet: %s\n"
1288 "Client: %s\n"
1289 "Storage: %s\n"
1290 "When: %s\n"
1291 "Priority: %d\n"),
1292 job->resource_name_, jcr->impl->res.fileset->resource_name_,
1293 NPRT(jcr->impl->res.client->resource_name_),
1294 jcr->impl->res.write_storage
1295 ? jcr->impl->res.write_storage->resource_name_
1296 : _("*None*"),
1297 bstrutime(dt, sizeof(dt), jcr->sched_time), jcr->JobPriority);
1298 }
1299 jcr->setJobLevel(L_FULL);
1300 break;
1301 case JT_CONSOLIDATE:
1302 if (ua->api) {
1303 ua->signal(BNET_RUN_CMD);
1304 ua->SendMsg(
1305 "Type: Consolidate\n"
1306 "Title: Run Consolidate Job\n"
1307 "JobName: %s\n"
1308 "FileSet: %s\n"
1309 "Client: %s\n"
1310 "Storage: %s\n"
1311 "When: %s\n"
1312 "Priority: %d\n",
1313 job->resource_name_, jcr->impl->res.fileset->resource_name_,
1314 NPRT(jcr->impl->res.client->resource_name_),
1315 jcr->impl->res.write_storage
1316 ? jcr->impl->res.write_storage->resource_name_
1317 : _("*None*"),
1318 bstrutime(dt, sizeof(dt), jcr->sched_time), jcr->JobPriority);
1319 } else {
1320 ua->SendMsg(
1321 _("Run Consolidate Job\n"
1322 "JobName: %s\n"
1323 "FileSet: %s\n"
1324 "Client: %s\n"
1325 "Storage: %s\n"
1326 "When: %s\n"
1327 "Priority: %d\n"),
1328 job->resource_name_, jcr->impl->res.fileset->resource_name_,
1329 NPRT(jcr->impl->res.client->resource_name_),
1330 jcr->impl->res.write_storage
1331 ? jcr->impl->res.write_storage->resource_name_
1332 : _("*None*"),
1333 bstrutime(dt, sizeof(dt), jcr->sched_time), jcr->JobPriority);
1334 }
1335 jcr->setJobLevel(L_FULL);
1336 break;
1337 case JT_BACKUP:
1338 case JT_VERIFY:
1339 if (jcr->is_JobType(JT_BACKUP)) {
1340 bool is_virtual = jcr->is_JobLevel(L_VIRTUAL_FULL);
1341
1342 if (ua->api) {
1343 ua->signal(BNET_RUN_CMD);
1344 ua->SendMsg(
1345 "Type: Backup\n"
1346 "Title: Run Backup Job\n"
1347 "JobName: %s\n"
1348 "Level: %s\n"
1349 "Client: %s\n"
1350 "Format: %s\n"
1351 "FileSet: %s\n"
1352 "Pool: %s\n"
1353 "%s%s%s"
1354 "Storage: %s\n"
1355 "When: %s\n"
1356 "Priority: %d\n"
1357 "%s%s%s",
1358 job->resource_name_, JobLevelToString(jcr->getJobLevel()),
1359 jcr->impl->res.client->resource_name_, jcr->impl->backup_format,
1360 jcr->impl->res.fileset->resource_name_,
1361 NPRT(jcr->impl->res.pool->resource_name_),
1362 is_virtual ? "NextPool: " : "",
1363 is_virtual ? (jcr->impl->res.next_pool
1364 ? jcr->impl->res.next_pool->resource_name_
1365 : _("*None*"))
1366 : "",
1367 is_virtual ? "\n" : "",
1368 jcr->impl->res.write_storage
1369 ? jcr->impl->res.write_storage->resource_name_
1370 : _("*None*"),
1371 bstrutime(dt, sizeof(dt), jcr->sched_time), jcr->JobPriority,
1372 jcr->impl->plugin_options ? "Plugin Options: " : "",
1373 jcr->impl->plugin_options ? jcr->impl->plugin_options : "",
1374 jcr->impl->plugin_options ? "\n" : "");
1375 } else {
1376 ua->SendMsg(
1377 _("Run Backup job\n"
1378 "JobName: %s\n"
1379 "Level: %s\n"
1380 "Client: %s\n"
1381 "Format: %s\n"
1382 "FileSet: %s\n"
1383 "Pool: %s (From %s)\n"
1384 "%s%s%s%s%s"
1385 "Storage: %s (From %s)\n"
1386 "When: %s\n"
1387 "Priority: %d\n"
1388 "%s%s%s"),
1389 job->resource_name_, JobLevelToString(jcr->getJobLevel()),
1390 jcr->impl->res.client->resource_name_, jcr->impl->backup_format,
1391 jcr->impl->res.fileset->resource_name_,
1392 NPRT(jcr->impl->res.pool->resource_name_),
1393 jcr->impl->res.pool_source, is_virtual ? "NextPool: " : "",
1394 is_virtual ? (jcr->impl->res.next_pool
1395 ? jcr->impl->res.next_pool->resource_name_
1396 : _("*None*"))
1397 : "",
1398 is_virtual ? " (From " : "",
1399 is_virtual ? jcr->impl->res.npool_source : "",
1400 is_virtual ? ")\n" : "",
1401 jcr->impl->res.write_storage
1402 ? jcr->impl->res.write_storage->resource_name_
1403 : _("*None*"),
1404 jcr->impl->res.wstore_source,
1405 bstrutime(dt, sizeof(dt), jcr->sched_time), jcr->JobPriority,
1406 jcr->impl->plugin_options ? "Plugin Options: " : "",
1407 jcr->impl->plugin_options ? jcr->impl->plugin_options : "",
1408 jcr->impl->plugin_options ? "\n" : "");
1409 }
1410 } else { /* JT_VERIFY */
1411 JobDbRecord jr;
1412 const char* Name;
1413 if (jcr->impl->res.verify_job) {
1414 Name = jcr->impl->res.verify_job->resource_name_;
1415 } else if (jcr->impl
1416 ->RestoreJobId) { /* Display job name if jobid requested
1417 */
1418 jr.JobId = jcr->impl->RestoreJobId;
1419 if (!ua->db->GetJobRecord(jcr, &jr)) {
1420 ua->ErrorMsg(
1421 _("Could not get job record for selected JobId. ERR=%s"),
1422 ua->db->strerror());
1423 return false;
1424 }
1425 Name = jr.Job;
1426 } else {
1427 Name = "";
1428 }
1429 if (!verify_list) { verify_list = job->WriteVerifyList; }
1430 if (!verify_list) { verify_list = ""; }
1431 if (ua->api) {
1432 ua->signal(BNET_RUN_CMD);
1433 ua->SendMsg(
1434 "Type: Verify\n"
1435 "Title: Run Verify Job\n"
1436 "JobName: %s\n"
1437 "Level: %s\n"
1438 "Client: %s\n"
1439 "FileSet: %s\n"
1440 "Pool: %s (From %s)\n"
1441 "Storage: %s (From %s)\n"
1442 "Verify Job: %s\n"
1443 "Verify List: %s\n"
1444 "When: %s\n"
1445 "Priority: %d\n",
1446 job->resource_name_, JobLevelToString(jcr->getJobLevel()),
1447 jcr->impl->res.client->resource_name_,
1448 jcr->impl->res.fileset->resource_name_,
1449 NPRT(jcr->impl->res.pool->resource_name_),
1450 jcr->impl->res.pool_source,
1451 jcr->impl->res.read_storage->resource_name_,
1452 jcr->impl->res.rstore_source, Name, verify_list,
1453 bstrutime(dt, sizeof(dt), jcr->sched_time), jcr->JobPriority);
1454 } else {
1455 ua->SendMsg(_("Run Verify Job\n"
1456 "JobName: %s\n"
1457 "Level: %s\n"
1458 "Client: %s\n"
1459 "FileSet: %s\n"
1460 "Pool: %s (From %s)\n"
1461 "Storage: %s (From %s)\n"
1462 "Verify Job: %s\n"
1463 "Verify List: %s\n"
1464 "When: %s\n"
1465 "Priority: %d\n"),
1466 job->resource_name_, JobLevelToString(jcr->getJobLevel()),
1467 jcr->impl->res.client->resource_name_,
1468 jcr->impl->res.fileset->resource_name_,
1469 NPRT(jcr->impl->res.pool->resource_name_),
1470 jcr->impl->res.pool_source,
1471 jcr->impl->res.read_storage->resource_name_,
1472 jcr->impl->res.rstore_source, Name, verify_list,
1473 bstrutime(dt, sizeof(dt), jcr->sched_time),
1474 jcr->JobPriority);
1475 }
1476 }
1477 break;
1478 case JT_RESTORE:
1479 if (jcr->impl->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
1480 if (rc.jid) {
1481 jcr->impl->RestoreJobId = str_to_int64(rc.jid);
1482 } else {
1483 if (!GetPint(ua, _("Please enter a JobId for restore: "))) {
1484 return false;
1485 }
1486 jcr->impl->RestoreJobId = ua->int64_val;
1487 }
1488 }
1489 jcr->setJobLevel(L_FULL); /* default level */
1490 Dmsg1(800, "JobId to restore=%d\n", jcr->impl->RestoreJobId);
1491 if (jcr->impl->RestoreJobId == 0) {
1492 /* RegexWhere is take before RestoreWhere */
1493 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
1494 if (ua->api) {
1495 ua->signal(BNET_RUN_CMD);
1496 ua->SendMsg(
1497 "Type: Restore\n"
1498 "Title: Run Restore Job\n"
1499 "JobName: %s\n"
1500 "Bootstrap: %s\n"
1501 "RegexWhere: %s\n"
1502 "Replace: %s\n"
1503 "FileSet: %s\n"
1504 "Backup Client: %s\n"
1505 "Restore Client: %s\n"
1506 "Format: %s\n"
1507 "Storage: %s\n"
1508 "When: %s\n"
1509 "Catalog: %s\n"
1510 "Priority: %d\n"
1511 "Plugin Options: %s\n",
1512 job->resource_name_, NPRT(jcr->RestoreBootstrap),
1513 jcr->RegexWhere ? jcr->RegexWhere : job->RegexWhere, rc.replace,
1514 jcr->impl->res.fileset->resource_name_, rc.client_name,
1515 jcr->impl->res.client->resource_name_,
1516 jcr->impl->backup_format,
1517 jcr->impl->res.read_storage->resource_name_,
1518 bstrutime(dt, sizeof(dt), jcr->sched_time),
1519 jcr->impl->res.catalog->resource_name_, jcr->JobPriority,
1520 NPRT(jcr->impl->plugin_options));
1521 } else {
1522 ua->SendMsg(_("Run Restore job\n"
1523 "JobName: %s\n"
1524 "Bootstrap: %s\n"
1525 "RegexWhere: %s\n"
1526 "Replace: %s\n"
1527 "FileSet: %s\n"
1528 "Backup Client: %s\n"
1529 "Restore Client: %s\n"
1530 "Format: %s\n"
1531 "Storage: %s\n"
1532 "When: %s\n"
1533 "Catalog: %s\n"
1534 "Priority: %d\n"
1535 "Plugin Options: %s\n"),
1536 job->resource_name_, NPRT(jcr->RestoreBootstrap),
1537 jcr->RegexWhere ? jcr->RegexWhere : job->RegexWhere,
1538 rc.replace, jcr->impl->res.fileset->resource_name_,
1539 rc.client_name, jcr->impl->res.client->resource_name_,
1540 jcr->impl->backup_format,
1541 jcr->impl->res.read_storage->resource_name_,
1542 bstrutime(dt, sizeof(dt), jcr->sched_time),
1543 jcr->impl->res.catalog->resource_name_,
1544 jcr->JobPriority, NPRT(jcr->impl->plugin_options));
1545 }
1546 } else {
1547 if (ua->api) {
1548 ua->signal(BNET_RUN_CMD);
1549 ua->SendMsg(
1550 "Type: Restore\n"
1551 "Title: Run Restore job\n"
1552 "JobName: %s\n"
1553 "Bootstrap: %s\n"
1554 "Where: %s\n"
1555 "Replace: %s\n"
1556 "FileSet: %s\n"
1557 "Backup Client: %s\n"
1558 "Restore Client: %s\n"
1559 "Format: %s\n"
1560 "Storage: %s\n"
1561 "When: %s\n"
1562 "Catalog: %s\n"
1563 "Priority: %d\n"
1564 "Plugin Options: %s\n",
1565 job->resource_name_, NPRT(jcr->RestoreBootstrap),
1566 jcr->where ? jcr->where : NPRT(job->RestoreWhere), rc.replace,
1567 jcr->impl->res.fileset->resource_name_, rc.client_name,
1568 jcr->impl->res.client->resource_name_,
1569 jcr->impl->backup_format,
1570 jcr->impl->res.read_storage->resource_name_,
1571 bstrutime(dt, sizeof(dt), jcr->sched_time),
1572 jcr->impl->res.catalog->resource_name_, jcr->JobPriority,
1573 NPRT(jcr->impl->plugin_options));
1574 } else {
1575 ua->SendMsg(_("Run Restore job\n"
1576 "JobName: %s\n"
1577 "Bootstrap: %s\n"
1578 "Where: %s\n"
1579 "Replace: %s\n"
1580 "FileSet: %s\n"
1581 "Backup Client: %s\n"
1582 "Restore Client: %s\n"
1583 "Format: %s\n"
1584 "Storage: %s\n"
1585 "When: %s\n"
1586 "Catalog: %s\n"
1587 "Priority: %d\n"
1588 "Plugin Options: %s\n"),
1589 job->resource_name_, NPRT(jcr->RestoreBootstrap),
1590 jcr->where ? jcr->where : NPRT(job->RestoreWhere),
1591 rc.replace, jcr->impl->res.fileset->resource_name_,
1592 rc.client_name, jcr->impl->res.client->resource_name_,
1593 jcr->impl->backup_format,
1594 jcr->impl->res.read_storage->resource_name_,
1595 bstrutime(dt, sizeof(dt), jcr->sched_time),
1596 jcr->impl->res.catalog->resource_name_,
1597 jcr->JobPriority, NPRT(jcr->impl->plugin_options));
1598 }
1599 }
1600
1601 } else {
1602 /* ***FIXME*** This needs to be fixed for bat */
1603 if (ua->api) ua->signal(BNET_RUN_CMD);
1604 ua->SendMsg(_("Run Restore job\n"
1605 "JobName: %s\n"
1606 "Bootstrap: %s\n"),
1607 job->resource_name_, NPRT(jcr->RestoreBootstrap));
1608
1609 /* RegexWhere is take before RestoreWhere */
1610 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
1611 ua->SendMsg(_("RegexWhere: %s\n"),
1612 jcr->RegexWhere ? jcr->RegexWhere : job->RegexWhere);
1613 } else {
1614 ua->SendMsg(_("Where: %s\n"),
1615 jcr->where ? jcr->where : NPRT(job->RestoreWhere));
1616 }
1617
1618 ua->SendMsg(_("Replace: %s\n"
1619 "Client: %s\n"
1620 "Format: %s\n"
1621 "Storage: %s\n"
1622 "JobId: %s\n"
1623 "When: %s\n"
1624 "Catalog: %s\n"
1625 "Priority: %d\n"
1626 "Plugin Options: %s\n"),
1627 rc.replace, jcr->impl->res.client->resource_name_,
1628 jcr->impl->backup_format,
1629 jcr->impl->res.read_storage->resource_name_,
1630 (jcr->impl->RestoreJobId == 0)
1631 ? _("*None*")
1632 : edit_uint64(jcr->impl->RestoreJobId, ec1),
1633 bstrutime(dt, sizeof(dt), jcr->sched_time),
1634 jcr->impl->res.catalog->resource_name_, jcr->JobPriority,
1635 NPRT(jcr->impl->plugin_options));
1636 }
1637 break;
1638 case JT_COPY:
1639 case JT_MIGRATE:
1640 const char* prt_type;
1641
1642 jcr->setJobLevel(L_FULL); /* default level */
1643 if (ua->api) {
1644 ua->signal(BNET_RUN_CMD);
1645 if (jcr->is_JobType(JT_COPY)) {
1646 prt_type = _("Type: Copy\nTitle: Run Copy Job\n");
1647 } else {
1648 prt_type = _("Type: Migration\nTitle: Run Migration Job\n");
1649 }
1650 ua->SendMsg(
1651 "%s"
1652 "JobName: %s\n"
1653 "Bootstrap: %s\n"
1654 "Read Storage: %s\n"
1655 "Pool: %s\n"
1656 "Write Storage: %s\n"
1657 "NextPool: %s\n"
1658 "JobId: %s\n"
1659 "When: %s\n"
1660 "Catalog: %s\n"
1661 "Priority: %d\n",
1662 prt_type, job->resource_name_, NPRT(jcr->RestoreBootstrap),
1663 jcr->impl->res.read_storage
1664 ? jcr->impl->res.read_storage->resource_name_
1665 : _("*None*"),
1666 NPRT(jcr->impl->res.pool->resource_name_),
1667 jcr->impl->res.next_pool
1668 ? jcr->impl->res.next_pool->resource_name_
1669 : _("*None*"),
1670 jcr->impl->res.write_storage
1671 ? jcr->impl->res.write_storage->resource_name_
1672 : _("*None*"),
1673 (jcr->impl->MigrateJobId == 0)
1674 ? _("*None*")
1675 : edit_uint64(jcr->impl->MigrateJobId, ec1),
1676 bstrutime(dt, sizeof(dt), jcr->sched_time),
1677 jcr->impl->res.catalog->resource_name_, jcr->JobPriority);
1678 } else {
1679 if (jcr->is_JobType(JT_COPY)) {
1680 prt_type = _("Run Copy job\n");
1681 } else {
1682 prt_type = _("Run Migration job\n");
1683 }
1684 ua->SendMsg(_("%s"
1685 "JobName: %s\n"
1686 "Bootstrap: %s\n"
1687 "Read Storage: %s (From %s)\n"
1688 "Pool: %s (From %s)\n"
1689 "Write Storage: %s (From %s)\n"
1690 "NextPool: %s (From %s)\n"
1691 "JobId: %s\n"
1692 "When: %s\n"
1693 "Catalog: %s\n"
1694 "Priority: %d\n"),
1695 prt_type, job->resource_name_, NPRT(jcr->RestoreBootstrap),
1696 jcr->impl->res.read_storage
1697 ? jcr->impl->res.read_storage->resource_name_
1698 : _("*None*"),
1699 jcr->impl->res.rstore_source,
1700 NPRT(jcr->impl->res.pool->resource_name_),
1701 jcr->impl->res.pool_source,
1702 jcr->impl->res.write_storage
1703 ? jcr->impl->res.write_storage->resource_name_
1704 : _("*None*"),
1705 jcr->impl->res.wstore_source,
1706 jcr->impl->res.next_pool
1707 ? jcr->impl->res.next_pool->resource_name_
1708 : _("*None*"),
1709 NPRT(jcr->impl->res.npool_source),
1710 jcr->impl->MigrateJobId == 0
1711 ? _("*None*")
1712 : edit_uint64(jcr->impl->MigrateJobId, ec1),
1713 bstrutime(dt, sizeof(dt), jcr->sched_time),
1714 jcr->impl->res.catalog->resource_name_, jcr->JobPriority);
1715 }
1716 break;
1717 default:
1718 ua->ErrorMsg(_("Unknown Job Type=%d\n"), jcr->getJobType());
1719 return false;
1720 }
1721 return true;
1722 }
1723
ScanCommandLineArguments(UaContext * ua,RunContext & rc)1724 static bool ScanCommandLineArguments(UaContext* ua, RunContext& rc)
1725 {
1726 bool kw_ok;
1727 int i, j;
1728 static const char* kw[] = {
1729 /* command line arguments */
1730 "job", /* 0 */
1731 "jobid", /* 1 */
1732 "client", /* 2 */
1733 "fd", /* 3 */
1734 "fileset", /* 4 */
1735 "level", /* 5 */
1736 "storage", /* 6 */
1737 "sd", /* 7 */
1738 "regexwhere", /* 8 - where string as a bregexp */
1739 "where", /* 9 */
1740 "bootstrap", /* 10 */
1741 "replace", /* 11 */
1742 "when", /* 12 */
1743 "priority", /* 13 */
1744 "yes", /* 14 -- if you change this change YES_POS too */
1745 "verifyjob", /* 15 */
1746 "files", /* 16 - number of files to restore */
1747 "catalog", /* 17 - override catalog */
1748 "since", /* 18 - since */
1749 "cloned", /* 19 - cloned */
1750 "verifylist", /* 20 - verify output list */
1751 "migrationjob", /* 21 - migration job name */
1752 "pool", /* 22 */
1753 "nextpool", /* 23 */
1754 "backupclient", /* 24 */
1755 "restoreclient", /* 25 */
1756 "pluginoptions", /* 26 */
1757 "spooldata", /* 27 */
1758 "comment", /* 28 */
1759 "ignoreduplicatecheck", /* 29 */
1760 "accurate", /* 30 */
1761 "backupformat", /* 31 */
1762 NULL};
1763
1764 #define YES_POS 14
1765
1766 rc.catalog_name = NULL;
1767 rc.job_name = NULL;
1768 rc.pool_name = NULL;
1769 rc.next_pool_name = NULL;
1770 rc.StoreName = NULL;
1771 rc.client_name = NULL;
1772 rc.restore_client_name = NULL;
1773 rc.fileset_name = NULL;
1774 rc.verify_job_name = NULL;
1775 rc.previous_job_name = NULL;
1776 rc.accurate_set = false;
1777 rc.spool_data_set = false;
1778 rc.ignoreduplicatecheck = false;
1779 rc.comment = NULL;
1780 rc.backup_format = NULL;
1781
1782 for (i = 1; i < ua->argc; i++) {
1783 Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
1784 kw_ok = false;
1785
1786 /*
1787 * Keep looking until we find a good keyword
1788 */
1789 for (j = 0; !kw_ok && kw[j]; j++) {
1790 if (Bstrcasecmp(ua->argk[i], kw[j])) {
1791 /*
1792 * Note, yes and run have no value, so do not fail
1793 */
1794 if (!ua->argv[i] && j != YES_POS /*yes*/) {
1795 ua->SendMsg(_("Value missing for keyword %s\n"), ua->argk[i]);
1796 return false;
1797 }
1798 Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
1799 switch (j) {
1800 case 0: /* job */
1801 if (rc.job_name) {
1802 ua->SendMsg(_("Job name specified twice.\n"));
1803 return false;
1804 }
1805 rc.job_name = ua->argv[i];
1806 kw_ok = true;
1807 break;
1808 case 1: /* JobId */
1809 if (rc.jid && !rc.mod) {
1810 ua->SendMsg(_("JobId specified twice.\n"));
1811 return false;
1812 }
1813 rc.jid = ua->argv[i];
1814 kw_ok = true;
1815 break;
1816 case 2: /* client */
1817 case 3: /* fd */
1818 if (rc.client_name) {
1819 ua->SendMsg(_("Client specified twice.\n"));
1820 return false;
1821 }
1822 rc.client_name = ua->argv[i];
1823 kw_ok = true;
1824 break;
1825 case 4: /* fileset */
1826 if (rc.fileset_name) {
1827 ua->SendMsg(_("FileSet specified twice.\n"));
1828 return false;
1829 }
1830 rc.fileset_name = ua->argv[i];
1831 kw_ok = true;
1832 break;
1833 case 5: /* level */
1834 if (rc.level_name) {
1835 ua->SendMsg(_("Level specified twice.\n"));
1836 return false;
1837 }
1838 rc.level_name = ua->argv[i];
1839 kw_ok = true;
1840 break;
1841 case 6: /* storage */
1842 case 7: /* sd */
1843 if (rc.StoreName) {
1844 ua->SendMsg(_("Storage specified twice.\n"));
1845 return false;
1846 }
1847 rc.StoreName = ua->argv[i];
1848 kw_ok = true;
1849 break;
1850 case 8: /* regexwhere */
1851 if ((rc.regexwhere || rc.where) && !rc.mod) {
1852 ua->SendMsg(_("RegexWhere or Where specified twice.\n"));
1853 return false;
1854 }
1855 rc.regexwhere = ua->argv[i];
1856 if (!ua->AclAccessOk(Where_ACL, rc.regexwhere, true)) {
1857 ua->SendMsg(
1858 _("No authorization for \"regexwhere\" specification.\n"));
1859 return false;
1860 }
1861 kw_ok = true;
1862 break;
1863 case 9: /* where */
1864 if ((rc.where || rc.regexwhere) && !rc.mod) {
1865 ua->SendMsg(_("Where or RegexWhere specified twice.\n"));
1866 return false;
1867 }
1868 rc.where = ua->argv[i];
1869 if (!ua->AclAccessOk(Where_ACL, rc.where, true)) {
1870 ua->SendMsg(_("No authoriztion for \"where\" specification.\n"));
1871 return false;
1872 }
1873 kw_ok = true;
1874 break;
1875 case 10: /* bootstrap */
1876 if (rc.bootstrap && !rc.mod) {
1877 ua->SendMsg(_("Bootstrap specified twice.\n"));
1878 return false;
1879 }
1880 rc.bootstrap = ua->argv[i];
1881 kw_ok = true;
1882 break;
1883 case 11: /* replace */
1884 if (rc.replace && !rc.mod) {
1885 ua->SendMsg(_("Replace specified twice.\n"));
1886 return false;
1887 }
1888 rc.replace = ua->argv[i];
1889 kw_ok = true;
1890 break;
1891 case 12: /* When */
1892 if (rc.when && !rc.mod) {
1893 ua->SendMsg(_("When specified twice.\n"));
1894 return false;
1895 }
1896 rc.when = ua->argv[i];
1897 kw_ok = true;
1898 break;
1899 case 13: /* Priority */
1900 if (rc.Priority && !rc.mod) {
1901 ua->SendMsg(_("Priority specified twice.\n"));
1902 return false;
1903 }
1904 rc.Priority = atoi(ua->argv[i]);
1905 if (rc.Priority <= 0) {
1906 ua->SendMsg(
1907 _("Priority must be positive nonzero setting it to 10.\n"));
1908 rc.Priority = 10;
1909 }
1910 kw_ok = true;
1911 break;
1912 case 14: /* yes */
1913 kw_ok = true;
1914 break;
1915 case 15: /* Verify Job */
1916 if (rc.verify_job_name) {
1917 ua->SendMsg(_("Verify Job specified twice.\n"));
1918 return false;
1919 }
1920 rc.verify_job_name = ua->argv[i];
1921 kw_ok = true;
1922 break;
1923 case 16: /* files */
1924 rc.files = atoi(ua->argv[i]);
1925 kw_ok = true;
1926 break;
1927 case 17: /* catalog */
1928 rc.catalog_name = ua->argv[i];
1929 kw_ok = true;
1930 break;
1931 case 18: /* since */
1932 rc.since = ua->argv[i];
1933 kw_ok = true;
1934 break;
1935 case 19: /* cloned */
1936 rc.cloned = true;
1937 kw_ok = true;
1938 break;
1939 case 20: /* write verify list output */
1940 rc.verify_list = ua->argv[i];
1941 kw_ok = true;
1942 break;
1943 case 21: /* Migration Job */
1944 if (rc.previous_job_name) {
1945 ua->SendMsg(_("Migration Job specified twice.\n"));
1946 return false;
1947 }
1948 rc.previous_job_name = ua->argv[i];
1949 kw_ok = true;
1950 break;
1951 case 22: /* pool */
1952 if (rc.pool_name) {
1953 ua->SendMsg(_("Pool specified twice.\n"));
1954 return false;
1955 }
1956 rc.pool_name = ua->argv[i];
1957 kw_ok = true;
1958 break;
1959 case 23: /* nextpool */
1960 if (rc.next_pool_name) {
1961 ua->SendMsg(_("NextPool specified twice.\n"));
1962 return false;
1963 }
1964 rc.next_pool_name = ua->argv[i];
1965 kw_ok = true;
1966 break;
1967 case 24: /* backupclient */
1968 if (rc.client_name) {
1969 ua->SendMsg(_("Client specified twice.\n"));
1970 return 0;
1971 }
1972 rc.client_name = ua->argv[i];
1973 kw_ok = true;
1974 break;
1975 case 25: /* restoreclient */
1976 if (rc.restore_client_name && !rc.mod) {
1977 ua->SendMsg(_("Restore Client specified twice.\n"));
1978 return false;
1979 }
1980 rc.restore_client_name = ua->argv[i];
1981 kw_ok = true;
1982 break;
1983 case 26: /* pluginoptions */
1984 if (rc.plugin_options) {
1985 ua->SendMsg(_("Plugin Options specified twice.\n"));
1986 return false;
1987 }
1988 rc.plugin_options = ua->argv[i];
1989 if (!ua->AclAccessOk(PluginOptions_ACL, rc.plugin_options, true)) {
1990 ua->SendMsg(
1991 _("No authorization for \"PluginOptions\" specification.\n"));
1992 return false;
1993 }
1994 kw_ok = true;
1995 break;
1996 case 27: /* spooldata */
1997 if (rc.spool_data_set) {
1998 ua->SendMsg(_("Spool flag specified twice.\n"));
1999 return false;
2000 }
2001 if (IsYesno(ua->argv[i], &rc.spool_data)) {
2002 rc.spool_data_set = true;
2003 kw_ok = true;
2004 } else {
2005 ua->SendMsg(_("Invalid spooldata flag.\n"));
2006 }
2007 break;
2008 case 28: /* comment */
2009 rc.comment = ua->argv[i];
2010 kw_ok = true;
2011 break;
2012 case 29: /* ignoreduplicatecheck */
2013 if (rc.ignoreduplicatecheck_set) {
2014 ua->SendMsg(_("IgnoreDuplicateCheck flag specified twice.\n"));
2015 return false;
2016 }
2017 if (IsYesno(ua->argv[i], &rc.ignoreduplicatecheck)) {
2018 rc.ignoreduplicatecheck_set = true;
2019 kw_ok = true;
2020 } else {
2021 ua->SendMsg(_("Invalid ignoreduplicatecheck flag.\n"));
2022 }
2023 break;
2024 case 30: /* accurate */
2025 if (rc.accurate_set) {
2026 ua->SendMsg(_("Accurate flag specified twice.\n"));
2027 return false;
2028 }
2029 if (IsYesno(ua->argv[i], &rc.accurate)) {
2030 rc.accurate_set = true;
2031 kw_ok = true;
2032 } else {
2033 ua->SendMsg(_("Invalid accurate flag.\n"));
2034 }
2035 break;
2036 case 31: /* backupformat */
2037 if (rc.backup_format && !rc.mod) {
2038 ua->SendMsg(_("Backup Format specified twice.\n"));
2039 return false;
2040 }
2041 rc.backup_format = ua->argv[i];
2042 kw_ok = true;
2043 break;
2044 default:
2045 break;
2046 }
2047 } /* end strcase compare */
2048 } /* end keyword loop */
2049
2050 /*
2051 * End of keyword for loop -- if not found, we got a bogus keyword
2052 */
2053 if (!kw_ok) {
2054 Dmsg1(800, "%s not found\n", ua->argk[i]);
2055 /*
2056 * Special case for Job Name, it can be the first
2057 * keyword that has no value.
2058 */
2059 if (!rc.job_name && !ua->argv[i]) {
2060 rc.job_name = ua->argk[i]; /* use keyword as job name */
2061 Dmsg1(800, "Set jobname=%s\n", rc.job_name);
2062 } else {
2063 ua->SendMsg(_("Invalid keyword: %s\n"), ua->argk[i]);
2064 return false;
2065 }
2066 }
2067 } /* end argc loop */
2068
2069 Dmsg0(800, "Done scan.\n");
2070 if (rc.comment) {
2071 if (!IsCommentLegal(ua, rc.comment)) { return false; }
2072 }
2073 if (rc.catalog_name) {
2074 rc.catalog = ua->GetCatalogResWithName(rc.catalog_name);
2075 if (rc.catalog == NULL) {
2076 ua->ErrorMsg(_("Catalog \"%s\" not found\n"), rc.catalog_name);
2077 return false;
2078 }
2079 }
2080 Dmsg1(800, "Using catalog=%s\n", NPRT(rc.catalog_name));
2081
2082 if (rc.job_name) {
2083 /* Find Job */
2084 rc.job = ua->GetJobResWithName(rc.job_name);
2085 if (!rc.job) {
2086 if (*rc.job_name != 0) {
2087 ua->SendMsg(_("Job \"%s\" not found\n"), rc.job_name);
2088 }
2089 rc.job = select_job_resource(ua);
2090 } else {
2091 Dmsg1(800, "Found job=%s\n", rc.job_name);
2092 }
2093 } else if (!rc.job) {
2094 ua->SendMsg(_("A job name must be specified.\n"));
2095 rc.job = select_job_resource(ua);
2096 }
2097 if (!rc.job) { return false; }
2098
2099 if (rc.pool_name) {
2100 rc.pool = ua->GetPoolResWithName(rc.pool_name);
2101 if (!rc.pool) {
2102 if (*rc.pool_name != 0) {
2103 ua->WarningMsg(_("Pool \"%s\" not found.\n"), rc.pool_name);
2104 }
2105 rc.pool = select_pool_resource(ua);
2106 }
2107 } else if (!rc.pool) {
2108 rc.pool = rc.job->pool; /* use default */
2109 }
2110 if (!rc.pool) { return false; }
2111 Dmsg1(100, "Using pool %s\n", rc.pool->resource_name_);
2112
2113 if (rc.next_pool_name) {
2114 rc.next_pool = ua->GetPoolResWithName(rc.next_pool_name);
2115 if (!rc.next_pool) {
2116 if (*rc.next_pool_name != 0) {
2117 ua->WarningMsg(_("Pool \"%s\" not found.\n"), rc.next_pool_name);
2118 }
2119 rc.next_pool = select_pool_resource(ua);
2120 }
2121 } else if (!rc.next_pool) {
2122 rc.next_pool = rc.pool->NextPool; /* use default */
2123 }
2124 if (rc.next_pool) {
2125 Dmsg1(100, "Using next pool %s\n", rc.next_pool->resource_name_);
2126 }
2127
2128 if (rc.StoreName) {
2129 rc.store->store = ua->GetStoreResWithName(rc.StoreName);
2130 PmStrcpy(rc.store->store_source, _("command line"));
2131 if (!rc.store->store) {
2132 if (*rc.StoreName != 0) {
2133 ua->WarningMsg(_("Storage \"%s\" not found.\n"), rc.StoreName);
2134 }
2135 rc.store->store = select_storage_resource(ua);
2136 PmStrcpy(rc.store->store_source, _("user selection"));
2137 }
2138 } else if (!rc.store->store) {
2139 GetJobStorage(rc.store, rc.job, NULL); /* use default */
2140 }
2141
2142 /*
2143 * For certain Jobs an explicit setting of the read storage is not
2144 * required as its determined when the Job is executed automatically.
2145 */
2146 switch (rc.job->JobType) {
2147 case JT_COPY:
2148 case JT_MIGRATE:
2149 break;
2150 default:
2151 if (!rc.store->store) {
2152 ua->ErrorMsg(_("No storage specified.\n"));
2153 return false;
2154 } else if (!ua->AclAccessOk(Storage_ACL, rc.store->store->resource_name_,
2155 true)) {
2156 ua->ErrorMsg(_("No authorization. Storage \"%s\".\n"),
2157 rc.store->store->resource_name_);
2158 return false;
2159 }
2160 Dmsg1(800, "Using storage=%s\n", rc.store->store->resource_name_);
2161 break;
2162 }
2163
2164 if (rc.client_name) {
2165 rc.client = ua->GetClientResWithName(rc.client_name);
2166 if (!rc.client) {
2167 if (*rc.client_name != 0) {
2168 ua->WarningMsg(_("Client \"%s\" not found.\n"), rc.client_name);
2169 }
2170 rc.client = select_client_resource(ua);
2171 }
2172 } else if (!rc.client) {
2173 rc.client = rc.job->client; /* use default */
2174 }
2175
2176 if (rc.client) {
2177 if (!ua->AclAccessOk(Client_ACL, rc.client->resource_name_, true)) {
2178 ua->ErrorMsg(_("No authorization. Client \"%s\".\n"),
2179 rc.client->resource_name_);
2180 return false;
2181 } else {
2182 Dmsg1(800, "Using client=%s\n", rc.client->resource_name_);
2183 }
2184 }
2185
2186 if (rc.restore_client_name) {
2187 rc.client = ua->GetClientResWithName(rc.restore_client_name);
2188 if (!rc.client) {
2189 if (*rc.restore_client_name != 0) {
2190 ua->WarningMsg(_("Restore Client \"%s\" not found.\n"),
2191 rc.restore_client_name);
2192 }
2193 rc.client = select_client_resource(ua);
2194 }
2195 } else if (!rc.client) {
2196 rc.client = rc.job->client; /* use default */
2197 }
2198
2199 if (rc.client) {
2200 if (!ua->AclAccessOk(Client_ACL, rc.client->resource_name_, true)) {
2201 ua->ErrorMsg(_("No authorization. Client \"%s\".\n"),
2202 rc.client->resource_name_);
2203 return false;
2204 } else {
2205 Dmsg1(800, "Using restore client=%s\n", rc.client->resource_name_);
2206 }
2207 }
2208
2209 if (rc.fileset_name) {
2210 rc.fileset = ua->GetFileSetResWithName(rc.fileset_name);
2211 if (!rc.fileset) {
2212 ua->SendMsg(_("FileSet \"%s\" not found.\n"), rc.fileset_name);
2213 rc.fileset = select_fileset_resource(ua);
2214 if (!rc.fileset) { return false; }
2215 }
2216 } else if (!rc.fileset) {
2217 rc.fileset = rc.job->fileset; /* use default */
2218 }
2219
2220 if (rc.verify_job_name) {
2221 rc.verify_job = ua->GetJobResWithName(rc.verify_job_name);
2222 if (!rc.verify_job) {
2223 ua->SendMsg(_("Verify Job \"%s\" not found.\n"), rc.verify_job_name);
2224 rc.verify_job = select_job_resource(ua);
2225 }
2226 } else if (!rc.verify_job) {
2227 rc.verify_job = rc.job->verify_job;
2228 }
2229
2230 if (rc.previous_job_name) {
2231 rc.previous_job = ua->GetJobResWithName(rc.previous_job_name);
2232 if (!rc.previous_job) {
2233 ua->SendMsg(_("Migration Job \"%s\" not found.\n"), rc.previous_job_name);
2234 rc.previous_job = select_job_resource(ua);
2235 }
2236 } else {
2237 rc.previous_job = rc.job->verify_job;
2238 }
2239 return true;
2240 }
2241 } /* namespace directordaemon */
2242