xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_callbacks.c (revision 24f5a37652e188ebdcdd6da454511686935025df)
1 /*
2  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /*
6  * BSD 3 Clause License
7  *
8  * Copyright (c) 2007, The Storage Networking Industry Association.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 	- Redistributions of source code must retain the above copyright
14  *	  notice, this list of conditions and the following disclaimer.
15  *
16  * 	- Redistributions in binary form must reproduce the above copyright
17  *	  notice, this list of conditions and the following disclaimer in
18  *	  the documentation and/or other materials provided with the
19  *	  distribution.
20  *
21  *	- Neither the name of The Storage Networking Industry Association (SNIA)
22  *	  nor the names of its contributors may be used to endorse or promote
23  *	  products derived from this software without specific prior written
24  *	  permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40 /* Copyright 2014 Nexenta Systems, Inc. All rights reserved. */
41 
42 #include <sys/types.h>
43 #include <stdlib.h>
44 #include <errno.h>
45 #include <stdarg.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include "ndmpd.h"
49 
50 
51 /*
52  * Message Id counter.  This number is increased by MOD_LOGV3 macro.
53  * MOD_LOGCONTV3 macro uses the number generated by the last MOD_LOGV3.
54  *
55  */
56 int ndmp_log_msg_id = 0;
57 
58 
59 /*
60  * ************************************************************************
61  * NDMP V2 CALLBACKS
62  * ************************************************************************
63  */
64 
65 /*
66  * ndmpd_api_done_v2
67  *
68  * Called when dump/restore has completed.
69  * Sends a notify_halt request to the NDMP client.
70  *
71  * Parameters:
72  *   session (input) - session pointer.
73  *   err     (input) - UNIX error code.
74  *
75  * Returns:
76  *   void
77  */
78 void
79 ndmpd_api_done_v2(void *cookie, int err)
80 {
81 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
82 	ndmp_notify_data_halted_request req_v2;
83 
84 	if (session == NULL)
85 		return;
86 
87 	if (session->ns_data.dd_state == NDMP_DATA_STATE_IDLE ||
88 	    session->ns_data.dd_state == NDMP_DATA_STATE_HALTED)
89 		return;
90 
91 	NDMP_LOG(LOG_DEBUG, "data.operation: %d",
92 	    session->ns_data.dd_operation);
93 
94 	if (session->ns_data.dd_operation == NDMP_DATA_OP_BACKUP) {
95 		/*
96 		 * Send/discard any buffered file history data.
97 		 */
98 		ndmpd_file_history_cleanup(session, (err == 0 ? TRUE : FALSE));
99 
100 		/*
101 		 * If mover local and successfull backup, write any
102 		 * remaining buffered data to tape.
103 		 */
104 		if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_LOCAL &&
105 		    err == 0) {
106 			if (ndmpd_local_write(session, 0, 0) < 0)
107 				err = EIO;
108 		}
109 	}
110 
111 	session->ns_data.dd_state = NDMP_DATA_STATE_HALTED;
112 
113 	switch (err) {
114 	case 0:
115 		session->ns_data.dd_halt_reason = NDMP_DATA_HALT_SUCCESSFUL;
116 		break;
117 	case EINTR:
118 		session->ns_data.dd_halt_reason = NDMP_DATA_HALT_ABORTED;
119 		break;
120 	case EIO:
121 		session->ns_data.dd_halt_reason = NDMP_DATA_HALT_CONNECT_ERROR;
122 		break;
123 	default:
124 		session->ns_data.dd_halt_reason = NDMP_DATA_HALT_INTERNAL_ERROR;
125 	}
126 
127 	req_v2.reason = session->ns_data.dd_halt_reason;
128 	req_v2.text_reason = "";
129 
130 	NDMP_LOG(LOG_DEBUG, "ndmp_send_request(NDMP_NOTIFY_DATA_HALTED)");
131 
132 	if (ndmp_send_request_lock(session->ns_connection,
133 	    NDMP_NOTIFY_DATA_HALTED, NDMP_NO_ERR, (void *)&req_v2, 0) < 0)
134 		NDMP_LOG(LOG_DEBUG, "Sending notify_data_halted request");
135 
136 	if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
137 
138 		if (session->ns_mover.md_sock != session->ns_data.dd_sock) {
139 			(void) close(session->ns_data.dd_sock);
140 		} else {
141 			NDMP_LOG(LOG_DEBUG, "Not closing as used by mover");
142 		}
143 
144 		session->ns_data.dd_sock = -1;
145 	} else {
146 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
147 	}
148 }
149 
150 
151 /*
152  * ndmpd_api_log_v2
153  *
154  * Sends a log request to the NDMP client.
155  *
156  * Parameters:
157  *   cookie (input) - session pointer.
158  *   str    (input) - null terminated string
159  *   format (input) - printf style format.
160  *   ...    (input) - format arguments.
161  *
162  * Returns:
163  *   0 - success.
164  *  -1 - error.
165  */
166 /*ARGSUSED*/
167 int
168 ndmpd_api_log_v2(void *cookie, char *format, ...)
169 {
170 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
171 	ndmp_log_log_request request;
172 	static char buf[1024];
173 	va_list ap;
174 
175 	if (session == NULL)
176 		return (-1);
177 
178 	va_start(ap, format);
179 
180 	/*LINTED variable format specifier */
181 	(void) vsnprintf(buf, sizeof (buf), format, ap);
182 	va_end(ap);
183 
184 	request.entry = buf;
185 
186 
187 	if (ndmp_send_request(session->ns_connection, _NDMP_LOG_LOG,
188 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
189 		NDMP_LOG(LOG_DEBUG, "Sending log request");
190 		return (-1);
191 	}
192 	return (0);
193 
194 }
195 
196 
197 /*
198  * ndmpd_api_read_v2
199  *
200  * Callback function called by the backup/recover module.
201  * Reads data from the mover.
202  * If the mover is remote, the data is read from the data connection.
203  * If the mover is local, the data is read from the tape device.
204  *
205  * Parameters:
206  *   client_data (input) - session pointer.
207  *   data       (input) - data to be written.
208  *   length     (input) - data length.
209  *
210  * Returns:
211  *   0 - data successfully read.
212  *  -1 - error.
213  *   1 - session terminated or operation aborted.
214  */
215 int
216 ndmpd_api_read_v2(void *client_data, char *data, ulong_t length)
217 {
218 	ndmpd_session_t *session = (ndmpd_session_t *)client_data;
219 
220 	if (session == NULL)
221 		return (-1);
222 
223 	/*
224 	 * Read the data from the data connection if the mover is remote.
225 	 */
226 	if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP)
227 		return (ndmpd_remote_read(session, data, length));
228 	else
229 		return (ndmpd_local_read(session, data, length));
230 }
231 
232 
233 /*
234  * ndmpd_api_seek_v2
235  *
236  * Seek to the specified position in the data stream and start a
237  * read for the specified amount of data.
238  *
239  * Parameters:
240  *   cookie (input) - session pointer.
241  *   offset (input) - stream position to seek to.
242  *   length (input) - amount of data that will be read using ndmpd_api_read
243  *
244  * Returns:
245  *   0 - seek successful.
246  *  -1 - error.
247  */
248 int
249 ndmpd_api_seek_v2(void *cookie, u_longlong_t offset, u_longlong_t length)
250 {
251 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
252 	int err;
253 
254 	if (session == NULL)
255 		return (-1);
256 
257 	session->ns_data.dd_read_offset = offset;
258 	session->ns_data.dd_read_length = length;
259 
260 	/*
261 	 * Send a notify_data_read request if the mover is remote.
262 	 */
263 	if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
264 		ndmp_notify_data_read_request request;
265 
266 		session->ns_mover.md_discard_length =
267 		    session->ns_mover.md_bytes_left_to_read;
268 		session->ns_mover.md_bytes_left_to_read = length;
269 		session->ns_mover.md_position = offset;
270 
271 		request.offset = long_long_to_quad(offset);
272 		request.length = long_long_to_quad(length);
273 
274 		if (ndmp_send_request_lock(session->ns_connection,
275 		    NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
276 		    (void *)&request, 0) < 0) {
277 
278 			NDMP_LOG(LOG_DEBUG,
279 			    "Sending notify_data_read request");
280 			return (-1);
281 		}
282 		return (0);
283 	}
284 	/* Mover is local. */
285 
286 	err = ndmpd_mover_seek(session, offset, length);
287 	if (err < 0) {
288 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
289 		return (-1);
290 	}
291 	if (err == 0)
292 		return (0);
293 
294 	/*
295 	 * NDMP client intervention is required to perform the seek.
296 	 * Wait for the client to either do the seek and send a continue
297 	 * request or send an abort request.
298 	 */
299 	return (ndmp_wait_for_mover(session));
300 }
301 
302 
303 /*
304  * ndmpd_api_file_recovered_v2
305  *
306  * Notify the NDMP client that the specified file was recovered.
307  *
308  * Parameters:
309  *   cookie (input) - session pointer.
310  *   name   (input) - name of recovered file.
311  *   error  (input) - 0 if file successfully recovered.
312  *		    otherwise, error code indicating why recovery failed.
313  *
314  * Returns:
315  *   void.
316  */
317 int
318 ndmpd_api_file_recovered_v2(void *cookie, char *name, int error)
319 {
320 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
321 	ndmp_log_file_request_v2 request;
322 
323 	if (session == NULL)
324 		return (-1);
325 
326 	request.name = name;
327 	request.ssid = 0;
328 
329 	switch (error) {
330 	case 0:
331 		request.error = NDMP_NO_ERR;
332 		break;
333 	case ENOENT:
334 		request.error = NDMP_FILE_NOT_FOUND_ERR;
335 		break;
336 	default:
337 		request.error = NDMP_PERMISSION_ERR;
338 	}
339 
340 	if (ndmp_send_request_lock(session->ns_connection, NDMP_LOG_FILE,
341 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
342 		NDMP_LOG(LOG_DEBUG, "Sending log file request");
343 		return (-1);
344 	}
345 	return (0);
346 }
347 
348 
349 /*
350  * ndmpd_api_write_v2
351  *
352  * Callback function called by the backup/restore module.
353  * Writes data to the mover.
354  * If the mover is remote, the data is written to the data connection.
355  * If the mover is local, the data is buffered and written to the
356  * tape device after a full record has been buffered.
357  *
358  * Parameters:
359  *   client_data (input) - session pointer.
360  *   data       (input) - data to be written.
361  *   length     (input) - data length.
362  *
363  * Returns:
364  *   0 - data successfully written.
365  *  -1 - error.
366  */
367 int
368 ndmpd_api_write_v2(void *client_data, char *data, ulong_t length)
369 {
370 	ndmpd_session_t *session = (ndmpd_session_t *)client_data;
371 
372 	if (session == NULL)
373 		return (-1);
374 
375 	/*
376 	 * Write the data to the data connection if the mover is remote.
377 	 */
378 	if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP)
379 		return (ndmpd_remote_write(session, data, length));
380 	else
381 		return (ndmpd_local_write(session, data, length));
382 }
383 
384 
385 /*
386  * ************************************************************************
387  * NDMP V3 CALLBACKS
388  * ************************************************************************
389  */
390 
391 /*
392  * ndmpd_api_done_v3
393  *
394  * Called when the data module has completed.
395  * Sends a notify_halt request to the NDMP client.
396  *
397  * Parameters:
398  *   session (input) - session pointer.
399  *   err     (input) - UNIX error code.
400  *
401  * Returns:
402  *   void
403  */
404 void
405 ndmpd_api_done_v3(void *cookie, int err)
406 {
407 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
408 	ndmp_data_halt_reason reason;
409 
410 	switch (err) {
411 	case 0:
412 		reason = NDMP_DATA_HALT_SUCCESSFUL;
413 		break;
414 
415 	case EINTR:
416 		reason = NDMP_DATA_HALT_ABORTED;
417 		break;
418 
419 	case EIO:
420 		reason = NDMP_DATA_HALT_CONNECT_ERROR;
421 		break;
422 
423 	default:
424 		reason = NDMP_DATA_HALT_INTERNAL_ERROR;
425 	}
426 
427 	ndmpd_data_error(session, reason);
428 }
429 
430 /*
431  * ndmpd_api_log_v3
432  *
433  * Sends a log request to the NDMP client.
434  *
435  * Parameters:
436  *   cookie (input) - session pointer.
437  *   format (input) - printf style format.
438  *   ...    (input) - format arguments.
439  *
440  * Returns:
441  *   0 - success.
442  *  -1 - error.
443  */
444 /*ARGSUSED*/
445 int
446 ndmpd_api_log_v3(void *cookie, ndmp_log_type type, ulong_t msg_id,
447     char *format, ...)
448 {
449 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
450 	ndmp_log_message_request_v3 request;
451 	static char buf[1024];
452 	va_list ap;
453 
454 	if (session == NULL)
455 		return (-1);
456 
457 	va_start(ap, format);
458 
459 	/*LINTED variable format specifier */
460 	(void) vsnprintf(buf, sizeof (buf), format, ap);
461 	va_end(ap);
462 
463 	request.entry = buf;
464 	request.log_type = type;
465 	request.message_id = msg_id;
466 
467 	if (ndmp_send_request(session->ns_connection, NDMP_LOG_MESSAGE,
468 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
469 		NDMP_LOG(LOG_DEBUG, "Error sending log message request.");
470 		return (-1);
471 	}
472 	return (0);
473 }
474 
475 
476 /*
477  * ndmpd_api_write_v3
478  *
479  * Callback function called by the backup/restore module.
480  * Writes data to the mover.
481  * If the mover is remote, the data is written to the data connection.
482  * If the mover is local, the data is buffered and written to the
483  * tape device after a full record has been buffered.
484  *
485  * Parameters:
486  *   client_data (input) - session pointer.
487  *   data       (input) - data to be written.
488  *   length     (input) - data length.
489  *
490  * Returns:
491  *   0 - data successfully written.
492  *  -1 - error.
493  */
494 int
495 ndmpd_api_write_v3(void *client_data, char *data, ulong_t length)
496 {
497 	ndmpd_session_t *session = (ndmpd_session_t *)client_data;
498 
499 	if (session == NULL)
500 		return (-1);
501 
502 	/*
503 	 * Write the data to the tape if the mover is local, otherwise,
504 	 * write the data to the data connection.
505 	 *
506 	 * The same write function for of v2 can be used in V3
507 	 * for writing data to the data connection to the mover.
508 	 * So we don't need ndmpd_remote_write_v3().
509 	 */
510 	if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL)
511 		return (ndmpd_local_write_v3(session, data, length));
512 	else
513 		return (ndmpd_remote_write(session, data, length));
514 }
515 
516 
517 /*
518  * ndmpd_api_read_v3
519  *
520  * Callback function called by the backup/recover module.
521  * Reads data from the mover.
522  * If the mover is remote, the data is read from the data connection.
523  * If the mover is local, the data is read from the tape device.
524  *
525  * Parameters:
526  *   client_data (input) - session pointer.
527  *   data       (input) - data to be written.
528  *   length     (input) - data length.
529  *
530  * Returns:
531  *   0 - data successfully read.
532  *  -1 - error.
533  *   1 - session terminated or operation aborted.
534  */
535 int
536 ndmpd_api_read_v3(void *client_data, char *data, ulong_t length)
537 {
538 	ndmpd_session_t *session = (ndmpd_session_t *)client_data;
539 
540 	if (session == NULL)
541 		return (-1);
542 
543 	/*
544 	 * Read the data from the data connection if the mover is remote.
545 	 */
546 	if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL)
547 		return (ndmpd_local_read_v3(session, data, length));
548 	else
549 		return (ndmpd_remote_read_v3(session, data, length));
550 }
551 
552 
553 /*
554  * ndmpd_api_get_name_v3
555  *
556  * Return the name entry at the specified index from the
557  * recover file name list.
558  *
559  * Parameters:
560  *       cookie    (input) - NDMP session pointer.
561  *       name_index (input) - index of entry to be returned.
562  *
563  * Returns:
564  *   Pointer to name entry.
565  *   0 if requested entry does not exist.
566  */
567 void *
568 ndmpd_api_get_name_v3(void *cookie, ulong_t name_index)
569 {
570 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
571 
572 	if (session == NULL)
573 		return (NULL);
574 
575 	if (name_index >= session->ns_data.dd_nlist_len)
576 		return (NULL);
577 
578 	return (&session->ns_data.dd_nlist_v3[name_index]);
579 }
580 
581 
582 /*
583  * ndmpd_api_file_recovered_v3
584  *
585  * Notify the NDMP client that the specified file was recovered.
586  *
587  * Parameters:
588  *   cookie (input) - session pointer.
589  *   name   (input) - name of recovered file.
590  *   ssid   (input) - selection set id.
591  *   error  (input) - 0 if file successfully recovered.
592  *		    otherwise, error code indicating why recovery failed.
593  *
594  * Returns:
595  *   0 - success.
596  *  -1 - error.
597  */
598 int
599 ndmpd_api_file_recovered_v3(void *cookie, char *name, int error)
600 {
601 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
602 	ndmp_log_file_request_v3 request;
603 
604 	if (session == NULL)
605 		return (-1);
606 
607 	request.name  = name;
608 
609 	switch (error) {
610 	case 0:
611 		request.error = NDMP_NO_ERR;
612 		break;
613 	case ENOENT:
614 		request.error = NDMP_FILE_NOT_FOUND_ERR;
615 		break;
616 	default:
617 		request.error = NDMP_PERMISSION_ERR;
618 	}
619 
620 	if (ndmp_send_request_lock(session->ns_connection, NDMP_LOG_FILE,
621 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
622 		NDMP_LOG(LOG_DEBUG, "Error sending log file request");
623 		return (-1);
624 	}
625 
626 	return (0);
627 }
628 
629 
630 /*
631  * ndmpd_api_seek_v3
632  *
633  * Seek to the specified position in the data stream and start a
634  * read for the specified amount of data.
635  *
636  * Parameters:
637  *   cookie (input) - session pointer.
638  *   offset (input) - stream position to seek to.
639  *   length (input) - amount of data that will be read using ndmpd_api_read
640  *
641  * Returns:
642  *   0 - seek successful.
643  *   1 - seek needed DMA(client) intervention.
644  *  -1 - error.
645  */
646 int
647 ndmpd_api_seek_v3(void *cookie, u_longlong_t offset, u_longlong_t length)
648 {
649 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
650 	int err;
651 	ndmp_notify_data_read_request request;
652 
653 	if (session == NULL)
654 		return (-1);
655 
656 	session->ns_data.dd_read_offset = offset;
657 	session->ns_data.dd_read_length = length;
658 
659 	/*
660 	 * Send a notify_data_read request if the mover is remote.
661 	 */
662 	if (session->ns_data.dd_data_addr.addr_type != NDMP_ADDR_LOCAL) {
663 		session->ns_data.dd_discard_length =
664 		    session->ns_data.dd_bytes_left_to_read;
665 		session->ns_data.dd_bytes_left_to_read = length;
666 		session->ns_data.dd_position = offset;
667 
668 		request.offset = long_long_to_quad(offset);
669 		request.length = long_long_to_quad(length);
670 
671 		if (ndmp_send_request_lock(session->ns_connection,
672 		    NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
673 		    (void *)&request, 0) < 0) {
674 			NDMP_LOG(LOG_DEBUG,
675 			    "Sending notify_data_read request");
676 			return (-1);
677 		}
678 
679 		return (0);
680 	}
681 
682 	/* Mover is local. */
683 
684 	err = ndmpd_mover_seek(session, offset, length);
685 	if (err < 0) {
686 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
687 		return (-1);
688 	}
689 
690 	if (err == 0)
691 		return (0);
692 
693 	/*
694 	 * NDMP client intervention is required to perform the seek.
695 	 * Wait for the client to either do the seek and send a continue
696 	 * request or send an abort request.
697 	 */
698 	err = ndmp_wait_for_mover(session);
699 
700 	/*
701 	 * If we needed a client intervention, then we should be able to
702 	 * detect this in DAR.
703 	 */
704 	if (err == 0)
705 		err = 1;
706 	return (err);
707 }
708 
709 
710 /*
711  * ************************************************************************
712  * NDMP V4 CALLBACKS
713  * ************************************************************************
714  */
715 
716 /*
717  * ndmpd_api_log_v4
718  *
719  * Sends a log request to the NDMP client.
720  * No message association is supported now, but can be added later on
721  * in this function.
722  *
723  * Parameters:
724  *   cookie (input) - session pointer.
725  *   format (input) - printf style format.
726  *   ...    (input) - format arguments.
727  *
728  * Returns:
729  *   0 - success.
730  *  -1 - error.
731  */
732 /*ARGSUSED*/
733 int
734 ndmpd_api_log_v4(void *cookie, ndmp_log_type type, ulong_t msg_id,
735     char *format, ...)
736 {
737 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
738 	ndmp_log_message_request_v4 request;
739 	static char buf[1024];
740 	va_list ap;
741 
742 	if (session == NULL)
743 		return (-1);
744 
745 	va_start(ap, format);
746 
747 	/*LINTED variable format specifier */
748 	(void) vsnprintf(buf, sizeof (buf), format, ap);
749 	va_end(ap);
750 
751 	request.entry = buf;
752 	request.log_type = type;
753 	request.message_id = msg_id;
754 	request.associated_message_valid = NDMP_NO_ASSOCIATED_MESSAGE;
755 	request.associated_message_sequence = 0;
756 
757 	if (ndmp_send_request(session->ns_connection, NDMP_LOG_MESSAGE,
758 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
759 		NDMP_LOG(LOG_DEBUG, "Error sending log message request.");
760 		return (-1);
761 	}
762 	return (0);
763 }
764 
765 
766 /*
767  * ndmpd_api_file_recovered_v4
768  *
769  * Notify the NDMP client that the specified file was recovered.
770  *
771  * Parameters:
772  *   cookie (input) - session pointer.
773  *   name   (input) - name of recovered file.
774  *   ssid   (input) - selection set id.
775  *   error  (input) - 0 if file successfully recovered.
776  *		    otherwise, error code indicating why recovery failed.
777  *
778  * Returns:
779  *   void.
780  */
781 int
782 ndmpd_api_file_recovered_v4(void *cookie, char *name, int error)
783 {
784 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
785 	ndmp_log_file_request_v4 request;
786 
787 	if (session == NULL)
788 		return (-1);
789 
790 	request.name  = name;
791 
792 	switch (error) {
793 	case 0:
794 		request.recovery_status = NDMP_RECOVERY_SUCCESSFUL;
795 		break;
796 	case EPERM:
797 		request.recovery_status = NDMP_RECOVERY_FAILED_PERMISSION;
798 		break;
799 	case ENOENT:
800 		request.recovery_status = NDMP_RECOVERY_FAILED_NOT_FOUND;
801 		break;
802 	case ENOTDIR:
803 		request.recovery_status = NDMP_RECOVERY_FAILED_NO_DIRECTORY;
804 		break;
805 	case ENOMEM:
806 		request.recovery_status = NDMP_RECOVERY_FAILED_OUT_OF_MEMORY;
807 		break;
808 	case EIO:
809 		request.recovery_status = NDMP_RECOVERY_FAILED_IO_ERROR;
810 		break;
811 	case EEXIST:
812 		request.recovery_status = NDMP_RECOVERY_FAILED_FILE_PATH_EXISTS;
813 		break;
814 	default:
815 		request.recovery_status = NDMP_RECOVERY_FAILED_UNDEFINED_ERROR;
816 		break;
817 	}
818 
819 	if (ndmp_send_request_lock(session->ns_connection, NDMP_LOG_FILE,
820 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
821 		NDMP_LOG(LOG_DEBUG, "Error sending log file request");
822 		return (-1);
823 	}
824 
825 	return (0);
826 }
827 
828 
829 /*
830  * ************************************************************************
831  * LOCALS
832  * ************************************************************************
833  */
834 
835 /*
836  * ndmpd_api_find_env
837  *
838  * Return the pointer of the environment variable from the variable
839  * array for the spcified environment variable.
840  *
841  * Parameters:
842  *       cookie (input) - NDMP session pointer.
843  *       name   (input) - name of variable.
844  *
845  * Returns:
846  *   Pointer to variable.
847  *   NULL if variable not found.
848  *
849  */
850 ndmp_pval *
851 ndmpd_api_find_env(void *cookie, char *name)
852 {
853 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
854 	ulong_t i;
855 	ndmp_pval *envp;
856 
857 	if (session == NULL)
858 		return (NULL);
859 
860 	envp = session->ns_data.dd_env;
861 	for (i = 0; envp && i < session->ns_data.dd_env_len; envp++, i++)
862 		if (strcmp(name, envp->name) == NULL)
863 			return (envp);
864 
865 	return (NULL);
866 }
867 
868 
869 /*
870  * ndmpd_api_get_env
871  *
872  * Return the value of an environment variable from the variable array.
873  *
874  * Parameters:
875  *       cookie (input) - NDMP session pointer.
876  *       name   (input) - name of variable.
877  *
878  * Returns:
879  *   Pointer to variable value.
880  *   0 if variable not found.
881  *
882  */
883 char *
884 ndmpd_api_get_env(void *cookie, char *name)
885 {
886 	ndmp_pval *envp;
887 
888 	envp = ndmpd_api_find_env(cookie, name);
889 	if (envp)
890 		return (envp->value);
891 
892 	return (NULL);
893 }
894 
895 
896 /*
897  * ndmpd_api_add_env
898  *
899  * Adds an environment variable name/value pair to the environment
900  * variable list.
901  *
902  * Parameters:
903  *   session (input) - session pointer.
904  *   name    (input) - variable name.
905  *   val     (input) - value.
906  *
907  * Returns:
908  *   0 - success.
909  *  -1 - error.
910  */
911 int
912 ndmpd_api_add_env(void *cookie, char *name, char *value)
913 {
914 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
915 	char *namebuf;
916 	char *valbuf;
917 
918 	if (session == NULL)
919 		return (-1);
920 
921 	session->ns_data.dd_env = realloc((void *)session->ns_data.dd_env,
922 	    sizeof (ndmp_pval) * (session->ns_data.dd_env_len + 1));
923 
924 	if (session->ns_data.dd_env == NULL) {
925 		NDMP_LOG(LOG_ERR, "Out of memory.");
926 		return (-1);
927 	}
928 	namebuf = strdup(name);
929 	if (namebuf == NULL)
930 		return (-1);
931 
932 	valbuf = strdup(value);
933 	if (valbuf == NULL) {
934 		free(namebuf);
935 		return (-1);
936 	}
937 
938 	(void) mutex_lock(&session->ns_lock);
939 	session->ns_data.dd_env[session->ns_data.dd_env_len].name = namebuf;
940 	session->ns_data.dd_env[session->ns_data.dd_env_len].value = valbuf;
941 	session->ns_data.dd_env_len++;
942 	(void) mutex_unlock(&session->ns_lock);
943 
944 	return (0);
945 }
946 
947 
948 /*
949  * ndmpd_api_set_env
950  *
951  * Sets an environment variable name/value pair in the environment
952  * variable list.  If the variable exists, it gets the new value,
953  * otherwise it's added as a new variable.
954  *
955  * Parameters:
956  *   session (input) - session pointer.
957  *   name    (input) - variable name.
958  *   val     (input) - value.
959  *
960  * Returns:
961  *   0 - success.
962  *  -1 - error.
963  */
964 int
965 ndmpd_api_set_env(void *cookie, char *name, char *value)
966 {
967 	char *valbuf;
968 	int rv;
969 	ndmp_pval *envp;
970 
971 	envp = ndmpd_api_find_env(cookie, name);
972 	if (!envp) {
973 		rv = ndmpd_api_add_env(cookie, name, value);
974 	} else if (!(valbuf = strdup(value))) {
975 		rv = -1;
976 	} else {
977 		rv = 0;
978 		free(envp->value);
979 		envp->value = valbuf;
980 	}
981 
982 	return (rv);
983 }
984 
985 
986 /*
987  * ndmpd_api_get_name
988  *
989  * Return the name entry at the specified index from the
990  * recover file name list.
991  *
992  * Parameters:
993  *   cookie    (input) - NDMP session pointer.
994  *   name_index (input) - index of entry to be returned.
995  *
996  * Returns:
997  *   Pointer to name entry.
998  *   0 if requested entry does not exist.
999  */
1000 void *
1001 ndmpd_api_get_name(void *cookie, ulong_t name_index)
1002 {
1003 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
1004 
1005 	if (session == NULL)
1006 		return (NULL);
1007 
1008 	if (name_index >= session->ns_data.dd_nlist_len)
1009 		return (NULL);
1010 
1011 	return (&session->ns_data.dd_nlist[name_index]);
1012 }
1013 
1014 
1015 /*
1016  * ndmpd_api_dispatch
1017  *
1018  * Process pending NDMP client requests and check registered files for
1019  * data availability.
1020  *
1021  * Parameters:
1022  *   cookie (input) - session pointer.
1023  *   block  (input) -
1024  * 		TRUE 	block until a request has been processed or
1025  *			until a file handler has been called.
1026  *		FALSE	don't block.
1027  *
1028  * Returns:
1029  *  -1 - abort request received or connection closed.
1030  *   0 - success.
1031  */
1032 int
1033 ndmpd_api_dispatch(void *cookie, boolean_t block)
1034 {
1035 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
1036 	int err;
1037 
1038 	if (session == NULL)
1039 		return (-1);
1040 
1041 	for (; ; ) {
1042 		err = ndmpd_select(session, block, HC_ALL);
1043 		if (err < 0 || session->ns_data.dd_abort == TRUE ||
1044 		    session->ns_eof)
1045 			return (-1);
1046 
1047 		if (err == 0)
1048 			return (0);
1049 
1050 		/*
1051 		 * Something was processed.
1052 		 * Set the block flag to false so that we will return as
1053 		 * soon as everything available to be processed has been
1054 		 * processed.
1055 		 */
1056 		block = FALSE;
1057 	}
1058 }
1059 
1060 
1061 /*
1062  * ndmpd_api_add_file_handler
1063  *
1064  * Adds a file handler to the file handler list.
1065  * The file handler list is used by ndmpd_api_dispatch.
1066  *
1067  * Parameters:
1068  *   daemon_cookie (input) - session pointer.
1069  *   cookie  (input) - opaque data to be passed to file hander when called.
1070  *   fd      (input) - file descriptor.
1071  *   mode    (input) - bitmask of the following:
1072  *	NDMP_SELECT_MODE_READ = watch file for ready for reading
1073  *	NDMP_SELECT_MODE_WRITE = watch file for ready for writing
1074  *	NDMP_SELECT_MODE_EXCEPTION = watch file for exception
1075  *   func    (input) - function to call when the file meets one of the
1076  *		     conditions specified by mode.
1077  *
1078  * Returns:
1079  *   0 - success.
1080  *  -1 - error.
1081  */
1082 int
1083 ndmpd_api_add_file_handler(void *daemon_cookie, void *cookie, int fd,
1084     ulong_t mode, ndmpd_file_handler_func_t *func)
1085 {
1086 	ndmpd_session_t *session = (ndmpd_session_t *)daemon_cookie;
1087 
1088 	return (ndmpd_add_file_handler(session, cookie, fd, mode, HC_MODULE,
1089 	    func));
1090 }
1091 
1092 
1093 /*
1094  * ndmpd_api_remove_file_handler
1095  *
1096  * Removes a file handler from the file handler list.
1097  *
1098  * Parameters:
1099  *   cookie  (input) - session pointer.
1100  *   fd      (input) - file descriptor.
1101  *
1102  * Returns:
1103  *   0 - success.
1104  *  -1 - error.
1105  */
1106 int
1107 ndmpd_api_remove_file_handler(void *cookie, int fd)
1108 {
1109 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
1110 
1111 	return (ndmpd_remove_file_handler(session, fd));
1112 }
1113