1 /*
2  * Copyright (c) 1998,1999,2000
3  *      Traakan, Inc., Los Altos, CA
4  *      All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * Project:  NDMJOB
31  * Ident:    $Id: $
32  *
33  * Description:
34  *
35  */
36 
37 #include "lib/version.h"
38 #include "ndmjob.h"
39 
40 
41 char* help_text[] = {
42     "ndmjob -v  -- print version and configuration info",
43     "ndmjob OPTIONS ... FILES ...",
44     "      FILES can be FILEPATH or NEWFILEPATH=OLDFILEPATH with",
45     "      '=' quoted by backslash.",
46     "Modes (exactly one required)",
47 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
48     "  -c       -- create a backup",
49     "  -t       -- list contents on a backup",
50     "  -x       -- extract from a backup",
51     "  -l       -- list media labels",
52     "  -q       -- query agent(s)",
53     "  -Z       -- clean up zee mess (put robot right)",
54     "  -o init-labels -- init media labels",
55 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
56 #ifndef NDMOS_EFFECT_NO_SERVER_AGENTS
57     "  -o daemon      -- launch session for incomming connections",
58     "  -o tape-limit=SIZE -- specify the length, in bytes of the simulated "
59     "tape",
60 #endif /* !NDMOS_EFFECT_NO_SERVER_AGENTS */
61 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
62     "  -o rewind      -- rewind tape in drive, need -T and -f",
63     "  -o eject       -- eject tape in drive, need -T and -f",
64     "  -o move        -- cmd ROBOT to move tape, need -o from/to-addr",
65     "  -o import=ELEMADDR -- cmd ROBOT to import tape from door to slot",
66     "  -o export=ELEMADDR -- cmd ROBOT to export tape from slot to door",
67     "  -o load=ELEMADDR   -- cmd ROBOT to load tape from slot to drive",
68     "  -o unload[=ELEMADDR]-- cmd ROBOT to unload tape, sometimes auto",
69     "  -o init-elem-status -- cmd ROBOT to rescan tape slots",
70 #ifndef NDMOS_OPTION_NO_TEST_AGENTS
71     "  -o test-tape   -- test TAPE agent NDMP_TAPE functions",
72     "  -o test-mover  -- test TAPE agent NDMP_MOVER functions",
73     "  -o test-data   -- test DATA agent NDMP_DATA functions",
74 #endif /* NDMOS_OPTION_NO_TEST_AGENTS */
75     "  -o time-limit=N",
76     "           -- check for reply within specified seconds (default 360)",
77     "  -o swap-connect -- perform DATA LISTEN & MOVER CONNECT",
78 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
79     "General and Logging parameters",
80     " --MACRO   -- expand MACRO from ndmjob-args file",
81     "  -d N     -- set debug level to N (default 0, max 9)",
82     "  -L FILE  -- set log file (default stderr, includes debug)",
83     "  -n       -- no-op, just show how args were handled",
84     "  -v       -- verbose, same messages as -d1 to standard out",
85     "  -S       -- Perform DATA listen and MOVER CONNECT",
86     "  -p PORT  -- NDMP port to listen on (for -o daemon)",
87     "  -o no-time-stamps -- log w/o time stamps, makes diff(1)s easier",
88     "  -o config-file=PATH",
89     "           -- set config file ($NDMJOB_CONFIG, "
90     "/usr/local/etc/ndmjob.conf)",
91 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
92     "CONTROL of DATA agent parameters",
93     "  -D AGENT -- data agent (see AGENT below)",
94     "  -B TYPE  -- set backup format (default tar)",
95     "  -C DIR   -- change directory on data agent before operation",
96     "  -e PATN  -- exclude files matching pattern",
97     "  -E NAME=VAL  -- add to data agent environment",
98     "  -F FILE  -- add FILE arg (used to not confuse arg processing)",
99     "  -o load-files=PATHNAME",
100     "           -- load FILES from the specified PATHANME",
101     "  -o import=ELEMADDR -- cmd ROBOT to import tape from door to slot",
102 
103     "  -I FILE  -- set output index file, enable FILEHIST (default to log)",
104     "  -J FILE  -- set input index file (default none)",
105     "  -U USER  -- user rights to use on data agent",
106     "  -o rules=RULES -- apply RULES to job (see RULES below)",
107     "CONTROL of TAPE agent parameters",
108     "  -T AGENT -- tape agent if different than -D (see AGENT below)",
109     "  -b N     -- block size in 512-byte records (default 20)",
110     "  -f TAPE  -- tape drive device name",
111     "  -o tape-timeout=SECONDS",
112     "           -- how long to retry opening drive (await tape)",
113     "  -o use-eject=N",
114     "           -- use eject when unloading tapes (default 0)",
115     "  -o tape-tcp=hostname:port -- send the data directly to that tcp port.",
116     "  -o D-agent-fd=<fd> -- file descriptor to read the -D agent.",
117     "CONTROL of ROBOT agent parameters",
118     "  -R AGENT -- robot agent if different than -T (see AGENT below)",
119     "  -m MEDIA -- add entry to media table (see below)",
120     "  -o tape-addr=ELEMADDR",
121     "           -- robot element address of drive (default first)",
122     "  -o tape-scsi=SCSI",
123     "           -- tape drive SCSI target (see below)",
124     "  -o robot-timeout=SECONDS",
125     "           -- how long to retry moving tapes (await robot)",
126     "  -r SCSI  -- tape robot target (see below)",
127     "",
128     "Definitions:",
129     "  AGENT      HOST[:PORT][/FLAGS][,USERNAME,PASSWORD]",
130     "    FLAGS    [234][ntm] 2->v2 3->v3 4->v4  n->AUTH_NONE t->TEXT m->MD5",
131     "  AGENT      .  (resident)",
132     "  SCSI       DEVICE[,[CNUM,]SID[,LUN]]",
133     "  MEDIA      [TAPE-LABEL][+SKIP-FILEMARKS][@ELEMADDR][/WINDOW-SIZE]",
134     "",
135     "RULES:",
136 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
137     0};
138 
139 
process_args(int argc,char * argv[])140 int process_args(int argc, char* argv[])
141 {
142   int c;
143   char options[100];
144   char** pp;
145   char* p;
146   char* op;
147   char* av[1000];
148   int ac = 0;
149 
150   progname = argv[0];
151 
152   if (argc == 2 && strcmp(argv[1], "-help") == 0) {
153     help();
154     exit(0);
155   }
156 
157   if (argc == 2 && strcmp(argv[1], "-v") == 0) {
158     ndmjob_version_info();
159     exit(0);
160   }
161 
162   if (argc < 2) usage();
163 
164   o_config_file = "./ndmjob.conf";
165   if ((p = getenv("NDMJOB_CONF")) != 0) { o_config_file = p; }
166 
167   op = options;
168   for (pp = help_text; *pp; pp++) {
169     p = *pp;
170 
171     if (strncmp(p, "  -", 3) != 0) continue;
172     if (p[3] == 'o') continue; /* don't include o: repeatedly */
173     *op++ = p[3];
174     if (p[5] != ' ') *op++ = ':';
175   }
176   *op++ = 'o'; /* include o: once */
177   *op++ = ':';
178   *op = 0;
179 
180   ac = copy_args_expanding_macros(argc, argv, av, 1000);
181 
182   while ((c = getopt(ac, av, options)) != EOF) {
183     switch (c) {
184       case 'o':
185         handle_long_option(optarg);
186         break;
187 
188 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
189       case 'c': /* -c       -- create a backup */
190         set_job_mode(NDM_JOB_OP_BACKUP);
191         break;
192 
193       case 't': /* -t       -- list contents on a backup */
194         set_job_mode(NDM_JOB_OP_TOC);
195         break;
196 
197       case 'x': /* -x       -- extract from a backup */
198         set_job_mode(NDM_JOB_OP_EXTRACT);
199         break;
200 
201       case 'l': /* -l       -- list media labels */
202         set_job_mode(NDM_JOB_OP_LIST_LABELS);
203         break;
204 
205       case 'q': /* -q       -- query agent(s) */
206         set_job_mode(NDM_JOB_OP_QUERY_AGENTS);
207         break;
208 
209       case 'Z': /* -Z       -- clean up zee mess */
210         set_job_mode(NDM_JOB_OP_REMEDY_ROBOT);
211         break;
212 
213       case 'B': /* -B TYPE  -- set backup format (default tar) */
214         if (B_bu_type) { error_byebye("more than one of -B"); }
215         B_bu_type = optarg;
216         break;
217 
218       case 'b': /* -b N -- block size in 512-byte records (20) */
219       {
220         long b = strtol(optarg, NULL, 10);
221         if (b < 1 || b > 200 || (!b && EINVAL == errno)) {
222           error_byebye("bad -b option");
223         }
224         b_bsize = (int)b;
225         break;
226       }
227 
228       case 'p': /* -p N -- port number for daemon mode (10000) */
229       {
230         long p = strtol(optarg, NULL, 10);
231         if (p < 1 || p > 65535 || (!p && EINVAL == errno)) {
232           error_byebye("bad -p option");
233         }
234         p_ndmp_port = (int)p;
235         break;
236       }
237 
238       case 'C': /* -C DIR   -- change directory on data agent */
239         C_chdir = optarg;
240         break;
241 
242       case 'D': /* -D AGENT -- data agent (see below) */
243         if (AGENT_GIVEN(D_data_agent)) { error_byebye("more than one of -D"); }
244         if (ndmagent_from_str(&D_data_agent, optarg)) {
245           error_byebye("bad -D argument");
246         }
247         break;
248 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
249 
250       case 'd': /* -d N     -- set debug level to N */
251         d_debug = atoi(optarg);
252         break;
253 
254 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
255       case 'E': /* -E NAME=VAL  -- add to data agent environment */
256         if (E_environment.n_env >= NDM_MAX_ENV) {
257           error_byebye("too many of -E");
258         }
259         {
260           char* p;
261           ndmp9_pval pv;
262 
263           p = optarg;
264           pv.name = p;
265           while (*p && *p != '=') p++;
266           if (*p != '=') { error_byebye("missing value in -E"); }
267           *p++ = 0;
268           pv.value = p;
269           ndma_store_env_list(&E_environment, &pv);
270         }
271         break;
272 
273       case 'e': /* -e PATN  -- exclude files matching pattern */
274         if (n_e_exclude_pattern >= MAX_EXCLUDE_PATTERN) {
275           error_byebye("too many of -e");
276         }
277         e_exclude_pattern[n_e_exclude_pattern++] = optarg;
278         break;
279 
280       case 'F': /* -F FILE -- add to list of files */
281         if (n_file_arg >= MAX_FILE_ARG) { error_byebye("too many FILE args"); }
282         if (strchr(optarg, '=')) {
283           char* p = strchr(optarg, '=');
284           *p++ = 0;
285           file_arg[n_file_arg] = p;
286           file_arg_new[n_file_arg] = optarg;
287           n_file_arg++;
288         } else {
289           file_arg[n_file_arg] = optarg;
290           file_arg_new[n_file_arg] = 0;
291           n_file_arg++;
292         }
293 
294         break;
295 
296       case 'f': /* -f TAPE  -- tape drive device name */
297         if (f_tape_device) { error_byebye("more than one of -f"); }
298         f_tape_device = optarg;
299         break;
300 
301       case 'I': /* -I FILE  -- output index, enab FILEHIST */
302         if (I_index_file) { error_byebye("more than one of -I"); }
303         I_index_file = optarg;
304         break;
305 
306       case 'J': /* -J FILE  -- input index */
307         if (J_index_file) { error_byebye("more than one of -J"); }
308         J_index_file = optarg;
309         break;
310 
311       case 'L': /* -L FILE  -- set log file (def stderr, incl. dbg) */
312         if (L_log_file) { error_byebye("more than one of -L"); }
313         L_log_file = optarg;
314         if (d_debug < 2) d_debug = 2;
315         break;
316 
317       case 'm': /* -m MEDIA -- add entry to media table (see below) */
318         if (m_media.n_media >= NDM_MAX_MEDIA) {
319           error_byebye("too many of -m");
320         }
321         {
322           struct ndmmedia me;
323 
324           if (ndmmedia_from_str(&me, optarg)) {
325             error_byebye("bad -m argument: %s", optarg);
326           }
327 
328           ndma_clone_media_entry(&m_media, &me);
329         }
330         break;
331 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
332 
333       case 'n': /* -n       -- no-op, show how args were handled */
334         n_noop++;
335         break;
336 
337 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
338       case 'R': /* -R AGENT -- robot agent if different than -T */
339         if (AGENT_GIVEN(R_robot_agent)) { error_byebye("more than one of -R"); }
340         if (ndmagent_from_str(&R_robot_agent, optarg)) {
341           error_byebye("bad -R argument");
342         }
343         break;
344 
345       case 'r': /* -r SCSI  -- tape robot target (see below) */
346         if (ROBOT_GIVEN()) { error_byebye("more than one of -r"); }
347         r_robot_target = NDMOS_API_MALLOC(sizeof(struct ndmscsi_target));
348         if (!r_robot_target) { error_byebye("No memory for robot target"); }
349         if (ndmscsi_target_from_str(r_robot_target, optarg)) {
350           error_byebye("bad -r argument");
351         }
352         break;
353 
354       case 'T': /* -T AGENT -- tape agent if different than -D */
355         if (AGENT_GIVEN(T_tape_agent)) { error_byebye("more than one of -T"); }
356         if (ndmagent_from_str(&T_tape_agent, optarg)) {
357           error_byebye("bad -T argument");
358         }
359         break;
360 
361       case 'U': /* -U USER  -- user rights to use on data agent */
362         if (U_user) { error_byebye("more than one of -U"); }
363         U_user = optarg;
364         break;
365 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
366 
367       case 'v': /* -v       -- verbose */
368         v_verbose++;
369         break;
370 
371       default:
372         usage();
373         break;
374     }
375   }
376 
377   if (n_noop && d_debug > 1) {
378     int i;
379 
380     for (i = 0; i < ac; i++) { printf(" av[%d] = '%s'\n", i, av[i]); }
381   }
382 
383   if (!the_mode) {
384 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
385     printf("must specify one of -[ctxlqZ] or other mode\n");
386 #else  /* !NDMOS_OPTION_NO_CONTROL_AGENT */
387     printf("must specify -o daemon\n");
388 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
389     usage();
390   }
391 
392 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
393   for (c = optind; c < ac; c++) {
394     if (n_file_arg >= MAX_FILE_ARG) { error_byebye("too many file args"); }
395     if (strchr(av[c], '=')) {
396       char* p = strchr(av[c], '=');
397       *p++ = 0;
398       file_arg[n_file_arg] = p;
399       file_arg_new[n_file_arg] = av[c];
400     } else {
401       file_arg[n_file_arg] = av[c];
402       file_arg_new[n_file_arg] = 0;
403     }
404     n_file_arg++;
405   }
406 
407   if (o_load_files_file) {
408     char buf[2048];
409     FILE* fp;
410     static struct load_file_entry {
411       struct load_file_entry* next;
412       char name[1];
413     }* load_files_list = 0;
414 
415     /* clean up old load_files_list */
416     while (load_files_list) {
417       struct load_file_entry* p;
418       p = load_files_list;
419       load_files_list = p->next;
420       p->next = 0;
421       free(p);
422     }
423 
424     fp = fopen(o_load_files_file, "r");
425     if (!fp) {
426       perror(o_load_files_file);
427       error_byebye("can't open load_files file %s", o_load_files_file);
428       /* no return */
429     }
430     while (fgets(buf, sizeof buf, fp) != NULL) {
431       char *bp = buf, *p, *ep;
432       int len, slen;
433       struct load_file_entry* lfe;
434 
435       bp = buf;
436       while (*bp && isspace(*bp)) bp++;
437       ep = bp;
438       while (*ep && (*ep != '\n') && (*ep != '\r')) ep++;
439       *ep = 0;
440       if (bp >= ep) continue;
441 
442       if (n_file_arg >= MAX_FILE_ARG) { error_byebye("too many FILE args"); }
443 
444       /* allocate memory */
445       slen = (ep - bp) + 2;
446       len = sizeof(struct load_file_entry) + (ep - bp) + 1;
447       lfe = malloc(len);
448       if (lfe == 0) {
449         error_byebye("can't allocate entry for load_files file line %s", bp);
450         /* no return */
451       }
452       lfe->next = 0;
453 
454       /* see if we have destination */
455       if ((p = strchr(bp, '=')) != 0) {
456         int plen;
457         char ch = *p;
458         *p = 0;
459 
460         /* double conversion -- assume the strings shrink */
461         plen = (p - bp);
462         ndmcstr_to_str(p, &lfe->name[plen + 2], slen - plen - 2);
463         ndmcstr_to_str(bp, lfe->name, plen + 1);
464         file_arg[n_file_arg] = &lfe->name[plen + 2];
465         file_arg_new[n_file_arg] = lfe->name;
466         *p = ch;
467       } else {
468         /* simple conversion copy */
469         ndmcstr_to_str(bp, lfe->name, slen - 1);
470         file_arg[n_file_arg] = lfe->name;
471         file_arg_new[n_file_arg] = 0;
472       }
473       n_file_arg++;
474 
475       /* link into list */
476       lfe->next = load_files_list;
477       load_files_list = lfe;
478     }
479 
480     fclose(fp);
481   } /* end of load_files option */
482 
483   if (!B_bu_type) B_bu_type = "tar";
484 
485   /*
486    * A quirk of the NDMP protocol is that the robot
487    * should be accessed over a different connection
488    * than the TAPE agent. (See the Workflow document).
489    */
490   if (ROBOT_GIVEN()) {
491     if (!AGENT_GIVEN(R_robot_agent)) {
492       if (AGENT_GIVEN(T_tape_agent))
493         R_robot_agent = T_tape_agent;
494       else
495         R_robot_agent = D_data_agent;
496 
497       if (!AGENT_GIVEN(R_robot_agent)) {
498         error_byebye("-r given, can't determine -R");
499       }
500     }
501   } else if (AGENT_GIVEN(R_robot_agent)) {
502     if (the_mode != NDM_JOB_OP_QUERY_AGENTS) { error_byebye("-R but no -r"); }
503   }
504 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
505 
506   return 0;
507 }
508 
509 struct ndmp_enum_str_table mode_long_name_table[] = {
510 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
511     {"init-labels", NDM_JOB_OP_INIT_LABELS},
512 #ifndef NDMOS_OPTION_NO_TEST_AGENTS
513     {"test-tape", NDM_JOB_OP_TEST_TAPE},
514     {"test-mover", NDM_JOB_OP_TEST_MOVER},
515     {"test-data", NDM_JOB_OP_TEST_DATA},
516 #endif /* NDMOS_OPTION_NO_TEST_AGENTS */
517     {"eject", NDM_JOB_OP_EJECT_TAPE},
518     {"rewind", NDM_JOB_OP_REWIND_TAPE},
519     {"move", NDM_JOB_OP_MOVE_TAPE},
520     {"import", NDM_JOB_OP_IMPORT_TAPE},
521     {"export", NDM_JOB_OP_EXPORT_TAPE},
522     {"load", NDM_JOB_OP_LOAD_TAPE},
523     {"unload", NDM_JOB_OP_UNLOAD_TAPE},
524     {"init-elem-status", NDM_JOB_OP_INIT_ELEM_STATUS},
525     {"-c", NDM_JOB_OP_BACKUP},
526     {"-t", NDM_JOB_OP_TOC},
527     {"-x", NDM_JOB_OP_EXTRACT},
528     {"-l", NDM_JOB_OP_LIST_LABELS},
529     {"-q", NDM_JOB_OP_QUERY_AGENTS},
530     {"-Z", NDM_JOB_OP_REMEDY_ROBOT},
531 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
532 #ifndef NDMOS_EFFECT_NO_SERVER_AGENTS
533     {"daemon", NDM_JOB_OP_DAEMON},
534 #endif /* !NDMOS_EFFECT_NO_SERVER_AGENTS */
535     {0}};
536 
537 
handle_long_option(char * str)538 int handle_long_option(char* str)
539 {
540   char* name;
541   char* value;
542   int mode;
543 
544   name = str;
545   for (value = str; *value; value++)
546     if (*value == '=') break;
547   if (*value)
548     *value++ = 0;
549   else
550     value = 0;
551 
552   if (ndmp_enum_from_str(&mode, name, mode_long_name_table)) {
553     set_job_mode(mode);
554 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
555     if (value) {
556       switch (mode) {
557         default: /* value part ignored */
558           break;
559 
560         case NDM_JOB_OP_LOAD_TAPE:
561         case NDM_JOB_OP_EXPORT_TAPE:
562           o_from_addr = atoi(value);
563           break;
564         case NDM_JOB_OP_UNLOAD_TAPE:
565         case NDM_JOB_OP_IMPORT_TAPE:
566           o_to_addr = atoi(value);
567           break;
568       }
569     }
570   } else if (strcmp(name, "swap-connect") == 0) {
571     /* value part ignored */
572     o_swap_connect++;
573   } else if (strcmp(name, "time-limit") == 0) {
574     if (!value) {
575       o_time_limit = 5 * 60;
576     } else {
577       o_time_limit = atoi(value);
578     }
579   } else if (strcmp(name, "use-eject") == 0) {
580     if (!value) {
581       o_use_eject = 1;
582     } else {
583       o_use_eject = atoi(value);
584     }
585   } else if (strcmp(name, "tape-addr") == 0 && value) {
586     o_tape_addr = atoi(value);
587   } else if (strcmp(name, "from-addr") == 0 && value) {
588     o_from_addr = atoi(value);
589   } else if (strcmp(name, "to-addr") == 0 && value) {
590     o_to_addr = atoi(value);
591   } else if (strcmp(name, "tape-timeout") == 0 && value) {
592     o_tape_timeout = atoi(value);
593   } else if (strcmp(name, "robot-timeout") == 0 && value) {
594     o_robot_timeout = atoi(value);
595   } else if (strcmp(name, "tape-scsi") == 0 && value) {
596     o_tape_scsi = NDMOS_API_MALLOC(sizeof(struct ndmscsi_target));
597     if (!o_tape_scsi) { error_byebye("No memory for tape-scsi target"); }
598     if (ndmscsi_target_from_str(o_tape_scsi, value)) {
599       error_byebye("bad -otape-scsi argument");
600     }
601   } else if (strcmp(name, "rules") == 0 && value) {
602     if (!value) error_byebye("missing RULES in -o rules");
603     o_rules = value;
604   } else if (strcmp(name, "load-files") == 0 && value) {
605     o_load_files_file = value;
606 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
607   } else if (strcmp(name, "no-time-stamps") == 0) {
608     /* value part ignored */
609     o_no_time_stamps++;
610   } else if (strcmp(name, "config-file") == 0 && value) {
611     o_config_file = value;
612   } else if (strcmp(name, "tape-tcp") == 0 && value) {
613     o_tape_tcp = value;
614   } else if (strcmp(name, "D-agent-fd") == 0 && value) {
615     char d_agent[1025];
616     int fd = atoi(value);
617     int size;
618 
619     if (AGENT_GIVEN(D_data_agent)) {
620       error_byebye("more than one of -D or -D-agent-fd");
621     }
622 
623     size = read(fd, d_agent, 1024);
624     d_agent[size] = '\0';
625     if (size > 0 && d_agent[size - 1] == '\n') d_agent[size - 1] = '\0';
626     close(fd);
627     if (ndmagent_from_str(&D_data_agent, d_agent)) {
628       error_byebye("bad -D-agent-fd argument");
629     }
630   } else if (strcmp(name, "tape-limit") == 0) {
631     if (!value) {
632       error_byebye("tape-limit argument is required");
633     } else {
634       o_tape_limit = atoi(value);
635     }
636   } else {
637     if (value) value[-1] = '=';
638     error_byebye("unknown/bad long option -o%s", str);
639   }
640 
641   if (value) value[-1] = '=';
642   return 0;
643 }
644 
set_job_mode(int mode)645 void set_job_mode(int mode)
646 {
647   if (the_mode) {
648     printf("more than one -[ctxlqZ] or other mode");
649     usage();
650   }
651   the_mode = mode;
652 }
653 
usage(void)654 void usage(void) { error_byebye("bad usage, use -help"); }
655 
help(void)656 void help(void)
657 {
658   char* p;
659   char** pp;
660 
661   for (pp = help_text; *pp; pp++) {
662     p = *pp;
663     printf("%s\n", p);
664   }
665 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
666   help_rules();
667 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
668 }
669 
ndmjob_version_info(void)670 void ndmjob_version_info(void)
671 {
672   char vbuf[100];
673   char abuf[100];
674   char obuf[5];
675 
676   *vbuf = 0;
677 #ifndef NDMOS_OPTION_NO_NDMP2
678   strcat(vbuf, " NDMPv2");
679 #endif /* !NDMOS_OPTION_NO_NDMP2 */
680 #ifndef NDMOS_OPTION_NO_NDMP3
681   strcat(vbuf, " NDMPv3");
682 #endif /* !NDMOS_OPTION_NO_NDMP3 */
683 #ifndef NDMOS_OPTION_NO_NDMP4
684   strcat(vbuf, " NDMPv4");
685 #endif /* !NDMOS_OPTION_NO_NDMP4 */
686 
687   *abuf = 0;
688 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
689   strcat(abuf, " CONTROL");
690 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
691 #ifndef NDMOS_OPTION_NO_DATA_AGENT
692   strcat(abuf, " DATA");
693 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
694 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
695   strcat(abuf, " TAPE");
696 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
697 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT
698   strcat(abuf, " ROBOT");
699 #endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */
700 
701   obuf[0] = (char)(NDMOS_ID >> 24);
702   obuf[1] = (char)(NDMOS_ID >> 16);
703   obuf[2] = (char)(NDMOS_ID >> 8);
704   obuf[3] = (char)(NDMOS_ID >> 0);
705   obuf[4] = 0;
706 
707   printf("%s (%s)\n", NDMOS_CONST_PRODUCT_NAME, NDMOS_CONST_VENDOR_NAME);
708 
709   printf("  Rev %s LIB:%d.%d/%s OS:%s (%s)\n", kBareosVersionStrings.Full,
710          NDMJOBLIB_VERSION, NDMJOBLIB_RELEASE, kBareosVersionStrings.Full,
711          NDMOS_CONST_NDMOS_REVISION, obuf);
712 
713   printf("  Agents:   %s\n", abuf);
714   printf("  Protocols:%s\n", vbuf);
715 }
716 
717 
dump_settings(void)718 void dump_settings(void)
719 {
720   int i;
721   char buf[100];
722   struct ndmmedia* me;
723   struct ndm_env_entry* env;
724 
725   *buf = 0; /* shuts up -Wall */
726   i = 0;    /* shuts up -Wall */
727 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
728   switch (the_mode) {
729     case 'x':
730       printf("mode = x (extract)\n");
731       break;
732 
733     case 'c':
734       printf("mode = c (create)\n");
735       break;
736 
737     case 't':
738       printf("mode = t (table-of-contents)\n");
739       break;
740 
741     case 'q':
742       printf("mode = q (query-agents)\n");
743       break;
744 
745     default:
746       printf("mode = %c (unknown)\n", the_mode);
747       break;
748   }
749 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
750 
751   if (v_verbose)
752     printf("verbose %d\n", v_verbose);
753   else
754     printf("not verbose\n");
755 
756 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
757   printf("blocksize = %d (%dkb, %db)\n", b_bsize, b_bsize / 2, b_bsize * 512);
758 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
759 
760   if (d_debug)
761     printf("debug %d\n", d_debug);
762   else
763     printf("no debug\n");
764 
765 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
766   printf("Data agent %s\n", D_data_agent.host);
767   if (AGENT_GIVEN(T_tape_agent))
768     printf("Tape agent %s\n", T_tape_agent.host);
769   else
770     printf("Tape agent same as data agent\n");
771 
772   printf("tape device %s\n", f_tape_device);
773 
774   printf("tape format %s\n", B_bu_type);
775 
776   if (C_chdir)
777     printf("Chdir %s\n", C_chdir);
778   else
779     printf("Chdir / (default)\n");
780 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
781 
782   if (L_log_file)
783     printf("Log to file %s\n", L_log_file);
784   else
785     printf("Log to stderr (default)\n");
786 
787 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
788   if (I_index_file) {
789     if (strcmp(I_index_file, "-") == 0) {
790       printf("Index to log, enable FILEHIST\n");
791     } else {
792       printf("Index to file %s, enable FILEHIST\n", I_index_file);
793     }
794   } else {
795     printf("Index off (default), no FILEHIST\n");
796   }
797 
798   printf("%d media entries\n", m_media.n_media);
799   for (me = m_media.head; me; me = me->next) {
800     ndmmedia_to_str(me, buf);
801     printf("  %2d: %s\n", i, buf);
802   }
803 
804   printf("%d excludes\n", n_e_exclude_pattern);
805   for (i = 0; i < n_e_exclude_pattern; i++) {
806     printf("  %2d: %s\n", i, e_exclude_pattern[i]);
807   }
808 
809   printf("%d environment values\n", E_environment.n_env);
810   for (env = E_environment.head; env; env = env->next) {
811     printf("  %2d: %s=%s\n", i, env->pval.name, env->pval.value);
812   }
813 
814   printf("%d files\n", n_file_arg);
815   for (i = 0; i < n_file_arg; i++) {
816     printf(
817         "  %2d: @%-8lld %s\n", i,
818         nlist[i].fh_info.valid ? nlist[i].fh_info.value : NDMP9_INVALID_U_QUAD,
819         file_arg[i]);
820   }
821 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
822 
823   return;
824 }
825 
copy_args_expanding_macros(int argc,char * argv[],char * av[],int max_ac)826 int copy_args_expanding_macros(int argc, char* argv[], char* av[], int max_ac)
827 {
828   int i, ac = 0, rc;
829   char* arg;
830   char* p;
831   char env_name[50];
832 
833   /* expand macros */
834   for (i = 0; i < argc; i++) {
835     arg = argv[i];
836 
837     if (strncmp(arg, "--", 2) != 0 || arg[2] == 0) {
838       av[ac++] = arg;
839       continue;
840     }
841 
842     snprintf(env_name, sizeof(env_name), "NDMJOB_%s", arg + 2);
843     if ((p = getenv(env_name)) != 0) {
844       ac += snarf_macro(&av[ac], p);
845       continue;
846     }
847 
848     rc = lookup_and_snarf(&av[ac], arg + 2);
849     if (rc < 0) { error_byebye("bad arg macro --%s", arg + 2); }
850     ac += rc;
851   }
852 
853   av[ac] = 0;
854 
855   return ac;
856 }
857 
lookup_and_snarf(char * av[],char * name)858 int lookup_and_snarf(char* av[], char* name)
859 {
860   FILE* fp;
861   char buf[512];
862   char* argfile;
863   int ac = 0;
864   int found = 0;
865 
866   argfile = o_config_file;
867   assert(argfile);
868 
869   fp = fopen(argfile, "r");
870   if (!fp) {
871     perror(argfile);
872     error_byebye("can't open config file %s", argfile);
873   }
874 
875   while (ndmstz_getstanza(fp, buf, sizeof buf) >= 0) {
876     if (buf[0] == '-' && buf[1] == '-' && strcmp(buf + 2, name) == 0) {
877       found = 1;
878       break;
879     }
880   }
881 
882   if (found) {
883     while (ndmstz_getline(fp, buf, sizeof buf) >= 0) {
884       if (*buf == 0) continue;
885       ac += snarf_macro(&av[ac], buf);
886     }
887   }
888 
889   fclose(fp);
890 
891   if (!found) return -1;
892 
893   return ac;
894 }
895 
snarf_macro(char * av[],char * val)896 int snarf_macro(char* av[], char* val)
897 {
898   char* p;
899   int ac = 0;
900   char* tmp_av[100];
901   int tmp_ac = 0;
902 
903   p = NDMOS_API_STRDUP(val);
904   if (!p) { error_byebye("bad strdup macro"); }
905   for (;;) {
906     while (isspace((int)*p)) p++;
907     if (*p == 0) break;
908     tmp_av[tmp_ac++] = p;
909     while (*p && !isspace((int)*p)) p++;
910     if (*p) *p++ = 0;
911   }
912 
913   ac = copy_args_expanding_macros(tmp_ac, tmp_av, av, 100);
914 
915   return ac;
916 }
917