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 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
42 
43 
44 int
build_job(void)45 build_job (void)
46 {
47 	struct ndm_job_param *	job = &the_job;
48 	int			i, rc, n_err;
49 	char			errbuf[100];
50 
51 	NDMOS_MACRO_ZEROFILL(job);
52 
53 	args_to_job ();
54 
55 	ndma_job_auto_adjust (job);
56 
57 	if (o_rules)
58 		apply_rules (job, o_rules);
59 
60 	i = n_err = 0;
61 	do {
62 		rc = ndma_job_audit (job, errbuf, i);
63 		if (rc > n_err || rc < 0) {
64 			ndmjob_log (0, "error: %s", errbuf);
65 		}
66 		n_err = rc;
67 	} while (i++ < n_err);
68 
69 	if (n_err) {
70 		error_byebye ("can't proceed");
71 		/* no return */
72 	}
73 
74 	return 0;
75 }
76 
77 
78 int
args_to_job(void)79 args_to_job (void)
80 {
81 	struct ndm_job_param *	job = &the_job;
82 	int			i;
83 
84 	switch (the_mode) {
85 	case NDM_JOB_OP_QUERY_AGENTS:
86 	case NDM_JOB_OP_INIT_LABELS:
87 	case NDM_JOB_OP_LIST_LABELS:
88 	case NDM_JOB_OP_REMEDY_ROBOT:
89 	case NDM_JOB_OP_TEST_TAPE:
90 	case NDM_JOB_OP_TEST_MOVER:
91 	case NDM_JOB_OP_TEST_DATA:
92 	case NDM_JOB_OP_REWIND_TAPE:
93 	case NDM_JOB_OP_EJECT_TAPE:
94 	case NDM_JOB_OP_MOVE_TAPE:
95 	case NDM_JOB_OP_IMPORT_TAPE:
96 	case NDM_JOB_OP_EXPORT_TAPE:
97 	case NDM_JOB_OP_LOAD_TAPE:
98 	case NDM_JOB_OP_UNLOAD_TAPE:
99 	case NDM_JOB_OP_INIT_ELEM_STATUS:
100 		break;
101 
102 	case NDM_JOB_OP_BACKUP:
103 		args_to_job_backup_env();
104 		break;
105 
106 	case NDM_JOB_OP_TOC:
107 		args_to_job_recover_env();
108 		args_to_job_recover_nlist();
109 		if (J_index_file) {
110 			jndex_doit();
111 			jndex_merge_environment();
112 		}
113 		break;
114 
115 	case NDM_JOB_OP_EXTRACT:
116 		args_to_job_recover_env();
117 		args_to_job_recover_nlist();
118 		jndex_doit();
119 		jndex_merge_environment();
120 		break;
121 
122 	case 'D':		/* -o daemon */
123 		return 0;
124 
125 	default:
126 		printf ("mode -%c not implemented yet\n", the_mode);
127 		break;
128 	}
129 	job->operation = the_mode;
130 
131 	/* DATA agent */
132 	job->data_agent  = D_data_agent;
133 	job->bu_type = B_bu_type;
134 	for (i = 0; i < nn_E_environment; i++)
135 		job->env_tab.env[i] = E_environment[i];
136 	job->env_tab.n_env = nn_E_environment;
137 	if (the_mode == NDM_JOB_OP_EXTRACT || the_mode == NDM_JOB_OP_TOC) {
138 	        for (i = 0; (i < n_file_arg) && (i < NDM_MAX_NLIST); i++) {
139 			job->nlist_tab.nlist[i] = nlist[i];
140 			job->nlist_tab.nlist_new[i] = nlist_new[i];
141 			job->nlist_tab.n_nlist = i + 1;
142 		}
143 	}
144 	job->index_log.deliver = ndmjob_ixlog_deliver;
145 
146 	/* TAPE agent */
147 	job->tape_agent  = T_tape_agent;
148 	job->tape_device = f_tape_device;
149 	job->record_size = b_bsize * 512;
150 	job->tape_timeout = o_tape_timeout;
151 	job->use_eject = o_use_eject;
152 	job->tape_target = o_tape_scsi;
153 	job->tape_tcp = o_tape_tcp;
154 
155 	/* ROBOT agent */
156 	job->robot_agent = R_robot_agent;
157 	job->robot_target = r_robot_target;
158 	job->robot_timeout = o_robot_timeout;
159 	if (o_tape_addr >= 0) {
160 		job->drive_addr = o_tape_addr;
161 		job->drive_addr_given = 1;
162 	}
163 	if (o_from_addr >= 0) {
164 		job->from_addr = o_from_addr;
165 		job->from_addr_given = 1;
166 	}
167 	if (o_to_addr >= 0) {
168 		job->to_addr = o_to_addr;
169 		job->to_addr_given = 1;
170 	}
171 	if (ROBOT_GIVEN())
172 		job->have_robot = 1;
173 
174 	/* media */
175 	for (i = 0; i < n_m_media; i++)
176 		job->media_tab.media[i] = m_media[i];
177 	job->media_tab.n_media = n_m_media;
178 
179 	return 0;
180 }
181 
182 
183 int
args_to_job_backup_env(void)184 args_to_job_backup_env (void)
185 {
186 	int		n_env = n_E_environment;
187 	int		i;
188 
189 	if (C_chdir) {
190 		E_environment[n_env].name = "FILESYSTEM";
191 		E_environment[n_env].value = C_chdir;
192 		n_env++;
193 	}
194 
195 	E_environment[n_env].name = "HIST";
196 	E_environment[n_env].value = I_index_file ? "y" : "n";
197 	n_env++;
198 
199 	E_environment[n_env].name = "TYPE";
200 	E_environment[n_env].value = B_bu_type;
201 	n_env++;
202 
203 	if (U_user) {
204 		E_environment[n_env].name = "USER";
205 		E_environment[n_env].value = U_user;
206 		n_env++;
207 	}
208 
209 	for (i = 0; (i < n_e_exclude_pattern) && (n_env < NDM_MAX_ENV-2); i++) {
210 		E_environment[n_env].name = "EXCLUDE";
211 		E_environment[n_env].value = e_exclude_pattern[i];
212 		n_env++;
213 	}
214 	for (i = 0; (i < n_file_arg) && (n_env < NDM_MAX_ENV-1); i++) {
215 		E_environment[n_env].name = "FILES";
216 		E_environment[n_env].value = file_arg[i];
217 		n_env++;
218 	}
219 
220 	if (o_rules) {
221 		E_environment[n_env].name = "RULES";
222 		E_environment[n_env].value = o_rules;
223 	}
224 
225 	nn_E_environment = n_env;
226 
227 	return n_env;
228 }
229 
230 int
args_to_job_recover_env(void)231 args_to_job_recover_env (void)
232 {
233 	int		n_env = n_E_environment;
234 	int		i;
235 
236 	if (C_chdir) {
237 		E_environment[n_env].name = "PREFIX";
238 		E_environment[n_env].value = C_chdir;
239 		n_env++;
240 	}
241 
242 	E_environment[n_env].name = "HIST";
243 	E_environment[n_env].value = I_index_file ? "y" : "n";
244 	n_env++;
245 
246 	E_environment[n_env].name = "TYPE";
247 	E_environment[n_env].value = B_bu_type;
248 	n_env++;
249 
250 	if (U_user) {
251 		E_environment[n_env].name = "USER";
252 		E_environment[n_env].value = U_user;
253 		n_env++;
254 	}
255 
256 	for (i = 0; i < n_e_exclude_pattern; i++) {
257 		E_environment[n_env].name = "EXCLUDE";
258 		E_environment[n_env].value = e_exclude_pattern[i];
259 		n_env++;
260 	}
261 
262 	if (o_rules) {
263 		E_environment[n_env].name = "RULES";
264 		E_environment[n_env].value = o_rules;
265 	}
266 
267 	nn_E_environment = n_env;
268 
269 	/* file_arg[]s are done in nlist[] */
270 
271 	jndex_merge_environment ();
272 
273 	return nn_E_environment;
274 }
275 
276 void
normalize_name(char * name)277 normalize_name (char *name)
278 {
279 	char *		p = name;
280 
281 	while (*p) {
282 		if (*p == '/' && p[1] == '/') {
283 			strcpy (p, p+1);
284 			continue;
285 		}
286 		if (p[0] == '/' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) {
287 			strcpy (p, p+2);
288 			continue;
289 		}
290 
291 		p++;
292 	}
293 }
294 
295 int
args_to_job_recover_nlist(void)296 args_to_job_recover_nlist (void)
297 {
298 	int		not_found = 0;
299 	int		i, prefix_len, len;
300 	char *		dest;
301 
302 	if (C_chdir) {
303 		prefix_len = strlen (C_chdir) + 2;
304 	} else {
305 		prefix_len = 0;
306 	}
307 
308 	for (i = 0; (i < n_file_arg) && (i < NDM_MAX_NLIST); i++) {
309 	    if (file_arg_new[i]) {
310 		len = strlen (file_arg_new[i]) + prefix_len + 1;
311 
312 		dest = NDMOS_API_MALLOC (len);
313 		*dest = 0;
314 		if (C_chdir) {
315 			strcpy (dest, C_chdir);
316 		}
317 		if (file_arg_new[i][0] != '/') {
318 			strcat (dest, "/");
319 		}
320 		strcat (dest, file_arg_new[i]);
321 
322 		normalize_name (file_arg_new[i]);
323 		normalize_name (file_arg[i]);
324 		normalize_name (dest);
325 
326 		nlist[i].original_path = file_arg[i];
327 		nlist[i].destination_path = dest;
328 	    } else {
329 		len = strlen (file_arg[i]) + prefix_len + 1;
330 
331 		dest = NDMOS_API_MALLOC (len);
332 		*dest = 0;
333 		if (C_chdir) {
334 			strcpy (dest, C_chdir);
335 		}
336 		if (file_arg[i][0] != '/') {
337 			strcat (dest, "/");
338 		}
339 
340 		strcat (dest, file_arg[i]);
341 
342 		normalize_name (file_arg[i]);
343 		normalize_name (dest);
344 
345 		nlist[i].original_path = file_arg[i];
346 		nlist[i].destination_path = dest;
347 	    }
348 	}
349 
350 	return not_found;	/* should ALWAYS be 0 */
351 }
352 
353 
354 /*
355  * Index files are sequentially searched. They can be VERY big.
356  * There is a credible effort for efficiency here.
357  * Probably lots and lots and lots of room for improvement.
358  */
359 
360 FILE *		jndex_open (void);
361 
362 
363 int
jndex_doit(void)364 jndex_doit (void)
365 {
366 	FILE *		fp;
367 	int		rc;
368 
369 	fp = jndex_open();
370 	if (!fp) {
371 		/* error messages already given */
372 		return -1;
373 	}
374 
375 	ndmjob_log (1, "Processing input index (-J%s)", J_index_file);
376 
377 	if (n_file_arg > 0) {
378 		rc = ndmfhdb_add_fh_info_to_nlist (fp, nlist, n_file_arg);
379 		if (rc < 0) {
380 			/* toast one way or another */
381 		}
382 	}
383 
384 	jndex_fetch_post_backup_data_env(fp);
385 	jndex_fetch_post_backup_media(fp);
386 
387 	jndex_tattle();
388 
389 	if (jndex_audit_not_found ()) {
390 		ndmjob_log (1,
391 			"Warning: Missing index entries, valid file name(s)?");
392 	}
393 
394 	jndex_merge_media ();
395 
396 	return 0;
397 }
398 
399 FILE *
jndex_open(void)400 jndex_open (void)
401 {
402 	char		buf[256];
403 	FILE *		fp;
404 
405 	if (!J_index_file) {
406 		/* Hmmm. */
407 		ndmjob_log (1, "Warning: No -J input index?");
408 		return 0;
409 	}
410 
411 	ndmjob_log (1, "Reading input index (-I%s)", J_index_file);
412 	fp = fopen(J_index_file, "r");
413 	if (!fp) {
414 		perror (J_index_file);
415 		error_byebye ("Can not open -J%s input index", J_index_file);
416 		/* no return */
417 	}
418 
419 	if (fgets (buf, sizeof buf, fp) == NULL) {
420 		fclose (fp);
421 		error_byebye ("Failed read 1st line of -J%s", J_index_file);
422 		/* no return */
423 	}
424 
425 	if (strcmp (buf, "##ndmjob -I\n") != 0) {
426 		fclose (fp);
427 		error_byebye ("Bad 1st line in -J%s", J_index_file);
428 		/* no return */
429 	}
430 
431 	if (fgets (buf, sizeof buf, fp) == NULL) {
432 		fclose (fp);
433 		error_byebye ("Failed read 2nd line of -J%s", J_index_file);
434 		/* no return */
435 	}
436 
437 	if (strcmp (buf, "##ndmjob -J\n") != 0) {
438 		fclose (fp);
439 		error_byebye ("Bad 2nd line in -J%s", J_index_file);
440 		/* no return */
441 	}
442 
443 	ndmjob_log (2, "Opened index (-J%s)", J_index_file);
444 
445 	return fp;
446 }
447 
448 
449 int
jndex_tattle(void)450 jndex_tattle (void)
451 {
452 	char		buf[100];
453 	int		i;
454 
455 	for (i = 0; i < n_ji_media; i++) {
456 		struct ndmmedia *	me = &ji_media[i];
457 
458 		ndmmedia_to_str (me, buf);
459 		ndmjob_log (3, "ji me[%d] %s", i, buf);
460 	}
461 
462 	for (i = 0; i < n_ji_environment; i++) {
463 		ndmp9_pval *		pv = &ji_environment[i];
464 
465 		ndmjob_log (3, "ji env[%d] %s=%s", i, pv->name, pv->value);
466 	}
467 
468 	for (i = 0; (i < n_file_arg) && (i < NDM_MAX_NLIST); i++) {
469 		if (nlist[i].fh_info.valid) {
470 			ndmjob_log (3, "ji fil[%d] fi=%lld %s",
471 				i, nlist[i].fh_info.value, file_arg[i]);
472 		} else {
473 			ndmjob_log (3, "ji fil[%d] not-found %s",
474 				i, file_arg[i]);
475 		}
476 	}
477 
478 	return 0;
479 }
480 
481 int
jndex_merge_media(void)482 jndex_merge_media (void)
483 {
484 	struct ndmmedia *	me;
485 	struct ndmmedia *	jme;
486 	int			i, j;
487 
488 	for (j = 0; j < n_ji_media; j++) {
489 		jme = &ji_media[j];
490 
491 		if (! jme->valid_label)
492 			continue;	/* can't match it up */
493 
494 		for (i = 0; i < n_m_media; i++) {
495 			me = &m_media[i];
496 
497 			if (! me->valid_label)
498 				continue;	/* can't match it up */
499 
500 			if (strcmp (jme->label, me->label) != 0)
501 				continue;
502 
503 			if (!jme->valid_slot &&  me->valid_slot) {
504 				jme->slot_addr = me->slot_addr;
505 				jme->valid_slot = 1;
506 			}
507 		}
508 	}
509 
510 	for (i = 0; i < n_ji_media; i++) {
511 		m_media[i] = ji_media[i];
512 	}
513 	n_m_media = i;
514 
515 	ndmjob_log (3, "After merging input -J index with -m entries");
516 	for (i = 0; i < n_m_media; i++) {
517 		char		buf[40];
518 
519 		me = &m_media[i];
520 		ndmmedia_to_str (me, buf);
521 		ndmjob_log (3, "%d: -m %s", i+1, buf);
522 	}
523 
524 	return 0;
525 }
526 
527 int
jndex_audit_not_found(void)528 jndex_audit_not_found (void)
529 {
530 	int		i;
531 	int		not_found = 0;
532 
533 	for (i = 0; (i < n_file_arg) && (i < NDM_MAX_NLIST); i++) {
534 		if (!nlist[i].fh_info.valid) {
535 			ndmjob_log (0, "No index entry for %s", file_arg[i]);
536 			not_found++;
537 		}
538 	}
539 
540 	return not_found;
541 }
542 
543 int
jndex_merge_environment(void)544 jndex_merge_environment (void)
545 {
546 	int		i;
547 
548 	for (i = 0; i < n_ji_environment; i++) {
549 		if (strcmp(ji_environment[i].name, "FILESYSTEM") != 0 &&
550 		    strcmp(ji_environment[i].name, "PREFIX") != 0 &&
551 		    strcmp(ji_environment[i].name, "HIST") != 0 &&
552 		    strcmp(ji_environment[i].name, "TYPE") != 0) {
553 			E_environment[nn_E_environment++] = ji_environment[i];
554 		}
555 	}
556 
557 	return 0;
558 }
559 
560 int
jndex_fetch_post_backup_data_env(FILE * fp)561 jndex_fetch_post_backup_data_env (FILE *fp)
562 {
563 	int		rc;
564 	char		buf[512];
565 	char *		p;
566 	char *		q;
567 
568 	rc = ndmbstf_first (fp, "DE ", buf, sizeof buf);
569 	if (rc <= 0) {
570 		return rc;	/* error or not found */
571 	}
572 
573 	/* DE HIST=Yes */
574 	while (buf[0] == 'D' && buf[1] == 'E' && buf[2] == ' ') {
575 		if (n_ji_environment >= NDM_MAX_ENV) {
576 			goto overflow;
577 		}
578 
579 		p = &buf[2];
580 		while (*p == ' ') p++;
581 
582 		if (!strchr (p, '=')) {
583 			goto malformed;
584 		}
585 
586 		p = NDMOS_API_STRDUP (p);
587 		q = strchr (p, '=');
588 		*q++ = 0;
589 
590 		ji_environment[n_ji_environment].name = p;
591 		ji_environment[n_ji_environment].value = q;
592 
593 		n_ji_environment++;
594 
595 		rc = ndmbstf_getline (fp, buf, sizeof buf);
596 		if (rc <= 0) {
597 			break;
598 		}
599 		continue;
600 
601   malformed:
602 		ndmjob_log (1, "Malformed in -J%s: %s", J_index_file, buf);
603 		continue;
604 
605   overflow:
606 		ndmjob_log (1, "Overflow in -J%s: %s", J_index_file, buf);
607 	}
608 
609 	return 0;
610 }
611 
612 int
jndex_fetch_post_backup_media(FILE * fp)613 jndex_fetch_post_backup_media (FILE *fp)
614 {
615 	int		rc;
616 	char		buf[512];
617 
618 	rc = ndmbstf_first (fp, "CM ", buf, sizeof buf);
619 	if (rc <= 0) {
620 		return rc;	/* error or not found */
621 	}
622 
623 	/* CM 01 T103/10850K */
624 	while (buf[0] == 'C' && buf[1] == 'M' && buf[2] == ' ') {
625 		struct ndmmedia *	me;
626 
627 		if (n_ji_media >= NDM_MAX_MEDIA) {
628 			goto overflow;
629 		}
630 
631 		me = &ji_media[n_ji_media];
632 		if (ndmmedia_from_str (me, &buf[6])) {
633 			goto malformed;
634 		}
635 		n_ji_media++;
636 
637 		rc = ndmbstf_getline (fp, buf, sizeof buf);
638 		if (rc <= 0) {
639 			break;
640 		}
641 		continue;
642 
643   malformed:
644 		ndmjob_log (1, "Malformed in -J%s: %s", J_index_file, buf);
645 		continue;
646 
647   overflow:
648 		ndmjob_log (1, "Overflow in -J%s: %s", J_index_file, buf);
649 	}
650 
651 	return 0;
652 }
653 
654 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
655