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 incoming connections",
58 	"  -o test-daemon -- launch session for incoming 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
process_args(int argc,char * argv[])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
handle_long_option(char * str)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
set_job_mode(int mode)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
usage(void)708 usage (void)
709 {
710 	error_byebye ("bad usage, use -help");
711 }
712 
713 void
help(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
ndmjob_version_info(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
dump_settings(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
copy_args_expanding_macros(int argc,char * argv[],char * av[],int max_ac)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
lookup_and_snarf(char * av[],char * name)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
snarf_macro(char * av[],char * val)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 }
992