xref: /titanic_44/usr/src/cmd/ndmpd/ndmp/ndmpd_data.c (revision 63ff6dceb8bca4c7bef31895a1286319033330d0)
1 /*
2  * Copyright (c) 2007, 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 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <errno.h>
45 #include <arpa/inet.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include "ndmpd_common.h"
49 #include "ndmpd.h"
50 
51 static int ndmpd_data_error_send_v4(ndmpd_session_t *session,
52     ndmp_data_halt_reason reason);
53 static int ndmpd_data_error_send(ndmpd_session_t *session,
54     ndmp_data_halt_reason reason);
55 static void data_accept_connection_v3(void *cookie, int fd, ulong_t mode);
56 static int create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr,
57     ushort_t *port);
58 static ndmp_error data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr,
59     ushort_t port);
60 static int discard_data_v3(ndmpd_session_t *session, ulong_t length);
61 static void nlp_release_job_stat(ndmpd_session_t *session);
62 static u_longlong_t ndmpd_data_get_info(ndmpd_session_t *session);
63 
64 static ndmp_error ndmpd_tar_start_backup_v2(ndmpd_session_t *, char *,
65     ndmp_pval *, ulong_t);
66 static ndmp_error ndmpd_tar_start_recover_v2(ndmpd_session_t *, char *,
67     ndmp_pval *, ulong_t, ndmp_name *, ulong_t);
68 static ndmp_error ndmpd_tar_start_backup_v3(ndmpd_session_t *, char *,
69     ndmp_pval *, ulong_t);
70 static ndmp_error ndmpd_tar_start_recover_v3(ndmpd_session_t *,
71     ndmp_pval *, ulong_t, ndmp_name_v3 *, ulong_t);
72 
73 static ndmp_error ndmpd_zfs_start_op(ndmpd_session_t *,
74     ndmp_pval *, ulong_t, ndmp_name_v3 *, ulong_t, enum ndmp_data_operation);
75 
76 
77 /*
78  * ************************************************************************
79  * NDMP V2 HANDLERS
80  * ************************************************************************
81  */
82 
83 /*
84  * ndmpd_data_get_state_v2
85  *
86  * Request handler. Returns current data state.
87  *
88  * Parameters:
89  *   connection (input) - connection handle.
90  *   body       (input) - request message body.
91  *
92  * Returns:
93  *   void
94  */
95 /*ARGSUSED*/
96 void
97 ndmpd_data_get_state_v2(ndmp_connection_t *connection, void *body)
98 {
99 	ndmp_data_get_state_reply_v2 reply;
100 	ndmpd_session_t *session = ndmp_get_client_data(connection);
101 
102 	reply.error = NDMP_NO_ERR;
103 	reply.operation = session->ns_data.dd_operation;
104 	reply.state = session->ns_data.dd_state;
105 	reply.halt_reason = session->ns_data.dd_halt_reason;
106 
107 	reply.est_time_remain =
108 	    session->ns_data.dd_module.dm_stats.ms_est_time_remaining;
109 	reply.est_bytes_remain =
110 	    long_long_to_quad(
111 	    session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining);
112 
113 	reply.bytes_processed =
114 	    long_long_to_quad(ndmpd_data_get_info(session));
115 
116 	reply.mover = session->ns_data.dd_mover;
117 	reply.read_offset = long_long_to_quad(session->ns_data.dd_read_offset);
118 	reply.read_length = long_long_to_quad(session->ns_data.dd_read_length);
119 
120 	ndmp_send_reply(connection, &reply,
121 	    "sending data_get_state reply");
122 }
123 
124 
125 /*
126  * ndmpd_data_start_backup_v2
127  *
128  * Request handler. Starts a backup.
129  *
130  * Parameters:
131  *   connection (input) - connection handle.
132  *   body       (input) - request message body.
133  *
134  * Returns:
135  *   void
136  */
137 void
138 ndmpd_data_start_backup_v2(ndmp_connection_t *connection, void *body)
139 {
140 	ndmp_data_start_backup_request_v2 *request;
141 	ndmp_data_start_backup_reply_v2 reply;
142 	ndmpd_session_t *session = ndmp_get_client_data(connection);
143 	ndmp_error err;
144 
145 	request = (ndmp_data_start_backup_request_v2 *)body;
146 
147 	reply.error = NDMP_NO_ERR;
148 	session->ns_data.dd_mover = request->mover;
149 
150 	err = ndmpd_tar_start_backup_v2(session, request->bu_type,
151 	    request->env.env_val, request->env.env_len);
152 
153 	/*
154 	 * start_backup sends the reply if the backup is successfully started.
155 	 * Otherwise, send the reply containing the error here.
156 	 */
157 	if (err != NDMP_NO_ERR) {
158 		NDMP_LOG(LOG_DEBUG, "err: %d", err);
159 		reply.error = err;
160 		ndmp_send_reply(connection, &reply,
161 		    "sending data_start_backup reply");
162 		ndmpd_data_cleanup(session);
163 	}
164 }
165 
166 /*
167  * ndmpd_data_start_recover_v2
168  *
169  * Request handler. Starts a restore.
170  *
171  * Parameters:
172  *   connection (input) - connection handle.
173  *   body       (input) - request message body.
174  *
175  * Returns:
176  *   void
177  */
178 void
179 ndmpd_data_start_recover_v2(ndmp_connection_t *connection, void *body)
180 {
181 	ndmp_data_start_recover_request_v2 *request;
182 	ndmp_data_start_recover_reply_v2 reply;
183 	ndmpd_session_t *session = ndmp_get_client_data(connection);
184 	ndmp_error err;
185 
186 	request = (ndmp_data_start_recover_request_v2 *) body;
187 	session->ns_data.dd_mover = request->mover;
188 
189 	err = ndmpd_tar_start_recover_v2(session, request->bu_type,
190 	    request->env.env_val, request->env.env_len,
191 	    request->nlist.nlist_val, request->nlist.nlist_len);
192 
193 	/*
194 	 * start_recover sends the reply if the recover is successfully started.
195 	 * Otherwise, send the reply containing the error here.
196 	 */
197 	if (err != NDMP_NO_ERR) {
198 		reply.error = err;
199 		ndmp_send_reply(connection, &reply,
200 		    "sending ndmp_data_start_recover_request_v2 reply");
201 		ndmpd_data_cleanup(session);
202 	}
203 }
204 
205 /*
206  * ndmpd_data_get_env_v2
207  *
208  * Request handler. Returns the environment variable array sent
209  * with the backup request. This request may only be sent with
210  * a backup operation is in progress.
211  *
212  * Parameters:
213  *   connection (input) - connection handle.
214  *   body       (input) - request message body.
215  *
216  * Returns:
217  *   void
218  */
219 /*ARGSUSED*/
220 void
221 ndmpd_data_get_env_v2(ndmp_connection_t *connection, void *body)
222 {
223 	ndmp_data_get_env_reply reply;
224 	ndmpd_session_t *session = ndmp_get_client_data(connection);
225 
226 	(void) memset((void*)&reply, 0, sizeof (reply));
227 	if (session->ns_data.dd_operation != NDMP_DATA_OP_BACKUP) {
228 		NDMP_LOG(LOG_ERR, "Backup operation not active.");
229 		reply.error = NDMP_ILLEGAL_STATE_ERR;
230 		reply.env.env_len = 0;
231 	} else {
232 		reply.error = NDMP_NO_ERR;
233 		reply.env.env_len = session->ns_data.dd_env_len;
234 		reply.env.env_val = session->ns_data.dd_env;
235 	}
236 
237 	ndmp_send_reply(connection, &reply, "sending data_get_env reply");
238 }
239 
240 
241 /*
242  * ndmpd_data_stop_v2
243  *
244  * Request handler. Stops the current data operation.
245  *
246  * Parameters:
247  *   connection (input) - connection handle.
248  *   body       (input) - request message body.
249  *
250  * Returns:
251  *   void
252  */
253 /*ARGSUSED*/
254 void
255 ndmpd_data_stop_v2(ndmp_connection_t *connection, void *body)
256 {
257 	ndmp_data_stop_reply reply;
258 	ndmpd_session_t *session = ndmp_get_client_data(connection);
259 
260 	if (session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
261 		NDMP_LOG(LOG_ERR, "Invalid state to process stop request.");
262 		reply.error = NDMP_ILLEGAL_STATE_ERR;
263 		ndmp_send_reply(connection, &reply,
264 		    "sending data_stop reply");
265 		return;
266 	}
267 	ndmp_waitfor_op(session);
268 	ndmpd_data_cleanup(session);
269 	ndmpd_file_history_cleanup(session, FALSE);
270 
271 	nlp_release_job_stat(session);
272 
273 	/* prepare for another data operation */
274 	(void) ndmpd_data_init(session);
275 	ndmpd_file_history_init(session);
276 
277 	reply.error = NDMP_NO_ERR;
278 	ndmp_send_reply(connection, &reply, "sending data_stop reply");
279 }
280 
281 
282 /*
283  * ndmpd_data_abort_v2
284  *
285  * Request handler. Aborts the current backup/restore. The operation
286  * state is not changed to the halted state until after the operation
287  * has actually been aborted and the notify_halt request has been sent.
288  *
289  * Parameters:
290  *   connection (input) - connection handle.
291  *   body       (input) - request message body.
292  *
293  * Returns:
294  *   void
295  */
296 /*ARGSUSED*/
297 void
298 ndmpd_data_abort_v2(ndmp_connection_t *connection, void *body)
299 {
300 	ndmp_data_abort_reply reply;
301 	ndmpd_session_t *session = ndmp_get_client_data(connection);
302 
303 	if (session->ns_data.dd_state == NDMP_DATA_STATE_IDLE ||
304 	    session->ns_data.dd_state == NDMP_DATA_STATE_HALTED) {
305 		NDMP_LOG(LOG_ERR, "Invalid state to process abort request.");
306 		reply.error = NDMP_ILLEGAL_STATE_ERR;
307 		ndmp_send_reply(connection, &reply,
308 		    "sending data_abort reply");
309 		return;
310 	}
311 	/*
312 	 * Don't go to HALTED state yet. Need to wait for data operation to
313 	 * abort. When this happens, ndmpd_done will get called and will
314 	 * perform the halt processing.
315 	 */
316 	session->ns_data.dd_abort = TRUE;
317 	(*session->ns_data.dd_module.dm_abort_func)(
318 	    session->ns_data.dd_module.dm_module_cookie);
319 
320 	reply.error = NDMP_NO_ERR;
321 	ndmp_send_reply(connection, &reply, "sending data_abort reply");
322 }
323 
324 /*
325  * ************************************************************************
326  * NDMP V3 HANDLERS
327  * ************************************************************************
328  */
329 
330 /*
331  * ndmpd_data_get_state_v3
332  *
333  * Request handler. Returns current data state.
334  *
335  * Parameters:
336  *   connection (input) - connection handle.
337  *   body       (input) - request message body.
338  *
339  * Returns:
340  *   void
341  */
342 /*ARGSUSED*/
343 void
344 ndmpd_data_get_state_v3(ndmp_connection_t *connection, void *body)
345 {
346 	ndmp_data_get_state_reply_v3 reply;
347 	ndmpd_session_t *session = ndmp_get_client_data(connection);
348 
349 	(void) memset((void*)&reply, 0, sizeof (reply));
350 
351 	reply.error = NDMP_NO_ERR;
352 	reply.invalid = NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID
353 	    | NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID;
354 	reply.operation = session->ns_data.dd_operation;
355 	reply.state = session->ns_data.dd_state;
356 	reply.halt_reason = session->ns_data.dd_halt_reason;
357 
358 	if (reply.operation == NDMP_DATA_OP_BACKUP)
359 		reply.bytes_processed =
360 		    long_long_to_quad(
361 		    session->ns_data.dd_module.dm_stats.ms_bytes_processed);
362 	else
363 		reply.bytes_processed =
364 		    long_long_to_quad(ndmpd_data_get_info(session));
365 
366 	reply.est_bytes_remain = long_long_to_quad(0LL);
367 	reply.est_time_remain = 0;
368 	if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE)
369 		ndmp_copy_addr_v3(&reply.data_connection_addr,
370 		    &session->ns_data.dd_data_addr);
371 	reply.read_offset = long_long_to_quad(session->ns_data.dd_read_offset);
372 	reply.read_length = long_long_to_quad(session->ns_data.dd_read_length);
373 
374 	ndmp_send_reply(connection, &reply,
375 	    "sending ndmp_data_get_state_v3 reply");
376 }
377 
378 
379 /*
380  * ndmpd_data_start_backup_v3
381  *
382  * Request handler. Starts a backup.
383  *
384  * Parameters:
385  *   connection (input) - connection handle.
386  *   body       (input) - request message body.
387  *
388  * Returns:
389  *   void
390  */
391 void
392 ndmpd_data_start_backup_v3(ndmp_connection_t *connection, void *body)
393 {
394 	ndmp_data_start_backup_request_v3 *request;
395 	ndmp_data_start_backup_reply_v3 reply;
396 	ndmpd_session_t *session = ndmp_get_client_data(connection);
397 
398 	request = (ndmp_data_start_backup_request_v3 *)body;
399 
400 	(void) memset((void*)&reply, 0, sizeof (reply));
401 
402 	if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
403 		NDMP_LOG(LOG_ERR,
404 		    "Can't start new backup in current state.");
405 		NDMP_LOG(LOG_ERR,
406 		    "Connection to the mover is not established.");
407 		reply.error = NDMP_ILLEGAL_STATE_ERR;
408 		goto _error;
409 	}
410 
411 	if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) {
412 		if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
413 			NDMP_LOG(LOG_ERR, "Write protected device.");
414 			reply.error = NDMP_WRITE_PROTECT_ERR;
415 			goto _error;
416 		}
417 	}
418 
419 	if (strcasecmp(request->bu_type, NDMP_TAR_TYPE) == 0) {
420 		session->ns_butype = NDMP_BUTYPE_TAR;
421 	} else if (strcasecmp(request->bu_type, NDMP_DUMP_TYPE) == 0) {
422 		session->ns_butype = NDMP_BUTYPE_DUMP;
423 	} else if (strcasecmp(request->bu_type, NDMP_ZFS_TYPE) == 0) {
424 		session->ns_butype = NDMP_BUTYPE_ZFS;
425 	} else {
426 		char msg_invalid[32];
427 		char msg_types[32];
428 
429 		(void) snprintf(msg_invalid, 32, "Invalid backup type: %s.",
430 		    request->bu_type);
431 		(void) snprintf(msg_types, 32,
432 		    "Supported backup types are tar, dump, and zfs.");
433 
434 		NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
435 		    msg_invalid);
436 		NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
437 		    msg_types);
438 		NDMP_LOG(LOG_ERR, msg_invalid);
439 		NDMP_LOG(LOG_ERR, msg_types);
440 
441 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
442 		goto _error;
443 	}
444 
445 	if (session->ns_butype == NDMP_BUTYPE_ZFS) {
446 		reply.error = ndmpd_zfs_start_op(session, request->env.env_val,
447 		    request->env.env_len, NULL, 0, NDMP_DATA_OP_BACKUP);
448 	} else {
449 		reply.error = ndmpd_tar_start_backup_v3(session,
450 		    request->bu_type, request->env.env_val,
451 		    request->env.env_len);
452 	}
453 
454 	/*
455 	 * *_start_backup* sends the reply if the backup is
456 	 * successfully started.  Otherwise, send the reply
457 	 * containing the error here.
458 	 */
459 
460 _error:
461 
462 	if (reply.error != NDMP_NO_ERR) {
463 		ndmp_send_reply(connection, &reply,
464 		    "sending data_start_backup_v3 reply");
465 		ndmpd_data_cleanup(session);
466 	}
467 }
468 
469 /*
470  * ndmpd_data_start_recover_v3
471  *
472  * Request handler. Starts a restore.
473  *
474  * Parameters:
475  *   connection (input) - connection handle.
476  *   body       (input) - request message body.
477  *
478  * Returns:
479  *   void
480  */
481 void
482 ndmpd_data_start_recover_v3(ndmp_connection_t *connection, void *body)
483 {
484 	ndmp_data_start_recover_request_v3 *request;
485 	ndmp_data_start_recover_reply_v3 reply;
486 	ndmpd_session_t *session = ndmp_get_client_data(connection);
487 
488 	request = (ndmp_data_start_recover_request_v3 *)body;
489 
490 	(void) memset((void*)&reply, 0, sizeof (reply));
491 
492 	if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
493 		NDMP_LOG(LOG_ERR, "Can't start new recover in current state.");
494 		reply.error = NDMP_ILLEGAL_STATE_ERR;
495 		goto _error;
496 	}
497 
498 	if (strcasecmp(request->bu_type, NDMP_TAR_TYPE) == 0) {
499 		session->ns_butype = NDMP_BUTYPE_TAR;
500 	} else if (strcasecmp(request->bu_type, NDMP_DUMP_TYPE) == 0) {
501 		session->ns_butype = NDMP_BUTYPE_DUMP;
502 	} else if (strcasecmp(request->bu_type, NDMP_ZFS_TYPE) == 0) {
503 		session->ns_butype = NDMP_BUTYPE_ZFS;
504 	} else {
505 		char msg_invalid[32];
506 		char msg_types[32];
507 
508 		(void) snprintf(msg_invalid, 32, "Invalid backup type: %s.",
509 		    request->bu_type);
510 		(void) snprintf(msg_types, 32,
511 		    "Supported backup types are tar, dump, and zfs.");
512 
513 		NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
514 		    msg_invalid);
515 		NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
516 		    msg_types);
517 		NDMP_LOG(LOG_ERR, msg_invalid);
518 		NDMP_LOG(LOG_ERR, msg_types);
519 
520 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
521 		goto _error;
522 	}
523 
524 	if (session->ns_butype == NDMP_BUTYPE_ZFS) {
525 		reply.error = ndmpd_zfs_start_op(session, request->env.env_val,
526 		    request->env.env_len, request->nlist.nlist_val,
527 		    request->nlist.nlist_len, NDMP_DATA_OP_RECOVER);
528 	} else {
529 		reply.error = ndmpd_tar_start_recover_v3(session,
530 		    request->env.env_val, request->env.env_len,
531 		    request->nlist.nlist_val, request->nlist.nlist_len);
532 	}
533 
534 	/*
535 	 * *_start_recover* sends the reply if the recover is
536 	 * successfully started.  Otherwise, send the reply
537 	 * containing the error here.
538 	 */
539 
540 _error:
541 
542 	if (reply.error != NDMP_NO_ERR) {
543 		ndmp_send_reply(connection, &reply,
544 		    "sending data_start_recover_v3 reply");
545 		ndmpd_data_error(session, NDMP_DATA_HALT_INTERNAL_ERROR);
546 		ndmpd_data_cleanup(session);
547 	}
548 }
549 
550 /*
551  * ndmpd_data_abort_v3
552  *
553  * Request handler. Aborts the current backup/restore. The operation
554  * state is not changed to the halted state until after the operation
555  * has actually been aborted and the notify_halt request has been sent.
556  *
557  * Parameters:
558  *   connection (input) - connection handle.
559  *   body       (input) - request message body.
560  *
561  * Returns:
562  *   void
563  */
564 /*ARGSUSED*/
565 void
566 ndmpd_data_abort_v3(ndmp_connection_t *connection, void *body)
567 {
568 	ndmp_data_abort_reply reply;
569 	ndmpd_session_t *session = ndmp_get_client_data(connection);
570 
571 	switch (session->ns_data.dd_state) {
572 	case NDMP_DATA_STATE_IDLE:
573 		reply.error = NDMP_ILLEGAL_STATE_ERR;
574 		NDMP_LOG(LOG_ERR, "Invalid state to process abort request.");
575 		break;
576 
577 	case NDMP_DATA_STATE_ACTIVE:
578 		/*
579 		 * Don't go to HALTED state yet.  Need to wait for data
580 		 * operation to abort.  When this happens, ndmpd_done_v3
581 		 * will get called and will perform the halt processing.
582 		 */
583 		reply.error = NDMP_NO_ERR;
584 		session->ns_data.dd_abort = TRUE;
585 		if (session->ns_data.dd_module.dm_abort_func)
586 			(*session->ns_data.dd_module.dm_abort_func)(
587 			    session->ns_data.dd_module.dm_module_cookie);
588 		break;
589 
590 	case NDMP_DATA_STATE_HALTED:
591 	case NDMP_DATA_STATE_LISTEN:
592 	case NDMP_DATA_STATE_CONNECTED:
593 		reply.error = NDMP_NO_ERR;
594 		session->ns_data.dd_abort = TRUE;
595 		ndmpd_data_error(session, NDMP_DATA_HALT_ABORTED);
596 		break;
597 	default:
598 		reply.error = NDMP_ILLEGAL_STATE_ERR;
599 		NDMP_LOG(LOG_DEBUG, "Unknown data V3 state %d",
600 		    session->ns_data.dd_state);
601 	}
602 
603 	ndmp_send_reply(connection, &reply,
604 	    "sending data_abort_v3 reply");
605 }
606 
607 
608 /*
609  * ndmpd_data_stop_v3
610  *
611  * Request handler. Stops the current data operation.
612  *
613  * Parameters:
614  *   connection (input) - connection handle.
615  *   body       (input) - request message body.
616  *
617  * Returns:
618  *   void
619  */
620 /*ARGSUSED*/
621 void
622 ndmpd_data_stop_v3(ndmp_connection_t *connection, void *body)
623 {
624 	ndmp_data_stop_reply reply;
625 	ndmpd_session_t *session = ndmp_get_client_data(connection);
626 
627 	if (session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
628 		NDMP_LOG(LOG_ERR, "Invalid state to process stop request.");
629 		reply.error = NDMP_ILLEGAL_STATE_ERR;
630 		ndmp_send_reply(connection, &reply,
631 		    "sending data_stop_v3 reply");
632 		return;
633 	}
634 	ndmp_waitfor_op(session);
635 	ndmpd_data_cleanup(session);
636 	ndmpd_file_history_cleanup(session, FALSE);
637 
638 	/* prepare for another data operation */
639 	(void) ndmpd_data_init(session);
640 	ndmpd_file_history_init(session);
641 
642 	reply.error = NDMP_NO_ERR;
643 	ndmp_send_reply(connection, &reply,
644 	    "sending data_stop_v3 reply");
645 }
646 
647 
648 /*
649  * ndmpd_data_listen_v3
650  *
651  * Request handler. Configures the server to listen for a connection
652  * from a remote mover.
653  *
654  * Parameters:
655  *   connection (input) - connection handle.
656  *   body       (input) - request message body.
657  *
658  * Returns:
659  *   void
660  */
661 void
662 ndmpd_data_listen_v3(ndmp_connection_t *connection, void *body)
663 {
664 	ndmp_data_listen_request_v3 *request;
665 	ndmp_data_listen_reply_v3 reply;
666 	ndmpd_session_t *session = ndmp_get_client_data(connection);
667 	ulong_t addr;
668 	ushort_t port;
669 
670 	request = (ndmp_data_listen_request_v3 *)body;
671 
672 	(void) memset((void*)&reply, 0, sizeof (reply));
673 
674 	if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
675 		reply.error = NDMP_ILLEGAL_STATE_ERR;
676 		NDMP_LOG(LOG_ERR,
677 		    "Invalid internal data state to process listen request.");
678 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
679 		reply.error = NDMP_ILLEGAL_STATE_ERR;
680 		NDMP_LOG(LOG_ERR,
681 		    "Invalid mover state to process listen request.");
682 	} else {
683 		reply.error = NDMP_NO_ERR;
684 	}
685 
686 	if (reply.error != NDMP_NO_ERR) {
687 		ndmp_send_reply(connection, &reply,
688 		    "ndmp_data_listen_request_v3 reply");
689 		return;
690 	}
691 
692 	switch (request->addr_type) {
693 	case NDMP_ADDR_LOCAL:
694 		reply.data_connection_addr.addr_type = request->addr_type;
695 		session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
696 		break;
697 	case NDMP_ADDR_TCP:
698 		if (create_listen_socket_v3(session, &addr, &port) < 0) {
699 			reply.error = NDMP_IO_ERR;
700 			break;
701 		}
702 
703 		reply.error = NDMP_NO_ERR;
704 		reply.data_connection_addr.addr_type = request->addr_type;
705 		reply.data_connection_addr.tcp_ip_v3 = htonl(addr);
706 		reply.data_connection_addr.tcp_port_v3 = htons(port);
707 		session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
708 		session->ns_data.dd_data_addr.tcp_ip_v3 = addr;
709 		session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(port);
710 		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
711 		    session->ns_data.dd_listen_sock);
712 		break;
713 
714 	default:
715 		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
716 		    request->addr_type);
717 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
718 		break;
719 	}
720 
721 	if (reply.error == NDMP_NO_ERR)
722 		session->ns_data.dd_state = NDMP_DATA_STATE_LISTEN;
723 
724 	ndmp_send_reply(connection, &reply,
725 	    "ndmp_data_listen_request_v3 reply");
726 }
727 
728 
729 /*
730  * ndmpd_data_connect_v3
731  *
732  * Request handler. Connects the data server to either a local
733  * or remote mover.
734  *
735  * Parameters:
736  *   connection (input) - connection handle.
737  *   body       (input) - request message body.
738  *
739  * Returns:
740  *   void
741  */
742 void
743 ndmpd_data_connect_v3(ndmp_connection_t *connection, void *body)
744 {
745 	ndmp_data_connect_request_v3 *request;
746 	ndmp_data_connect_reply_v3 reply;
747 	ndmpd_session_t *session = ndmp_get_client_data(connection);
748 
749 	request = (ndmp_data_connect_request_v3 *)body;
750 
751 	(void) memset((void*)&reply, 0, sizeof (reply));
752 
753 	if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
754 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
755 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
756 		    request->addr.addr_type);
757 	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
758 		reply.error = NDMP_ILLEGAL_STATE_ERR;
759 		NDMP_LOG(LOG_ERR, "Invalid state to process connect request.");
760 	} else {
761 		reply.error = NDMP_NO_ERR;
762 	}
763 
764 	if (reply.error != NDMP_NO_ERR) {
765 		ndmp_send_reply(connection, &reply,
766 		    "sending ndmp_data_connect_v3 reply");
767 		return;
768 	}
769 
770 	switch (request->addr.addr_type) {
771 	case NDMP_ADDR_LOCAL:
772 		/*
773 		 * Verify that the mover is listening for a
774 		 * local connection
775 		 */
776 		if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN ||
777 		    session->ns_mover.md_listen_sock != -1) {
778 			reply.error = NDMP_ILLEGAL_STATE_ERR;
779 			NDMP_LOG(LOG_ERR,
780 			    "Mover is not in local listen state.");
781 		} else {
782 			session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
783 		}
784 		break;
785 
786 	case NDMP_ADDR_TCP:
787 		reply.error = data_connect_sock_v3(session,
788 		    request->addr.tcp_ip_v3, request->addr.tcp_port_v3);
789 		break;
790 
791 	default:
792 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
793 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
794 		    request->addr.addr_type);
795 	}
796 
797 	if (reply.error == NDMP_NO_ERR)
798 		session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
799 
800 	ndmp_send_reply(connection, &reply,
801 	    "sending ndmp_data_connect_v3 reply");
802 }
803 
804 
805 /*
806  * ************************************************************************
807  * NDMP V4 HANDLERS
808  * ************************************************************************
809  */
810 
811 /*
812  * ndmpd_data_get_env_v4
813  *
814  * Request handler. Returns the environment variable array sent
815  * with the backup request. This request may only be sent with
816  * a backup operation is in progress.
817  *
818  * Parameters:
819  *   connection (input) - connection handle.
820  *   body       (input) - request message body.
821  *
822  * Returns:
823  *   void
824  */
825 /*ARGSUSED*/
826 void
827 ndmpd_data_get_env_v4(ndmp_connection_t *connection, void *body)
828 {
829 	ndmp_data_get_env_reply reply;
830 	ndmpd_session_t *session = ndmp_get_client_data(connection);
831 
832 	(void) memset((void*)&reply, 0, sizeof (reply));
833 
834 	if (session->ns_data.dd_state != NDMP_DATA_STATE_ACTIVE &&
835 	    session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
836 		NDMP_LOG(LOG_ERR, "Invalid state for the data server.");
837 		reply.error = NDMP_ILLEGAL_STATE_ERR;
838 		reply.env.env_len = 0;
839 	} else if (session->ns_data.dd_operation != NDMP_DATA_OP_BACKUP) {
840 		NDMP_LOG(LOG_ERR, "Backup operation not active.");
841 		reply.error = NDMP_ILLEGAL_STATE_ERR;
842 		reply.env.env_len = 0;
843 	} else {
844 		reply.error = NDMP_NO_ERR;
845 		reply.env.env_len = session->ns_data.dd_env_len;
846 		reply.env.env_val = session->ns_data.dd_env;
847 	}
848 
849 	ndmp_send_reply(connection, &reply, "sending data_get_env reply");
850 }
851 
852 /*
853  * ndmpd_data_get_state_v4
854  *
855  * Request handler. Returns current data state.
856  *
857  * Parameters:
858  *   connection (input) - connection handle.
859  *   body       (input) - request message body.
860  *
861  * Returns:
862  *   void
863  */
864 /*ARGSUSED*/
865 void
866 ndmpd_data_get_state_v4(ndmp_connection_t *connection, void *body)
867 {
868 	ndmp_data_get_state_reply_v4 reply;
869 	ndmpd_session_t *session = ndmp_get_client_data(connection);
870 
871 	(void) memset((void*)&reply, 0, sizeof (reply));
872 
873 	reply.error = NDMP_NO_ERR;
874 	reply.unsupported = NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID
875 	    | NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID;
876 	reply.operation = session->ns_data.dd_operation;
877 	reply.state = session->ns_data.dd_state;
878 	reply.halt_reason = session->ns_data.dd_halt_reason;
879 
880 	if (reply.operation == NDMP_DATA_OP_BACKUP)
881 		reply.bytes_processed = long_long_to_quad(
882 		    session->ns_data.dd_module.dm_stats.ms_bytes_processed);
883 	else
884 		reply.bytes_processed =
885 		    long_long_to_quad(ndmpd_data_get_info(session));
886 
887 	reply.est_bytes_remain = long_long_to_quad(0LL);
888 	reply.est_time_remain = 0;
889 	if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE)
890 		ndmp_copy_addr_v4(&reply.data_connection_addr,
891 		    &session->ns_data.dd_data_addr_v4);
892 
893 	reply.read_offset = long_long_to_quad(session->ns_data.dd_read_offset);
894 	reply.read_length = long_long_to_quad(session->ns_data.dd_read_length);
895 
896 	ndmp_send_reply(connection, &reply,
897 	    "sending ndmp_data_get_state_v4 reply");
898 	free(reply.data_connection_addr.tcp_addr_v4);
899 }
900 
901 
902 /*
903  * ndmpd_data_connect_v4
904  *
905  * Request handler. Connects the data server to either a local
906  * or remote mover.
907  *
908  * Parameters:
909  *   connection (input) - connection handle.
910  *   body       (input) - request message body.
911  *
912  * Returns:
913  *   void
914  */
915 void
916 ndmpd_data_connect_v4(ndmp_connection_t *connection, void *body)
917 {
918 	ndmp_data_connect_request_v4 *request;
919 	ndmp_data_connect_reply_v4 reply;
920 	ndmpd_session_t *session = ndmp_get_client_data(connection);
921 
922 	request = (ndmp_data_connect_request_v4 *)body;
923 
924 	(void) memset((void*)&reply, 0, sizeof (reply));
925 
926 	if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
927 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
928 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
929 		    request->addr.addr_type);
930 	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
931 		reply.error = NDMP_ILLEGAL_STATE_ERR;
932 		NDMP_LOG(LOG_ERR, "Invalid state to process connect request.");
933 	} else {
934 		reply.error = NDMP_NO_ERR;
935 	}
936 
937 	if (reply.error != NDMP_NO_ERR) {
938 		ndmp_send_reply(connection, &reply,
939 		    "sending ndmp_data_connect_v4 reply");
940 		return;
941 	}
942 
943 	switch (request->addr.addr_type) {
944 	case NDMP_ADDR_LOCAL:
945 		/*
946 		 * Verify that the mover is listening for a
947 		 * local connection
948 		 */
949 		if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN ||
950 		    session->ns_mover.md_listen_sock != -1) {
951 			reply.error = NDMP_ILLEGAL_STATE_ERR;
952 			NDMP_LOG(LOG_ERR,
953 			    "Mover is not in local listen state.");
954 		} else {
955 			session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
956 		}
957 		break;
958 
959 	case NDMP_ADDR_TCP:
960 		reply.error = data_connect_sock_v3(session,
961 		    request->addr.tcp_ip_v4(0), request->addr.tcp_port_v4(0));
962 		break;
963 
964 	default:
965 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
966 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
967 		    request->addr.addr_type);
968 	}
969 
970 	if (reply.error == NDMP_NO_ERR)
971 		session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
972 
973 	ndmp_send_reply(connection, &reply,
974 	    "sending ndmp_data_connect_v4 reply");
975 }
976 
977 /*
978  * ndmpd_data_listen_v4
979  *
980  * Request handler. Configures the server to listen for a connection
981  * from a remote mover.
982  *
983  * Parameters:
984  *   connection (input) - connection handle.
985  *   body       (input) - request message body.
986  *
987  * Returns:
988  *   void
989  */
990 void
991 ndmpd_data_listen_v4(ndmp_connection_t *connection, void *body)
992 {
993 	ndmp_data_listen_request_v4 *request;
994 	ndmp_data_listen_reply_v4 reply;
995 	ndmpd_session_t *session = ndmp_get_client_data(connection);
996 	ulong_t addr;
997 	ushort_t port;
998 
999 	request = (ndmp_data_listen_request_v4 *)body;
1000 
1001 	(void) memset((void*)&reply, 0, sizeof (reply));
1002 
1003 	if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
1004 		reply.error = NDMP_ILLEGAL_STATE_ERR;
1005 		NDMP_LOG(LOG_ERR,
1006 		    "Invalid internal data state to process listen request.");
1007 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1008 		reply.error = NDMP_ILLEGAL_STATE_ERR;
1009 		NDMP_LOG(LOG_ERR,
1010 		    "Invalid mover state to process listen request.");
1011 	} else {
1012 		reply.error = NDMP_NO_ERR;
1013 	}
1014 
1015 	if (reply.error != NDMP_NO_ERR) {
1016 		ndmp_send_reply(connection, &reply,
1017 		    "ndmp_data_listen_request_v4 reply");
1018 		return;
1019 	}
1020 
1021 	switch (request->addr_type) {
1022 	case NDMP_ADDR_LOCAL:
1023 		reply.connect_addr.addr_type = request->addr_type;
1024 		session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
1025 		break;
1026 	case NDMP_ADDR_TCP:
1027 		if (create_listen_socket_v3(session, &addr, &port) < 0) {
1028 			reply.error = NDMP_IO_ERR;
1029 			break;
1030 		}
1031 
1032 		reply.error = NDMP_NO_ERR;
1033 		reply.connect_addr.addr_type = request->addr_type;
1034 		reply.connect_addr.tcp_addr_v4 =
1035 		    ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1036 
1037 		reply.connect_addr.tcp_ip_v4(0) = htonl(addr);
1038 		reply.connect_addr.tcp_port_v4(0) = htons(port);
1039 		reply.connect_addr.tcp_len_v4 = 1;
1040 
1041 		session->ns_data.dd_data_addr_v4.addr_type = NDMP_ADDR_TCP;
1042 		session->ns_data.dd_data_addr_v4.tcp_addr_v4 =
1043 		    ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1044 
1045 		session->ns_data.dd_data_addr_v4.tcp_ip_v4(0) = addr;
1046 		session->ns_data.dd_data_addr_v4.tcp_port_v4(0) = ntohs(port);
1047 		session->ns_data.dd_data_addr_v4.tcp_len_v4 = 1;
1048 
1049 		/* Copy that to data_addr for compatibility */
1050 		session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
1051 		session->ns_data.dd_data_addr.tcp_ip_v3 = addr;
1052 		session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(port);
1053 		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
1054 		    session->ns_data.dd_listen_sock);
1055 		break;
1056 
1057 	default:
1058 		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
1059 		    request->addr_type);
1060 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1061 		break;
1062 	}
1063 
1064 	if (reply.error == NDMP_NO_ERR)
1065 		session->ns_data.dd_state = NDMP_DATA_STATE_LISTEN;
1066 
1067 	ndmp_send_reply(connection, &reply,
1068 	    "ndmp_data_listen_request_v4 reply");
1069 }
1070 
1071 
1072 /*
1073  * ndmpd_data_start_recover_filehist_v4
1074  *
1075  * Request handler. Recovers the file history (not supported yet)
1076  * This command has an optional support in V4.
1077  *
1078  * Parameters:
1079  *   connection (input) - connection handle.
1080  *   body       (input) - request message body.
1081  *
1082  * Returns:
1083  *   void
1084  */
1085 /*ARGSUSED*/
1086 void
1087 ndmpd_data_start_recover_filehist_v4(ndmp_connection_t *connection, void *body)
1088 {
1089 	ndmp_data_start_recover_filehist_reply_v4 reply;
1090 
1091 	NDMP_LOG(LOG_DEBUG, "Request not supported");
1092 	reply.error = NDMP_NOT_SUPPORTED_ERR;
1093 
1094 	ndmp_send_reply(connection, &reply,
1095 	    "sending ndmp_data_start_recover_filehist_reply_v4 reply");
1096 }
1097 
1098 /*
1099  * ************************************************************************
1100  * LOCALS
1101  * ************************************************************************
1102  */
1103 
1104 /*
1105  * ndmpd_data_error_send
1106  *
1107  * This function sends the notify message to the client.
1108  *
1109  * Parameters:
1110  *   session (input) - session pointer.
1111  *   reason  (input) - halt reason.
1112  *
1113  * Returns:
1114  *   Error code
1115  */
1116 /*ARGSUSED*/
1117 static int
1118 ndmpd_data_error_send(ndmpd_session_t *session, ndmp_data_halt_reason reason)
1119 {
1120 	ndmp_notify_data_halted_request req;
1121 
1122 	req.reason = session->ns_data.dd_halt_reason;
1123 	req.text_reason = "";
1124 
1125 	return (ndmp_send_request(session->ns_connection,
1126 	    NDMP_NOTIFY_DATA_HALTED, NDMP_NO_ERR, &req, 0));
1127 }
1128 
1129 
1130 /*
1131  * ndmpd_data_error_send_v4
1132  *
1133  * This function sends the notify message to the client.
1134  *
1135  * Parameters:
1136  *   session (input) - session pointer.
1137  *   reason  (input) - halt reason.
1138  *
1139  * Returns:
1140  *   Error code
1141  */
1142 /*ARGSUSED*/
1143 static int
1144 ndmpd_data_error_send_v4(ndmpd_session_t *session, ndmp_data_halt_reason reason)
1145 {
1146 	ndmp_notify_data_halted_request_v4 req;
1147 
1148 	req.reason = session->ns_data.dd_halt_reason;
1149 
1150 	return ndmp_send_request(session->ns_connection,
1151 	    NDMP_NOTIFY_DATA_HALTED, NDMP_NO_ERR, &req, 0);
1152 }
1153 
1154 
1155 /*
1156  * ndmpd_data_error
1157  *
1158  * This function is called when a data error has been detected.
1159  * A notify message is sent to the client and the data server is
1160  * placed into the halted state.
1161  *
1162  * Parameters:
1163  *   session (input) - session pointer.
1164  *   reason  (input) - halt reason.
1165  *
1166  * Returns:
1167  *   void
1168  */
1169 void
1170 ndmpd_data_error(ndmpd_session_t *session, ndmp_data_halt_reason reason)
1171 {
1172 	if (session->ns_data.dd_state == NDMP_DATA_STATE_IDLE ||
1173 	    session->ns_data.dd_state == NDMP_DATA_STATE_HALTED)
1174 		return;
1175 
1176 	if (session->ns_data.dd_operation == NDMP_DATA_OP_BACKUP) {
1177 		/*
1178 		 * Send/discard any buffered file history data.
1179 		 */
1180 		ndmpd_file_history_cleanup(session,
1181 		    (reason == NDMP_DATA_HALT_SUCCESSFUL ? TRUE : FALSE));
1182 
1183 		/*
1184 		 * If mover local and successful backup, write any
1185 		 * remaining buffered data to tape.
1186 		 */
1187 		if (session->ns_data.dd_data_addr.addr_type
1188 		    == NDMP_ADDR_LOCAL && reason == NDMP_DATA_HALT_SUCCESSFUL)
1189 			(void) ndmpd_local_write_v3(session, 0, 0);
1190 	}
1191 
1192 	session->ns_data.dd_state = NDMP_DATA_STATE_HALTED;
1193 	session->ns_data.dd_halt_reason = reason;
1194 
1195 	if (session->ns_protocol_version == NDMPV4) {
1196 		if (ndmpd_data_error_send_v4(session, reason) < 0)
1197 			NDMP_LOG(LOG_DEBUG,
1198 			    "Error sending notify_data_halted request");
1199 	} else {
1200 		if (ndmpd_data_error_send(session, reason) < 0)
1201 			NDMP_LOG(LOG_DEBUG,
1202 			    "Error sending notify_data_halted request");
1203 	}
1204 
1205 	if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP) {
1206 		if (session->ns_data.dd_sock != -1) {
1207 			(void) ndmpd_remove_file_handler(session,
1208 			    session->ns_data.dd_sock);
1209 			/*
1210 			 * ndmpcopy: we use the same socket for the mover,
1211 			 * so expect to close when mover is done!
1212 			 */
1213 			if (session->ns_data.dd_sock !=
1214 			    session->ns_mover.md_sock)
1215 				(void) close(session->ns_data.dd_sock);
1216 
1217 			session->ns_data.dd_sock = -1;
1218 		}
1219 		if (session->ns_data.dd_listen_sock != -1) {
1220 			(void) ndmpd_remove_file_handler(session,
1221 			    session->ns_data.dd_listen_sock);
1222 
1223 			(void) close(session->ns_data.dd_listen_sock);
1224 			session->ns_data.dd_listen_sock = -1;
1225 		}
1226 	} else {
1227 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
1228 	}
1229 }
1230 
1231 
1232 /*
1233  * data_accept_connection_v3
1234  *
1235  * Accept a data connection from a remote mover.
1236  * Called by ndmpd_select when a connection is pending on
1237  * the data listen socket.
1238  *
1239  * Parameters:
1240  *   cookie  (input) - session pointer.
1241  *   fd      (input) - file descriptor.
1242  *   mode    (input) - select mode.
1243  *
1244  * Returns:
1245  *   void
1246  */
1247 /*ARGSUSED*/
1248 static void
1249 data_accept_connection_v3(void *cookie, int fd, ulong_t mode)
1250 {
1251 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
1252 	int from_len;
1253 	struct sockaddr_in from;
1254 	int flag = 1;
1255 
1256 	from_len = sizeof (from);
1257 	session->ns_data.dd_sock = accept(fd, (struct sockaddr *)&from,
1258 	    &from_len);
1259 
1260 	NDMP_LOG(LOG_DEBUG, "sock fd: %d",
1261 	    session->ns_data.dd_sock);
1262 	NDMP_LOG(LOG_DEBUG, "sin: port %d addr %s",
1263 	    ntohs(from.sin_port),
1264 	    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
1265 
1266 	(void) ndmpd_remove_file_handler(session, fd);
1267 	(void) close(session->ns_data.dd_listen_sock);
1268 	session->ns_data.dd_listen_sock = -1;
1269 
1270 	if (session->ns_data.dd_sock < 0) {
1271 		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
1272 		ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
1273 		return;
1274 	}
1275 
1276 	/*
1277 	 * Save the peer address.
1278 	 */
1279 	session->ns_data.dd_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
1280 	session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(from.sin_port);
1281 
1282 	/*
1283 	 * Set the parameter of the new socket.
1284 	 */
1285 	(void) setsockopt(session->ns_data.dd_sock, SOL_SOCKET, SO_KEEPALIVE,
1286 	    &flag, sizeof (flag));
1287 	ndmp_set_socket_nodelay(session->ns_data.dd_sock);
1288 	if (ndmp_sbs > 0)
1289 		ndmp_set_socket_snd_buf(session->ns_data.dd_sock,
1290 		    ndmp_sbs * KILOBYTE);
1291 	if (ndmp_rbs > 0)
1292 		ndmp_set_socket_rcv_buf(session->ns_data.dd_sock,
1293 		    ndmp_rbs * KILOBYTE);
1294 
1295 	session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1296 }
1297 
1298 
1299 /*
1300  * create_listen_socket_v3
1301  *
1302  * Creates the data sockets for listening for a remote mover/data
1303  * incoming connections.
1304  */
1305 static int
1306 create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
1307 {
1308 	session->ns_data.dd_listen_sock = ndmp_create_socket(addr, port);
1309 	if (session->ns_data.dd_listen_sock < 0)
1310 		return (-1);
1311 
1312 	/*
1313 	 * Add a file handler for the listen socket.
1314 	 * ndmpd_select will call data_accept_connection when a
1315 	 * connection is ready to be accepted.
1316 	 */
1317 	if (ndmpd_add_file_handler(session, (void*)session,
1318 	    session->ns_data.dd_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
1319 	    data_accept_connection_v3) < 0) {
1320 		(void) close(session->ns_data.dd_listen_sock);
1321 		session->ns_data.dd_listen_sock = -1;
1322 		return (-1);
1323 	}
1324 	NDMP_LOG(LOG_DEBUG, "addr: %s:%d",
1325 	    inet_ntoa(IN_ADDR(*addr)), ntohs(*port));
1326 
1327 	return (0);
1328 }
1329 
1330 
1331 /*
1332  * data_connect_sock_v3
1333  *
1334  * Connect the data interface socket to the specified ip/port
1335  *
1336  * Parameters:
1337  *   session (input) - session pointer.
1338  *   addr    (input) - IP address
1339  *   port    (input) - port number
1340  *
1341  * Returns:
1342  *   NDMP_NO_ERR - backup successfully started.
1343  *   otherwise - error code of backup start error.
1344  */
1345 static ndmp_error
1346 data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr, ushort_t port)
1347 {
1348 	int sock;
1349 
1350 	sock = ndmp_connect_sock_v3(addr, port);
1351 	if (sock < 0)
1352 		return (NDMP_CONNECT_ERR);
1353 
1354 	session->ns_data.dd_sock = sock;
1355 	session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
1356 	session->ns_data.dd_data_addr.tcp_ip_v3 = ntohl(addr);
1357 	session->ns_data.dd_data_addr.tcp_port_v3 = port;
1358 
1359 	return (NDMP_NO_ERR);
1360 }
1361 
1362 
1363 /*
1364  * ndmpd_tar_start_backup_v3
1365  *
1366  * Start the backup work
1367  *
1368  * Parameters:
1369  *   session   (input) - session pointer.
1370  *   bu_type   (input) - backup type.
1371  *   env_val   (input) - environment variable array.
1372  *   env_len   (input) - length of env_val.
1373  *
1374  * Returns:
1375  *   NDMP_NO_ERR - backup successfully started.
1376  *   otherwise - error code of backup start error.
1377  */
1378 static ndmp_error
1379 ndmpd_tar_start_backup_v3(ndmpd_session_t *session, char *bu_type,
1380     ndmp_pval *env_val, ulong_t env_len)
1381 {
1382 	int err;
1383 	ndmp_lbr_params_t *nlp;
1384 	ndmpd_module_params_t *params;
1385 	ndmp_data_start_backup_reply_v3 reply;
1386 
1387 	(void) memset((void*)&reply, 0, sizeof (reply));
1388 
1389 	err = ndmpd_save_env(session, env_val, env_len);
1390 	if (err != NDMP_NO_ERR)
1391 		return (err);
1392 
1393 	nlp = ndmp_get_nlp(session);
1394 	NDMP_FREE(nlp->nlp_params);
1395 	params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
1396 	if (!params)
1397 		return (NDMP_NO_MEM_ERR);
1398 
1399 	params->mp_daemon_cookie = (void *)session;
1400 	params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
1401 	params->mp_protocol_version = session->ns_protocol_version;
1402 	params->mp_operation = NDMP_DATA_OP_BACKUP;
1403 	params->mp_get_env_func = ndmpd_api_get_env;
1404 	params->mp_add_env_func = ndmpd_api_add_env;
1405 	params->mp_set_env_func = ndmpd_api_set_env;
1406 	params->mp_get_name_func = 0;
1407 	params->mp_dispatch_func = ndmpd_api_dispatch;
1408 	params->mp_done_func = ndmpd_api_done_v3;
1409 	if (session->ns_protocol_version == NDMPV4)
1410 		params->mp_log_func_v3 = ndmpd_api_log_v4;
1411 	else
1412 		params->mp_log_func_v3 = ndmpd_api_log_v3;
1413 
1414 	params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
1415 	params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
1416 	params->mp_write_func = ndmpd_api_write_v3;
1417 	params->mp_read_func = 0;
1418 	params->mp_file_recovered_func = 0;
1419 	params->mp_stats = &session->ns_data.dd_module.dm_stats;
1420 	session->ns_data.dd_module.dm_module_cookie = 0;
1421 
1422 	if (strcmp(bu_type, NDMP_DUMP_TYPE) == 0) {
1423 		NLP_SET(nlp, NLPF_DUMP);
1424 		params->mp_file_history_path_func = 0;
1425 		params->mp_file_history_dir_func =
1426 		    ndmpd_api_file_history_dir_v3;
1427 		params->mp_file_history_node_func =
1428 		    ndmpd_api_file_history_node_v3;
1429 	} else if (strcmp(bu_type, NDMP_TAR_TYPE) == 0) {
1430 		NLP_SET(nlp, NLPF_TAR);
1431 		params->mp_file_history_path_func =
1432 		    ndmpd_api_file_history_file_v3;
1433 		params->mp_file_history_dir_func = 0;
1434 		params->mp_file_history_node_func = 0;
1435 	} else {
1436 		NLP_UNSET(nlp, NLPF_DUMP);
1437 		NLP_UNSET(nlp, NLPF_TAR);
1438 	}
1439 
1440 	session->ns_data.dd_module.dm_start_func = ndmpd_tar_backup_starter_v3;
1441 	session->ns_data.dd_module.dm_abort_func = ndmpd_tar_backup_abort_v3;
1442 
1443 	session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1444 	session->ns_data.dd_module.dm_stats.ms_est_time_remaining  = 0;
1445 	session->ns_data.dd_nlist_v3 = 0;
1446 	session->ns_data.dd_nlist_len = 0;
1447 	session->ns_data.dd_bytes_left_to_read = 0;
1448 	session->ns_data.dd_position = 0;
1449 	session->ns_data.dd_discard_length = 0;
1450 	session->ns_data.dd_read_offset = 0;
1451 	session->ns_data.dd_read_length = 0;
1452 
1453 	reply.error = ndmp_backup_get_params_v3(session, params);
1454 	if (reply.error != NDMP_NO_ERR) {
1455 		NDMP_LOG(LOG_DEBUG, "err: %d", err);
1456 		NDMP_FREE(nlp->nlp_params);
1457 		return (reply.error);
1458 	}
1459 
1460 	reply.error = NDMP_NO_ERR;
1461 	if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1462 	    &reply) < 0) {
1463 		NDMP_LOG(LOG_DEBUG, "Sending data_start_backup_v3 reply");
1464 		return (NDMP_NO_ERR);
1465 	}
1466 
1467 	NS_INC(nbk);
1468 	session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
1469 	session->ns_data.dd_operation = NDMP_DATA_OP_BACKUP;
1470 	session->ns_data.dd_abort = FALSE;
1471 
1472 	/*
1473 	 * perform the backup
1474 	 *
1475 	 * Cannot wait for the thread to exit as we are replying to the
1476 	 * client request here.
1477 	 */
1478 	err = pthread_create(NULL, NULL,
1479 	    (funct_t)session->ns_data.dd_module.dm_start_func,
1480 	    params);
1481 	if (err != 0) {
1482 		NDMP_LOG(LOG_ERR, "Can't start backup session.");
1483 		return (NDMP_ILLEGAL_ARGS_ERR);
1484 	}
1485 
1486 	return (NDMP_NO_ERR);
1487 }
1488 
1489 /*
1490  * ndmpd_tar_start_recover_v3
1491  *
1492  * Start the restore work
1493  *
1494  * Parameters:
1495  *   session   (input) - session pointer.
1496  *   bu_type   (input) - backup type.
1497  *   env_val   (input) - environment variable array.
1498  *   env_len   (input) - length of env_val.
1499  *   nlist_val (input) - list of files.
1500  *   nlist_len (input) - length of nlist_val.
1501  *
1502  * Returns:
1503  *   NDMP_NO_ERR - recover successfully started.
1504  *   otherwise   - error code of recover start error.
1505  */
1506 static ndmp_error
1507 ndmpd_tar_start_recover_v3(ndmpd_session_t *session,
1508     ndmp_pval *env_val, ulong_t env_len, ndmp_name_v3 *nlist_val,
1509     ulong_t nlist_len)
1510 {
1511 	ndmp_data_start_recover_reply_v3 reply;
1512 	ndmpd_module_params_t *params;
1513 	ndmp_lbr_params_t *nlp;
1514 	int err;
1515 
1516 	(void) memset((void*)&reply, 0, sizeof (reply));
1517 
1518 	nlp = ndmp_get_nlp(session);
1519 	NDMP_FREE(nlp->nlp_params);
1520 	params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
1521 	if (!params) {
1522 		return (NDMP_NO_MEM_ERR);
1523 	}
1524 
1525 	reply.error = ndmpd_save_env(session, env_val, env_len);
1526 	if (reply.error != NDMP_NO_ERR) {
1527 		NDMP_FREE(nlp->nlp_params);
1528 		return (NDMP_NO_MEM_ERR);
1529 	}
1530 
1531 	reply.error = ndmpd_save_nlist_v3(session, nlist_val, nlist_len);
1532 	if (reply.error != NDMP_NO_ERR) {
1533 		NDMP_FREE(nlp->nlp_params);
1534 		return (NDMP_NO_MEM_ERR);
1535 	}
1536 
1537 	/*
1538 	 * Setup restore parameters.
1539 	 */
1540 	params->mp_daemon_cookie = (void *)session;
1541 	params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
1542 	params->mp_protocol_version = session->ns_protocol_version;
1543 	params->mp_operation = NDMP_DATA_OP_RECOVER;
1544 	params->mp_get_env_func = ndmpd_api_get_env;
1545 	params->mp_add_env_func = ndmpd_api_add_env;
1546 	params->mp_set_env_func = ndmpd_api_set_env;
1547 	params->mp_get_name_func = ndmpd_api_get_name_v3;
1548 	params->mp_dispatch_func = ndmpd_api_dispatch;
1549 	params->mp_done_func = ndmpd_api_done_v3;
1550 	if (session->ns_protocol_version == NDMPV4) {
1551 		params->mp_log_func_v3 = ndmpd_api_log_v4;
1552 		params->mp_file_recovered_func = ndmpd_api_file_recovered_v4;
1553 	} else {
1554 		params->mp_log_func_v3 = ndmpd_api_log_v3;
1555 		params->mp_file_recovered_func = ndmpd_api_file_recovered_v3;
1556 	}
1557 
1558 	params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
1559 	params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
1560 	params->mp_write_func = 0;
1561 	params->mp_file_history_path_func = 0;
1562 	params->mp_file_history_dir_func = 0;
1563 	params->mp_file_history_node_func = 0;
1564 	params->mp_read_func = ndmpd_api_read_v3;
1565 	params->mp_seek_func = ndmpd_api_seek_v3;
1566 	params->mp_stats = &session->ns_data.dd_module.dm_stats;
1567 
1568 	session->ns_data.dd_module.dm_module_cookie = 0;
1569 	session->ns_data.dd_module.dm_start_func = ndmpd_tar_restore_starter_v3;
1570 	session->ns_data.dd_module.dm_abort_func = ndmpd_tar_restore_abort_v3;
1571 	session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1572 	session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
1573 	session->ns_data.dd_bytes_left_to_read = 0;
1574 	session->ns_data.dd_position = 0;
1575 	session->ns_data.dd_discard_length = 0;
1576 	session->ns_data.dd_read_offset = 0;
1577 	session->ns_data.dd_read_length = 0;
1578 
1579 	err = ndmp_restore_get_params_v3(session, params);
1580 	if (err != NDMP_NO_ERR) {
1581 		NDMP_FREE(nlp->nlp_params);
1582 		return (err);
1583 	}
1584 
1585 	reply.error = NDMP_NO_ERR;
1586 	if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1587 	    &reply) < 0) {
1588 		NDMP_FREE(nlp->nlp_params);
1589 		ndmpd_free_nlist_v3(session);
1590 		NDMP_LOG(LOG_DEBUG,
1591 		    "Error sending ndmp_data_start_recover_reply");
1592 		ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
1593 		return (NDMP_NO_ERR);
1594 	}
1595 
1596 	NS_INC(nrs);
1597 	session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
1598 	session->ns_data.dd_operation = NDMP_DATA_OP_RECOVER;
1599 	session->ns_data.dd_abort = FALSE;
1600 
1601 	/*
1602 	 * perform the restore
1603 	 *
1604 	 * Cannot wait for the thread to exit as we are replying to the
1605 	 * client request here.
1606 	 */
1607 	err = pthread_create(NULL, NULL,
1608 	    (funct_t)session->ns_data.dd_module.dm_start_func,
1609 	    params);
1610 
1611 	if (err != 0) {
1612 		NDMP_LOG(LOG_ERR, "Can't start recover session.");
1613 		return (NDMP_ILLEGAL_ARGS_ERR);
1614 	}
1615 	return (NDMP_NO_ERR);
1616 }
1617 
1618 static ndmp_error
1619 ndmpd_zfs_start_op(ndmpd_session_t *session, ndmp_pval *env_val,
1620     ulong_t env_len, ndmp_name_v3 *nlist_val, ulong_t nlist_len,
1621     enum ndmp_data_operation op)
1622 {
1623 	ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
1624 	ndmp_data_start_backup_reply_v3 backup_reply;
1625 	ndmp_data_start_recover_reply_v3 recover_reply;
1626 	pthread_t tid;
1627 	void *reply;
1628 	char str[8];
1629 	int err;
1630 
1631 	if (ndmpd_zfs_init(session) != 0)
1632 		return (NDMP_UNDEFINED_ERR);
1633 
1634 	err = ndmpd_save_env(session, env_val, env_len);
1635 	if (err != NDMP_NO_ERR) {
1636 		ndmpd_zfs_fini(ndmpd_zfs_args);
1637 		return (err);
1638 	}
1639 
1640 	switch (op) {
1641 	case NDMP_DATA_OP_BACKUP:
1642 		if (!ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args)) {
1643 			ndmpd_zfs_fini(ndmpd_zfs_args);
1644 			return (NDMP_ILLEGAL_ARGS_ERR);
1645 		}
1646 
1647 		if (ndmpd_zfs_pre_backup(ndmpd_zfs_args)) {
1648 			NDMP_LOG(LOG_ERR, "pre_backup error");
1649 			return (NDMP_ILLEGAL_ARGS_ERR);
1650 		}
1651 
1652 		session->ns_data.dd_module.dm_start_func =
1653 		    ndmpd_zfs_backup_starter;
1654 		(void) strlcpy(str, "backup", 8);
1655 		break;
1656 	case NDMP_DATA_OP_RECOVER:
1657 		err = ndmpd_save_nlist_v3(session, nlist_val, nlist_len);
1658 		if (err != NDMP_NO_ERR) {
1659 			ndmpd_zfs_fini(ndmpd_zfs_args);
1660 			return (NDMP_NO_MEM_ERR);
1661 		}
1662 
1663 		if (!ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args)) {
1664 			ndmpd_zfs_fini(ndmpd_zfs_args);
1665 			return (NDMP_ILLEGAL_ARGS_ERR);
1666 		}
1667 
1668 		if (ndmpd_zfs_pre_restore(ndmpd_zfs_args)) {
1669 			NDMP_LOG(LOG_ERR, "pre_restore error");
1670 			(void) ndmpd_zfs_post_restore(ndmpd_zfs_args);
1671 			return (NDMP_ILLEGAL_ARGS_ERR);
1672 		}
1673 		session->ns_data.dd_module.dm_start_func =
1674 		    ndmpd_zfs_restore_starter;
1675 		(void) strlcpy(str, "recover", 8);
1676 		break;
1677 	}
1678 
1679 	ndmpd_zfs_params->mp_operation = op;
1680 	session->ns_data.dd_operation = op;
1681 	session->ns_data.dd_module.dm_abort_func = ndmpd_zfs_abort;
1682 	session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
1683 	session->ns_data.dd_abort = FALSE;
1684 
1685 	if (op == NDMP_DATA_OP_BACKUP) {
1686 		(void) memset((void*)&backup_reply, 0, sizeof (backup_reply));
1687 		backup_reply.error = NDMP_NO_ERR;
1688 		reply = &backup_reply;
1689 	} else {
1690 		(void) memset((void*)&recover_reply, 0, sizeof (recover_reply));
1691 		recover_reply.error = NDMP_NO_ERR;
1692 		reply = &recover_reply;
1693 	}
1694 
1695 	if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1696 	    reply) < 0) {
1697 		NDMP_LOG(LOG_DEBUG, "Sending data_start_%s_v3 reply", str);
1698 		if (op == NDMP_DATA_OP_RECOVER)
1699 			ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
1700 		ndmpd_zfs_fini(ndmpd_zfs_args);
1701 		return (NDMP_NO_ERR);
1702 	}
1703 
1704 	err = pthread_create(&tid, NULL,
1705 	    (funct_t)session->ns_data.dd_module.dm_start_func, ndmpd_zfs_args);
1706 
1707 	if (err) {
1708 		NDMP_LOG(LOG_ERR, "Can't start %s session (errno %d)",
1709 		    str, err);
1710 		ndmpd_zfs_fini(ndmpd_zfs_args);
1711 		MOD_DONE(ndmpd_zfs_params, -1);
1712 		return (NDMP_NO_ERR);
1713 	}
1714 
1715 	(void) pthread_detach(tid);
1716 
1717 	if (op == NDMP_DATA_OP_BACKUP)
1718 		NS_INC(nbk);
1719 	else
1720 		NS_INC(nrs);
1721 
1722 	ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_NORMAL,
1723 	    "'zfs' %s starting\n", str);
1724 
1725 	return (NDMP_NO_ERR);
1726 }
1727 
1728 /*
1729  * discard_data_v3
1730  *
1731  * Read and discard data from the data connection.
1732  * Called when a module has called ndmpd_seek() prior to
1733  * reading all of the data from the previous seek.
1734  *
1735  * Parameters:
1736  *   session (input) - session pointer.
1737  *
1738  * Returns:
1739  *   number of bytes read and discarded.
1740  *  -1 - error.
1741  */
1742 static int
1743 discard_data_v3(ndmpd_session_t *session, ulong_t length)
1744 {
1745 	static char buf[MAX_RECORD_SIZE];
1746 	int n, toread;
1747 
1748 	toread = (length < MAX_RECORD_SIZE) ? length :
1749 	    MAX_RECORD_SIZE;
1750 
1751 	/* Read and discard the data. */
1752 	n = read(session->ns_data.dd_sock, buf, toread);
1753 	if (n < 0) {
1754 		NDMP_LOG(LOG_ERR, "Socket read error: %m.");
1755 		n = -1;
1756 	}
1757 
1758 	return (n);
1759 }
1760 
1761 
1762 /*
1763  * ndmpd_remote_read_v3
1764  *
1765  * Reads data from the remote mover.
1766  *
1767  * Parameters:
1768  *   session (input) - session pointer.
1769  *   data    (input) - data to be written.
1770  *   length  (input) - data length.
1771  *
1772  * Returns:
1773  *   0 - data successfully read.
1774  *  -1 - error.
1775  */
1776 int
1777 ndmpd_remote_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
1778 {
1779 	ulong_t count;
1780 	ulong_t len;
1781 	ssize_t n;
1782 	ndmp_notify_data_read_request request;
1783 	tlm_job_stats_t *jstat;
1784 	longlong_t fsize;
1785 
1786 	NDMP_LOG(LOG_DEBUG, "ns_data.dd_xx: [%llu, %llu, %llu, %llu, %llu]",
1787 	    session->ns_data.dd_bytes_left_to_read,
1788 	    session->ns_data.dd_read_offset,
1789 	    session->ns_data.dd_read_length,
1790 	    session->ns_data.dd_position,
1791 	    session->ns_data.dd_discard_length);
1792 
1793 	count = 0;
1794 	while (count < length) {
1795 		len = length - count;
1796 
1797 		/*
1798 		 * If the end of the seek window has been reached then
1799 		 * send an ndmp_read request to the client.
1800 		 * The NDMP client will then send a mover_data_read request to
1801 		 * the remote mover and the mover will send more data.
1802 		 * This condition can occur if the module attempts to read past
1803 		 * a seek window set via a prior call to ndmpd_seek() or
1804 		 * the module has not issued a seek. If no seek was issued then
1805 		 * pretend that a seek was issued to read the entire tape.
1806 		 */
1807 		if (session->ns_data.dd_bytes_left_to_read == 0) {
1808 			/* ndmpd_seek() never called? */
1809 			if (session->ns_data.dd_read_length == 0) {
1810 				session->ns_data.dd_bytes_left_to_read = ~0LL;
1811 				session->ns_data.dd_read_offset = 0LL;
1812 				session->ns_data.dd_read_length = ~0LL;
1813 			} else {
1814 				/*
1815 				 * While restoring a file, restoreFile()
1816 				 * records the number of bytes still need to
1817 				 * be restored.  We use this as a guidance
1818 				 * when asking for data from the tape.
1819 				 */
1820 				jstat = session->ns_ndmp_lbr_params->nlp_jstat;
1821 				fsize = jstat->js_bytes_in_file;
1822 
1823 				NDMP_LOG(LOG_DEBUG, "bytes_left [%llu / %u]",
1824 				    fsize, len);
1825 
1826 				/*
1827 				 * Fall back to the old way if fsize if too
1828 				 * small.
1829 				 */
1830 				if (fsize < len)
1831 					fsize = len;
1832 
1833 				session->ns_data.dd_bytes_left_to_read = fsize;
1834 				session->ns_data.dd_read_offset =
1835 				    session->ns_data.dd_position;
1836 				session->ns_data.dd_read_length = fsize;
1837 			}
1838 
1839 			request.offset =
1840 			    long_long_to_quad(session->ns_data.dd_read_offset);
1841 			request.length =
1842 			    long_long_to_quad(session->ns_data.dd_read_length);
1843 
1844 			NDMP_LOG(LOG_DEBUG, "to NOTIFY_DATA_READ [%llu, %llu]",
1845 			    session->ns_data.dd_read_offset,
1846 			    session->ns_data.dd_read_length);
1847 
1848 			if (ndmp_send_request_lock(session->ns_connection,
1849 			    NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
1850 			    &request, 0) < 0) {
1851 				NDMP_LOG(LOG_DEBUG,
1852 				    "Sending notify_data_read request");
1853 				return (-1);
1854 			}
1855 		}
1856 
1857 		/*
1858 		 * If the module called ndmpd_seek() prior to reading all of the
1859 		 * data that the remote mover was requested to send, then the
1860 		 * excess data from the seek has to be discarded.
1861 		 */
1862 		if (session->ns_data.dd_discard_length != 0) {
1863 			n = discard_data_v3(session,
1864 			    (ulong_t)session->ns_data.dd_discard_length);
1865 			if (n < 0)
1866 				return (-1);
1867 
1868 			session->ns_data.dd_discard_length -= n;
1869 			continue;
1870 		}
1871 
1872 		/*
1873 		 * Don't attempt to read more data than the remote is sending.
1874 		 */
1875 		if (len > session->ns_data.dd_bytes_left_to_read)
1876 			len = session->ns_data.dd_bytes_left_to_read;
1877 
1878 		if ((n = read(session->ns_data.dd_sock, &data[count],
1879 		    len)) < 0) {
1880 			NDMP_LOG(LOG_ERR, "Socket read error: %m.");
1881 			return (-1);
1882 		}
1883 
1884 		/* read returns 0 if the connection was closed */
1885 		if (n == 0) {
1886 			NDMP_LOG(LOG_DEBUG, "n 0 errno %d",
1887 			    errno);
1888 			return (-1);
1889 		}
1890 
1891 		count += n;
1892 		session->ns_data.dd_bytes_left_to_read -= n;
1893 		session->ns_data.dd_position += n;
1894 	}
1895 	return (0);
1896 }
1897 
1898 /*
1899  * nlp_release_job_stat
1900  *
1901  * Unreference the job statistics
1902  *
1903  * Parameters:
1904  *   session (input) - session pointer.
1905  *
1906  * Returns:
1907  *   void
1908  */
1909 static void
1910 nlp_release_job_stat(ndmpd_session_t *session)
1911 {
1912 	ndmp_lbr_params_t *nlp;
1913 
1914 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1915 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1916 		return;
1917 	}
1918 	if (nlp->nlp_jstat != NULL) {
1919 		nlp->nlp_bytes_total =
1920 		    (u_longlong_t)nlp->nlp_jstat->js_bytes_total;
1921 		tlm_un_ref_job_stats(nlp->nlp_jstat->js_job_name);
1922 		nlp->nlp_jstat = NULL;
1923 	} else
1924 		NDMP_LOG(LOG_DEBUG, "JSTAT == NULL");
1925 }
1926 
1927 
1928 /* *** ndmpd global internal functions *********************************** */
1929 
1930 /*
1931  * ndmpd_data_init
1932  *
1933  * Initializes data specific session variables.
1934  *
1935  * Parameters:
1936  *   session (input) - session pointer.
1937  *
1938  * Returns:
1939  *   void
1940  */
1941 int
1942 ndmpd_data_init(ndmpd_session_t *session)
1943 {
1944 	session->ns_data.dd_operation = NDMP_DATA_OP_NOACTION;
1945 	session->ns_data.dd_state = NDMP_DATA_STATE_IDLE;
1946 	session->ns_data.dd_halt_reason = NDMP_DATA_HALT_NA;
1947 	session->ns_data.dd_abort = FALSE;
1948 	session->ns_data.dd_env = 0;
1949 	session->ns_data.dd_env_len = 0;
1950 	session->ns_data.dd_nlist = 0;
1951 	session->ns_data.dd_nlist_len = 0;
1952 	session->ns_data.dd_mover.addr_type = NDMP_ADDR_LOCAL;
1953 	session->ns_data.dd_sock = -1;
1954 	session->ns_data.dd_read_offset = 0;
1955 	session->ns_data.dd_read_length = 0;
1956 	session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1957 	session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
1958 	/*
1959 	 * NDMP V3
1960 	 */
1961 	session->ns_data.dd_state = NDMP_DATA_STATE_IDLE;
1962 	session->ns_data.dd_nlist_v3 = 0;
1963 	session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
1964 	session->ns_data.dd_listen_sock = -1;
1965 	session->ns_data.dd_bytes_left_to_read = 0LL;
1966 	session->ns_data.dd_position = 0LL;
1967 	session->ns_data.dd_discard_length = 0LL;
1968 	return (0);
1969 }
1970 
1971 
1972 
1973 /*
1974  * ndmpd_data_cleanup
1975  *
1976  * Releases resources allocated during a data operation.
1977  *
1978  * Parameters:
1979  *   session (input) - session pointer.
1980  *
1981  * Returns:
1982  *   void
1983  */
1984 void
1985 ndmpd_data_cleanup(ndmpd_session_t *session)
1986 {
1987 	if (session->ns_data.dd_listen_sock != -1) {
1988 		NDMP_LOG(LOG_DEBUG, "data.listen_sock: %d",
1989 		    session->ns_data.dd_listen_sock);
1990 		(void) ndmpd_remove_file_handler(session,
1991 		    session->ns_data.dd_listen_sock);
1992 		(void) close(session->ns_data.dd_listen_sock);
1993 		session->ns_data.dd_listen_sock = -1;
1994 	}
1995 	if (session->ns_data.dd_sock != -1) {
1996 		NDMP_LOG(LOG_DEBUG, "data.sock: %d",
1997 		    session->ns_data.dd_sock);
1998 
1999 		/*
2000 		 * ndmpcopy: we use the same socket for the mover,
2001 		 * so expect to close when mover is done!
2002 		 */
2003 		if (session->ns_data.dd_sock != session->ns_mover.md_sock)
2004 			(void) close(session->ns_data.dd_sock);
2005 
2006 		session->ns_data.dd_sock = -1;
2007 	}
2008 
2009 	ndmpd_free_env(session);
2010 	ndmpd_free_nlist(session);
2011 }
2012 
2013 
2014 /*
2015  * ndmp_data_get_mover_mode
2016  *
2017  * Return the mover mode
2018  *
2019  * Parameters:
2020  *   session (input) - session pointer.
2021  *
2022  * Returns:
2023  *   remote - remote backup
2024  *   local  - local backup
2025  */
2026 char *
2027 ndmp_data_get_mover_mode(ndmpd_session_t *session)
2028 {
2029 	char *rv;
2030 
2031 	switch (session->ns_protocol_version) {
2032 	case NDMPV2:
2033 		rv = ((session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP)
2034 		    ? "remote" : "local");
2035 		break;
2036 	case NDMPV3:
2037 		rv = ((session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP)
2038 		    ? "remote" : "local");
2039 		break;
2040 	case NDMPV4:
2041 		rv = ((session->ns_data.dd_data_addr.addr_type ==
2042 		    NDMP_ADDR_TCP ||
2043 		    (session->ns_data.dd_data_addr_v4.addr_type ==
2044 		    NDMP_ADDR_TCP)) ? "remote" : "local");
2045 		break;
2046 	default:
2047 		rv = "Unknown";
2048 		NDMP_LOG(LOG_ERR, "Invalid protocol version %d.",
2049 		    session->ns_protocol_version);
2050 	}
2051 
2052 	return (rv);
2053 }
2054 
2055 /* *** static functions ******************************************** */
2056 
2057 /*
2058  * ndmpd_tar_start_backup_v2
2059  *
2060  * Request handling code common to version 1 and
2061  * version 2 data_start_backup request handlers.
2062  *
2063  * Parameters:
2064  *   session   (input) - session pointer.
2065  *   bu_type   (input) - backup type.
2066  *   env_val   (input) - environment variable array.
2067  *   env_len   (input) - length of env_val.
2068  *
2069  * Returns:
2070  *   NDMP_NO_ERR - backup successfully started.
2071  *   otherwise - error code of backup start error.
2072  */
2073 static ndmp_error
2074 ndmpd_tar_start_backup_v2(ndmpd_session_t *session, char *bu_type,
2075     ndmp_pval *env_val, ulong_t env_len)
2076 {
2077 	ndmp_data_start_backup_reply reply;
2078 	ndmpd_module_params_t *params;
2079 	ndmp_lbr_params_t *nlp;
2080 	int err;
2081 
2082 	if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
2083 		NDMP_LOG(LOG_ERR, "Can't start new backup in current state.");
2084 		return (NDMP_ILLEGAL_STATE_ERR);
2085 	}
2086 	if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
2087 	    strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
2088 		NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", bu_type);
2089 		NDMP_LOG(LOG_ERR, "Supported backup types are tar and dump.");
2090 		return (NDMP_ILLEGAL_ARGS_ERR);
2091 	}
2092 	if ((err = ndmpd_save_env(session, env_val, env_len)) != NDMP_NO_ERR)
2093 		return (err);
2094 
2095 	nlp = ndmp_get_nlp(session);
2096 	NDMP_FREE(nlp->nlp_params);
2097 	params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
2098 	if (params == NULL)
2099 		return (NDMP_NO_MEM_ERR);
2100 
2101 	params->mp_daemon_cookie = (void *)session;
2102 	params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
2103 	params->mp_protocol_version = session->ns_protocol_version;
2104 	params->mp_operation = NDMP_DATA_OP_BACKUP;
2105 	params->mp_get_env_func = ndmpd_api_get_env;
2106 	params->mp_add_env_func = ndmpd_api_add_env;
2107 	params->mp_get_name_func = ndmpd_api_get_name;
2108 	params->mp_dispatch_func = ndmpd_api_dispatch;
2109 	params->mp_done_func = ndmpd_api_done_v2;
2110 	params->mp_log_func = ndmpd_api_log_v2;
2111 	params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
2112 	params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
2113 	params->mp_write_func = ndmpd_api_write_v2;
2114 	params->mp_read_func = 0;
2115 	params->mp_file_recovered_func = 0;
2116 	params->mp_stats = &session->ns_data.dd_module.dm_stats;
2117 
2118 	session->ns_data.dd_module.dm_module_cookie = 0;
2119 	if (strcmp(bu_type, NDMP_DUMP_TYPE) == 0) {
2120 		NLP_SET(nlp, NLPF_DUMP);
2121 		params->mp_file_history_path_func = 0;
2122 		params->mp_file_history_dir_func =
2123 		    ndmpd_api_file_history_dir_v2;
2124 		params->mp_file_history_node_func =
2125 		    ndmpd_api_file_history_node_v2;
2126 	} else if (strcmp(bu_type, NDMP_TAR_TYPE) == 0) {
2127 		/* backup type == NDMP_TAR_TYPE */
2128 		NLP_SET(nlp, NLPF_TAR);
2129 		params->mp_file_history_path_func =
2130 		    ndmpd_api_file_history_path_v2;
2131 		params->mp_file_history_dir_func = 0;
2132 		params->mp_file_history_node_func = 0;
2133 	} else {
2134 		NLP_UNSET(nlp, NLPF_DUMP);
2135 		NLP_UNSET(nlp, NLPF_TAR);
2136 	}
2137 
2138 	session->ns_data.dd_module.dm_start_func = ndmpd_tar_backup_starter;
2139 	session->ns_data.dd_module.dm_abort_func = ndmpd_tar_backup_abort;
2140 
2141 	session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
2142 	session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
2143 	session->ns_data.dd_nlist = 0;
2144 	session->ns_data.dd_nlist_len = 0;
2145 	session->ns_data.dd_read_offset = 0;
2146 	session->ns_data.dd_read_length = 0;
2147 
2148 	if ((err = ndmp_backup_extract_params(session,
2149 	    params)) != NDMP_NO_ERR) {
2150 		NDMP_LOG(LOG_DEBUG, "err: %d", err);
2151 		NDMP_FREE(nlp->nlp_params);
2152 		return (err);
2153 	}
2154 
2155 	err = ndmpd_mover_connect(session, NDMP_MOVER_MODE_READ);
2156 	if (err != NDMP_NO_ERR) {
2157 		NDMP_LOG(LOG_DEBUG,
2158 		    "mover connect err: %d", err);
2159 		NDMP_FREE(nlp->nlp_params);
2160 		return (err);
2161 	}
2162 
2163 	session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
2164 
2165 	session->ns_data.dd_operation = NDMP_DATA_OP_BACKUP;
2166 	session->ns_data.dd_abort = FALSE;
2167 
2168 	NDMP_LOG(LOG_DEBUG, "starting backup");
2169 
2170 	reply.error = NDMP_NO_ERR;
2171 	if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
2172 	    &reply) < 0) {
2173 		NDMP_LOG(LOG_DEBUG, "Sending data_start_backup reply");
2174 		NDMP_FREE(nlp->nlp_params);
2175 		if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
2176 			/*
2177 			 * ndmpcopy: we use the same socket for the mover,
2178 			 * so expect to close when mover is done!
2179 			 */
2180 			if (session->ns_data.dd_sock !=
2181 			    session->ns_mover.md_sock)
2182 				(void) close(session->ns_data.dd_sock);
2183 
2184 			session->ns_data.dd_sock = -1;
2185 		} else
2186 			ndmpd_mover_error(session,
2187 			    NDMP_MOVER_HALT_CONNECT_CLOSED);
2188 		return (NDMP_NO_ERR);
2189 	}
2190 
2191 	/*
2192 	 * perform the backup
2193 	 *
2194 	 * Cannot wait for the thread to exit as we are replying to the
2195 	 * client request here.
2196 	 */
2197 	(void) pthread_create(NULL, NULL,
2198 	    (funct_t)session->ns_data.dd_module.dm_start_func,
2199 	    params);
2200 
2201 	return (NDMP_NO_ERR);
2202 }
2203 
2204 /*
2205  * ndmpd_tar_start_recover_v2
2206  *
2207  * The main recover/restore function
2208  *
2209  * Parameters:
2210  *   session   (input) - session pointer.
2211  *   bu_type   (input) - backup type.
2212  *   env_val   (input) - environment variable array.
2213  *   env_len   (input) - length of env_val.
2214  *   nlist_val (input) - list of files.
2215  *   nlist_len (input) - length of nlist_val.
2216  *
2217  * Returns:
2218  *   NDMP_NO_ERR - recover successfully started.
2219  *   otherwise - error code of backup start error.
2220  */
2221 static ndmp_error
2222 ndmpd_tar_start_recover_v2(ndmpd_session_t *session, char *bu_type,
2223     ndmp_pval *env_val, ulong_t env_len, ndmp_name *nlist_val,
2224     ulong_t nlist_len)
2225 {
2226 	ndmp_data_start_recover_reply_v2 reply;
2227 	ndmpd_module_params_t *params;
2228 	ndmp_lbr_params_t *nlp;
2229 	int err;
2230 
2231 	if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
2232 		NDMP_LOG(LOG_ERR, "Can't start new recover in current state.");
2233 		return (NDMP_ILLEGAL_STATE_ERR);
2234 	}
2235 
2236 	if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
2237 	    strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
2238 		NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", bu_type);
2239 		NDMP_LOG(LOG_ERR, "Supported backup types are tar and dump.");
2240 		return (NDMP_ILLEGAL_ARGS_ERR);
2241 	}
2242 
2243 	reply.error = ndmpd_save_env(session, env_val, env_len);
2244 	if (reply.error != NDMP_NO_ERR)
2245 		return (NDMP_NO_MEM_ERR);
2246 
2247 	reply.error = ndmpd_save_nlist_v2(session, nlist_val, nlist_len);
2248 	if (reply.error != NDMP_NO_ERR)
2249 		return (NDMP_NO_MEM_ERR);
2250 
2251 	nlp = ndmp_get_nlp(session);
2252 	NDMP_FREE(nlp->nlp_params);
2253 	params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
2254 	if (params == NULL)
2255 		return (NDMP_NO_MEM_ERR);
2256 
2257 	/*
2258 	 * Setup restore parameters.
2259 	 */
2260 	params->mp_daemon_cookie = (void *)session;
2261 	params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
2262 	params->mp_protocol_version = session->ns_protocol_version;
2263 	params->mp_operation = NDMP_DATA_OP_RECOVER;
2264 	params->mp_get_env_func = ndmpd_api_get_env;
2265 	params->mp_add_env_func = ndmpd_api_add_env;
2266 	params->mp_get_name_func = ndmpd_api_get_name;
2267 	params->mp_dispatch_func = ndmpd_api_dispatch;
2268 	params->mp_done_func = ndmpd_api_done_v2;
2269 	params->mp_log_func = ndmpd_api_log_v2;
2270 	params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
2271 	params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
2272 	params->mp_write_func = 0;
2273 	params->mp_file_history_path_func = 0;
2274 	params->mp_file_history_dir_func = 0;
2275 	params->mp_file_history_node_func = 0;
2276 	params->mp_read_func = ndmpd_api_read_v2;
2277 	params->mp_seek_func = ndmpd_api_seek_v2;
2278 	params->mp_file_recovered_func = ndmpd_api_file_recovered_v2;
2279 	params->mp_stats = &session->ns_data.dd_module.dm_stats;
2280 
2281 	session->ns_data.dd_module.dm_module_cookie = 0;
2282 	session->ns_data.dd_module.dm_start_func = ndmpd_tar_restore_starter;
2283 	session->ns_data.dd_module.dm_abort_func = ndmpd_tar_restore_abort;
2284 	session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
2285 	session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
2286 	session->ns_data.dd_read_offset = 0;
2287 	session->ns_data.dd_read_length = 0;
2288 
2289 	if ((err = ndmp_restore_extract_params(session,
2290 	    params)) != NDMP_NO_ERR) {
2291 		NDMP_FREE(nlp->nlp_params);
2292 		return (err);
2293 	}
2294 
2295 	err = ndmpd_mover_connect(session, NDMP_MOVER_MODE_WRITE);
2296 	if (err != NDMP_NO_ERR) {
2297 		NDMP_FREE(nlp->nlp_params);
2298 		return (err);
2299 	}
2300 
2301 	session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
2302 	session->ns_data.dd_operation = NDMP_DATA_OP_RECOVER;
2303 	session->ns_data.dd_abort = FALSE;
2304 
2305 	reply.error = NDMP_NO_ERR;
2306 	if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
2307 	    &reply) < 0) {
2308 		NDMP_LOG(LOG_DEBUG, "Sending data_start_recover reply");
2309 		NDMP_FREE(nlp->nlp_params);
2310 		if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
2311 			/*
2312 			 * ndmpcopy: we use the same socket for the mover,
2313 			 * so expect to close when mover is done!
2314 			 */
2315 			if (session->ns_data.dd_sock !=
2316 			    session->ns_mover.md_sock)
2317 				(void) close(session->ns_data.dd_sock);
2318 
2319 			session->ns_data.dd_sock = -1;
2320 		} else {
2321 			ndmpd_mover_error(session,
2322 			    NDMP_MOVER_HALT_CONNECT_CLOSED);
2323 		}
2324 		return (NDMP_NO_ERR);
2325 	}
2326 
2327 
2328 	/*
2329 	 * perform the restore
2330 	 *
2331 	 * Cannot wait for the thread to exit as we are replying to the
2332 	 * client request here.
2333 	 */
2334 	(void) pthread_create(NULL, NULL,
2335 	    (funct_t)session->ns_data.dd_module.dm_start_func,
2336 	    params);
2337 
2338 	return (NDMP_NO_ERR);
2339 }
2340 
2341 /*
2342  * ndmpd_data_get_info
2343  *
2344  * Return the total number of bytes processed
2345  *
2346  * Parameters:
2347  *   session   (input) - session pointer.
2348  *
2349  * Returns:
2350  *   the number of bytes processed
2351  */
2352 static u_longlong_t
2353 ndmpd_data_get_info(ndmpd_session_t *session)
2354 {
2355 	ndmp_lbr_params_t *nlp;
2356 
2357 	nlp = ndmp_get_nlp(session);
2358 	if (nlp == NULL)
2359 		return ((u_longlong_t)0);
2360 
2361 	if (nlp->nlp_jstat == NULL)
2362 		return (nlp->nlp_bytes_total);
2363 
2364 	return ((u_longlong_t)nlp->nlp_jstat->js_bytes_total);
2365 }
2366