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