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