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 "ndmagents.h"
39 #include "wraplib.h"
40 
41 #ifndef NDMOS_OPTION_NO_DATA_AGENT
42 
43 
44 
45 /*
46  * Initialization and Cleanup
47  ****************************************************************
48  */
49 
50 /* Initialize -- Set data structure to know value, ignore current value */
51 int
ndmda_initialize(struct ndm_session * sess)52 ndmda_initialize (struct ndm_session *sess)
53 {
54 	struct ndm_data_agent *	da = &sess->data_acb;
55 
56 	NDMOS_MACRO_ZEROFILL (da);
57 	da->data_state.state = NDMP9_DATA_STATE_IDLE;
58 	ndmchan_initialize (&da->formatter_error, "dfp-error");
59 	ndmchan_initialize (&da->formatter_wrap, "dfp-wrap");
60 	ndmchan_initialize (&da->formatter_image, "dfp-image");
61 	ndmda_fh_initialize (sess);
62 
63 	return 0;
64 }
65 
66 /* Commission -- Get agent ready. Entire session has been initialize()d */
67 int
ndmda_commission(struct ndm_session * sess)68 ndmda_commission (struct ndm_session *sess)
69 {
70 	struct ndm_data_agent *	da = &sess->data_acb;
71 
72 	da->data_state.state = NDMP9_DATA_STATE_IDLE;
73 	ndmda_fh_commission (sess);
74 
75 	return 0;
76 }
77 
78 /* Decommission -- Discard agent */
79 int
ndmda_decommission(struct ndm_session * sess)80 ndmda_decommission (struct ndm_session *sess)
81 {
82 	ndmis_data_close (sess);
83 	ndmda_purge_environment (sess);
84 	ndmda_purge_nlist (sess);
85 	ndmda_fh_decommission (sess);
86 	NDMOS_API_BZERO (sess->data_acb.bu_type,sizeof sess->data_acb.bu_type);
87 
88 	ndmda_commission (sess);
89 
90 	return 0;
91 }
92 
93 /* Belay -- Cancel partially issued activation/start */
94 int
ndmda_belay(struct ndm_session * sess)95 ndmda_belay (struct ndm_session *sess)
96 {
97 	ndmda_fh_belay (sess);
98 	return ndmda_decommission (sess);
99 }
100 
101 
102 
103 
104 /*
105  * Semantic actions -- called from ndma_dispatch()
106  ****************************************************************
107  */
108 
109 static int
add_env(struct ndm_env_table * envtab,char * cmd)110 add_env (struct ndm_env_table *envtab, char *cmd)
111 {
112 	char		buf[1024];
113 	int		i;
114 
115 	for (i = 0; i < envtab->n_env; i++) {
116 		strcpy (buf, envtab->env[i].name);
117 		strcat (buf, "=");
118 		strcat (buf, envtab->env[i].value);
119 		ndmda_add_to_cmd (cmd, "-E");
120 		ndmda_add_to_cmd (cmd, buf);
121 	}
122 
123 	return 0;
124 }
125 
126 static int
add_nlist(struct ndm_nlist_table * nlisttab,char * cmd)127 add_nlist (struct ndm_nlist_table *nlisttab, char *cmd)
128 {
129 	char		buf[32];
130 	int		i;
131 
132 	for (i = 0; i < nlisttab->n_nlist; i++) {
133 		ndmp9_name *	nl = &nlisttab->nlist[i];
134 
135 		ndmda_add_to_cmd (cmd, nl->original_path);
136 		if (nl->fh_info.valid == NDMP9_VALIDITY_VALID) {
137 			sprintf (buf, "@%llu", nl->fh_info.value);
138 			ndmda_add_to_cmd (cmd, buf);
139 		} else {
140 			ndmda_add_to_cmd (cmd, "@-");
141 		}
142 		ndmda_add_to_cmd (cmd, nl->destination_path);
143 	}
144 
145 	return 0;
146 }
147 
148 
149 ndmp9_error
ndmda_data_start_backup(struct ndm_session * sess)150 ndmda_data_start_backup (struct ndm_session *sess)
151 {
152 	struct ndm_data_agent *	da = &sess->data_acb;
153 	ndmp9_error		error = NDMP9_NO_ERR;
154 	char			cmd[NDMDA_MAX_CMD];
155 
156 	strcpy (cmd, "/amanda/h1/linux-3.3/libexec/amanda/application/wrap_");
157 	strcat (cmd, da->bu_type);
158 
159 	if (sess->param.log_level > 0) {
160 	    char tmpbuf[40];
161 	    sprintf(tmpbuf, "-d%d", sess->param.log_level);
162 	    ndmda_add_to_cmd (cmd, tmpbuf);
163 	}
164 
165 	ndmda_add_to_cmd (cmd, "-c");
166 	ndmda_add_to_cmd (cmd, "-I#3");
167 	add_env (&da->env_tab, cmd);
168 
169 	ndma_send_logmsg (sess, NDMP9_LOG_DEBUG, sess->plumb.data,
170 		"CMD: %s", cmd);
171 
172 	if (ndmda_pipe_fork_exec (sess, cmd, 1) < 0) {
173 		return NDMP9_UNDEFINED_ERR;
174 	}
175 
176 	ndmis_data_start (sess, NDMCHAN_MODE_WRITE);
177 
178 	da->data_state.state = NDMP9_DATA_STATE_ACTIVE;
179 	da->data_state.operation = NDMP9_DATA_OP_BACKUP;
180 
181 	return error;
182 }
183 
184 ndmp9_error
ndmda_data_start_recover(struct ndm_session * sess)185 ndmda_data_start_recover (struct ndm_session *sess)
186 {
187 	struct ndm_data_agent *	da = &sess->data_acb;
188 	ndmp9_error		error = NDMP9_NO_ERR;
189 	char			cmd[NDMDA_MAX_CMD];
190 
191 	strcpy (cmd, "/amanda/h1/linux-3.3/libexec/amanda/application/wrap_");
192 	strcat (cmd, da->bu_type);
193 
194 	if (sess->param.log_level > 0) {
195 	    char tmpbuf[40];
196 	    sprintf(tmpbuf, "-d%d", sess->param.log_level);
197 	    ndmda_add_to_cmd (cmd, tmpbuf);
198 	}
199 
200 	ndmda_add_to_cmd (cmd, "-x");
201 	ndmda_add_to_cmd (cmd, "-I#3");
202 	add_env (&da->env_tab, cmd);
203 	add_nlist (&da->nlist_tab, cmd);
204 
205 	ndma_send_logmsg (sess, NDMP9_LOG_DEBUG, sess->plumb.data,
206 		"CMD: %s", cmd);
207 
208 	if (ndmda_pipe_fork_exec (sess, cmd, 0) < 0) {
209 		return NDMP9_UNDEFINED_ERR;
210 	}
211 
212 	ndmis_data_start (sess, NDMCHAN_MODE_READ);
213 
214 	da->data_state.state = NDMP9_DATA_STATE_ACTIVE;
215 	da->data_state.operation = NDMP9_DATA_OP_RECOVER;
216 
217 	return error;
218 }
219 
220 ndmp9_error
ndmda_data_start_recover_fh(struct ndm_session * sess)221 ndmda_data_start_recover_fh (struct ndm_session *sess)
222 {
223 	struct ndm_data_agent *	da = &sess->data_acb;
224 	ndmp9_error		error = NDMP9_NO_ERR;
225 	char			cmd[NDMDA_MAX_CMD];
226 
227 	strcpy (cmd, "/amanda/h1/linux-3.3/libexec/amanda/application/wrap_");
228 	strcat (cmd, da->bu_type);
229 	ndmda_add_to_cmd (cmd, "-t");
230 	ndmda_add_to_cmd (cmd, "-I#3");
231 	add_env (&da->env_tab, cmd);
232 	add_nlist (&da->nlist_tab, cmd);
233 
234 	ndma_send_logmsg (sess, NDMP9_LOG_DEBUG,  sess->plumb.data,
235 		"CMD: %s", cmd);
236 
237 	if (ndmda_pipe_fork_exec (sess, cmd, 0) < 0) {
238 		return NDMP9_UNDEFINED_ERR;
239 	}
240 
241 	ndmis_data_start (sess, NDMCHAN_MODE_READ);
242 
243 	da->data_state.state = NDMP9_DATA_STATE_ACTIVE;
244 	da->data_state.operation = NDMP9_DATA_OP_RECOVER_FILEHIST;
245 
246 	return error;
247 }
248 
249 void
ndmda_sync_state(struct ndm_session * sess)250 ndmda_sync_state (struct ndm_session *sess)
251 {
252 	/* no-op, always accurate */
253 }
254 
255 void
ndmda_data_abort(struct ndm_session * sess)256 ndmda_data_abort (struct ndm_session *sess)
257 {
258 	ndmda_data_halt (sess, NDMP9_DATA_HALT_ABORTED);
259 }
260 
261 void
ndmda_sync_environment(struct ndm_session * sess)262 ndmda_sync_environment (struct ndm_session *sess)
263 {
264 	/* no-op, always accurate */
265 }
266 
267 ndmp9_error
ndmda_data_listen(struct ndm_session * sess)268 ndmda_data_listen (struct ndm_session *sess)
269 {
270 	struct ndm_data_agent *	da = &sess->data_acb;
271 
272 	da->data_state.state = NDMP9_DATA_STATE_LISTEN;
273 	da->data_state.halt_reason = NDMP9_DATA_HALT_NA;
274 
275 	return NDMP9_NO_ERR;
276 }
277 
278 ndmp9_error
ndmda_data_connect(struct ndm_session * sess)279 ndmda_data_connect (struct ndm_session *sess)
280 {
281 	struct ndm_data_agent *	da = &sess->data_acb;
282 
283 	da->data_state.state = NDMP9_DATA_STATE_CONNECTED;
284 	da->data_state.halt_reason = NDMP9_DATA_HALT_NA;
285 
286 	return NDMP9_NO_ERR;
287 }
288 
289 void
ndmda_data_halt(struct ndm_session * sess,ndmp9_data_halt_reason reason)290 ndmda_data_halt (struct ndm_session *sess, ndmp9_data_halt_reason reason)
291 {
292 	struct ndm_data_agent *	da = &sess->data_acb;
293 
294 	da->data_state.state = NDMP9_DATA_STATE_HALTED;
295 	da->data_state.halt_reason = reason;
296 	da->data_notify_pending = 1;
297 
298 	ndmda_fh_flush (sess);
299 
300 	ndmis_data_close (sess);
301 
302 	ndmchan_cleanup (&da->formatter_image);
303 	ndmchan_cleanup (&da->formatter_error);
304 	ndmchan_cleanup (&da->formatter_wrap);
305 
306 	/* this needs to be better */
307 	if (da->formatter_pid) {
308 		sleep (1);	/* give gtar a chance to stop by itself */
309 		kill (da->formatter_pid, SIGTERM);
310 	}
311 }
312 
313 void
ndmda_data_stop(struct ndm_session * sess)314 ndmda_data_stop (struct ndm_session *sess)
315 {
316 	ndmda_decommission (sess);
317 }
318 
319 
320 
321 
322 /*
323  * Quantum -- get a bit of work done
324  ****************************************************************
325  */
326 
327 int
ndmda_quantum(struct ndm_session * sess)328 ndmda_quantum (struct ndm_session *sess)
329 {
330 	struct ndm_data_agent *	da = &sess->data_acb;
331 	int			did_something = 0;	/* did nothing */
332 
333 
334 	switch (da->data_state.state) {
335 	default:
336 		ndmalogf (sess, 0, 0, "BOTCH data state");
337 		return -1;
338 
339 	case NDMP9_DATA_STATE_IDLE:
340 	case NDMP9_DATA_STATE_HALTED:
341 	case NDMP9_DATA_STATE_CONNECTED:
342 		break;
343 
344 	case NDMP9_DATA_STATE_LISTEN:
345 		switch (sess->plumb.image_stream.data_ep.connect_status) {
346 		case NDMIS_CONN_LISTEN:		/* no connection yet */
347 			break;
348 
349 		case NDMIS_CONN_ACCEPTED:	/* we're in business */
350 			/* drum roll please... */
351 			da->data_state.state = NDMP9_DATA_STATE_CONNECTED;
352 			/* tah-dah */
353 			did_something++;	/* did something */
354 			break;
355 
356 		case NDMIS_CONN_BOTCHED:	/* accept() went south */
357 		default:			/* ain't suppose to happen */
358 			ndmda_data_halt (sess, NDMP9_DATA_HALT_CONNECT_ERROR);
359 			did_something++;	/* did something */
360 			break;
361 		}
362 		break;
363 
364 	case NDMP9_DATA_STATE_ACTIVE:
365 		did_something |= ndmda_quantum_stderr (sess);
366 		did_something |= ndmda_quantum_wrap (sess);
367 		did_something |= ndmda_quantum_image (sess);
368 		break;
369 	}
370 
371 	ndmda_send_notice (sess);
372 
373 	return did_something;
374 }
375 
376 int
ndmda_quantum_stderr(struct ndm_session * sess)377 ndmda_quantum_stderr (struct ndm_session *sess)
378 {
379 	struct ndm_data_agent *	da = &sess->data_acb;
380 	struct ndmchan *	ch = &da->formatter_error;
381 	int			did_something = 0;
382 	char *			p;
383 	char *			data;
384 	char *			pend;
385 	unsigned		n_ready;
386 
387   again:
388 	n_ready = ndmchan_n_ready (ch);
389 	if (n_ready == 0)
390 		return did_something;
391 
392 	data = p = &ch->data[ch->beg_ix];
393 	pend = p + n_ready;
394 
395 	while (p < pend && *p != '\n') p++;
396 
397 
398 	if (p < pend && *p == '\n') {
399 		*p++ = 0;
400 		ndma_send_logmsg (sess, NDMP9_LOG_NORMAL,  sess->plumb.data,
401 			"%s", data);
402 		ch->beg_ix += p - data;
403 		did_something++;
404 		goto again;
405 	}
406 
407 	if (!ch->eof)
408 		return did_something;
409 
410 	/* content w/o newline, and EOF */
411 	/* p == pend */
412 	if (ch->end_ix >= ch->data_size) {
413 		if (data != ch->data) {
414 			ndmchan_compress (ch);
415 			goto again;
416 		}
417 		/* that's one huge message */
418 		p--;	/* lose last byte */
419 	}
420 
421 	ch->data[ch->end_ix++] = '\n';
422 	did_something++;
423 	goto again;
424 }
425 
426 int
ndmda_quantum_wrap(struct ndm_session * sess)427 ndmda_quantum_wrap (struct ndm_session *sess)
428 {
429 	struct ndm_data_agent *	da = &sess->data_acb;
430 	struct ndmchan *	ch = &da->formatter_wrap;
431 	int			did_something = 0;
432 	char *			p;
433 	char *			data;
434 	char *			pend;
435 	unsigned		n_ready;
436 	int			is_recover = 0;
437 
438 	switch (da->data_state.operation) {
439 	default:
440 		assert (0);
441 		break;
442 
443 	case NDMP9_DATA_OP_BACKUP:
444 		break;
445 
446 	case NDMP9_DATA_OP_RECOVER:
447 	case NDMP9_DATA_OP_RECOVER_FILEHIST:
448 		is_recover = 1;
449 		break;
450 	}
451 
452   again:
453 	n_ready = ndmchan_n_ready (ch);
454 	if (n_ready == 0) {
455 		if (ch->eof && is_recover) {
456 			ndmda_data_halt (sess, NDMP9_DATA_HALT_SUCCESSFUL);
457 		}
458 		return did_something;
459 	}
460 	data = p = &ch->data[ch->beg_ix];
461 	pend = p + n_ready;
462 
463 	while (p < pend && *p != '\n') p++;
464 
465 
466 	if (p < pend && *p == '\n') {
467 		*p++ = 0;
468 		ndmda_wrap_in (sess, data);
469 		ch->beg_ix += p - data;
470 		did_something++;
471 		goto again;
472 	}
473 
474 	if (!ch->eof)
475 		return did_something;
476 
477 	/* content w/o newline, and EOF */
478 	/* p == pend */
479 	if (ch->end_ix >= ch->data_size) {
480 		if (data != ch->data) {
481 			ndmchan_compress (ch);
482 			goto again;
483 		}
484 		/* that's one huge message */
485 		p--;	/* lose last byte */
486 	}
487 
488 	ch->data[ch->end_ix++] = '\n';
489 	did_something++;
490 	goto again;
491 }
492 
493 
494 
495 int
ndmda_quantum_image(struct ndm_session * sess)496 ndmda_quantum_image (struct ndm_session *sess)
497 {
498 	struct ndm_data_agent *	da = &sess->data_acb;
499 	struct ndmchan *	from_chan;
500 	struct ndmchan *	to_chan;
501 	unsigned		n_ready, n_avail, n_copy;
502 	int			is_backup = 0;
503 
504 	switch (da->data_state.operation) {
505 	default:
506 		assert (0);
507 		from_chan = 0;
508 		to_chan = 0;
509 		break;
510 
511 	case NDMP9_DATA_OP_BACKUP:
512 		from_chan = &da->formatter_image;
513 		to_chan = &sess->plumb.image_stream.chan;
514 		is_backup = 1;
515 		break;
516 
517 	case NDMP9_DATA_OP_RECOVER:
518 	case NDMP9_DATA_OP_RECOVER_FILEHIST:
519 		from_chan = &sess->plumb.image_stream.chan;
520 		to_chan = &da->formatter_image;
521 		break;
522 	}
523 
524   again:
525 	n_copy = n_ready = ndmchan_n_ready (from_chan);
526 	if (n_ready == 0) {
527 		if (from_chan->eof) {
528 			to_chan->eof = 1;
529 			if (ndmchan_n_ready (to_chan) == 0) {
530 				if (is_backup) {
531 					ndmda_data_halt (sess,
532 						NDMP9_DATA_HALT_SUCCESSFUL);
533 				}
534 			}
535 		}
536 		return 0;	/* data blocked */
537 	}
538 
539 	n_avail = ndmchan_n_avail (to_chan);
540 	if (n_copy > n_avail)
541 		n_copy = n_avail;
542 
543 	if (da->enable_hist) {
544 		if (n_copy > da->pass_resid)
545 			n_copy = da->pass_resid;
546 	}
547 
548 	if (n_copy > 0) {
549 		bcopy (&from_chan->data[from_chan->beg_ix],
550 			&to_chan->data[to_chan->end_ix],
551 			n_copy);
552 		from_chan->beg_ix += n_copy;
553 		to_chan->end_ix += n_copy;
554 		da->data_state.bytes_processed += n_copy;
555 		da->pass_resid -= n_copy;
556 		goto again;	/* do as much as possible */
557 	}
558 
559 	return 0;
560 
561 }
562 
563 
564 
565 
566 /*
567  * Process WRAP messages from the formatter. Called from
568  * ndmda_quantum_wrap(). The formatter sends one line text
569  * messages via the WRAP pipe (fd=3 on formatter).
570  * The WRAP message contain log messages, file history,
571  * status updates, etc, etc, etc.
572  *
573  * Here the messages are parsed and directed to the
574  * right NDMP interface toward the Control Agent.
575  */
576 
577 void		ndmp9_fstat_from_wrap_fstat (ndmp9_file_stat *fstat9,
578 				struct wrap_fstat *fstatw);
579 
580 int
ndmda_wrap_in(struct ndm_session * sess,char * wrap_line)581 ndmda_wrap_in (struct ndm_session *sess, char *wrap_line)
582 {
583 	struct wrap_msg_buf	_wmsg, *wmsg = &_wmsg;
584 	int			rc;
585 	ndmp9_file_stat		fstat9;
586 
587 	NDMOS_MACRO_ZEROFILL (wmsg);
588 
589 	rc = wrap_parse_msg (wrap_line, wmsg);
590 	if (rc != 0) {
591 		ndmalogf (sess, 0, 2, "Malformed wrap: %s", wrap_line);
592 		return -1;
593 	}
594 
595 	switch (wmsg->msg_type) {
596 	case WRAP_MSGTYPE_LOG_MESSAGE:
597 		ndmalogf (sess, "WRAP", 2, "%s",
598 			wmsg->body.log_message.message);
599 		ndma_send_logmsg (sess, NDMP9_LOG_NORMAL, sess->plumb.data,
600 			"WRAP: %s", wmsg->body.log_message.message);
601 		break;
602 
603 	case WRAP_MSGTYPE_ADD_FILE:
604 		ndmp9_fstat_from_wrap_fstat (&fstat9,
605 				&wmsg->body.add_file.fstat);
606 		fstat9.fh_info.valid = NDMP9_VALIDITY_VALID;
607 		fstat9.fh_info.value = wmsg->body.add_file.fhinfo;
608 		ndmda_fh_add_file (sess, &fstat9, wmsg->body.add_file.path);
609 		break;
610 
611 	case WRAP_MSGTYPE_ADD_DIRENT:
612 		ndmda_fh_add_dir (sess,
613 			wmsg->body.add_dirent.dir_fileno,
614 			wmsg->body.add_dirent.name,
615 			wmsg->body.add_dirent.fileno);
616 		break;
617 
618 	case WRAP_MSGTYPE_ADD_NODE:
619 		ndmp9_fstat_from_wrap_fstat (&fstat9,
620 				&wmsg->body.add_node.fstat);
621 		fstat9.fh_info.valid = NDMP9_VALIDITY_VALID;
622 		fstat9.fh_info.value = wmsg->body.add_node.fhinfo;
623 		ndmda_fh_add_node (sess, &fstat9);
624 		break;
625 
626 	case WRAP_MSGTYPE_DATA_READ:
627 		ndmda_send_data_read (sess,
628 			wmsg->body.data_read.offset,
629 			wmsg->body.data_read.length);
630 		break;
631 
632 	case WRAP_MSGTYPE_ADD_ENV:
633 	case WRAP_MSGTYPE_DATA_STATS:
634 	case WRAP_MSGTYPE_RECOVERY_RESULT:
635 		ndmalogf (sess, 0, 2, "Unimplemented wrap: %s", wrap_line);
636 		break;
637 	}
638 
639 	return 0;
640 }
641 
642 void
ndmp9_fstat_from_wrap_fstat(ndmp9_file_stat * fstat9,struct wrap_fstat * fstatw)643 ndmp9_fstat_from_wrap_fstat (ndmp9_file_stat *fstat9,
644   struct wrap_fstat *fstatw)
645 {
646 	NDMOS_MACRO_ZEROFILL (fstat9);
647 
648 	switch (fstatw->ftype) {
649 	default:
650 	case WRAP_FTYPE_INVALID:fstat9->ftype = NDMP9_FILE_OTHER;	break;
651 	case WRAP_FTYPE_DIR:	fstat9->ftype = NDMP9_FILE_DIR;		break;
652 	case WRAP_FTYPE_FIFO:	fstat9->ftype = NDMP9_FILE_FIFO;	break;
653 	case WRAP_FTYPE_CSPEC:	fstat9->ftype = NDMP9_FILE_CSPEC;	break;
654 	case WRAP_FTYPE_BSPEC:	fstat9->ftype = NDMP9_FILE_BSPEC;	break;
655 	case WRAP_FTYPE_REG:	fstat9->ftype = NDMP9_FILE_REG;		break;
656 	case WRAP_FTYPE_SLINK:	fstat9->ftype = NDMP9_FILE_SLINK;	break;
657 	case WRAP_FTYPE_SOCK:	fstat9->ftype = NDMP9_FILE_SOCK;	break;
658 	case WRAP_FTYPE_REGISTRY:fstat9->ftype = NDMP9_FILE_REGISTRY;	break;
659 	case WRAP_FTYPE_OTHER:	fstat9->ftype = NDMP9_FILE_OTHER;	break;
660 	}
661 
662 	if (fstatw->valid & WRAP_FSTAT_VALID_FTYPE) {
663 	}
664 
665 	if (fstatw->valid & WRAP_FSTAT_VALID_MODE) {
666 		fstat9->mode.valid = NDMP9_VALIDITY_VALID;
667 		fstat9->mode.value = fstatw->mode;
668 	}
669 
670 	if (fstatw->valid & WRAP_FSTAT_VALID_SIZE) {
671 		fstat9->size.valid = NDMP9_VALIDITY_VALID;
672 		fstat9->size.value = fstatw->size;
673 	}
674 
675 	if (fstatw->valid & WRAP_FSTAT_VALID_LINKS) {
676 		fstat9->links.valid = NDMP9_VALIDITY_VALID;
677 		fstat9->links.value = fstatw->size;
678 	}
679 
680 	if (fstatw->valid & WRAP_FSTAT_VALID_UID) {
681 		fstat9->uid.valid = NDMP9_VALIDITY_VALID;
682 		fstat9->uid.value = fstatw->uid;
683 	}
684 
685 	if (fstatw->valid & WRAP_FSTAT_VALID_GID) {
686 		fstat9->gid.valid = NDMP9_VALIDITY_VALID;
687 		fstat9->gid.value = fstatw->gid;
688 	}
689 
690 	if (fstatw->valid & WRAP_FSTAT_VALID_ATIME) {
691 		fstat9->atime.valid = NDMP9_VALIDITY_VALID;
692 		fstat9->atime.value = fstatw->atime;
693 	}
694 
695 	if (fstatw->valid & WRAP_FSTAT_VALID_MTIME) {
696 		fstat9->mtime.valid = NDMP9_VALIDITY_VALID;
697 		fstat9->mtime.value = fstatw->mtime;
698 	}
699 
700 	if (fstatw->valid & WRAP_FSTAT_VALID_CTIME) {
701 		fstat9->ctime.valid = NDMP9_VALIDITY_VALID;
702 		fstat9->ctime.value = fstatw->ctime;
703 	}
704 
705 	if (fstatw->valid & WRAP_FSTAT_VALID_FILENO) {
706 		fstat9->node.valid = NDMP9_VALIDITY_VALID;
707 		fstat9->node.value = fstatw->fileno;
708 	}
709 
710 
711 
712 
713 }
714 
715 
716 
717 
718 /*
719  * Send LOG and NOTIFY messages
720  ****************************************************************
721  */
722 
723 #if 0
724 void
725 ndmda_send_logmsg (struct ndm_session *sess, char *fmt, ...)
726 {
727 	struct ndmconn *	conn = sess->plumb.control;
728 	char			buf[4096];
729 	va_list			ap;
730 
731 	va_start (ap, fmt);
732 	vsnprintf (buf, sizeof(buf), fmt, ap);
733 	va_end (ap);
734 
735 	// we don't handle our own messages so don't send them....
736 	if (conn->conn_type == NDMCONN_TYPE_RESIDENT) {
737 	    ndmalogf(sess, 0, 2, "RESIDENT AGENT LOGMSG: %s", buf);
738 	    return;
739 	}
740 
741 	ndma_send_logmsg (sess, buf, conn);
742 }
743 #endif
744 
745 void
ndmda_send_notice(struct ndm_session * sess)746 ndmda_send_notice (struct ndm_session *sess)
747 {
748 	struct ndm_data_agent *	da = &sess->data_acb;
749 
750 	if (!da->data_notify_pending)
751 		return;
752 
753 	da->data_notify_pending = 0;
754 
755 	switch (da->data_state.state) {
756 	case NDMP9_DATA_STATE_HALTED:
757 		ndma_notify_data_halted (sess);
758 		break;
759 
760 	default:
761 		/* Hmm. Why are we here. Race? */
762 		break;
763 	}
764 }
765 
766 void
ndmda_send_data_read(struct ndm_session * sess,unsigned long long offset,unsigned long long length)767 ndmda_send_data_read (struct ndm_session *sess,
768   unsigned long long offset, unsigned long long length)
769 {
770 	struct ndm_data_agent *	da = &sess->data_acb;
771 	ndmp9_addr_type		addr_type;
772 
773 	addr_type = da->data_state.data_connection_addr.addr_type;
774 #if 0
775 	da->reco_read_offset = offset;
776 	da->reco_read_length = length;
777 #endif
778 
779 	if (NDMP9_ADDR_LOCAL == addr_type) {
780 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
781 		if (ndmta_local_mover_read (sess, offset, length) != 0) {
782 			ndma_send_logmsg (sess, NDMP9_LOG_ERROR,
783 				sess->plumb.data,
784 				"local_mover_read failed");
785 			ndmda_data_halt (sess, NDMP9_DATA_HALT_INTERNAL_ERROR);
786 		}
787 #else /* !NDMOS_OPTION_NO_TAPE_AGENT */
788 		ndma_send_logmsg (sess, NDMP9_LOG_ERROR,
789 				sess->plumb.data,
790 				"local_mover_read not configured");
791 		ndmda_data_halt (sess, NDMP9_DATA_HALT_INTERNAL_ERROR);
792 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
793 		return;
794 	}
795 
796 	switch (addr_type) {
797 	case NDMP9_ADDR_TCP:
798 		ndma_notify_data_read (sess, offset, length);
799 		break;
800 
801 	default:
802 		ndma_send_logmsg (sess, NDMP9_LOG_ERROR, sess->plumb.data,
803 			"bogus mover.addr_type");
804 		ndmda_data_halt (sess, NDMP9_DATA_HALT_INTERNAL_ERROR);
805 		break;
806 	}
807 }
808 
809 
810 
811 
812 /*
813  * Misc -- env[] and nlist[] subroutines, etc
814  ****************************************************************
815  */
816 
817 int
ndmda_copy_environment(struct ndm_session * sess,ndmp9_pval * env,unsigned n_env)818 ndmda_copy_environment (struct ndm_session *sess,
819   ndmp9_pval *env, unsigned n_env)
820 {
821 	struct ndm_data_agent *	da = &sess->data_acb;
822 	int			i;
823 	unsigned int		j;
824 	ndmp9_pval *		src_pv;
825 	ndmp9_pval *		dst_pv;
826 
827 	for (j = 0; j < n_env; j++) {
828 		src_pv = &env[j];
829 		dst_pv = &da->env_tab.env[da->env_tab.n_env];
830 
831 		dst_pv->name  = NDMOS_API_STRDUP (src_pv->name);
832 		dst_pv->value = NDMOS_API_STRDUP (src_pv->value);
833 
834 		if (!dst_pv->name || !dst_pv->value)
835 			goto fail;
836 
837 		da->env_tab.n_env++;
838 	}
839 
840 	return 0;
841 
842   fail:
843 	for (i = 0; i < da->env_tab.n_env; i++) {
844 		char *		p;
845 
846 		dst_pv = &da->env_tab.env[da->env_tab.n_env];
847 
848 		if ((p = dst_pv->name) != 0)
849 			NDMOS_API_FREE (p);
850 
851 		if ((p = dst_pv->value) != 0)
852 			NDMOS_API_FREE (p);
853 	}
854 	da->env_tab.n_env = 0;
855 
856 	return -1;
857 }
858 
859 struct ndmp9_pval *
ndmda_find_env(struct ndm_session * sess,char * name)860 ndmda_find_env (struct ndm_session *sess, char *name)
861 {
862 	struct ndm_data_agent *	da = &sess->data_acb;
863 	int			i;
864 	struct ndmp9_pval *	pv;
865 
866 	for (i = 0; i < da->env_tab.n_env; i++) {
867 		pv = &da->env_tab.env[i];
868 		if (strcmp (pv->name, name) == 0)
869 			return pv;
870 	}
871 
872 	return 0;
873 }
874 
875 
876 int
ndmda_interpret_boolean_value(char * value_str,int default_value)877 ndmda_interpret_boolean_value (char *value_str, int default_value)
878 {
879 	if (strcasecmp (value_str, "y") == 0
880 	 || strcasecmp (value_str, "yes") == 0
881 	 || strcasecmp (value_str, "t") == 0
882 	 || strcasecmp (value_str, "true") == 0
883 	 || strcasecmp (value_str, "1") == 0)
884 		return 1;
885 
886 	if (strcasecmp (value_str, "n") == 0
887 	 || strcasecmp (value_str, "no") == 0
888 	 || strcasecmp (value_str, "f") == 0
889 	 || strcasecmp (value_str, "false") == 0
890 	 || strcasecmp (value_str, "0") == 0)
891 		return 0;
892 
893 	return default_value;
894 }
895 
896 void
ndmda_purge_environment(struct ndm_session * sess)897 ndmda_purge_environment (struct ndm_session *sess)
898 {
899 	struct ndm_data_agent *	da = &sess->data_acb;
900 	int			i;
901 	struct ndmp9_pval *	pv;
902 
903 	for (i = 0; i < da->env_tab.n_env; i++) {
904 		pv = &da->env_tab.env[i];
905 
906 		if (pv->name)  NDMOS_API_FREE (pv->name);
907 		if (pv->value) NDMOS_API_FREE (pv->value);
908 		pv->name = 0;
909 		pv->value = 0;
910 	}
911 	da->env_tab.n_env = 0;
912 }
913 
914 
915 int
ndmda_copy_nlist(struct ndm_session * sess,ndmp9_name * nlist,unsigned n_nlist)916 ndmda_copy_nlist (struct ndm_session *sess,
917   ndmp9_name *nlist, unsigned n_nlist)
918 {
919 	struct ndm_data_agent *	da = &sess->data_acb;
920 	unsigned int		i;
921 	int			j;
922 	ndmp9_name *		src_nl;
923 	ndmp9_name *		dst_nl;
924 
925 	for (i = 0; i < n_nlist; i++) {
926 		j = da->nlist_tab.n_nlist;
927 		src_nl = &nlist[i];
928 		dst_nl = &da->nlist_tab.nlist[j];
929 
930 		dst_nl->original_path =
931 			NDMOS_API_STRDUP (src_nl->original_path);
932 		dst_nl->destination_path =
933 			NDMOS_API_STRDUP (src_nl->destination_path);
934 		dst_nl->fh_info = src_nl->fh_info;
935 		da->nlist_tab.result_err[j] = NDMP9_UNDEFINED_ERR;
936 		da->nlist_tab.result_count[j] = 0;
937 
938 		if (!dst_nl->original_path || !dst_nl->destination_path)
939 			return -1;	/* no mem */
940 
941 		da->nlist_tab.n_nlist++;
942 	}
943 
944 	/* TODO: sort */
945 
946 	return 0;
947 }
948 
949 void
ndmda_purge_nlist(struct ndm_session * sess)950 ndmda_purge_nlist (struct ndm_session *sess)
951 {
952 	struct ndm_data_agent *	da = &sess->data_acb;
953 	int			i;
954 	struct ndmp9_name *	nl;
955 
956 	for (i = 0; i < da->nlist_tab.n_nlist; i++) {
957 		nl = &da->nlist_tab.nlist[i];
958 
959 		if (nl->original_path) {
960 			NDMOS_API_FREE (nl->original_path);
961 		}
962 		if (nl->destination_path) {
963 			NDMOS_API_FREE (nl->destination_path);
964 		}
965 
966 		nl->original_path = 0;
967 		nl->destination_path = 0;
968 	}
969 	da->nlist_tab.n_nlist = 0;
970 }
971 
972 int
ndmda_count_invalid_fh_info(struct ndm_session * sess)973 ndmda_count_invalid_fh_info (struct ndm_session *sess)
974 {
975 	struct ndm_data_agent *	da = &sess->data_acb;
976 	int			i, count;
977 	struct ndmp9_name *	nl;
978 
979 	count = 0;
980 	for (i = 0; i < da->nlist_tab.n_nlist; i++) {
981 		nl = &da->nlist_tab.nlist[i];
982 
983 		if (nl->fh_info.valid != NDMP9_VALIDITY_VALID)
984 			count++;
985 	}
986 
987 	return count;
988 }
989 
990 int
ndmda_count_invalid_fh_info_pending(struct ndm_session * sess)991 ndmda_count_invalid_fh_info_pending (struct ndm_session *sess)
992 {
993 	struct ndm_data_agent *	da = &sess->data_acb;
994 	int			i, count;
995 	struct ndmp9_name *	nl;
996 
997 	count = 0;
998 	for (i = 0; i < da->nlist_tab.n_nlist; i++) {
999 		nl = &da->nlist_tab.nlist[i];
1000 
1001 		if (da->nlist_tab.result_err[i] == NDMP9_UNDEFINED_ERR
1002 		 && nl->fh_info.valid != NDMP9_VALIDITY_VALID) {
1003 			count++;
1004 		}
1005 	}
1006 
1007 	return count;
1008 }
1009 
1010 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
1011