1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 *
21 * Bacula Director -- User Agent Prompt and Selection code
22 *
23 * Kern Sibbald, October MMI
24 *
25 */
26
27 #include "bacula.h"
28 #include "dird.h"
29
30 /* Imported variables */
31 extern struct s_jl joblevels[];
32
confirm_retention_yesno(UAContext * ua,utime_t ret,const char * msg)33 int confirm_retention_yesno(UAContext *ua, utime_t ret, const char *msg)
34 {
35 char ed1[100];
36 int val;
37
38 /* Look for "yes" in command line */
39 if (find_arg(ua, NT_("yes")) != -1) {
40 return 1;
41 }
42
43 for ( ;; ) {
44 ua->info_msg(_("The current %s retention period is: %s\n"),
45 msg, edit_utime(ret, ed1, sizeof(ed1)));
46 if (!get_cmd(ua, _("Continue? (yes/no): "))) {
47 return 0;
48 }
49 if (is_yesno(ua->cmd, &val)) {
50 return val; /* is 1 for yes, 0 for no */
51 }
52 }
53 return 1;
54 }
55
56 /*
57 * Confirm a retention period
58 */
confirm_retention(UAContext * ua,utime_t * ret,const char * msg)59 int confirm_retention(UAContext *ua, utime_t *ret, const char *msg)
60 {
61 char ed1[100];
62 int val;
63
64 /* Look for "yes" in command line */
65 if (find_arg(ua, NT_("yes")) != -1) {
66 return 1;
67 }
68
69 for ( ;; ) {
70 ua->info_msg(_("The current %s retention period is: %s\n"),
71 msg, edit_utime(*ret, ed1, sizeof(ed1)));
72
73 if (!get_cmd(ua, _("Continue? (yes/mod/no): "))) {
74 return 0;
75 }
76 if (strcasecmp(ua->cmd, _("mod")) == 0) {
77 if (!get_cmd(ua, _("Enter new retention period: "))) {
78 return 0;
79 }
80 if (!duration_to_utime(ua->cmd, ret)) {
81 ua->error_msg(_("Invalid period.\n"));
82 continue;
83 }
84 continue;
85 }
86 if (is_yesno(ua->cmd, &val)) {
87 return val; /* is 1 for yes, 0 for no */
88 }
89 }
90 return 1;
91 }
92
93 /*
94 * Given a list of keywords, find the first one
95 * that is in the argument list.
96 * Returns: -1 if not found
97 * index into list (base 0) on success
98 */
find_arg_keyword(UAContext * ua,const char ** list)99 int find_arg_keyword(UAContext *ua, const char **list)
100 {
101 for (int i=1; i<ua->argc; i++) {
102 for(int j=0; list[j]; j++) {
103 if (strcasecmp(list[j], ua->argk[i]) == 0) {
104 return j;
105 }
106 }
107 }
108 return -1;
109 }
110
111 /*
112 * Given one keyword, find the first one that
113 * is in the argument list.
114 * Returns: argk index (always gt 0)
115 * -1 if not found
116 */
find_arg(UAContext * ua,const char * keyword)117 int find_arg(UAContext *ua, const char *keyword)
118 {
119 for (int i=1; i<ua->argc; i++) {
120 if (strcasecmp(keyword, ua->argk[i]) == 0) {
121 return i;
122 }
123 }
124 return -1;
125 }
126
127 /*
128 * Given a single keyword, find it in the argument list, but
129 * it must have a value
130 * Returns: -1 if not found or no value
131 * list index (base 0) on success
132 */
find_arg_with_value(UAContext * ua,const char * keyword)133 int find_arg_with_value(UAContext *ua, const char *keyword)
134 {
135 for (int i=1; i<ua->argc; i++) {
136 if (strcasecmp(keyword, ua->argk[i]) == 0) {
137 if (ua->argv[i]) {
138 return i;
139 } else {
140 return -1;
141 }
142 }
143 }
144 return -1;
145 }
146
147 /*
148 * Given a list of keywords, prompt the user
149 * to choose one.
150 *
151 * Returns: -1 on failure
152 * index into list (base 0) on success
153 */
do_keyword_prompt(UAContext * ua,const char * msg,const char ** list)154 int do_keyword_prompt(UAContext *ua, const char *msg, const char **list)
155 {
156 int i;
157 start_prompt(ua, _("You have the following choices:\n"));
158 for (i=0; list[i]; i++) {
159 add_prompt(ua, list[i]);
160 }
161 return do_prompt(ua, "", msg, NULL, 0);
162 }
163
164
165 /*
166 * Select a Storage resource from prompt list
167 * If unique is set storage resources that have the main address are
168 * combined into one (i.e. they are all part of the same)
169 * storage. Note, not all commands want this.
170 */
select_storage_resource(UAContext * ua,bool unique)171 STORE *select_storage_resource(UAContext *ua, bool unique)
172 {
173 POOL_MEM tmp;
174 char name[MAX_NAME_LENGTH];
175 STORE *store;
176
177 /* Does user want a full selection? */
178 if (unique && find_arg(ua, NT_("select")) > 0) {
179 unique = false;
180 }
181 start_prompt(ua, _("The defined Storage resources are:\n"));
182 LockRes();
183 foreach_res(store, R_STORAGE) {
184 if (store->is_enabled() && acl_access_ok(ua, Storage_ACL, store->name())) {
185 if (unique) {
186 Mmsg(tmp, "%s:%d", store->address, store->SDport);
187 add_prompt(ua, store->name(), tmp.c_str());
188 } else {
189 add_prompt(ua, store->name());
190 }
191 }
192 }
193 UnlockRes();
194 if (do_prompt(ua, _("Storage"), _("Select Storage resource"), name, sizeof(name)) < 0) {
195 return NULL;
196 }
197 store = (STORE *)GetResWithName(R_STORAGE, name);
198 return store;
199 }
200
201 /*
202 * Select a FileSet resource from prompt list
203 */
select_fileset_resource(UAContext * ua)204 FILESET *select_fileset_resource(UAContext *ua)
205 {
206 char name[MAX_NAME_LENGTH];
207 FILESET *fs;
208
209 start_prompt(ua, _("The defined FileSet resources are:\n"));
210 LockRes();
211 foreach_res(fs, R_FILESET) {
212 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
213 add_prompt(ua, fs->name());
214 }
215 }
216 UnlockRes();
217 if (do_prompt(ua, _("FileSet"), _("Select FileSet resource"), name, sizeof(name)) < 0) {
218 return NULL;
219 }
220 fs = (FILESET *)GetResWithName(R_FILESET, name);
221 return fs;
222 }
223
224
225 /*
226 * Get a catalog resource from prompt list
227 */
get_catalog_resource(UAContext * ua)228 CAT *get_catalog_resource(UAContext *ua)
229 {
230 char name[MAX_NAME_LENGTH];
231 CAT *catalog = NULL;
232 CLIENT *client = NULL;
233 int i;
234
235 for (i=1; i<ua->argc; i++) {
236 if (strcasecmp(ua->argk[i], NT_("catalog")) == 0 && ua->argv[i]) {
237 if (acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
238 catalog = (CAT *)GetResWithName(R_CATALOG, ua->argv[i]);
239 break;
240 }
241 }
242 if (strcasecmp(ua->argk[i], NT_("client")) == 0 && ua->argv[i]) {
243 if (acl_access_client_ok(ua, ua->argv[i], JT_BACKUP_RESTORE)) {
244 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
245 break;
246 }
247 }
248 }
249 if (!catalog && client) { /* Try to take the catalog from the client */
250 catalog = client->catalog;
251 }
252 if (ua->gui && !catalog) {
253 LockRes();
254 catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
255 UnlockRes();
256 if (!catalog) {
257 ua->error_msg(_("Could not find a Catalog resource\n"));
258 return NULL;
259 } else if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
260 ua->error_msg(_("You must specify a \"use <catalog-name>\" command before continuing.\n"));
261 return NULL;
262 }
263 return catalog;
264 }
265 if (!catalog) {
266 start_prompt(ua, _("The defined Catalog resources are:\n"));
267 LockRes();
268 foreach_res(catalog, R_CATALOG) {
269 if (acl_access_ok(ua, Catalog_ACL, catalog->name())) {
270 add_prompt(ua, catalog->name());
271 }
272 }
273 UnlockRes();
274 if (do_prompt(ua, _("Catalog"), _("Select Catalog resource"), name, sizeof(name)) < 0) {
275 return NULL;
276 }
277 catalog = (CAT *)GetResWithName(R_CATALOG, name);
278 }
279 return catalog;
280 }
281
282
283 /*
284 * Select a job to enable or disable
285 */
select_enable_disable_job_resource(UAContext * ua,bool enable)286 JOB *select_enable_disable_job_resource(UAContext *ua, bool enable)
287 {
288 char name[MAX_NAME_LENGTH];
289 JOB *job;
290
291 LockRes();
292 if (enable) {
293 start_prompt(ua, _("The disabled Job resources are:\n"));
294 } else {
295 start_prompt(ua, _("The enabled Job resources are:\n"));
296 }
297 foreach_res(job, R_JOB) {
298 if (!acl_access_ok(ua, Job_ACL, job->name())) {
299 continue;
300 }
301 if (job->is_enabled() == enable) { /* Already enabled/disabled? */
302 continue; /* yes, skip */
303 }
304 add_prompt(ua, job->name());
305 }
306 UnlockRes();
307 if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
308 return NULL;
309 }
310 job = (JOB *)GetResWithName(R_JOB, name);
311 return job;
312 }
313
314 /*
315 * Select a Job resource from prompt list
316 */
select_job_resource(UAContext * ua)317 JOB *select_job_resource(UAContext *ua)
318 {
319 char name[MAX_NAME_LENGTH];
320 JOB *job;
321
322 start_prompt(ua, _("The defined Job resources are:\n"));
323 LockRes();
324 foreach_res(job, R_JOB) {
325 if (job->is_enabled() && acl_access_ok(ua, Job_ACL, job->name())) {
326 add_prompt(ua, job->name());
327 }
328 }
329 UnlockRes();
330 if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
331 return NULL;
332 }
333 job = (JOB *)GetResWithName(R_JOB, name);
334 return job;
335 }
336
337 /*
338 * Select a Restore Job resource from argument or prompt
339 */
get_restore_job(UAContext * ua)340 JOB *get_restore_job(UAContext *ua)
341 {
342 JOB *job;
343 int i = find_arg_with_value(ua, "restorejob");
344 if (i >= 0 && acl_access_ok(ua, Job_ACL, ua->argv[i])) {
345 job = (JOB *)GetResWithName(R_JOB, ua->argv[i]);
346 if (job && job->JobType == JT_RESTORE) {
347 return job;
348 }
349 ua->error_msg(_("Error: Restore Job resource \"%s\" does not exist.\n"),
350 ua->argv[i]);
351 }
352 return select_restore_job_resource(ua);
353 }
354
355 /*
356 * Select a Restore Job resource from prompt list
357 */
select_restore_job_resource(UAContext * ua)358 JOB *select_restore_job_resource(UAContext *ua)
359 {
360 char name[MAX_NAME_LENGTH];
361 JOB *job;
362
363 start_prompt(ua, _("The defined Restore Job resources are:\n"));
364 LockRes();
365 foreach_res(job, R_JOB) {
366 if (job->JobType == JT_RESTORE && job->is_enabled() &&
367 acl_access_ok(ua, Job_ACL, job->name())) {
368 add_prompt(ua, job->name());
369 }
370 }
371 UnlockRes();
372 if (do_prompt(ua, _("Job"), _("Select Restore Job"), name, sizeof(name)) < 0) {
373 return NULL;
374 }
375 job = (JOB *)GetResWithName(R_JOB, name);
376 return job;
377 }
378
379 /*
380 * Select a client to enable or disable
381 */
select_enable_disable_client_resource(UAContext * ua,bool enable)382 CLIENT *select_enable_disable_client_resource(UAContext *ua, bool enable)
383 {
384 char name[MAX_NAME_LENGTH];
385 CLIENT *client;
386
387 LockRes();
388 start_prompt(ua, _("The defined Client resources are:\n"));
389 foreach_res(client, R_CLIENT) {
390 if (!acl_access_client_ok(ua, client->name(), JT_BACKUP_RESTORE)) {
391 continue;
392 }
393 if (client->is_enabled() == enable) { /* Already enabled/disabled? */
394 continue; /* yes, skip */
395 }
396 add_prompt(ua, client->name());
397 }
398 UnlockRes();
399 if (do_prompt(ua, _("Client"), _("Select Client resource"), name, sizeof(name)) < 0) {
400 return NULL;
401 }
402 client = (CLIENT *)GetResWithName(R_CLIENT, name);
403 return client;
404 }
405
406
407 /*
408 * Select a client resource from prompt list
409 */
select_client_resource(UAContext * ua,int32_t jobtype)410 CLIENT *select_client_resource(UAContext *ua, int32_t jobtype)
411 {
412 char name[MAX_NAME_LENGTH];
413 CLIENT *client;
414
415 start_prompt(ua, _("The defined Client resources are:\n"));
416 LockRes();
417 foreach_res(client, R_CLIENT) {
418 if (client->is_enabled() && acl_access_client_ok(ua, client->name(), jobtype)) {
419 add_prompt(ua, client->name());
420 }
421 }
422 UnlockRes();
423 if (do_prompt(ua, _("Client"), _("Select Client (File daemon) resource"), name, sizeof(name)) < 0) {
424 return NULL;
425 }
426 client = (CLIENT *)GetResWithName(R_CLIENT, name);
427 return client;
428 }
429
430 /*
431 * Get client resource, start by looking for
432 * client=<client-name>
433 * if we don't find the keyword, we prompt the user.
434 */
get_client_resource(UAContext * ua,int32_t jobtype)435 CLIENT *get_client_resource(UAContext *ua, int32_t jobtype)
436 {
437 CLIENT *client = NULL;
438 int i;
439
440 for (i=1; i<ua->argc; i++) {
441 if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
442 strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
443 if (!acl_access_client_ok(ua, ua->argv[i], jobtype)) {
444 break;
445 }
446 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
447 if (client) {
448 return client;
449 }
450 ua->error_msg(_("Error: Client resource %s does not exist.\n"), ua->argv[i]);
451 break;
452 }
453 }
454 return select_client_resource(ua, jobtype);
455 }
456
457 /*
458 * Select a schedule to enable or disable
459 */
select_enable_disable_schedule_resource(UAContext * ua,bool enable)460 SCHED *select_enable_disable_schedule_resource(UAContext *ua, bool enable)
461 {
462 char name[MAX_NAME_LENGTH];
463 SCHED *sched;
464
465 LockRes();
466 start_prompt(ua, _("The defined Schedule resources are:\n"));
467 foreach_res(sched, R_SCHEDULE) {
468 if (!acl_access_ok(ua, Schedule_ACL, sched->name())) {
469 continue;
470 }
471 if (sched->is_enabled() == enable) { /* Already enabled/disabled? */
472 continue; /* yes, skip */
473 }
474 add_prompt(ua, sched->name());
475 }
476 UnlockRes();
477 if (do_prompt(ua, _("Schedule"), _("Select Schedule resource"), name, sizeof(name)) < 0) {
478 return NULL;
479 }
480 sched = (SCHED *)GetResWithName(R_SCHEDULE, name);
481 return sched;
482 }
483
484
485 /* Scan what the user has entered looking for:
486 *
487 * client=<client-name>
488 *
489 * if error or not found, put up a list of client DBRs
490 * to choose from.
491 *
492 * returns: 0 on error
493 * 1 on success and fills in CLIENT_DBR
494 */
get_client_dbr(UAContext * ua,CLIENT_DBR * cr,int32_t jobtype)495 bool get_client_dbr(UAContext *ua, CLIENT_DBR *cr, int32_t jobtype)
496 {
497 int i;
498
499 if (cr->Name[0]) { /* If name already supplied */
500 if (db_get_client_record(ua->jcr, ua->db, cr)) {
501 return 1;
502 }
503 ua->error_msg(_("Could not find Client %s: ERR=%s"), cr->Name, db_strerror(ua->db));
504 }
505 for (i=1; i<ua->argc; i++) {
506 if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
507 strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
508 if (!acl_access_client_ok(ua, ua->argv[i], jobtype)) {
509 break;
510 }
511 bstrncpy(cr->Name, ua->argv[i], sizeof(cr->Name));
512 if (!db_get_client_record(ua->jcr, ua->db, cr)) {
513 ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), ua->argv[i],
514 db_strerror(ua->db));
515 cr->ClientId = 0;
516 break;
517 }
518 return 1;
519 }
520 }
521 if (!select_client_dbr(ua, cr, jobtype)) { /* try once more by proposing a list */
522 return 0;
523 }
524 return 1;
525 }
526
527 /*
528 * Select a Client record from the catalog
529 * Returns 1 on success
530 * 0 on failure
531 */
select_client_dbr(UAContext * ua,CLIENT_DBR * cr,int32_t jobtype)532 bool select_client_dbr(UAContext *ua, CLIENT_DBR *cr, int32_t jobtype)
533 {
534 CLIENT_DBR ocr;
535 char name[MAX_NAME_LENGTH];
536 int num_clients, i;
537 uint32_t *ids;
538
539
540 cr->ClientId = 0;
541 if (!db_get_client_ids(ua->jcr, ua->db, &num_clients, &ids)) {
542 ua->error_msg(_("Error obtaining client ids. ERR=%s\n"), db_strerror(ua->db));
543 return 0;
544 }
545 if (num_clients <= 0) {
546 ua->error_msg(_("No clients defined. You must run a job before using this command.\n"));
547 return 0;
548 }
549
550 start_prompt(ua, _("Defined Clients:\n"));
551 for (i=0; i < num_clients; i++) {
552 ocr.ClientId = ids[i];
553 if (!db_get_client_record(ua->jcr, ua->db, &ocr) ||
554 !acl_access_client_ok(ua, ocr.Name, jobtype)) {
555 continue;
556 }
557 add_prompt(ua, ocr.Name);
558 }
559 free(ids);
560 if (do_prompt(ua, _("Client"), _("Select the Client"), name, sizeof(name)) < 0) {
561 return 0;
562 }
563 memset(&ocr, 0, sizeof(ocr));
564 bstrncpy(ocr.Name, name, sizeof(ocr.Name));
565
566 if (!db_get_client_record(ua->jcr, ua->db, &ocr)) {
567 ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), name, db_strerror(ua->db));
568 return 0;
569 }
570 memcpy(cr, &ocr, sizeof(ocr));
571 return 1;
572 }
573
574 /* Scan what the user has entered looking for:
575 *
576 * argk=<pool-name>
577 *
578 * where argk can be : pool, recyclepool, scratchpool, nextpool etc..
579 *
580 * if error or not found, put up a list of pool DBRs
581 * to choose from.
582 *
583 * returns: false on error
584 * true on success and fills in POOL_DBR
585 */
get_pool_dbr(UAContext * ua,POOL_DBR * pr,const char * argk)586 bool get_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
587 {
588 if (pr->Name[0]) { /* If name already supplied */
589 if (db_get_pool_numvols(ua->jcr, ua->db, pr) &&
590 acl_access_ok(ua, Pool_ACL, pr->Name)) {
591 return true;
592 }
593 ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), pr->Name, db_strerror(ua->db));
594 }
595 if (!select_pool_dbr(ua, pr, argk)) { /* try once more */
596 return false;
597 }
598 return true;
599 }
600
601 /*
602 * Select a Pool record from catalog
603 * argk can be pool, recyclepool, scratchpool etc..
604 */
select_pool_dbr(UAContext * ua,POOL_DBR * pr,const char * argk)605 bool select_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
606 {
607 POOL_DBR opr;
608 char name[MAX_NAME_LENGTH];
609 int num_pools, i;
610 uint32_t *ids = NULL;
611
612 for (i=1; i<ua->argc; i++) {
613 if (strcasecmp(ua->argk[i], argk) == 0 && ua->argv[i] &&
614 acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
615 bstrncpy(pr->Name, ua->argv[i], sizeof(pr->Name));
616 if (!db_get_pool_numvols(ua->jcr, ua->db, pr)) {
617 ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), ua->argv[i],
618 db_strerror(ua->db));
619 pr->PoolId = 0;
620 break;
621 }
622 return true;
623 }
624 }
625
626 pr->PoolId = 0;
627 if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
628 ua->error_msg(_("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
629 return 0;
630 }
631 if (num_pools <= 0) {
632 ua->error_msg(_("No pools defined. Use the \"create\" command to create one.\n"));
633 if (ids) {
634 free(ids);
635 }
636 return false;
637 }
638
639 start_prompt(ua, _("Defined Pools:\n"));
640 if (bstrcmp(argk, NT_("recyclepool"))) {
641 add_prompt(ua, _("*None*"));
642 }
643 for (i=0; i < num_pools; i++) {
644 opr.PoolId = ids[i];
645 if (!db_get_pool_numvols(ua->jcr, ua->db, &opr) ||
646 !acl_access_ok(ua, Pool_ACL, opr.Name)) {
647 continue;
648 }
649 add_prompt(ua, opr.Name);
650 }
651 free(ids);
652 if (do_prompt(ua, _("Pool"), _("Select the Pool"), name, sizeof(name)) < 0) {
653 return false;
654 }
655
656 bmemset(&opr, 0, sizeof(opr));
657 /* *None* is only returned when selecting a recyclepool, and in that case
658 * the calling code is only interested in opr.Name, so then we can leave
659 * pr as all zero.
660 */
661 if (!bstrcmp(name, _("*None*"))) {
662 bstrncpy(opr.Name, name, sizeof(opr.Name));
663
664 if (!db_get_pool_numvols(ua->jcr, ua->db, &opr)) {
665 ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), name, db_strerror(ua->db));
666 return false;
667 }
668 }
669
670 memcpy((void*)pr, &opr, sizeof(opr));
671 return true;
672 }
673
674 /*
675 * Select a Pool and a Media (Volume) record from the database
676 */
select_pool_and_media_dbr(UAContext * ua,POOL_DBR * pr,MEDIA_DBR * mr)677 int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr)
678 {
679
680 if (!select_media_dbr(ua, mr)) {
681 return 0;
682 }
683 bmemset(pr, 0, sizeof(POOL_DBR));
684 pr->PoolId = mr->PoolId;
685 if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
686 ua->error_msg("%s", db_strerror(ua->db));
687 return 0;
688 }
689 if (!acl_access_ok(ua, Pool_ACL, pr->Name)) {
690 ua->error_msg(_("No access to Pool \"%s\"\n"), pr->Name);
691 return 0;
692 }
693 return 1;
694 }
695
696 /* Select a Media (Volume) record from the database */
select_media_dbr(UAContext * ua,MEDIA_DBR * mr)697 int select_media_dbr(UAContext *ua, MEDIA_DBR *mr)
698 {
699 int i;
700 int ret = 0;
701 POOLMEM *err = get_pool_memory(PM_FNAME);
702 *err=0;
703
704 mr->clear();
705 i = find_arg_with_value(ua, "volume");
706 if (i >= 0) {
707 if (is_name_valid(ua->argv[i], &err)) {
708 bstrncpy(mr->VolumeName, ua->argv[i], sizeof(mr->VolumeName));
709 } else {
710 goto bail_out;
711 }
712 }
713 if (mr->VolumeName[0] == 0) {
714 POOL_DBR pr;
715 bmemset(&pr, 0, sizeof(pr));
716 /* Get the pool from pool=<pool-name> */
717 if (!get_pool_dbr(ua, &pr)) {
718 goto bail_out;
719 }
720 mr->PoolId = pr.PoolId;
721 db_list_media_records(ua->jcr, ua->db, mr, prtit, ua, HORZ_LIST);
722 if (!get_cmd(ua, _("Enter a Volume name or *MediaId: "))) {
723 goto bail_out;
724 }
725 if (ua->cmd[0] == '*' && is_a_number(ua->cmd+1)) {
726 mr->MediaId = str_to_int64(ua->cmd+1);
727 } else if (is_name_valid(ua->cmd, &err)) {
728 bstrncpy(mr->VolumeName, ua->cmd, sizeof(mr->VolumeName));
729 } else {
730 goto bail_out;
731 }
732 }
733
734 if (!db_get_media_record(ua->jcr, ua->db, mr)) {
735 pm_strcpy(err, db_strerror(ua->db));
736 goto bail_out;
737 }
738 ret = 1;
739
740 bail_out:
741 if (!ret && *err) {
742 ua->error_msg("%s", err);
743 }
744 free_pool_memory(err);
745 return ret;
746 }
747
748
749 /*
750 * Select a pool resource from prompt list
751 */
select_pool_resource(UAContext * ua)752 POOL *select_pool_resource(UAContext *ua)
753 {
754 char name[MAX_NAME_LENGTH];
755 POOL *pool;
756
757 start_prompt(ua, _("The defined Pool resources are:\n"));
758 LockRes();
759 foreach_res(pool, R_POOL) {
760 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
761 add_prompt(ua, pool->name());
762 }
763 }
764 UnlockRes();
765 if (do_prompt(ua, _("Pool"), _("Select Pool resource"), name, sizeof(name)) < 0) {
766 return NULL;
767 }
768 pool = (POOL *)GetResWithName(R_POOL, name);
769 return pool;
770 }
771
772
773 /*
774 * If you are thinking about using it, you
775 * probably want to use select_pool_dbr()
776 * or get_pool_dbr() above.
777 */
get_pool_resource(UAContext * ua)778 POOL *get_pool_resource(UAContext *ua)
779 {
780 POOL *pool = NULL;
781 int i;
782
783 i = find_arg_with_value(ua, "pool");
784 if (i >= 0 && acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
785 pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
786 if (pool) {
787 return pool;
788 }
789 ua->error_msg(_("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]);
790 }
791 return select_pool_resource(ua);
792 }
793
794 /*
795 * List all jobs and ask user to select one
796 */
select_job_dbr(UAContext * ua,JOB_DBR * jr)797 static int select_job_dbr(UAContext *ua, JOB_DBR *jr)
798 {
799 db_list_job_records(ua->jcr, ua->db, jr, prtit, ua, HORZ_LIST);
800 if (!get_pint(ua, _("Enter the JobId to select: "))) {
801 return 0;
802 }
803 jr->JobId = ua->int64_val;
804 if (!db_get_job_record(ua->jcr, ua->db, jr)) {
805 ua->error_msg("%s", db_strerror(ua->db));
806 return 0;
807 }
808 return jr->JobId;
809
810 }
811
812
813 /* Scan what the user has entered looking for:
814 *
815 * jobid=nn
816 *
817 * if error or not found, put up a list of Jobs
818 * to choose from.
819 *
820 * returns: 0 on error
821 * JobId on success and fills in JOB_DBR
822 */
get_job_dbr(UAContext * ua,JOB_DBR * jr)823 int get_job_dbr(UAContext *ua, JOB_DBR *jr)
824 {
825 int i;
826
827 for (i=1; i<ua->argc; i++) {
828 if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0 && ua->argv[i]) {
829 jr->JobId = 0;
830 bstrncpy(jr->Job, ua->argv[i], sizeof(jr->Job));
831 } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0 && ua->argv[i]) {
832 jr->JobId = str_to_int64(ua->argv[i]);
833 jr->Job[0] = 0;
834 } else {
835 continue;
836 }
837 if (!db_get_job_record(ua->jcr, ua->db, jr)) {
838 ua->error_msg(_("Could not find Job \"%s\": ERR=%s"), ua->argv[i],
839 db_strerror(ua->db));
840 jr->JobId = 0;
841 break;
842 }
843 return jr->JobId;
844 }
845
846 jr->JobId = 0;
847 jr->Job[0] = 0;
848
849 for (i=1; i<ua->argc; i++) {
850 if ((strcasecmp(ua->argk[i], NT_("jobname")) == 0 ||
851 strcasecmp(ua->argk[i], NT_("job")) == 0) && ua->argv[i]) {
852 jr->JobId = 0;
853 bstrncpy(jr->Name, ua->argv[i], sizeof(jr->Name));
854 break;
855 }
856 }
857 if (!select_job_dbr(ua, jr)) { /* try once more */
858 return 0;
859 }
860 return jr->JobId;
861 }
862
863 /*
864 * Implement unique set of prompts
865 */
start_prompt(UAContext * ua,const char * msg)866 void start_prompt(UAContext *ua, const char *msg)
867 {
868 if (ua->max_prompts == 0) {
869 ua->max_prompts = 10;
870 ua->prompt = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
871 ua->unique = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
872 }
873 ua->num_prompts = 1;
874 ua->prompt[0] = bstrdup(msg);
875 ua->unique[0] = NULL;
876 }
877
878 /*
879 * Add to prompts -- keeping them unique by name
880 */
add_prompt(UAContext * ua,const char * prompt,char * unique)881 void add_prompt(UAContext *ua, const char *prompt, char *unique)
882 {
883 int i;
884 if (ua->num_prompts == ua->max_prompts) {
885 ua->max_prompts *= 2;
886 ua->prompt = (char **)brealloc(ua->prompt, sizeof(char *) *
887 ua->max_prompts);
888 ua->unique = (char **)brealloc(ua->unique, sizeof(char *) *
889 ua->max_prompts);
890 }
891 for (i=1; i < ua->num_prompts; i++) {
892 if (strcmp(ua->prompt[i], prompt) == 0) {
893 return;
894 } else if (unique && strcmp(ua->unique[i], unique) == 0) {
895 return;
896 }
897 }
898 ua->prompt[ua->num_prompts] = bstrdup(prompt);
899 if (unique) {
900 ua->unique[ua->num_prompts++] = bstrdup(unique);
901 } else {
902 ua->unique[ua->num_prompts++] = NULL;
903 }
904 }
905
906 /*
907 * Display prompts and get user's choice
908 *
909 * Returns: -1 on error
910 * index base 0 on success, and choice
911 * is copied to prompt if not NULL
912 * prompt is set to the chosen prompt item string
913 */
do_prompt(UAContext * ua,const char * automsg,const char * msg,char * prompt,int max_prompt)914 int do_prompt(UAContext *ua, const char *automsg, const char *msg,
915 char *prompt, int max_prompt)
916 {
917 int i, item;
918 char pmsg[MAXSTRING];
919 BSOCK *user = ua->UA_sock;
920
921 if (prompt) {
922 *prompt = 0;
923 }
924 if (ua->num_prompts == 2) {
925 item = 1;
926 if (prompt) {
927 bstrncpy(prompt, ua->prompt[1], max_prompt);
928 }
929 ua->send_msg(_("Automatically selected %s: %s\n"), NPRTB(automsg), ua->prompt[1]);
930 goto done;
931 }
932 /* If running non-interactive, bail out */
933 if (ua->batch) {
934 /* First print the choices he wanted to make */
935 ua->send_msg(ua->prompt[0]);
936 for (i=1; i < ua->num_prompts; i++) {
937 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
938 }
939 /* Now print error message */
940 ua->send_msg(_("Your request has multiple choices for \"%s\". Selection is not possible in batch mode.\n"), automsg);
941 item = -1;
942 goto done;
943 }
944 if (ua->api) user->signal(BNET_START_SELECT);
945 ua->send_msg(ua->prompt[0]);
946 for (i=1; i < ua->num_prompts; i++) {
947 if (ua->api) {
948 ua->send_msg("%s", ua->prompt[i]);
949 } else {
950 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
951 }
952 }
953 if (ua->api) user->signal(BNET_END_SELECT);
954
955 for ( ;; ) {
956 /* First item is the prompt string, not the items */
957 if (ua->num_prompts == 1) {
958 ua->error_msg(_("Selection list for \"%s\" is empty!\n"), automsg);
959 item = -1; /* list is empty ! */
960 break;
961 }
962 if (ua->num_prompts == 2) {
963 item = 1;
964 ua->send_msg(_("Automatically selected: %s\n"), ua->prompt[1]);
965 if (prompt) {
966 bstrncpy(prompt, ua->prompt[1], max_prompt);
967 }
968 break;
969 } else {
970 sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
971 }
972 /* Either a . or an @ will get you out of the loop */
973 if (ua->api) user->signal(BNET_SELECT_INPUT);
974 if (!get_pint(ua, pmsg)) {
975 item = -1; /* error */
976 ua->info_msg(_("Selection aborted, nothing done.\n"));
977 break;
978 }
979 item = ua->pint32_val;
980 if (item < 1 || item >= ua->num_prompts) {
981 ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
982 continue;
983 }
984 if (prompt) {
985 bstrncpy(prompt, ua->prompt[item], max_prompt);
986 }
987 break;
988 }
989
990 done:
991 for (i=0; i < ua->num_prompts; i++) {
992 free(ua->prompt[i]);
993 if (ua->unique[i]) free(ua->unique[i]);
994 }
995 ua->num_prompts = 0;
996 return item>0 ? item-1 : item;
997 }
998
999 /*
1000 * Display prompts and get user's choice
1001 *
1002 * Returns: -1 on error
1003 * number of items selected and the choices are
1004 * copied to selected if not NULL
1005 * selected is an alist of the prompts chosen
1006 * Note! selected must already be initialized.
1007 */
do_alist_prompt(UAContext * ua,const char * automsg,const char * msg,alist * selected)1008 int do_alist_prompt(UAContext *ua, const char *automsg, const char *msg,
1009 alist *selected)
1010 {
1011 int i, item;
1012 char pmsg[MAXSTRING];
1013 BSOCK *user = ua->UA_sock;
1014 sellist sl;
1015
1016 /* First item is the prompt string, not the items */
1017 if (ua->num_prompts == 1) {
1018 ua->error_msg(_("Selection list for \"%s\" is empty!\n"), automsg);
1019 item = -1; /* list is empty ! */
1020 goto done;
1021 }
1022 if (ua->num_prompts == 2) {
1023 item = 1;
1024 selected->append(bstrdup(ua->prompt[1]));
1025 ua->send_msg(_("Automatically selected %s: %s\n"), automsg, ua->prompt[1]);
1026 goto done;
1027 }
1028 /* If running non-interactive, bail out */
1029 if (ua->batch) {
1030 /* First print the choices he wanted to make */
1031 ua->send_msg(ua->prompt[0]);
1032 for (i=1; i < ua->num_prompts; i++) {
1033 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
1034 }
1035 /* Now print error message */
1036 ua->send_msg(_("Your request has multiple choices for \"%s\". Selection is not possible in batch mode.\n"), automsg);
1037 item = -1;
1038 goto done;
1039 }
1040 if (ua->api) user->signal(BNET_START_SELECT);
1041 ua->send_msg(ua->prompt[0]);
1042 for (i=1; i < ua->num_prompts; i++) {
1043 if (ua->api) {
1044 ua->send_msg("%s", ua->prompt[i]);
1045 } else {
1046 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
1047 }
1048 }
1049 if (ua->api) user->signal(BNET_END_SELECT);
1050
1051 sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
1052
1053 for ( ;; ) {
1054 bool ok = true;
1055 /* Either a . or an @ will get you out of the loop */
1056 if (ua->api) user->signal(BNET_SELECT_INPUT);
1057
1058 if (!get_selection_list(ua, sl, pmsg, false)) {
1059 item = -1;
1060 break;
1061 }
1062
1063 if (sl.is_all()) {
1064 for (i=1; i < ua->num_prompts; i++) {
1065 selected->append(bstrdup(ua->prompt[i]));
1066 }
1067 } else {
1068 while ( (item = sl.next()) > 0) {
1069 if (item < 1 || item >= ua->num_prompts) {
1070 ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
1071 ok = false;
1072 break;
1073 }
1074 selected->append(bstrdup(ua->prompt[item]));
1075 }
1076 }
1077 if (ok) {
1078 item = selected->size();
1079 break;
1080 }
1081 }
1082
1083 done:
1084 for (i=0; i < ua->num_prompts; i++) {
1085 free(ua->prompt[i]);
1086 if (ua->unique[i]) free(ua->unique[i]);
1087 }
1088 ua->num_prompts = 0;
1089 return item;
1090 }
1091
1092
1093 /*
1094 * We scan what the user has entered looking for
1095 * storage=<storage-resource>
1096 * job=<job_name>
1097 * jobid=<jobid>
1098 * ? (prompt him with storage list)
1099 * <some-error> (prompt him with storage list)
1100 *
1101 * If use_default is set, we assume that any keyword without a value
1102 * is the name of the Storage resource wanted.
1103 */
get_storage_resource(UAContext * ua,bool use_default,bool unique)1104 STORE *get_storage_resource(UAContext *ua, bool use_default, bool unique)
1105 {
1106 char store_name[MAX_NAME_LENGTH];
1107 STORE *store = NULL;
1108 int jobid;
1109 JCR *jcr;
1110 int i;
1111 char ed1[50];
1112 *store_name = 0;
1113
1114 for (i=1; i<ua->argc; i++) {
1115 if (use_default && !ua->argv[i]) {
1116 /* Ignore slots, scan and barcode(s) keywords */
1117 if (strcasecmp("scan", ua->argk[i]) == 0 ||
1118 strcasecmp("barcode", ua->argk[i]) == 0 ||
1119 strcasecmp("barcodes", ua->argk[i]) == 0 ||
1120 strcasecmp("slots", ua->argk[i]) == 0) {
1121 continue;
1122 }
1123 /* Default argument is storage (except in enable/disable command) */
1124 if (store_name[0]) {
1125 ua->error_msg(_("Storage name given twice.\n"));
1126 return NULL;
1127 }
1128 bstrncpy(store_name, ua->argk[i], sizeof(store_name));
1129 if (store_name[0] == '?') {
1130 *store_name = 0;
1131 break;
1132 }
1133 } else {
1134 if (strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
1135 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
1136 bstrncpy(store_name, NPRTB(ua->argv[i]), sizeof(store_name));
1137
1138 } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
1139 jobid = str_to_int64(ua->argv[i]);
1140 if (jobid <= 0) {
1141 ua->error_msg(_("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
1142 return NULL;
1143 }
1144 if (!(jcr=get_jcr_by_id(jobid))) {
1145 ua->error_msg(_("JobId %s is not running.\n"), edit_int64(jobid, ed1));
1146 return NULL;
1147 }
1148 if (jcr->wstore) {
1149 bstrncpy(store_name, jcr->wstore->name(), sizeof(store_name));
1150 }
1151 free_jcr(jcr);
1152
1153 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0 ||
1154 strcasecmp(ua->argk[i], NT_("jobname")) == 0) {
1155 if (!ua->argv[i]) {
1156 ua->error_msg(_("Expecting job=xxx, got: %s.\n"), ua->argk[i]);
1157 return NULL;
1158 }
1159 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
1160 ua->error_msg(_("Job \"%s\" is not running.\n"), ua->argv[i]);
1161 return NULL;
1162 }
1163 if (jcr->wstore) {
1164 bstrncpy(store_name, jcr->wstore->name(), sizeof(store_name));
1165 }
1166 free_jcr(jcr);
1167
1168 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
1169 if (!ua->argv[i]) {
1170 ua->error_msg(_("Expecting ujobid=xxx, got: %s.\n"), ua->argk[i]);
1171 return NULL;
1172 }
1173 if ((jcr=get_jcr_by_full_name(ua->argv[i]))) {
1174 if (jcr->wstore) {
1175 bstrncpy(store_name, jcr->wstore->name(), sizeof(store_name));
1176 }
1177 free_jcr(jcr);
1178 }
1179 }
1180 if (store_name[0]) {
1181 break; /* We can stop the loop if we have something */
1182 }
1183 }
1184 }
1185
1186 if (store_name[0] != 0) {
1187 store = (STORE *)GetResWithName(R_STORAGE, store_name);
1188 if (!store && strcmp(store_name, "storage") != 0) {
1189 /* Looks that the first keyword of the line was not a storage name, make
1190 * sure that it's not "storage=" before we print the following message
1191 */
1192 ua->error_msg(_("Storage resource \"%s\": not found\n"), store_name);
1193 }
1194 }
1195 if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
1196 store = NULL;
1197 }
1198 /* No keywords found, so present a selection list */
1199 if (!store) {
1200 store = select_storage_resource(ua, unique);
1201 }
1202 return store;
1203 }
1204
1205 /* Get drive that we are working with for this storage */
get_storage_drive(UAContext * ua,STORE * store)1206 int get_storage_drive(UAContext *ua, STORE *store)
1207 {
1208 int i, drive = -1;
1209 /* Get drive for autochanger if possible */
1210 i = find_arg_with_value(ua, "drive");
1211 if (i >=0) {
1212 drive = atoi(ua->argv[i]);
1213 } else if (store && store->autochanger) {
1214 /* If our structure is not set ask SD for # drives */
1215 if (store->drives == 0) {
1216 store->drives = get_num_drives_from_SD(ua);
1217 }
1218 /* If only one drive, default = 0 */
1219 if (store->drives == 1) {
1220 drive = 0;
1221 } else {
1222 /* Ask user to enter drive number */
1223 ua->cmd[0] = 0;
1224 if (!get_cmd(ua, _("Enter autochanger drive[0]: "))) {
1225 drive = -1; /* None */
1226 } else {
1227 drive = atoi(ua->cmd);
1228 }
1229 }
1230 }
1231 return drive;
1232 }
1233
1234 /* Get slot that we are working with for this storage */
get_storage_slot(UAContext * ua,STORE * store)1235 int get_storage_slot(UAContext *ua, STORE *store)
1236 {
1237 int i, slot = -1;
1238 /* Get slot for autochanger if possible */
1239 i = find_arg_with_value(ua, "slot");
1240 if (i >=0) {
1241 slot = atoi(ua->argv[i]);
1242 } else if (store && store->autochanger) {
1243 /* Ask user to enter slot number */
1244 ua->cmd[0] = 0;
1245 if (!get_cmd(ua, _("Enter autochanger slot: "))) {
1246 slot = -1; /* None */
1247 } else {
1248 slot = atoi(ua->cmd);
1249 }
1250 }
1251 return slot;
1252 }
1253
1254
1255
1256 /*
1257 * Scan looking for mediatype=
1258 *
1259 * if not found or error, put up selection list
1260 *
1261 * Returns: 0 on error
1262 * 1 on success, MediaType is set
1263 */
get_media_type(UAContext * ua,char * MediaType,int max_media)1264 int get_media_type(UAContext *ua, char *MediaType, int max_media)
1265 {
1266 STORE *store;
1267 int i;
1268
1269 i = find_arg_with_value(ua, "mediatype");
1270 if (i >= 0) {
1271 bstrncpy(MediaType, ua->argv[i], max_media);
1272 return 1;
1273 }
1274
1275 start_prompt(ua, _("Media Types defined in conf file:\n"));
1276 LockRes();
1277 foreach_res(store, R_STORAGE) {
1278 if (store->is_enabled()) {
1279 add_prompt(ua, store->media_type);
1280 }
1281 }
1282 UnlockRes();
1283 return (do_prompt(ua, _("Media Type"), _("Select the Media Type"), MediaType, max_media) < 0) ? 0 : 1;
1284 }
1285
get_level_code_from_name(const char * level_name)1286 int get_level_code_from_name(const char *level_name)
1287 {
1288 int ret = 0;
1289 if (!level_name) {
1290 return ret;
1291 }
1292 for (int i=0; joblevels[i].level_name; i++) {
1293 if (strcasecmp(level_name, joblevels[i].level_name) == 0) {
1294 ret = joblevels[i].level;
1295 break;
1296 }
1297 }
1298 return ret;
1299 }
1300
get_level_from_name(JCR * jcr,const char * level_name)1301 bool get_level_from_name(JCR *jcr, const char *level_name)
1302 {
1303 int level = get_level_code_from_name(level_name);
1304 if (level > 0) {
1305 jcr->setJobLevel(level);
1306 return true;
1307 }
1308 return false;
1309 }
1310
count_running_jobs(UAContext * ua)1311 static int count_running_jobs(UAContext *ua)
1312 {
1313 int tjobs = 0; /* total # number jobs */
1314 int njobs = 0;
1315 JCR *jcr;
1316 /* Count Jobs running */
1317 foreach_jcr(jcr) {
1318 if (jcr->is_internal_job()) { /* this is us */
1319 continue;
1320 }
1321 tjobs++; /* count of all jobs */
1322 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1323 continue; /* skip not authorized */
1324 }
1325 njobs++; /* count of authorized jobs */
1326 }
1327 endeach_jcr(jcr);
1328
1329 if (njobs == 0) { /* no authorized */
1330 if (tjobs == 0) {
1331 ua->send_msg(_("No Jobs running.\n"));
1332 } else {
1333 ua->send_msg(_("None of your jobs are running.\n"));
1334 }
1335 }
1336 return njobs;
1337 }
1338
1339
1340 /* Get a list of running jobs
1341 * "reason" is used in user messages
1342 * can be: cancel, limit, ...
1343 * Returns: -1 on error
1344 * nb of JCR on success (should be free_jcr() after)
1345 */
select_running_jobs(UAContext * ua,alist * jcrs,const char * reason)1346 int select_running_jobs(UAContext *ua, alist *jcrs, const char *reason)
1347 {
1348 int i;
1349 JCR *jcr = NULL;
1350 int njobs = 0;
1351 char JobName[MAX_NAME_LENGTH];
1352 char temp[256];
1353 alist *selected = NULL;
1354
1355 for (i=1; i<ua->argc; i++) {
1356 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
1357 sellist sl;
1358 int32_t JobId;
1359
1360 if (!ua->argv[i]) {
1361 ua->error_msg(_("No value given for \"jobid\".\n"));
1362 goto bail_out;
1363 }
1364 if (!sl.set_string(ua->argv[i], true)) {
1365 ua->send_msg("%s", sl.get_errmsg());
1366 goto bail_out;
1367 }
1368 foreach_sellist(JobId, &sl) {
1369 jcr = get_jcr_by_id(JobId);
1370 if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1371 jcrs->append(jcr);
1372 } else if (jcr) {
1373 ua->error_msg(_("Unauthorized command from this console "
1374 "for JobId=%d.\n"), JobId);
1375 free_jcr(jcr);
1376 } else {
1377 ua->warning_msg(_("Warning Job JobId=%d is not running.\n"), JobId);
1378 }
1379 }
1380 if (jcrs->size() == 0) {
1381 goto bail_out; /* If we did not find specified jobid, get out */
1382 }
1383 break;
1384
1385 /* TODO: might want to implement filters (client, status, etc...) */
1386 } else if (strcasecmp(ua->argk[i], NT_("all")) == 0) {
1387 foreach_jcr(jcr) {
1388 if (jcr->is_internal_job()) { /* Do not cancel consoles */
1389 continue;
1390 }
1391 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1392 continue; /* skip not authorized */
1393 }
1394 jcr->inc_use_count();
1395 jcrs->append(jcr);
1396 }
1397 endeach_jcr(jcr);
1398
1399 /* If we have something and no "yes" on command line, get confirmation */
1400 if (jcrs->size() > 0 && find_arg(ua, NT_("yes")) < 0) {
1401 char nbuf[1000];
1402 bsnprintf(nbuf, sizeof(nbuf), _("Confirm %s of %d Job%s (yes/no): "),
1403 reason, jcrs->size(), jcrs->size()>1?"s":"");
1404 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
1405 foreach_alist(jcr, jcrs) {
1406 jcr->dec_use_count();
1407 }
1408 jcrs->destroy();
1409 goto bail_out;
1410 }
1411 }
1412 if (jcrs->size() == 0) {
1413 goto bail_out; /* If we did not find specified jobid, get out */
1414 }
1415 break;
1416
1417 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1418 if (!ua->argv[i]) {
1419 ua->error_msg(_("No value given for \"job\".\n"));
1420 goto bail_out;
1421 }
1422 jcr = get_jcr_by_partial_name(ua->argv[i]);
1423
1424 if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1425 jcrs->append(jcr);
1426
1427 } else if (jcr) {
1428 if (jcr->job) {
1429 ua->error_msg(_("Unauthorized command from this console "
1430 "for job=%s.\n"), ua->argv[i]);
1431 }
1432 free_jcr(jcr);
1433
1434 } else {
1435 ua->warning_msg(_("Warning Job %s is not running.\n"), ua->argv[i]);
1436 }
1437 if (jcrs->size() == 0) {
1438 goto bail_out; /* If we did not find specified jobid, get out */
1439 }
1440 break;
1441
1442 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
1443 if (!ua->argv[i]) {
1444 ua->error_msg(_("No value given for \"ujobid\".\n"));
1445 goto bail_out;
1446 }
1447 jcr = get_jcr_by_full_name(ua->argv[i]);
1448
1449 if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1450 jcrs->append(jcr);
1451
1452 } else if (jcr) {
1453 if (jcr->job) {
1454 ua->error_msg(_("Unauthorized command from this console "
1455 "for ujobid=%s.\n"), ua->argv[i]);
1456 }
1457 free_jcr(jcr);
1458
1459 } else {
1460 ua->warning_msg(_("Warning Job %s is not running.\n"), ua->argv[i]);
1461 }
1462 if (jcrs->size() == 0) {
1463 goto bail_out; /* If we did not find specified jobid, get out */
1464 }
1465 break;
1466 }
1467 }
1468
1469 if (jcrs->size() == 0) {
1470 /*
1471 * If we still do not have a jcr,
1472 * throw up a list and ask the user to select one.
1473 */
1474 char *item;
1475 char buf[1000];
1476 njobs = count_running_jobs(ua);
1477 if (njobs == 0) {
1478 goto bail_out;
1479 }
1480 start_prompt(ua, _("Select Job(s):\n"));
1481 foreach_jcr(jcr) {
1482 char ed1[50];
1483 if (jcr->is_internal_job()) { /* this is us */
1484 continue;
1485 }
1486 bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
1487 add_prompt(ua, buf);
1488 }
1489 endeach_jcr(jcr);
1490 bsnprintf(temp, sizeof(temp), _("Choose Job list to %s"), _(reason));
1491 selected = New(alist(5, owned_by_alist));
1492 if (do_alist_prompt(ua, _("Job"), temp, selected) < 0) {
1493 goto bail_out;
1494 }
1495 /* Possibly ask for confirmation */
1496 if (selected->size() > 0 && find_arg(ua, NT_("yes")) < 0) {
1497 char nbuf[1000];
1498 foreach_alist(item, selected) {
1499 ua->send_msg("%s\n", item);
1500 }
1501 bsnprintf(nbuf, sizeof(nbuf), _("Confirm %s of %d Job%s (yes/no): "),
1502 reason, selected->size(), selected->size()>1?"s":"");
1503 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
1504 goto bail_out;
1505 }
1506 }
1507
1508 foreach_alist(item, selected) {
1509 if (sscanf(item, "JobId=%d Job=%127s", &njobs, JobName) != 2) {
1510 ua->warning_msg(_("Job \"%s\" not found.\n"), item);
1511 continue;
1512 }
1513 jcr = get_jcr_by_full_name(JobName);
1514 if (jcr) {
1515 jcrs->append(jcr);
1516 } else {
1517 ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);
1518 }
1519 }
1520 }
1521 bail_out:
1522 if (selected) delete selected;
1523 return jcrs->size();
1524 }
1525
1526 /* Small helper to scan storage daemon commands and search for volumes */
scan_storage_cmd(UAContext * ua,const char * cmd,bool allfrompool,int * drive,MEDIA_DBR * mr,POOL_DBR * pr,const char ** action,char * storage,int * nb,uint32_t ** results)1527 int scan_storage_cmd(UAContext *ua, const char *cmd,
1528 bool allfrompool, /* Choose to select a specific volume or not */
1529 int *drive, /* Drive number */
1530 MEDIA_DBR *mr, /* Media Record, can have options already filled */
1531 POOL_DBR *pr, /* Pool Record */
1532 const char **action, /* action= argument, can be NULL if not relevant */
1533 char *storage, /* Storage name, must be MAX_NAME_LENGTH long */
1534 int *nb, /* Number of media found */
1535 uint32_t **results) /* List of MediaId */
1536 {
1537 bool allpools=false, has_vol = false;;
1538 STORE *store;
1539
1540 *nb = 0;
1541 *results = NULL;
1542
1543 /* Optional parameters */
1544 if (drive) {
1545 *drive = 0;
1546 }
1547 if (storage) {
1548 *storage = 0;
1549 }
1550
1551 /* Look at arguments */
1552 for (int i=1; i<ua->argc; i++) {
1553 if (strcasecmp(ua->argk[i], NT_("allpools")) == 0) {
1554 allpools = true;
1555
1556 } else if (strcasecmp(ua->argk[i], NT_("allfrompool")) == 0) {
1557 allfrompool = true;
1558
1559 } else if (strcasecmp(ua->argk[i], NT_("volume")) == 0
1560 && is_name_valid(ua->argv[i], NULL)) {
1561 bstrncpy(mr->VolumeName, ua->argv[i], sizeof(mr->VolumeName));
1562 has_vol = true;
1563
1564 } else if (strcasecmp(ua->argk[i], NT_("mediatype")) == 0
1565 && ua->argv[i]) {
1566 bstrncpy(mr->MediaType, ua->argv[i], sizeof(mr->MediaType));
1567
1568 } else if (strcasecmp(ua->argk[i], NT_("drive")) == 0 && ua->argv[i]) {
1569 if (drive) {
1570 *drive = atoi(ua->argv[i]);
1571 } else {
1572 ua->warning_msg(_("Invalid argument \"drive\".\n"));
1573 }
1574
1575 } else if (strcasecmp(ua->argk[i], NT_("action")) == 0
1576 && is_name_valid(ua->argv[i], NULL)) {
1577
1578 if (action) {
1579 *action = ua->argv[i];
1580 } else {
1581 ua->warning_msg(_("Invalid argument \"action\".\n"));
1582 }
1583 }
1584 }
1585
1586 if (storage) {
1587 /* Choose storage */
1588 ua->jcr->wstore = store = get_storage_resource(ua, false);
1589 if (!store) {
1590 goto bail_out;
1591 }
1592 bstrncpy(storage, store->dev_name(), MAX_NAME_LENGTH);
1593 set_storageid_in_mr(store, mr);
1594 }
1595
1596 if (!open_db(ua)) {
1597 Dmsg0(100, "Can't open db\n");
1598 goto bail_out;
1599 }
1600
1601 /*
1602 * Look for all volumes that are enabled
1603 */
1604 mr->Enabled = 1;
1605
1606 if (allfrompool && !has_vol) { /* We need a list of volumes */
1607
1608 /* We don't take all pools and we don't have a volume in argument,
1609 * so we need to choose a pool
1610 */
1611 if (!allpools) {
1612 /* force pool selection */
1613 POOL *pool = get_pool_resource(ua);
1614
1615 if (!pool) {
1616 Dmsg0(100, "Can't get pool resource\n");
1617 goto bail_out;
1618 }
1619 bstrncpy(pr->Name, pool->name(), sizeof(pr->Name));
1620 if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
1621 Dmsg0(100, "Can't get pool record\n");
1622 goto bail_out;
1623 }
1624 mr->PoolId = pr->PoolId;
1625 }
1626
1627 if (!db_get_media_ids(ua->jcr, ua->db, mr, nb, results)) {
1628 Dmsg0(100, "No results from db_get_media_ids\n");
1629 goto bail_out;
1630 }
1631
1632 } else { /* We want a single volume */
1633 MEDIA_DBR mr2;
1634 if (!select_media_dbr(ua, &mr2)) {
1635 goto bail_out;
1636 }
1637 mr->MediaId = mr2.MediaId;
1638 mr->Recycle = mr2.Recycle; /* Should be the same to find a result */
1639 if (!db_get_media_ids(ua->jcr, ua->db, mr, nb, results)) {
1640 Dmsg0(100, "No results from db_get_media_ids\n");
1641 goto bail_out;
1642 }
1643 }
1644
1645 if (*nb == 0) {
1646 goto bail_out;
1647 }
1648 return 1;
1649
1650 bail_out:
1651 if (!*nb) {
1652 ua->send_msg(_("No Volumes found to perform the command.\n"));
1653 }
1654
1655 close_db(ua);
1656 ua->jcr->wstore = NULL;
1657 if (*results) {
1658 free(*results);
1659 *results = NULL;
1660 }
1661 *nb = 0;
1662 return 0;
1663 }
1664
1665 /* Small helper to scan storage daemon commands and search for volumes */
scan_truncate_cmd(UAContext * ua,const char * cmd,char * truncate_opt)1666 int scan_truncate_cmd(UAContext *ua, const char *cmd,
1667 char *truncate_opt) /* truncate option, must be MAX_NAME_LENGTH long */
1668 {
1669 *truncate_opt = 0;
1670
1671 /* Look at arguments */
1672 for (int i=1; i<ua->argc; i++) {
1673 if (strcasecmp(ua->argk[i], NT_("truncate")) == 0
1674 && is_name_valid(ua->argv[i], NULL)) {
1675 bstrncpy(truncate_opt, ua->argv[i], MAX_NAME_LENGTH);
1676 }
1677 }
1678 return 1;
1679 }
1680