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 */
56int 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 */
78void
79ndmpd_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*/
167int
168ndmpd_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 */
215int
216ndmpd_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 */
248int
249ndmpd_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 */
317int
318ndmpd_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 */
367int
368ndmpd_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 */
404void
405ndmpd_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*/
445int
446ndmpd_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 */
494int
495ndmpd_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 */
535int
536ndmpd_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 */
567void *
568ndmpd_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 */
598int
599ndmpd_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 */
646int
647ndmpd_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*/
733int
734ndmpd_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 */
781int
782ndmpd_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 */
850ndmp_pval *
851ndmpd_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) == 0)
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 */
883char *
884ndmpd_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 */
911int
912ndmpd_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 */
964int
965ndmpd_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 */
1000void *
1001ndmpd_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 */
1032int
1033ndmpd_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 */
1082int
1083ndmpd_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 */
1106int
1107ndmpd_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