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