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