xref: /titanic_50/usr/src/cmd/ndmpd/ndmp/ndmpd_callbacks.c (revision da14cebe459d3275048785f25bd869cb09b5307f)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * BSD 3 Clause License
8  *
9  * Copyright (c) 2007, The Storage Networking Industry Association.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 	- Redistributions of source code must retain the above copyright
15  *	  notice, this list of conditions and the following disclaimer.
16  *
17  * 	- Redistributions in binary form must reproduce the above copyright
18  *	  notice, this list of conditions and the following disclaimer in
19  *	  the documentation and/or other materials provided with the
20  *	  distribution.
21  *
22  *	- Neither the name of The Storage Networking Industry Association (SNIA)
23  *	  nor the names of its contributors may be used to endorse or promote
24  *	  products derived from this software without specific prior written
25  *	  permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. 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 	nlp_ref_nw(session);
300 	for (; ; ) {
301 		nlp_wait_nw(session);
302 
303 		if (nlp_event_rv_get(session) < 0) {
304 			nlp_unref_nw(session);
305 			return (-1);
306 		}
307 
308 		if (session->ns_eof == TRUE) {
309 			nlp_unref_nw(session);
310 			return (-1);
311 		}
312 
313 		switch (session->ns_mover.md_state) {
314 		case NDMP_MOVER_STATE_ACTIVE:
315 			/*
316 			 * There is a bug in the original SDK code which
317 			 * causes to fall in an infinite loop after the
318 			 * break.
319 			 */
320 			nlp_unref_nw(session);
321 			break;
322 
323 		case NDMP_MOVER_STATE_PAUSED:
324 			continue;
325 
326 		default:
327 			nlp_unref_nw(session);
328 			return (-1);
329 		}
330 	}
331 }
332 
333 
334 /*
335  * ndmpd_api_file_recovered_v2
336  *
337  * Notify the NDMP client that the specified file was recovered.
338  *
339  * Parameters:
340  *   cookie (input) - session pointer.
341  *   name   (input) - name of recovered file.
342  *   error  (input) - 0 if file successfully recovered.
343  *		    otherwise, error code indicating why recovery failed.
344  *
345  * Returns:
346  *   void.
347  */
348 int
349 ndmpd_api_file_recovered_v2(void *cookie, char *name, int error)
350 {
351 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
352 	ndmp_log_file_request_v2 request;
353 
354 	if (session == NULL)
355 		return (-1);
356 
357 	request.name = name;
358 	request.ssid = 0;
359 
360 	switch (error) {
361 	case 0:
362 		request.error = NDMP_NO_ERR;
363 		break;
364 	case ENOENT:
365 		request.error = NDMP_FILE_NOT_FOUND_ERR;
366 		break;
367 	default:
368 		request.error = NDMP_PERMISSION_ERR;
369 	}
370 
371 	if (ndmp_send_request(session->ns_connection, NDMP_LOG_FILE,
372 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
373 		NDMP_LOG(LOG_DEBUG, "Sending log file request");
374 		return (-1);
375 	}
376 	return (0);
377 }
378 
379 
380 /*
381  * ndmpd_api_write_v2
382  *
383  * Callback function called by the backup/restore module.
384  * Writes data to the mover.
385  * If the mover is remote, the data is written to the data connection.
386  * If the mover is local, the data is buffered and written to the
387  * tape device after a full record has been buffered.
388  *
389  * Parameters:
390  *   client_data (input) - session pointer.
391  *   data       (input) - data to be written.
392  *   length     (input) - data length.
393  *
394  * Returns:
395  *   0 - data successfully written.
396  *  -1 - error.
397  */
398 int
399 ndmpd_api_write_v2(void *client_data, char *data, ulong_t length)
400 {
401 	ndmpd_session_t *session = (ndmpd_session_t *)client_data;
402 
403 	if (session == NULL)
404 		return (-1);
405 
406 	/*
407 	 * Write the data to the data connection if the mover is remote.
408 	 */
409 	if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP)
410 		return (ndmpd_remote_write(session, data, length));
411 	else
412 		return (ndmpd_local_write(session, data, length));
413 }
414 
415 
416 /*
417  * ************************************************************************
418  * NDMP V3 CALLBACKS
419  * ************************************************************************
420  */
421 
422 /*
423  * ndmpd_api_done_v3
424  *
425  * Called when the data module has completed.
426  * Sends a notify_halt request to the NDMP client.
427  *
428  * Parameters:
429  *   session (input) - session pointer.
430  *   err     (input) - UNIX error code.
431  *
432  * Returns:
433  *   void
434  */
435 void
436 ndmpd_api_done_v3(void *cookie, int err)
437 {
438 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
439 	ndmp_data_halt_reason reason;
440 
441 	switch (err) {
442 	case 0:
443 		reason = NDMP_DATA_HALT_SUCCESSFUL;
444 		break;
445 
446 	case EINTR:
447 		reason = NDMP_DATA_HALT_ABORTED;
448 		break;
449 
450 	case EIO:
451 		reason = NDMP_DATA_HALT_CONNECT_ERROR;
452 		break;
453 
454 	default:
455 		reason = NDMP_DATA_HALT_INTERNAL_ERROR;
456 	}
457 
458 	ndmpd_data_error(session, reason);
459 }
460 
461 /*
462  * ndmpd_api_log_v3
463  *
464  * Sends a log request to the NDMP client.
465  *
466  * Parameters:
467  *   cookie (input) - session pointer.
468  *   format (input) - printf style format.
469  *   ...    (input) - format arguments.
470  *
471  * Returns:
472  *   0 - success.
473  *  -1 - error.
474  */
475 /*ARGSUSED*/
476 int
477 ndmpd_api_log_v3(void *cookie, ndmp_log_type type, ulong_t msg_id,
478     char *format, ...)
479 {
480 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
481 	ndmp_log_message_request_v3 request;
482 	static char buf[1024];
483 	va_list ap;
484 
485 	if (session == NULL)
486 		return (-1);
487 
488 	va_start(ap, format);
489 
490 	/*LINTED variable format specifier */
491 	(void) vsnprintf(buf, sizeof (buf), format, ap);
492 	va_end(ap);
493 
494 	request.entry = buf;
495 	request.log_type = type;
496 	request.message_id = msg_id;
497 
498 	if (ndmp_send_request(session->ns_connection, NDMP_LOG_MESSAGE,
499 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
500 		NDMP_LOG(LOG_DEBUG, "Error sending log message request.");
501 		return (-1);
502 	}
503 	return (0);
504 }
505 
506 
507 /*
508  * ndmpd_api_write_v3
509  *
510  * Callback function called by the backup/restore module.
511  * Writes data to the mover.
512  * If the mover is remote, the data is written to the data connection.
513  * If the mover is local, the data is buffered and written to the
514  * tape device after a full record has been buffered.
515  *
516  * Parameters:
517  *   client_data (input) - session pointer.
518  *   data       (input) - data to be written.
519  *   length     (input) - data length.
520  *
521  * Returns:
522  *   0 - data successfully written.
523  *  -1 - error.
524  */
525 int
526 ndmpd_api_write_v3(void *client_data, char *data, ulong_t length)
527 {
528 	ndmpd_session_t *session = (ndmpd_session_t *)client_data;
529 
530 	if (session == NULL)
531 		return (-1);
532 
533 	/*
534 	 * Write the data to the tape if the mover is local, otherwise,
535 	 * write the data to the data connection.
536 	 *
537 	 * The same write function for of v2 can be used in V3
538 	 * for writing data to the data connection to the mover.
539 	 * So we don't need ndmpd_remote_write_v3().
540 	 */
541 	if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL)
542 		return (ndmpd_local_write_v3(session, data, length));
543 	else
544 		return (ndmpd_remote_write(session, data, length));
545 }
546 
547 
548 /*
549  * ndmpd_api_read_v3
550  *
551  * Callback function called by the backup/recover module.
552  * Reads data from the mover.
553  * If the mover is remote, the data is read from the data connection.
554  * If the mover is local, the data is read from the tape device.
555  *
556  * Parameters:
557  *   client_data (input) - session pointer.
558  *   data       (input) - data to be written.
559  *   length     (input) - data length.
560  *
561  * Returns:
562  *   0 - data successfully read.
563  *  -1 - error.
564  *   1 - session terminated or operation aborted.
565  */
566 int
567 ndmpd_api_read_v3(void *client_data, char *data, ulong_t length)
568 {
569 	ndmpd_session_t *session = (ndmpd_session_t *)client_data;
570 
571 	if (session == NULL)
572 		return (-1);
573 
574 	/*
575 	 * Read the data from the data connection if the mover is remote.
576 	 */
577 	if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL)
578 		return (ndmpd_local_read_v3(session, data, length));
579 	else
580 		return (ndmpd_remote_read_v3(session, data, length));
581 }
582 
583 
584 /*
585  * ndmpd_api_get_name_v3
586  *
587  * Return the name entry at the specified index from the
588  * recover file name list.
589  *
590  * Parameters:
591  *       cookie    (input) - NDMP session pointer.
592  *       name_index (input) - index of entry to be returned.
593  *
594  * Returns:
595  *   Pointer to name entry.
596  *   0 if requested entry does not exist.
597  */
598 void *
599 ndmpd_api_get_name_v3(void *cookie, ulong_t name_index)
600 {
601 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
602 
603 	if (session == NULL)
604 		return (NULL);
605 
606 	if (name_index >= session->ns_data.dd_nlist_len)
607 		return (NULL);
608 
609 	return (&session->ns_data.dd_nlist_v3[name_index]);
610 }
611 
612 
613 /*
614  * ndmpd_api_file_recovered_v3
615  *
616  * Notify the NDMP client that the specified file was recovered.
617  *
618  * Parameters:
619  *   cookie (input) - session pointer.
620  *   name   (input) - name of recovered file.
621  *   ssid   (input) - selection set id.
622  *   error  (input) - 0 if file successfully recovered.
623  *		    otherwise, error code indicating why recovery failed.
624  *
625  * Returns:
626  *   0 - success.
627  *  -1 - error.
628  */
629 int
630 ndmpd_api_file_recovered_v3(void *cookie, char *name, int error)
631 {
632 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
633 	ndmp_log_file_request_v3 request;
634 
635 	if (session == NULL)
636 		return (-1);
637 
638 	request.name  = name;
639 
640 	switch (error) {
641 	case 0:
642 		request.error = NDMP_NO_ERR;
643 		break;
644 	case ENOENT:
645 		request.error = NDMP_FILE_NOT_FOUND_ERR;
646 		break;
647 	default:
648 		request.error = NDMP_PERMISSION_ERR;
649 	}
650 
651 	if (ndmp_send_request(session->ns_connection, NDMP_LOG_FILE,
652 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
653 		NDMP_LOG(LOG_DEBUG, "Error sending log file request");
654 		return (-1);
655 	}
656 
657 	return (0);
658 }
659 
660 
661 /*
662  * ndmpd_api_seek_v3
663  *
664  * Seek to the specified position in the data stream and start a
665  * read for the specified amount of data.
666  *
667  * Parameters:
668  *   cookie (input) - session pointer.
669  *   offset (input) - stream position to seek to.
670  *   length (input) - amount of data that will be read using ndmpd_api_read
671  *
672  * Returns:
673  *   0 - seek successful.
674  *   1 - seek needed DMA(client) intervention.
675  *  -1 - error.
676  */
677 int
678 ndmpd_api_seek_v3(void *cookie, u_longlong_t offset, u_longlong_t length)
679 {
680 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
681 	int err;
682 	ndmp_notify_data_read_request request;
683 
684 	if (session == NULL)
685 		return (-1);
686 
687 	session->ns_data.dd_read_offset = offset;
688 	session->ns_data.dd_read_length = length;
689 
690 	/*
691 	 * Send a notify_data_read request if the mover is remote.
692 	 */
693 	if (session->ns_data.dd_data_addr.addr_type != NDMP_ADDR_LOCAL) {
694 		session->ns_data.dd_discard_length =
695 		    session->ns_data.dd_bytes_left_to_read;
696 		session->ns_data.dd_bytes_left_to_read = length;
697 		session->ns_data.dd_position = offset;
698 
699 		request.offset = long_long_to_quad(offset);
700 		request.length = long_long_to_quad(length);
701 
702 		if (ndmp_send_request_lock(session->ns_connection,
703 		    NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
704 		    (void *)&request, 0) < 0) {
705 			NDMP_LOG(LOG_DEBUG,
706 			    "Sending notify_data_read request");
707 			return (-1);
708 		}
709 
710 		return (0);
711 	}
712 
713 	/* Mover is local. */
714 
715 	err = ndmpd_mover_seek(session, offset, length);
716 	if (err < 0) {
717 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
718 		return (-1);
719 	}
720 
721 	if (err == 0)
722 		return (0);
723 
724 	/*
725 	 * NDMP client intervention is required to perform the seek.
726 	 * Wait for the client to either do the seek and send a continue
727 	 * request or send an abort request.
728 	 */
729 	err = ndmpd_mover_wait_v3(session);
730 
731 	/*
732 	 * If we needed a client intervention, then we should be able to
733 	 * detect this in DAR.
734 	 */
735 	if (err == 0)
736 		err = 1;
737 	return (err);
738 }
739 
740 
741 /*
742  * ************************************************************************
743  * NDMP V4 CALLBACKS
744  * ************************************************************************
745  */
746 
747 /*
748  * ndmpd_api_log_v4
749  *
750  * Sends a log request to the NDMP client.
751  * No message association is supported now, but can be added later on
752  * in this function.
753  *
754  * Parameters:
755  *   cookie (input) - session pointer.
756  *   format (input) - printf style format.
757  *   ...    (input) - format arguments.
758  *
759  * Returns:
760  *   0 - success.
761  *  -1 - error.
762  */
763 /*ARGSUSED*/
764 int
765 ndmpd_api_log_v4(void *cookie, ndmp_log_type type, ulong_t msg_id,
766     char *format, ...)
767 {
768 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
769 	ndmp_log_message_request_v4 request;
770 	static char buf[1024];
771 	va_list ap;
772 
773 	if (session == NULL)
774 		return (-1);
775 
776 	va_start(ap, format);
777 
778 	/*LINTED variable format specifier */
779 	(void) vsnprintf(buf, sizeof (buf), format, ap);
780 	va_end(ap);
781 
782 	request.entry = buf;
783 	request.log_type = type;
784 	request.message_id = msg_id;
785 	request.associated_message_valid = NDMP_NO_ASSOCIATED_MESSAGE;
786 	request.associated_message_sequence = 0;
787 
788 	if (ndmp_send_request(session->ns_connection, NDMP_LOG_MESSAGE,
789 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
790 		NDMP_LOG(LOG_DEBUG, "Error sending log message request.");
791 		return (-1);
792 	}
793 	return (0);
794 }
795 
796 
797 /*
798  * ndmpd_api_file_recovered_v4
799  *
800  * Notify the NDMP client that the specified file was recovered.
801  *
802  * Parameters:
803  *   cookie (input) - session pointer.
804  *   name   (input) - name of recovered file.
805  *   ssid   (input) - selection set id.
806  *   error  (input) - 0 if file successfully recovered.
807  *		    otherwise, error code indicating why recovery failed.
808  *
809  * Returns:
810  *   void.
811  */
812 int
813 ndmpd_api_file_recovered_v4(void *cookie, char *name, int error)
814 {
815 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
816 	ndmp_log_file_request_v4 request;
817 
818 	if (session == NULL)
819 		return (-1);
820 
821 	request.name  = name;
822 
823 	switch (error) {
824 	case 0:
825 		request.recovery_status = NDMP_RECOVERY_SUCCESSFUL;
826 		break;
827 	case EPERM:
828 		request.recovery_status = NDMP_RECOVERY_FAILED_PERMISSION;
829 		break;
830 	case ENOENT:
831 		request.recovery_status = NDMP_RECOVERY_FAILED_NOT_FOUND;
832 		break;
833 	case ENOTDIR:
834 		request.recovery_status = NDMP_RECOVERY_FAILED_NO_DIRECTORY;
835 		break;
836 	case ENOMEM:
837 		request.recovery_status = NDMP_RECOVERY_FAILED_OUT_OF_MEMORY;
838 		break;
839 	case EIO:
840 		request.recovery_status = NDMP_RECOVERY_FAILED_IO_ERROR;
841 		break;
842 	case EEXIST:
843 		request.recovery_status = NDMP_RECOVERY_FAILED_FILE_PATH_EXISTS;
844 		break;
845 	default:
846 		request.recovery_status = NDMP_RECOVERY_FAILED_UNDEFINED_ERROR;
847 		break;
848 	}
849 
850 	if (ndmp_send_request(session->ns_connection, NDMP_LOG_FILE,
851 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
852 		NDMP_LOG(LOG_DEBUG, "Error sending log file request");
853 		return (-1);
854 	}
855 
856 	return (0);
857 }
858 
859 
860 /*
861  * ************************************************************************
862  * LOCALS
863  * ************************************************************************
864  */
865 
866 /*
867  * ndmpd_api_find_env
868  *
869  * Return the pointer of the environment variable from the variable
870  * array for the spcified environment variable.
871  *
872  * Parameters:
873  *       cookie (input) - NDMP session pointer.
874  *       name   (input) - name of variable.
875  *
876  * Returns:
877  *   Pointer to variable.
878  *   NULL if variable not found.
879  *
880  */
881 ndmp_pval *
882 ndmpd_api_find_env(void *cookie, char *name)
883 {
884 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
885 	ulong_t i;
886 	ndmp_pval *envp;
887 
888 	if (session == NULL)
889 		return (NULL);
890 
891 	envp = session->ns_data.dd_env;
892 	for (i = 0; envp && i < session->ns_data.dd_env_len; envp++, i++)
893 		if (strcmp(name, envp->name) == NULL)
894 			return (envp);
895 
896 	return (NULL);
897 }
898 
899 
900 /*
901  * ndmpd_api_get_env
902  *
903  * Return the value of an environment variable from the variable array.
904  *
905  * Parameters:
906  *       cookie (input) - NDMP session pointer.
907  *       name   (input) - name of variable.
908  *
909  * Returns:
910  *   Pointer to variable value.
911  *   0 if variable not found.
912  *
913  */
914 char *
915 ndmpd_api_get_env(void *cookie, char *name)
916 {
917 	ndmp_pval *envp;
918 
919 	envp = ndmpd_api_find_env(cookie, name);
920 	if (envp)
921 		return (envp->value);
922 
923 	return (NULL);
924 }
925 
926 
927 /*
928  * ndmpd_api_add_env
929  *
930  * Adds an environment variable name/value pair to the environment
931  * variable list.
932  *
933  * Parameters:
934  *   session (input) - session pointer.
935  *   name    (input) - variable name.
936  *   val     (input) - value.
937  *
938  * Returns:
939  *   0 - success.
940  *  -1 - error.
941  */
942 int
943 ndmpd_api_add_env(void *cookie, char *name, char *value)
944 {
945 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
946 	char *namebuf;
947 	char *valbuf;
948 
949 	if (session == NULL)
950 		return (-1);
951 
952 	session->ns_data.dd_env = realloc((void *)session->ns_data.dd_env,
953 	    sizeof (ndmp_pval) * (session->ns_data.dd_env_len + 1));
954 
955 	if (session->ns_data.dd_env == NULL) {
956 		NDMP_LOG(LOG_ERR, "Out of memory.");
957 		return (-1);
958 	}
959 	namebuf = strdup(name);
960 	if (namebuf == NULL)
961 		return (-1);
962 
963 	valbuf = strdup(value);
964 	if (valbuf == NULL) {
965 		free(namebuf);
966 		return (-1);
967 	}
968 
969 	(void) mutex_lock(&session->ns_lock);
970 	session->ns_data.dd_env[session->ns_data.dd_env_len].name = namebuf;
971 	session->ns_data.dd_env[session->ns_data.dd_env_len].value = valbuf;
972 	session->ns_data.dd_env_len++;
973 	(void) mutex_unlock(&session->ns_lock);
974 
975 	return (0);
976 }
977 
978 
979 /*
980  * ndmpd_api_set_env
981  *
982  * Sets an environment variable name/value pair in the environment
983  * variable list.  If the variable exists, it gets the new value,
984  * otherwise it's added as a new variable.
985  *
986  * Parameters:
987  *   session (input) - session pointer.
988  *   name    (input) - variable name.
989  *   val     (input) - value.
990  *
991  * Returns:
992  *   0 - success.
993  *  -1 - error.
994  */
995 int
996 ndmpd_api_set_env(void *cookie, char *name, char *value)
997 {
998 	char *valbuf;
999 	int rv;
1000 	ndmp_pval *envp;
1001 
1002 	envp = ndmpd_api_find_env(cookie, name);
1003 	if (!envp) {
1004 		rv = ndmpd_api_add_env(cookie, name, value);
1005 	} else if (!(valbuf = strdup(value))) {
1006 		rv = -1;
1007 	} else {
1008 		rv = 0;
1009 		free(envp->value);
1010 		envp->value = valbuf;
1011 	}
1012 
1013 	return (rv);
1014 }
1015 
1016 
1017 /*
1018  * ndmpd_api_get_name
1019  *
1020  * Return the name entry at the specified index from the
1021  * recover file name list.
1022  *
1023  * Parameters:
1024  *   cookie    (input) - NDMP session pointer.
1025  *   name_index (input) - index of entry to be returned.
1026  *
1027  * Returns:
1028  *   Pointer to name entry.
1029  *   0 if requested entry does not exist.
1030  */
1031 void *
1032 ndmpd_api_get_name(void *cookie, ulong_t name_index)
1033 {
1034 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
1035 
1036 	if (session == NULL)
1037 		return (NULL);
1038 
1039 	if (name_index >= session->ns_data.dd_nlist_len)
1040 		return (NULL);
1041 
1042 	return (&session->ns_data.dd_nlist[name_index]);
1043 }
1044 
1045 
1046 /*
1047  * ndmpd_api_dispatch
1048  *
1049  * Process pending NDMP client requests and check registered files for
1050  * data availability.
1051  *
1052  * Parameters:
1053  *   cookie (input) - session pointer.
1054  *   block  (input) -
1055  * 		TRUE 	block until a request has been processed or
1056  *			until a file handler has been called.
1057  *		FALSE	don't block.
1058  *
1059  * Returns:
1060  *  -1 - abort request received or connection closed.
1061  *   0 - success.
1062  */
1063 int
1064 ndmpd_api_dispatch(void *cookie, boolean_t block)
1065 {
1066 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
1067 	int err;
1068 
1069 	if (session == NULL)
1070 		return (-1);
1071 
1072 	for (; ; ) {
1073 		err = ndmpd_select(session, block, HC_ALL);
1074 		if (err < 0 || session->ns_data.dd_abort == TRUE ||
1075 		    session->ns_eof)
1076 			return (-1);
1077 
1078 		if (err == 0)
1079 			return (0);
1080 
1081 		/*
1082 		 * Something was processed.
1083 		 * Set the block flag to false so that we will return as
1084 		 * soon as everything available to be processed has been
1085 		 * processed.
1086 		 */
1087 		block = FALSE;
1088 	}
1089 }
1090 
1091 
1092 /*
1093  * ndmpd_api_add_file_handler
1094  *
1095  * Adds a file handler to the file handler list.
1096  * The file handler list is used by ndmpd_api_dispatch.
1097  *
1098  * Parameters:
1099  *   daemon_cookie (input) - session pointer.
1100  *   cookie  (input) - opaque data to be passed to file hander when called.
1101  *   fd      (input) - file descriptor.
1102  *   mode    (input) - bitmask of the following:
1103  *	NDMP_SELECT_MODE_READ = watch file for ready for reading
1104  *	NDMP_SELECT_MODE_WRITE = watch file for ready for writing
1105  *	NDMP_SELECT_MODE_EXCEPTION = watch file for exception
1106  *   func    (input) - function to call when the file meets one of the
1107  *		     conditions specified by mode.
1108  *
1109  * Returns:
1110  *   0 - success.
1111  *  -1 - error.
1112  */
1113 int
1114 ndmpd_api_add_file_handler(void *daemon_cookie, void *cookie, int fd,
1115     ulong_t mode, ndmpd_file_handler_func_t *func)
1116 {
1117 	ndmpd_session_t *session = (ndmpd_session_t *)daemon_cookie;
1118 
1119 	return (ndmpd_add_file_handler(session, cookie, fd, mode, HC_MODULE,
1120 	    func));
1121 }
1122 
1123 
1124 /*
1125  * ndmpd_api_remove_file_handler
1126  *
1127  * Removes a file handler from the file handler list.
1128  *
1129  * Parameters:
1130  *   cookie  (input) - session pointer.
1131  *   fd      (input) - file descriptor.
1132  *
1133  * Returns:
1134  *   0 - success.
1135  *  -1 - error.
1136  */
1137 int
1138 ndmpd_api_remove_file_handler(void *cookie, int fd)
1139 {
1140 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
1141 
1142 	return (ndmpd_remove_file_handler(session, fd));
1143 }
1144