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