Home | History | Annotate | Download | only in ndmp
      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