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