2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
9 * Copyright (c) 2007, The Storage Networking Industry Association.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
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
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
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.
39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/socket.h>
44 #include <netinet/in.h>
46 #include <arpa/inet.h>
49 #include "ndmpd_common.h"
52 static int ndmpd_data_error_send_v4(ndmpd_session_t
*session
,
53 ndmp_data_halt_reason reason
);
54 static int ndmpd_data_error_send(ndmpd_session_t
*session
,
55 ndmp_data_halt_reason reason
);
56 static void data_accept_connection_v3(void *cookie
, int fd
, ulong_t mode
);
57 static int create_listen_socket_v3(ndmpd_session_t
*session
, ulong_t
*addr
,
59 static ndmp_error
data_connect_sock_v3(ndmpd_session_t
*session
, ulong_t addr
,
61 static int discard_data_v3(ndmpd_session_t
*session
, ulong_t length
);
62 static void nlp_release_job_stat(ndmpd_session_t
*session
);
63 static u_longlong_t
ndmpd_data_get_info(ndmpd_session_t
*session
);
65 static ndmp_error
ndmpd_tar_start_backup_v2(ndmpd_session_t
*, char *,
66 ndmp_pval
*, ulong_t
);
67 static ndmp_error
ndmpd_tar_start_recover_v2(ndmpd_session_t
*, char *,
68 ndmp_pval
*, ulong_t
, ndmp_name
*, ulong_t
);
69 static ndmp_error
ndmpd_tar_start_backup_v3(ndmpd_session_t
*, char *,
70 ndmp_pval
*, ulong_t
);
71 static ndmp_error
ndmpd_tar_start_recover_v3(ndmpd_session_t
*,
72 ndmp_pval
*, ulong_t
, ndmp_name_v3
*, ulong_t
);
74 static ndmp_error
ndmpd_zfs_start_op(ndmpd_session_t
*,
75 ndmp_pval
*, ulong_t
, ndmp_name_v3
*, ulong_t
, enum ndmp_data_operation
);
79 * ************************************************************************
81 * ************************************************************************
85 * ndmpd_data_get_state_v2
87 * Request handler. Returns current data state.
90 * connection (input) - connection handle.
91 * body (input) - request message body.
98 ndmpd_data_get_state_v2(ndmp_connection_t
*connection
, void *body
)
100 ndmp_data_get_state_reply_v2 reply
;
101 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
103 reply
.error
= NDMP_NO_ERR
;
104 reply
.operation
= session
->ns_data
.dd_operation
;
105 reply
.state
= session
->ns_data
.dd_state
;
106 reply
.halt_reason
= session
->ns_data
.dd_halt_reason
;
108 reply
.est_time_remain
=
109 session
->ns_data
.dd_module
.dm_stats
.ms_est_time_remaining
;
110 reply
.est_bytes_remain
=
112 session
->ns_data
.dd_module
.dm_stats
.ms_est_bytes_remaining
);
114 reply
.bytes_processed
=
115 long_long_to_quad(ndmpd_data_get_info(session
));
117 reply
.mover
= session
->ns_data
.dd_mover
;
118 reply
.read_offset
= long_long_to_quad(session
->ns_data
.dd_read_offset
);
119 reply
.read_length
= long_long_to_quad(session
->ns_data
.dd_read_length
);
121 ndmp_send_reply(connection
, &reply
,
122 "sending data_get_state reply");
127 * ndmpd_data_start_backup_v2
129 * Request handler. Starts a backup.
132 * connection (input) - connection handle.
133 * body (input) - request message body.
139 ndmpd_data_start_backup_v2(ndmp_connection_t
*connection
, void *body
)
141 ndmp_data_start_backup_request_v2
*request
;
142 ndmp_data_start_backup_reply_v2 reply
;
143 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
146 request
= (ndmp_data_start_backup_request_v2
*)body
;
148 reply
.error
= NDMP_NO_ERR
;
149 session
->ns_data
.dd_mover
= request
->mover
;
151 err
= ndmpd_tar_start_backup_v2(session
, request
->bu_type
,
152 request
->env
.env_val
, request
->env
.env_len
);
155 * start_backup sends the reply if the backup is successfully started.
156 * Otherwise, send the reply containing the error here.
158 if (err
!= NDMP_NO_ERR
) {
159 NDMP_LOG(LOG_DEBUG
, "err: %d", err
);
161 ndmp_send_reply(connection
, &reply
,
162 "sending data_start_backup reply");
163 ndmpd_data_cleanup(session
);
168 * ndmpd_data_start_recover_v2
170 * Request handler. Starts a restore.
173 * connection (input) - connection handle.
174 * body (input) - request message body.
180 ndmpd_data_start_recover_v2(ndmp_connection_t
*connection
, void *body
)
182 ndmp_data_start_recover_request_v2
*request
;
183 ndmp_data_start_recover_reply_v2 reply
;
184 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
187 request
= (ndmp_data_start_recover_request_v2
*) body
;
188 session
->ns_data
.dd_mover
= request
->mover
;
190 err
= ndmpd_tar_start_recover_v2(session
, request
->bu_type
,
191 request
->env
.env_val
, request
->env
.env_len
,
192 request
->nlist
.nlist_val
, request
->nlist
.nlist_len
);
195 * start_recover sends the reply if the recover is successfully started.
196 * Otherwise, send the reply containing the error here.
198 if (err
!= NDMP_NO_ERR
) {
200 ndmp_send_reply(connection
, &reply
,
201 "sending ndmp_data_start_recover_request_v2 reply");
202 ndmpd_data_cleanup(session
);
207 * ndmpd_data_get_env_v2
209 * Request handler. Returns the environment variable array sent
210 * with the backup request. This request may only be sent with
211 * a backup operation is in progress.
214 * connection (input) - connection handle.
215 * body (input) - request message body.
222 ndmpd_data_get_env_v2(ndmp_connection_t
*connection
, void *body
)
224 ndmp_data_get_env_reply reply
;
225 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
227 (void) memset((void*)&reply
, 0, sizeof (reply
));
228 if (session
->ns_data
.dd_operation
!= NDMP_DATA_OP_BACKUP
) {
229 NDMP_LOG(LOG_ERR
, "Backup operation not active.");
230 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
231 reply
.env
.env_len
= 0;
233 reply
.error
= NDMP_NO_ERR
;
234 reply
.env
.env_len
= session
->ns_data
.dd_env_len
;
235 reply
.env
.env_val
= session
->ns_data
.dd_env
;
238 ndmp_send_reply(connection
, &reply
, "sending data_get_env reply");
245 * Request handler. Stops the current data operation.
248 * connection (input) - connection handle.
249 * body (input) - request message body.
256 ndmpd_data_stop_v2(ndmp_connection_t
*connection
, void *body
)
258 ndmp_data_stop_reply reply
;
259 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
261 if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_HALTED
) {
262 NDMP_LOG(LOG_ERR
, "Invalid state to process stop request.");
263 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
264 ndmp_send_reply(connection
, &reply
,
265 "sending data_stop reply");
268 ndmp_waitfor_op(session
);
269 ndmpd_data_cleanup(session
);
270 ndmpd_file_history_cleanup(session
, FALSE
);
272 nlp_release_job_stat(session
);
274 /* prepare for another data operation */
275 (void) ndmpd_data_init(session
);
276 ndmpd_file_history_init(session
);
278 reply
.error
= NDMP_NO_ERR
;
279 ndmp_send_reply(connection
, &reply
, "sending data_stop reply");
284 * ndmpd_data_abort_v2
286 * Request handler. Aborts the current backup/restore. The operation
287 * state is not changed to the halted state until after the operation
288 * has actually been aborted and the notify_halt request has been sent.
291 * connection (input) - connection handle.
292 * body (input) - request message body.
299 ndmpd_data_abort_v2(ndmp_connection_t
*connection
, void *body
)
301 ndmp_data_abort_reply reply
;
302 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
304 if (session
->ns_data
.dd_state
== NDMP_DATA_STATE_IDLE
||
305 session
->ns_data
.dd_state
== NDMP_DATA_STATE_HALTED
) {
306 NDMP_LOG(LOG_ERR
, "Invalid state to process abort request.");
307 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
308 ndmp_send_reply(connection
, &reply
,
309 "sending data_abort reply");
313 * Don't go to HALTED state yet. Need to wait for data operation to
314 * abort. When this happens, ndmpd_done will get called and will
315 * perform the halt processing.
317 session
->ns_data
.dd_abort
= TRUE
;
318 (*session
->ns_data
.dd_module
.dm_abort_func
)(
319 session
->ns_data
.dd_module
.dm_module_cookie
);
321 reply
.error
= NDMP_NO_ERR
;
322 ndmp_send_reply(connection
, &reply
, "sending data_abort reply");
326 * ************************************************************************
328 * ************************************************************************
332 * ndmpd_data_get_state_v3
334 * Request handler. Returns current data state.
337 * connection (input) - connection handle.
338 * body (input) - request message body.
345 ndmpd_data_get_state_v3(ndmp_connection_t
*connection
, void *body
)
347 ndmp_data_get_state_reply_v3 reply
;
348 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
350 (void) memset((void*)&reply
, 0, sizeof (reply
));
352 reply
.error
= NDMP_NO_ERR
;
353 reply
.invalid
= NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID
354 | NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID
;
355 reply
.operation
= session
->ns_data
.dd_operation
;
356 reply
.state
= session
->ns_data
.dd_state
;
357 reply
.halt_reason
= session
->ns_data
.dd_halt_reason
;
359 if (reply
.operation
== NDMP_DATA_OP_BACKUP
)
360 reply
.bytes_processed
=
362 session
->ns_data
.dd_module
.dm_stats
.ms_bytes_processed
);
364 reply
.bytes_processed
=
365 long_long_to_quad(ndmpd_data_get_info(session
));
367 reply
.est_bytes_remain
= long_long_to_quad(0LL);
368 reply
.est_time_remain
= 0;
369 if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_IDLE
)
370 ndmp_copy_addr_v3(&reply
.data_connection_addr
,
371 &session
->ns_data
.dd_data_addr
);
372 reply
.read_offset
= long_long_to_quad(session
->ns_data
.dd_read_offset
);
373 reply
.read_length
= long_long_to_quad(session
->ns_data
.dd_read_length
);
375 ndmp_send_reply(connection
, &reply
,
376 "sending ndmp_data_get_state_v3 reply");
381 * ndmpd_data_start_backup_v3
383 * Request handler. Starts a backup.
386 * connection (input) - connection handle.
387 * body (input) - request message body.
393 ndmpd_data_start_backup_v3(ndmp_connection_t
*connection
, void *body
)
395 ndmp_data_start_backup_request_v3
*request
;
396 ndmp_data_start_backup_reply_v3 reply
;
397 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
399 request
= (ndmp_data_start_backup_request_v3
*)body
;
401 (void) memset((void*)&reply
, 0, sizeof (reply
));
403 if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_CONNECTED
) {
405 "Can't start new backup in current state.");
407 "Connection to the mover is not established.");
408 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
412 if (session
->ns_data
.dd_data_addr
.addr_type
== NDMP_ADDR_LOCAL
) {
413 if (session
->ns_tape
.td_mode
== NDMP_TAPE_READ_MODE
) {
414 NDMP_LOG(LOG_ERR
, "Write protected device.");
415 reply
.error
= NDMP_WRITE_PROTECT_ERR
;
420 if (strcasecmp(request
->bu_type
, NDMP_TAR_TYPE
) == 0) {
421 session
->ns_butype
= NDMP_BUTYPE_TAR
;
422 } else if (strcasecmp(request
->bu_type
, NDMP_DUMP_TYPE
) == 0) {
423 session
->ns_butype
= NDMP_BUTYPE_DUMP
;
424 } else if (strcasecmp(request
->bu_type
, NDMP_ZFS_TYPE
) == 0) {
425 session
->ns_butype
= NDMP_BUTYPE_ZFS
;
427 char msg_invalid
[32];
430 (void) snprintf(msg_invalid
, 32, "Invalid backup type: %s.",
432 (void) snprintf(msg_types
, 32,
433 "Supported backup types are tar, dump, and zfs.");
435 NDMP_APILOG((void *) session
, NDMP_LOG_ERROR
, ++ndmp_log_msg_id
,
437 NDMP_APILOG((void *) session
, NDMP_LOG_ERROR
, ++ndmp_log_msg_id
,
439 NDMP_LOG(LOG_ERR
, msg_invalid
);
440 NDMP_LOG(LOG_ERR
, msg_types
);
442 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
446 if (session
->ns_butype
== NDMP_BUTYPE_ZFS
) {
447 reply
.error
= ndmpd_zfs_start_op(session
, request
->env
.env_val
,
448 request
->env
.env_len
, NULL
, 0, NDMP_DATA_OP_BACKUP
);
450 reply
.error
= ndmpd_tar_start_backup_v3(session
,
451 request
->bu_type
, request
->env
.env_val
,
452 request
->env
.env_len
);
456 * *_start_backup* sends the reply if the backup is
457 * successfully started. Otherwise, send the reply
458 * containing the error here.
463 if (reply
.error
!= NDMP_NO_ERR
) {
464 ndmp_send_reply(connection
, &reply
,
465 "sending data_start_backup_v3 reply");
466 ndmpd_data_cleanup(session
);
471 * ndmpd_data_start_recover_v3
473 * Request handler. Starts a restore.
476 * connection (input) - connection handle.
477 * body (input) - request message body.
483 ndmpd_data_start_recover_v3(ndmp_connection_t
*connection
, void *body
)
485 ndmp_data_start_recover_request_v3
*request
;
486 ndmp_data_start_recover_reply_v3 reply
;
487 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
489 request
= (ndmp_data_start_recover_request_v3
*)body
;
491 (void) memset((void*)&reply
, 0, sizeof (reply
));
493 if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_CONNECTED
) {
494 NDMP_LOG(LOG_ERR
, "Can't start new recover in current state.");
495 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
499 if (strcasecmp(request
->bu_type
, NDMP_TAR_TYPE
) == 0) {
500 session
->ns_butype
= NDMP_BUTYPE_TAR
;
501 } else if (strcasecmp(request
->bu_type
, NDMP_DUMP_TYPE
) == 0) {
502 session
->ns_butype
= NDMP_BUTYPE_DUMP
;
503 } else if (strcasecmp(request
->bu_type
, NDMP_ZFS_TYPE
) == 0) {
504 session
->ns_butype
= NDMP_BUTYPE_ZFS
;
506 char msg_invalid
[32];
509 (void) snprintf(msg_invalid
, 32, "Invalid backup type: %s.",
511 (void) snprintf(msg_types
, 32,
512 "Supported backup types are tar, dump, and zfs.");
514 NDMP_APILOG((void *) session
, NDMP_LOG_ERROR
, ++ndmp_log_msg_id
,
516 NDMP_APILOG((void *) session
, NDMP_LOG_ERROR
, ++ndmp_log_msg_id
,
518 NDMP_LOG(LOG_ERR
, msg_invalid
);
519 NDMP_LOG(LOG_ERR
, msg_types
);
521 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
525 if (session
->ns_butype
== NDMP_BUTYPE_ZFS
) {
526 reply
.error
= ndmpd_zfs_start_op(session
, request
->env
.env_val
,
527 request
->env
.env_len
, request
->nlist
.nlist_val
,
528 request
->nlist
.nlist_len
, NDMP_DATA_OP_RECOVER
);
530 reply
.error
= ndmpd_tar_start_recover_v3(session
,
531 request
->env
.env_val
, request
->env
.env_len
,
532 request
->nlist
.nlist_val
, request
->nlist
.nlist_len
);
536 * *_start_recover* sends the reply if the recover is
537 * successfully started. Otherwise, send the reply
538 * containing the error here.
543 if (reply
.error
!= NDMP_NO_ERR
) {
544 ndmp_send_reply(connection
, &reply
,
545 "sending data_start_recover_v3 reply");
546 ndmpd_data_error(session
, NDMP_DATA_HALT_INTERNAL_ERROR
);
547 ndmpd_data_cleanup(session
);
552 * ndmpd_data_abort_v3
554 * Request handler. Aborts the current backup/restore. The operation
555 * state is not changed to the halted state until after the operation
556 * has actually been aborted and the notify_halt request has been sent.
559 * connection (input) - connection handle.
560 * body (input) - request message body.
567 ndmpd_data_abort_v3(ndmp_connection_t
*connection
, void *body
)
569 ndmp_data_abort_reply reply
;
570 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
572 switch (session
->ns_data
.dd_state
) {
573 case NDMP_DATA_STATE_IDLE
:
574 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
575 NDMP_LOG(LOG_ERR
, "Invalid state to process abort request.");
578 case NDMP_DATA_STATE_ACTIVE
:
580 * Don't go to HALTED state yet. Need to wait for data
581 * operation to abort. When this happens, ndmpd_done_v3
582 * will get called and will perform the halt processing.
584 reply
.error
= NDMP_NO_ERR
;
585 session
->ns_data
.dd_abort
= TRUE
;
586 if (session
->ns_data
.dd_module
.dm_abort_func
)
587 (*session
->ns_data
.dd_module
.dm_abort_func
)(
588 session
->ns_data
.dd_module
.dm_module_cookie
);
591 case NDMP_DATA_STATE_HALTED
:
592 case NDMP_DATA_STATE_LISTEN
:
593 case NDMP_DATA_STATE_CONNECTED
:
594 reply
.error
= NDMP_NO_ERR
;
595 session
->ns_data
.dd_abort
= TRUE
;
596 ndmpd_data_error(session
, NDMP_DATA_HALT_ABORTED
);
599 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
600 NDMP_LOG(LOG_DEBUG
, "Unknown data V3 state %d",
601 session
->ns_data
.dd_state
);
604 ndmp_send_reply(connection
, &reply
,
605 "sending data_abort_v3 reply");
612 * Request handler. Stops the current data operation.
615 * connection (input) - connection handle.
616 * body (input) - request message body.
623 ndmpd_data_stop_v3(ndmp_connection_t
*connection
, void *body
)
625 ndmp_data_stop_reply reply
;
626 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
628 if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_HALTED
) {
629 NDMP_LOG(LOG_ERR
, "Invalid state to process stop request.");
630 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
631 ndmp_send_reply(connection
, &reply
,
632 "sending data_stop_v3 reply");
635 ndmp_waitfor_op(session
);
636 ndmpd_data_cleanup(session
);
637 ndmpd_file_history_cleanup(session
, FALSE
);
639 /* prepare for another data operation */
640 (void) ndmpd_data_init(session
);
641 ndmpd_file_history_init(session
);
643 reply
.error
= NDMP_NO_ERR
;
644 ndmp_send_reply(connection
, &reply
,
645 "sending data_stop_v3 reply");
650 * ndmpd_data_listen_v3
652 * Request handler. Configures the server to listen for a connection
653 * from a remote mover.
656 * connection (input) - connection handle.
657 * body (input) - request message body.
663 ndmpd_data_listen_v3(ndmp_connection_t
*connection
, void *body
)
665 ndmp_data_listen_request_v3
*request
;
666 ndmp_data_listen_reply_v3 reply
;
667 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
671 request
= (ndmp_data_listen_request_v3
*)body
;
673 (void) memset((void*)&reply
, 0, sizeof (reply
));
675 if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_IDLE
) {
676 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
678 "Invalid internal data state to process listen request.");
679 } else if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_IDLE
) {
680 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
682 "Invalid mover state to process listen request.");
684 reply
.error
= NDMP_NO_ERR
;
687 if (reply
.error
!= NDMP_NO_ERR
) {
688 ndmp_send_reply(connection
, &reply
,
689 "ndmp_data_listen_request_v3 reply");
693 switch (request
->addr_type
) {
694 case NDMP_ADDR_LOCAL
:
695 reply
.data_connection_addr
.addr_type
= request
->addr_type
;
696 session
->ns_data
.dd_data_addr
.addr_type
= NDMP_ADDR_LOCAL
;
699 if (create_listen_socket_v3(session
, &addr
, &port
) < 0) {
700 reply
.error
= NDMP_IO_ERR
;
704 reply
.error
= NDMP_NO_ERR
;
705 reply
.data_connection_addr
.addr_type
= request
->addr_type
;
706 reply
.data_connection_addr
.tcp_ip_v3
= htonl(addr
);
707 reply
.data_connection_addr
.tcp_port_v3
= htons(port
);
708 session
->ns_data
.dd_data_addr
.addr_type
= NDMP_ADDR_TCP
;
709 session
->ns_data
.dd_data_addr
.tcp_ip_v3
= addr
;
710 session
->ns_data
.dd_data_addr
.tcp_port_v3
= ntohs(port
);
711 NDMP_LOG(LOG_DEBUG
, "listen_socket: %d",
712 session
->ns_data
.dd_listen_sock
);
716 NDMP_LOG(LOG_DEBUG
, "Invalid address type: %d",
718 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
722 if (reply
.error
== NDMP_NO_ERR
)
723 session
->ns_data
.dd_state
= NDMP_DATA_STATE_LISTEN
;
725 ndmp_send_reply(connection
, &reply
,
726 "ndmp_data_listen_request_v3 reply");
731 * ndmpd_data_connect_v3
733 * Request handler. Connects the data server to either a local
737 * connection (input) - connection handle.
738 * body (input) - request message body.
744 ndmpd_data_connect_v3(ndmp_connection_t
*connection
, void *body
)
746 ndmp_data_connect_request_v3
*request
;
747 ndmp_data_connect_reply_v3 reply
;
748 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
750 request
= (ndmp_data_connect_request_v3
*)body
;
752 (void) memset((void*)&reply
, 0, sizeof (reply
));
754 if (!ndmp_valid_v3addr_type(request
->addr
.addr_type
)) {
755 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
756 NDMP_LOG(LOG_DEBUG
, "Invalid address type %d",
757 request
->addr
.addr_type
);
758 } else if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_IDLE
) {
759 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
760 NDMP_LOG(LOG_ERR
, "Invalid state to process connect request.");
762 reply
.error
= NDMP_NO_ERR
;
765 if (reply
.error
!= NDMP_NO_ERR
) {
766 ndmp_send_reply(connection
, &reply
,
767 "sending ndmp_data_connect_v3 reply");
771 switch (request
->addr
.addr_type
) {
772 case NDMP_ADDR_LOCAL
:
774 * Verify that the mover is listening for a
777 if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_LISTEN
||
778 session
->ns_mover
.md_listen_sock
!= -1) {
779 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
781 "Mover is not in local listen state.");
783 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_ACTIVE
;
788 reply
.error
= data_connect_sock_v3(session
,
789 request
->addr
.tcp_ip_v3
, request
->addr
.tcp_port_v3
);
793 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
794 NDMP_LOG(LOG_DEBUG
, "Invalid address type %d",
795 request
->addr
.addr_type
);
798 if (reply
.error
== NDMP_NO_ERR
)
799 session
->ns_data
.dd_state
= NDMP_DATA_STATE_CONNECTED
;
801 ndmp_send_reply(connection
, &reply
,
802 "sending ndmp_data_connect_v3 reply");
807 * ************************************************************************
809 * ************************************************************************
813 * ndmpd_data_get_env_v4
815 * Request handler. Returns the environment variable array sent
816 * with the backup request. This request may only be sent with
817 * a backup operation is in progress.
820 * connection (input) - connection handle.
821 * body (input) - request message body.
828 ndmpd_data_get_env_v4(ndmp_connection_t
*connection
, void *body
)
830 ndmp_data_get_env_reply reply
;
831 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
833 (void) memset((void*)&reply
, 0, sizeof (reply
));
835 if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_ACTIVE
&&
836 session
->ns_data
.dd_state
!= NDMP_DATA_STATE_HALTED
) {
837 NDMP_LOG(LOG_ERR
, "Invalid state for the data server.");
838 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
839 reply
.env
.env_len
= 0;
840 } else if (session
->ns_data
.dd_operation
!= NDMP_DATA_OP_BACKUP
) {
841 NDMP_LOG(LOG_ERR
, "Backup operation not active.");
842 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
843 reply
.env
.env_len
= 0;
845 reply
.error
= NDMP_NO_ERR
;
846 reply
.env
.env_len
= session
->ns_data
.dd_env_len
;
847 reply
.env
.env_val
= session
->ns_data
.dd_env
;
850 ndmp_send_reply(connection
, &reply
, "sending data_get_env reply");
854 * ndmpd_data_get_state_v4
856 * Request handler. Returns current data state.
859 * connection (input) - connection handle.
860 * body (input) - request message body.
867 ndmpd_data_get_state_v4(ndmp_connection_t
*connection
, void *body
)
869 ndmp_data_get_state_reply_v4 reply
;
870 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
872 (void) memset((void*)&reply
, 0, sizeof (reply
));
874 reply
.error
= NDMP_NO_ERR
;
875 reply
.unsupported
= NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID
876 | NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID
;
877 reply
.operation
= session
->ns_data
.dd_operation
;
878 reply
.state
= session
->ns_data
.dd_state
;
879 reply
.halt_reason
= session
->ns_data
.dd_halt_reason
;
881 if (reply
.operation
== NDMP_DATA_OP_BACKUP
)
882 reply
.bytes_processed
= long_long_to_quad(
883 session
->ns_data
.dd_module
.dm_stats
.ms_bytes_processed
);
885 reply
.bytes_processed
=
886 long_long_to_quad(ndmpd_data_get_info(session
));
888 reply
.est_bytes_remain
= long_long_to_quad(0LL);
889 reply
.est_time_remain
= 0;
890 if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_IDLE
)
891 ndmp_copy_addr_v4(&reply
.data_connection_addr
,
892 &session
->ns_data
.dd_data_addr_v4
);
894 reply
.read_offset
= long_long_to_quad(session
->ns_data
.dd_read_offset
);
895 reply
.read_length
= long_long_to_quad(session
->ns_data
.dd_read_length
);
897 ndmp_send_reply(connection
, &reply
,
898 "sending ndmp_data_get_state_v4 reply");
899 free(reply
.data_connection_addr
.tcp_addr_v4
);
904 * ndmpd_data_connect_v4
906 * Request handler. Connects the data server to either a local
910 * connection (input) - connection handle.
911 * body (input) - request message body.
917 ndmpd_data_connect_v4(ndmp_connection_t
*connection
, void *body
)
919 ndmp_data_connect_request_v4
*request
;
920 ndmp_data_connect_reply_v4 reply
;
921 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
923 request
= (ndmp_data_connect_request_v4
*)body
;
925 (void) memset((void*)&reply
, 0, sizeof (reply
));
927 if (!ndmp_valid_v3addr_type(request
->addr
.addr_type
)) {
928 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
929 NDMP_LOG(LOG_DEBUG
, "Invalid address type %d",
930 request
->addr
.addr_type
);
931 } else if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_IDLE
) {
932 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
933 NDMP_LOG(LOG_ERR
, "Invalid state to process connect request.");
935 reply
.error
= NDMP_NO_ERR
;
938 if (reply
.error
!= NDMP_NO_ERR
) {
939 ndmp_send_reply(connection
, &reply
,
940 "sending ndmp_data_connect_v4 reply");
944 switch (request
->addr
.addr_type
) {
945 case NDMP_ADDR_LOCAL
:
947 * Verify that the mover is listening for a
950 if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_LISTEN
||
951 session
->ns_mover
.md_listen_sock
!= -1) {
952 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
954 "Mover is not in local listen state.");
956 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_ACTIVE
;
961 reply
.error
= data_connect_sock_v3(session
,
962 request
->addr
.tcp_ip_v4(0), request
->addr
.tcp_port_v4(0));
966 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
967 NDMP_LOG(LOG_DEBUG
, "Invalid address type %d",
968 request
->addr
.addr_type
);
971 if (reply
.error
== NDMP_NO_ERR
)
972 session
->ns_data
.dd_state
= NDMP_DATA_STATE_CONNECTED
;
974 ndmp_send_reply(connection
, &reply
,
975 "sending ndmp_data_connect_v4 reply");
979 * ndmpd_data_listen_v4
981 * Request handler. Configures the server to listen for a connection
982 * from a remote mover.
985 * connection (input) - connection handle.
986 * body (input) - request message body.
992 ndmpd_data_listen_v4(ndmp_connection_t
*connection
, void *body
)
994 ndmp_data_listen_request_v4
*request
;
995 ndmp_data_listen_reply_v4 reply
;
996 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
1000 request
= (ndmp_data_listen_request_v4
*)body
;
1002 (void) memset((void*)&reply
, 0, sizeof (reply
));
1004 if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_IDLE
) {
1005 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
1007 "Invalid internal data state to process listen request.");
1008 } else if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_IDLE
) {
1009 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
1011 "Invalid mover state to process listen request.");
1013 reply
.error
= NDMP_NO_ERR
;
1016 if (reply
.error
!= NDMP_NO_ERR
) {
1017 ndmp_send_reply(connection
, &reply
,
1018 "ndmp_data_listen_request_v4 reply");
1022 switch (request
->addr_type
) {
1023 case NDMP_ADDR_LOCAL
:
1024 reply
.connect_addr
.addr_type
= request
->addr_type
;
1025 session
->ns_data
.dd_data_addr
.addr_type
= NDMP_ADDR_LOCAL
;
1028 if (create_listen_socket_v3(session
, &addr
, &port
) < 0) {
1029 reply
.error
= NDMP_IO_ERR
;
1033 reply
.error
= NDMP_NO_ERR
;
1034 reply
.connect_addr
.addr_type
= request
->addr_type
;
1035 reply
.connect_addr
.tcp_addr_v4
=
1036 ndmp_malloc(sizeof (ndmp_tcp_addr_v4
));
1038 reply
.connect_addr
.tcp_ip_v4(0) = htonl(addr
);
1039 reply
.connect_addr
.tcp_port_v4(0) = htons(port
);
1040 reply
.connect_addr
.tcp_len_v4
= 1;
1042 session
->ns_data
.dd_data_addr_v4
.addr_type
= NDMP_ADDR_TCP
;
1043 session
->ns_data
.dd_data_addr_v4
.tcp_addr_v4
=
1044 ndmp_malloc(sizeof (ndmp_tcp_addr_v4
));
1046 session
->ns_data
.dd_data_addr_v4
.tcp_ip_v4(0) = addr
;
1047 session
->ns_data
.dd_data_addr_v4
.tcp_port_v4(0) = ntohs(port
);
1048 session
->ns_data
.dd_data_addr_v4
.tcp_len_v4
= 1;
1050 /* Copy that to data_addr for compatibility */
1051 session
->ns_data
.dd_data_addr
.addr_type
= NDMP_ADDR_TCP
;
1052 session
->ns_data
.dd_data_addr
.tcp_ip_v3
= addr
;
1053 session
->ns_data
.dd_data_addr
.tcp_port_v3
= ntohs(port
);
1054 NDMP_LOG(LOG_DEBUG
, "listen_socket: %d",
1055 session
->ns_data
.dd_listen_sock
);
1059 NDMP_LOG(LOG_DEBUG
, "Invalid address type: %d",
1060 request
->addr_type
);
1061 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
1065 if (reply
.error
== NDMP_NO_ERR
)
1066 session
->ns_data
.dd_state
= NDMP_DATA_STATE_LISTEN
;
1068 ndmp_send_reply(connection
, &reply
,
1069 "ndmp_data_listen_request_v4 reply");
1074 * ndmpd_data_start_recover_filehist_v4
1076 * Request handler. Recovers the file history (not supported yet)
1077 * This command has an optional support in V4.
1080 * connection (input) - connection handle.
1081 * body (input) - request message body.
1088 ndmpd_data_start_recover_filehist_v4(ndmp_connection_t
*connection
, void *body
)
1090 ndmp_data_start_recover_filehist_reply_v4 reply
;
1092 NDMP_LOG(LOG_DEBUG
, "Request not supported");
1093 reply
.error
= NDMP_NOT_SUPPORTED_ERR
;
1095 ndmp_send_reply(connection
, &reply
,
1096 "sending ndmp_data_start_recover_filehist_reply_v4 reply");
1100 * ************************************************************************
1102 * ************************************************************************
1106 * ndmpd_data_error_send
1108 * This function sends the notify message to the client.
1111 * session (input) - session pointer.
1112 * reason (input) - halt reason.
1119 ndmpd_data_error_send(ndmpd_session_t
*session
, ndmp_data_halt_reason reason
)
1121 ndmp_notify_data_halted_request req
;
1123 req
.reason
= session
->ns_data
.dd_halt_reason
;
1124 req
.text_reason
= "";
1126 return (ndmp_send_request(session
->ns_connection
,
1127 NDMP_NOTIFY_DATA_HALTED
, NDMP_NO_ERR
, &req
, 0));
1132 * ndmpd_data_error_send_v4
1134 * This function sends the notify message to the client.
1137 * session (input) - session pointer.
1138 * reason (input) - halt reason.
1145 ndmpd_data_error_send_v4(ndmpd_session_t
*session
, ndmp_data_halt_reason reason
)
1147 ndmp_notify_data_halted_request_v4 req
;
1149 req
.reason
= session
->ns_data
.dd_halt_reason
;
1151 return ndmp_send_request(session
->ns_connection
,
1152 NDMP_NOTIFY_DATA_HALTED
, NDMP_NO_ERR
, &req
, 0);
1159 * This function is called when a data error has been detected.
1160 * A notify message is sent to the client and the data server is
1161 * placed into the halted state.
1164 * session (input) - session pointer.
1165 * reason (input) - halt reason.
1171 ndmpd_data_error(ndmpd_session_t
*session
, ndmp_data_halt_reason reason
)
1173 if (session
->ns_data
.dd_state
== NDMP_DATA_STATE_IDLE
||
1174 session
->ns_data
.dd_state
== NDMP_DATA_STATE_HALTED
)
1177 if (session
->ns_data
.dd_operation
== NDMP_DATA_OP_BACKUP
) {
1179 * Send/discard any buffered file history data.
1181 ndmpd_file_history_cleanup(session
,
1182 (reason
== NDMP_DATA_HALT_SUCCESSFUL
? TRUE
: FALSE
));
1185 * If mover local and successful backup, write any
1186 * remaining buffered data to tape.
1188 if (session
->ns_data
.dd_data_addr
.addr_type
1189 == NDMP_ADDR_LOCAL
&& reason
== NDMP_DATA_HALT_SUCCESSFUL
)
1190 (void) ndmpd_local_write_v3(session
, 0, 0);
1193 session
->ns_data
.dd_state
= NDMP_DATA_STATE_HALTED
;
1194 session
->ns_data
.dd_halt_reason
= reason
;
1196 if (session
->ns_protocol_version
== NDMPV4
) {
1197 if (ndmpd_data_error_send_v4(session
, reason
) < 0)
1199 "Error sending notify_data_halted request");
1201 if (ndmpd_data_error_send(session
, reason
) < 0)
1203 "Error sending notify_data_halted request");
1206 if (session
->ns_data
.dd_data_addr
.addr_type
== NDMP_ADDR_TCP
) {
1207 if (session
->ns_data
.dd_sock
!= -1) {
1208 (void) ndmpd_remove_file_handler(session
,
1209 session
->ns_data
.dd_sock
);
1211 * ndmpcopy: we use the same socket for the mover,
1212 * so expect to close when mover is done!
1214 if (session
->ns_data
.dd_sock
!=
1215 session
->ns_mover
.md_sock
)
1216 (void) close(session
->ns_data
.dd_sock
);
1218 session
->ns_data
.dd_sock
= -1;
1220 if (session
->ns_data
.dd_listen_sock
!= -1) {
1221 (void) ndmpd_remove_file_handler(session
,
1222 session
->ns_data
.dd_listen_sock
);
1224 (void) close(session
->ns_data
.dd_listen_sock
);
1225 session
->ns_data
.dd_listen_sock
= -1;
1228 ndmpd_mover_error(session
, NDMP_MOVER_HALT_CONNECT_CLOSED
);
1234 * data_accept_connection_v3
1236 * Accept a data connection from a remote mover.
1237 * Called by ndmpd_select when a connection is pending on
1238 * the data listen socket.
1241 * cookie (input) - session pointer.
1242 * fd (input) - file descriptor.
1243 * mode (input) - select mode.
1250 data_accept_connection_v3(void *cookie
, int fd
, ulong_t mode
)
1252 ndmpd_session_t
*session
= (ndmpd_session_t
*)cookie
;
1254 struct sockaddr_in from
;
1256 from_len
= sizeof (from
);
1257 session
->ns_data
.dd_sock
= accept(fd
, (struct sockaddr
*)&from
,
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
)));
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;
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
);
1277 * Save the peer address.
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
);
1282 /* Set the parameter of the new socket */
1283 set_socket_options(session
->ns_data
.dd_sock
);
1285 session
->ns_data
.dd_state
= NDMP_DATA_STATE_CONNECTED
;
1290 * create_listen_socket_v3
1292 * Creates the data sockets for listening for a remote mover/data
1293 * incoming connections.
1296 create_listen_socket_v3(ndmpd_session_t
*session
, ulong_t
*addr
, ushort_t
*port
)
1298 session
->ns_data
.dd_listen_sock
= ndmp_create_socket(addr
, port
);
1299 if (session
->ns_data
.dd_listen_sock
< 0)
1303 * Add a file handler for the listen socket.
1304 * ndmpd_select will call data_accept_connection when a
1305 * connection is ready to be accepted.
1307 if (ndmpd_add_file_handler(session
, (void*)session
,
1308 session
->ns_data
.dd_listen_sock
, NDMPD_SELECT_MODE_READ
, HC_MOVER
,
1309 data_accept_connection_v3
) < 0) {
1310 (void) close(session
->ns_data
.dd_listen_sock
);
1311 session
->ns_data
.dd_listen_sock
= -1;
1314 NDMP_LOG(LOG_DEBUG
, "addr: %s:%d",
1315 inet_ntoa(IN_ADDR(*addr
)), ntohs(*port
));
1322 * data_connect_sock_v3
1324 * Connect the data interface socket to the specified ip/port
1327 * session (input) - session pointer.
1328 * addr (input) - IP address
1329 * port (input) - port number
1332 * NDMP_NO_ERR - backup successfully started.
1333 * otherwise - error code of backup start error.
1336 data_connect_sock_v3(ndmpd_session_t
*session
, ulong_t addr
, ushort_t port
)
1340 sock
= ndmp_connect_sock_v3(addr
, port
);
1342 return (NDMP_CONNECT_ERR
);
1344 session
->ns_data
.dd_sock
= sock
;
1345 session
->ns_data
.dd_data_addr
.addr_type
= NDMP_ADDR_TCP
;
1346 session
->ns_data
.dd_data_addr
.tcp_ip_v3
= ntohl(addr
);
1347 session
->ns_data
.dd_data_addr
.tcp_port_v3
= port
;
1349 return (NDMP_NO_ERR
);
1354 * ndmpd_tar_start_backup_v3
1356 * Start the backup work
1359 * session (input) - session pointer.
1360 * bu_type (input) - backup type.
1361 * env_val (input) - environment variable array.
1362 * env_len (input) - length of env_val.
1365 * NDMP_NO_ERR - backup successfully started.
1366 * otherwise - error code of backup start error.
1369 ndmpd_tar_start_backup_v3(ndmpd_session_t
*session
, char *bu_type
,
1370 ndmp_pval
*env_val
, ulong_t env_len
)
1373 ndmp_lbr_params_t
*nlp
;
1374 ndmpd_module_params_t
*params
;
1375 ndmp_data_start_backup_reply_v3 reply
;
1377 (void) memset((void*)&reply
, 0, sizeof (reply
));
1379 err
= ndmpd_save_env(session
, env_val
, env_len
);
1380 if (err
!= NDMP_NO_ERR
)
1383 nlp
= ndmp_get_nlp(session
);
1384 NDMP_FREE(nlp
->nlp_params
);
1385 params
= nlp
->nlp_params
= ndmp_malloc(sizeof (ndmpd_module_params_t
));
1387 return (NDMP_NO_MEM_ERR
);
1389 params
->mp_daemon_cookie
= (void *)session
;
1390 params
->mp_module_cookie
= &session
->ns_data
.dd_module
.dm_module_cookie
;
1391 params
->mp_protocol_version
= session
->ns_protocol_version
;
1392 params
->mp_operation
= NDMP_DATA_OP_BACKUP
;
1393 params
->mp_get_env_func
= ndmpd_api_get_env
;
1394 params
->mp_add_env_func
= ndmpd_api_add_env
;
1395 params
->mp_set_env_func
= ndmpd_api_set_env
;
1396 params
->mp_get_name_func
= 0;
1397 params
->mp_dispatch_func
= ndmpd_api_dispatch
;
1398 params
->mp_done_func
= ndmpd_api_done_v3
;
1399 if (session
->ns_protocol_version
== NDMPV4
)
1400 params
->mp_log_func_v3
= ndmpd_api_log_v4
;
1402 params
->mp_log_func_v3
= ndmpd_api_log_v3
;
1404 params
->mp_add_file_handler_func
= ndmpd_api_add_file_handler
;
1405 params
->mp_remove_file_handler_func
= ndmpd_api_remove_file_handler
;
1406 params
->mp_write_func
= ndmpd_api_write_v3
;
1407 params
->mp_read_func
= 0;
1408 params
->mp_file_recovered_func
= 0;
1409 params
->mp_stats
= &session
->ns_data
.dd_module
.dm_stats
;
1410 session
->ns_data
.dd_module
.dm_module_cookie
= 0;
1412 if (strcmp(bu_type
, NDMP_DUMP_TYPE
) == 0) {
1413 NLP_SET(nlp
, NLPF_DUMP
);
1414 params
->mp_file_history_path_func
= 0;
1415 params
->mp_file_history_dir_func
=
1416 ndmpd_api_file_history_dir_v3
;
1417 params
->mp_file_history_node_func
=
1418 ndmpd_api_file_history_node_v3
;
1419 } else if (strcmp(bu_type
, NDMP_TAR_TYPE
) == 0) {
1420 NLP_SET(nlp
, NLPF_TAR
);
1421 params
->mp_file_history_path_func
=
1422 ndmpd_api_file_history_file_v3
;
1423 params
->mp_file_history_dir_func
= 0;
1424 params
->mp_file_history_node_func
= 0;
1426 NLP_UNSET(nlp
, NLPF_DUMP
);
1427 NLP_UNSET(nlp
, NLPF_TAR
);
1430 session
->ns_data
.dd_module
.dm_start_func
= ndmpd_tar_backup_starter_v3
;
1431 session
->ns_data
.dd_module
.dm_abort_func
= ndmpd_tar_backup_abort_v3
;
1433 session
->ns_data
.dd_module
.dm_stats
.ms_est_bytes_remaining
= 0;
1434 session
->ns_data
.dd_module
.dm_stats
.ms_est_time_remaining
= 0;
1435 session
->ns_data
.dd_nlist_v3
= 0;
1436 session
->ns_data
.dd_nlist_len
= 0;
1437 session
->ns_data
.dd_bytes_left_to_read
= 0;
1438 session
->ns_data
.dd_position
= 0;
1439 session
->ns_data
.dd_discard_length
= 0;
1440 session
->ns_data
.dd_read_offset
= 0;
1441 session
->ns_data
.dd_read_length
= 0;
1443 reply
.error
= ndmp_backup_get_params_v3(session
, params
);
1444 if (reply
.error
!= NDMP_NO_ERR
) {
1445 NDMP_LOG(LOG_DEBUG
, "err: %d", err
);
1446 NDMP_FREE(nlp
->nlp_params
);
1447 return (reply
.error
);
1450 reply
.error
= NDMP_NO_ERR
;
1451 if (ndmp_send_response(session
->ns_connection
, NDMP_NO_ERR
,
1453 NDMP_LOG(LOG_DEBUG
, "Sending data_start_backup_v3 reply");
1454 return (NDMP_NO_ERR
);
1458 session
->ns_data
.dd_state
= NDMP_DATA_STATE_ACTIVE
;
1459 session
->ns_data
.dd_operation
= NDMP_DATA_OP_BACKUP
;
1460 session
->ns_data
.dd_abort
= FALSE
;
1463 * perform the backup
1465 * Cannot wait for the thread to exit as we are replying to the
1466 * client request here.
1468 err
= pthread_create(NULL
, NULL
,
1469 (funct_t
)session
->ns_data
.dd_module
.dm_start_func
,
1472 NDMP_LOG(LOG_ERR
, "Can't start backup session.");
1473 return (NDMP_ILLEGAL_ARGS_ERR
);
1476 return (NDMP_NO_ERR
);
1480 * ndmpd_tar_start_recover_v3
1482 * Start the restore work
1485 * session (input) - session pointer.
1486 * bu_type (input) - backup type.
1487 * env_val (input) - environment variable array.
1488 * env_len (input) - length of env_val.
1489 * nlist_val (input) - list of files.
1490 * nlist_len (input) - length of nlist_val.
1493 * NDMP_NO_ERR - recover successfully started.
1494 * otherwise - error code of recover start error.
1497 ndmpd_tar_start_recover_v3(ndmpd_session_t
*session
,
1498 ndmp_pval
*env_val
, ulong_t env_len
, ndmp_name_v3
*nlist_val
,
1501 ndmp_data_start_recover_reply_v3 reply
;
1502 ndmpd_module_params_t
*params
;
1503 ndmp_lbr_params_t
*nlp
;
1506 (void) memset((void*)&reply
, 0, sizeof (reply
));
1508 nlp
= ndmp_get_nlp(session
);
1509 NDMP_FREE(nlp
->nlp_params
);
1510 params
= nlp
->nlp_params
= ndmp_malloc(sizeof (ndmpd_module_params_t
));
1512 return (NDMP_NO_MEM_ERR
);
1515 reply
.error
= ndmpd_save_env(session
, env_val
, env_len
);
1516 if (reply
.error
!= NDMP_NO_ERR
) {
1517 NDMP_FREE(nlp
->nlp_params
);
1518 return (NDMP_NO_MEM_ERR
);
1521 reply
.error
= ndmpd_save_nlist_v3(session
, nlist_val
, nlist_len
);
1522 if (reply
.error
!= NDMP_NO_ERR
) {
1523 NDMP_FREE(nlp
->nlp_params
);
1524 return (NDMP_NO_MEM_ERR
);
1528 * Setup restore parameters.
1530 params
->mp_daemon_cookie
= (void *)session
;
1531 params
->mp_module_cookie
= &session
->ns_data
.dd_module
.dm_module_cookie
;
1532 params
->mp_protocol_version
= session
->ns_protocol_version
;
1533 params
->mp_operation
= NDMP_DATA_OP_RECOVER
;
1534 params
->mp_get_env_func
= ndmpd_api_get_env
;
1535 params
->mp_add_env_func
= ndmpd_api_add_env
;
1536 params
->mp_set_env_func
= ndmpd_api_set_env
;
1537 params
->mp_get_name_func
= ndmpd_api_get_name_v3
;
1538 params
->mp_dispatch_func
= ndmpd_api_dispatch
;
1539 params
->mp_done_func
= ndmpd_api_done_v3
;
1540 if (session
->ns_protocol_version
== NDMPV4
) {
1541 params
->mp_log_func_v3
= ndmpd_api_log_v4
;
1542 params
->mp_file_recovered_func
= ndmpd_api_file_recovered_v4
;
1544 params
->mp_log_func_v3
= ndmpd_api_log_v3
;
1545 params
->mp_file_recovered_func
= ndmpd_api_file_recovered_v3
;
1548 params
->mp_add_file_handler_func
= ndmpd_api_add_file_handler
;
1549 params
->mp_remove_file_handler_func
= ndmpd_api_remove_file_handler
;
1550 params
->mp_write_func
= 0;
1551 params
->mp_file_history_path_func
= 0;
1552 params
->mp_file_history_dir_func
= 0;
1553 params
->mp_file_history_node_func
= 0;
1554 params
->mp_read_func
= ndmpd_api_read_v3
;
1555 params
->mp_seek_func
= ndmpd_api_seek_v3
;
1556 params
->mp_stats
= &session
->ns_data
.dd_module
.dm_stats
;
1558 session
->ns_data
.dd_module
.dm_module_cookie
= 0;
1559 session
->ns_data
.dd_module
.dm_start_func
= ndmpd_tar_restore_starter_v3
;
1560 session
->ns_data
.dd_module
.dm_abort_func
= ndmpd_tar_restore_abort_v3
;
1561 session
->ns_data
.dd_module
.dm_stats
.ms_est_bytes_remaining
= 0;
1562 session
->ns_data
.dd_module
.dm_stats
.ms_est_time_remaining
= 0;
1563 session
->ns_data
.dd_bytes_left_to_read
= 0;
1564 session
->ns_data
.dd_position
= 0;
1565 session
->ns_data
.dd_discard_length
= 0;
1566 session
->ns_data
.dd_read_offset
= 0;
1567 session
->ns_data
.dd_read_length
= 0;
1569 err
= ndmp_restore_get_params_v3(session
, params
);
1570 if (err
!= NDMP_NO_ERR
) {
1571 NDMP_FREE(nlp
->nlp_params
);
1575 reply
.error
= NDMP_NO_ERR
;
1576 if (ndmp_send_response(session
->ns_connection
, NDMP_NO_ERR
,
1578 NDMP_FREE(nlp
->nlp_params
);
1579 ndmpd_free_nlist_v3(session
);
1581 "Error sending ndmp_data_start_recover_reply");
1582 ndmpd_data_error(session
, NDMP_DATA_HALT_CONNECT_ERROR
);
1583 return (NDMP_NO_ERR
);
1587 session
->ns_data
.dd_state
= NDMP_DATA_STATE_ACTIVE
;
1588 session
->ns_data
.dd_operation
= NDMP_DATA_OP_RECOVER
;
1589 session
->ns_data
.dd_abort
= FALSE
;
1592 * perform the restore
1594 * Cannot wait for the thread to exit as we are replying to the
1595 * client request here.
1597 err
= pthread_create(NULL
, NULL
,
1598 (funct_t
)session
->ns_data
.dd_module
.dm_start_func
,
1602 NDMP_LOG(LOG_ERR
, "Can't start recover session.");
1603 return (NDMP_ILLEGAL_ARGS_ERR
);
1605 return (NDMP_NO_ERR
);
1609 ndmpd_zfs_start_op(ndmpd_session_t
*session
, ndmp_pval
*env_val
,
1610 ulong_t env_len
, ndmp_name_v3
*nlist_val
, ulong_t nlist_len
,
1611 enum ndmp_data_operation op
)
1613 ndmpd_zfs_args_t
*ndmpd_zfs_args
= &session
->ns_ndmpd_zfs_args
;
1614 ndmp_data_start_backup_reply_v3 backup_reply
;
1615 ndmp_data_start_recover_reply_v3 recover_reply
;
1621 if (ndmpd_zfs_init(session
) != 0)
1622 return (NDMP_UNDEFINED_ERR
);
1624 err
= ndmpd_save_env(session
, env_val
, env_len
);
1625 if (err
!= NDMP_NO_ERR
) {
1626 ndmpd_zfs_fini(ndmpd_zfs_args
);
1631 case NDMP_DATA_OP_BACKUP
:
1632 if (!ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args
)) {
1633 ndmpd_zfs_fini(ndmpd_zfs_args
);
1634 return (NDMP_ILLEGAL_ARGS_ERR
);
1637 if (ndmpd_zfs_pre_backup(ndmpd_zfs_args
)) {
1638 NDMP_LOG(LOG_ERR
, "pre_backup error");
1639 return (NDMP_ILLEGAL_ARGS_ERR
);
1642 session
->ns_data
.dd_module
.dm_start_func
=
1643 ndmpd_zfs_backup_starter
;
1644 (void) strlcpy(str
, "backup", 8);
1646 case NDMP_DATA_OP_RECOVER
:
1647 err
= ndmpd_save_nlist_v3(session
, nlist_val
, nlist_len
);
1648 if (err
!= NDMP_NO_ERR
) {
1649 ndmpd_zfs_fini(ndmpd_zfs_args
);
1650 return (NDMP_NO_MEM_ERR
);
1653 if (!ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args
)) {
1654 ndmpd_zfs_fini(ndmpd_zfs_args
);
1655 return (NDMP_ILLEGAL_ARGS_ERR
);
1658 if (ndmpd_zfs_pre_restore(ndmpd_zfs_args
)) {
1659 NDMP_LOG(LOG_ERR
, "pre_restore error");
1660 (void) ndmpd_zfs_post_restore(ndmpd_zfs_args
);
1661 return (NDMP_ILLEGAL_ARGS_ERR
);
1663 session
->ns_data
.dd_module
.dm_start_func
=
1664 ndmpd_zfs_restore_starter
;
1665 (void) strlcpy(str
, "recover", 8);
1669 ndmpd_zfs_params
->mp_operation
= op
;
1670 session
->ns_data
.dd_operation
= op
;
1671 session
->ns_data
.dd_module
.dm_abort_func
= ndmpd_zfs_abort
;
1672 session
->ns_data
.dd_state
= NDMP_DATA_STATE_ACTIVE
;
1673 session
->ns_data
.dd_abort
= FALSE
;
1675 if (op
== NDMP_DATA_OP_BACKUP
) {
1676 (void) memset((void*)&backup_reply
, 0, sizeof (backup_reply
));
1677 backup_reply
.error
= NDMP_NO_ERR
;
1678 reply
= &backup_reply
;
1680 (void) memset((void*)&recover_reply
, 0, sizeof (recover_reply
));
1681 recover_reply
.error
= NDMP_NO_ERR
;
1682 reply
= &recover_reply
;
1685 if (ndmp_send_response(session
->ns_connection
, NDMP_NO_ERR
,
1687 NDMP_LOG(LOG_DEBUG
, "Sending data_start_%s_v3 reply", str
);
1688 if (op
== NDMP_DATA_OP_RECOVER
)
1689 ndmpd_data_error(session
, NDMP_DATA_HALT_CONNECT_ERROR
);
1690 ndmpd_zfs_fini(ndmpd_zfs_args
);
1691 return (NDMP_NO_ERR
);
1694 err
= pthread_create(&tid
, NULL
,
1695 (funct_t
)session
->ns_data
.dd_module
.dm_start_func
, ndmpd_zfs_args
);
1698 NDMP_LOG(LOG_ERR
, "Can't start %s session (errno %d)",
1700 ndmpd_zfs_fini(ndmpd_zfs_args
);
1701 MOD_DONE(ndmpd_zfs_params
, -1);
1702 return (NDMP_NO_ERR
);
1705 (void) pthread_detach(tid
);
1707 if (op
== NDMP_DATA_OP_BACKUP
)
1712 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_NORMAL
,
1713 "'zfs' %s starting\n", str
);
1715 return (NDMP_NO_ERR
);
1721 * Read and discard data from the data connection.
1722 * Called when a module has called ndmpd_seek() prior to
1723 * reading all of the data from the previous seek.
1726 * session (input) - session pointer.
1729 * number of bytes read and discarded.
1733 discard_data_v3(ndmpd_session_t
*session
, ulong_t length
)
1735 static char buf
[MAX_RECORD_SIZE
];
1738 toread
= (length
< MAX_RECORD_SIZE
) ? length
:
1741 /* Read and discard the data. */
1742 n
= read(session
->ns_data
.dd_sock
, buf
, toread
);
1744 NDMP_LOG(LOG_ERR
, "Socket read error: %m.");
1753 * ndmpd_remote_read_v3
1755 * Reads data from the remote mover.
1758 * session (input) - session pointer.
1759 * data (input) - data to be written.
1760 * length (input) - data length.
1763 * 0 - data successfully read.
1767 ndmpd_remote_read_v3(ndmpd_session_t
*session
, char *data
, ulong_t length
)
1772 ndmp_notify_data_read_request request
;
1773 tlm_job_stats_t
*jstat
;
1776 NDMP_LOG(LOG_DEBUG
, "ns_data.dd_xx: [%llu, %llu, %llu, %llu, %llu]",
1777 session
->ns_data
.dd_bytes_left_to_read
,
1778 session
->ns_data
.dd_read_offset
,
1779 session
->ns_data
.dd_read_length
,
1780 session
->ns_data
.dd_position
,
1781 session
->ns_data
.dd_discard_length
);
1784 while (count
< length
) {
1785 len
= length
- count
;
1788 * If the end of the seek window has been reached then
1789 * send an ndmp_read request to the client.
1790 * The NDMP client will then send a mover_data_read request to
1791 * the remote mover and the mover will send more data.
1792 * This condition can occur if the module attempts to read past
1793 * a seek window set via a prior call to ndmpd_seek() or
1794 * the module has not issued a seek. If no seek was issued then
1795 * pretend that a seek was issued to read the entire tape.
1797 if (session
->ns_data
.dd_bytes_left_to_read
== 0) {
1798 /* ndmpd_seek() never called? */
1799 if (session
->ns_data
.dd_read_length
== 0) {
1800 session
->ns_data
.dd_bytes_left_to_read
= ~0LL;
1801 session
->ns_data
.dd_read_offset
= 0LL;
1802 session
->ns_data
.dd_read_length
= ~0LL;
1805 * While restoring a file, restoreFile()
1806 * records the number of bytes still need to
1807 * be restored. We use this as a guidance
1808 * when asking for data from the tape.
1810 jstat
= session
->ns_ndmp_lbr_params
->nlp_jstat
;
1811 fsize
= jstat
->js_bytes_in_file
;
1813 NDMP_LOG(LOG_DEBUG
, "bytes_left [%llu / %u]",
1817 * Fall back to the old way if fsize if too
1823 session
->ns_data
.dd_bytes_left_to_read
= fsize
;
1824 session
->ns_data
.dd_read_offset
=
1825 session
->ns_data
.dd_position
;
1826 session
->ns_data
.dd_read_length
= fsize
;
1830 long_long_to_quad(session
->ns_data
.dd_read_offset
);
1832 long_long_to_quad(session
->ns_data
.dd_read_length
);
1834 NDMP_LOG(LOG_DEBUG
, "to NOTIFY_DATA_READ [%llu, %llu]",
1835 session
->ns_data
.dd_read_offset
,
1836 session
->ns_data
.dd_read_length
);
1838 if (ndmp_send_request_lock(session
->ns_connection
,
1839 NDMP_NOTIFY_DATA_READ
, NDMP_NO_ERR
,
1842 "Sending notify_data_read request");
1848 * If the module called ndmpd_seek() prior to reading all of the
1849 * data that the remote mover was requested to send, then the
1850 * excess data from the seek has to be discarded.
1852 if (session
->ns_data
.dd_discard_length
!= 0) {
1853 n
= discard_data_v3(session
,
1854 (ulong_t
)session
->ns_data
.dd_discard_length
);
1858 session
->ns_data
.dd_discard_length
-= n
;
1863 * Don't attempt to read more data than the remote is sending.
1865 if (len
> session
->ns_data
.dd_bytes_left_to_read
)
1866 len
= session
->ns_data
.dd_bytes_left_to_read
;
1868 if ((n
= read(session
->ns_data
.dd_sock
, &data
[count
],
1870 NDMP_LOG(LOG_ERR
, "Socket read error: %m.");
1874 /* read returns 0 if the connection was closed */
1876 NDMP_LOG(LOG_DEBUG
, "n 0 errno %d",
1882 session
->ns_data
.dd_bytes_left_to_read
-= n
;
1883 session
->ns_data
.dd_position
+= n
;
1889 * nlp_release_job_stat
1891 * Unreference the job statistics
1894 * session (input) - session pointer.
1900 nlp_release_job_stat(ndmpd_session_t
*session
)
1902 ndmp_lbr_params_t
*nlp
;
1904 if ((nlp
= ndmp_get_nlp(session
)) == NULL
) {
1905 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
1908 if (nlp
->nlp_jstat
!= NULL
) {
1909 nlp
->nlp_bytes_total
=
1910 (u_longlong_t
)nlp
->nlp_jstat
->js_bytes_total
;
1911 tlm_un_ref_job_stats(nlp
->nlp_jstat
->js_job_name
);
1912 nlp
->nlp_jstat
= NULL
;
1914 NDMP_LOG(LOG_DEBUG
, "JSTAT == NULL");
1918 /* *** ndmpd global internal functions *********************************** */
1923 * Initializes data specific session variables.
1926 * session (input) - session pointer.
1932 ndmpd_data_init(ndmpd_session_t
*session
)
1934 session
->ns_data
.dd_operation
= NDMP_DATA_OP_NOACTION
;
1935 session
->ns_data
.dd_state
= NDMP_DATA_STATE_IDLE
;
1936 session
->ns_data
.dd_halt_reason
= NDMP_DATA_HALT_NA
;
1937 session
->ns_data
.dd_abort
= FALSE
;
1938 session
->ns_data
.dd_env
= 0;
1939 session
->ns_data
.dd_env_len
= 0;
1940 session
->ns_data
.dd_nlist
= 0;
1941 session
->ns_data
.dd_nlist_len
= 0;
1942 session
->ns_data
.dd_mover
.addr_type
= NDMP_ADDR_LOCAL
;
1943 session
->ns_data
.dd_sock
= -1;
1944 session
->ns_data
.dd_read_offset
= 0;
1945 session
->ns_data
.dd_read_length
= 0;
1946 session
->ns_data
.dd_module
.dm_stats
.ms_est_bytes_remaining
= 0;
1947 session
->ns_data
.dd_module
.dm_stats
.ms_est_time_remaining
= 0;
1951 session
->ns_data
.dd_state
= NDMP_DATA_STATE_IDLE
;
1952 session
->ns_data
.dd_nlist_v3
= 0;
1953 session
->ns_data
.dd_data_addr
.addr_type
= NDMP_ADDR_LOCAL
;
1954 session
->ns_data
.dd_listen_sock
= -1;
1955 session
->ns_data
.dd_bytes_left_to_read
= 0LL;
1956 session
->ns_data
.dd_position
= 0LL;
1957 session
->ns_data
.dd_discard_length
= 0LL;
1964 * ndmpd_data_cleanup
1966 * Releases resources allocated during a data operation.
1969 * session (input) - session pointer.
1975 ndmpd_data_cleanup(ndmpd_session_t
*session
)
1977 if (session
->ns_data
.dd_listen_sock
!= -1) {
1978 NDMP_LOG(LOG_DEBUG
, "data.listen_sock: %d",
1979 session
->ns_data
.dd_listen_sock
);
1980 (void) ndmpd_remove_file_handler(session
,
1981 session
->ns_data
.dd_listen_sock
);
1982 (void) close(session
->ns_data
.dd_listen_sock
);
1983 session
->ns_data
.dd_listen_sock
= -1;
1985 if (session
->ns_data
.dd_sock
!= -1) {
1986 NDMP_LOG(LOG_DEBUG
, "data.sock: %d",
1987 session
->ns_data
.dd_sock
);
1990 * ndmpcopy: we use the same socket for the mover,
1991 * so expect to close when mover is done!
1993 if (session
->ns_data
.dd_sock
!= session
->ns_mover
.md_sock
)
1994 (void) close(session
->ns_data
.dd_sock
);
1996 session
->ns_data
.dd_sock
= -1;
1999 ndmpd_free_env(session
);
2000 ndmpd_free_nlist(session
);
2005 * ndmp_data_get_mover_mode
2007 * Return the mover mode
2010 * session (input) - session pointer.
2013 * remote - remote backup
2014 * local - local backup
2017 ndmp_data_get_mover_mode(ndmpd_session_t
*session
)
2021 switch (session
->ns_protocol_version
) {
2023 rv
= ((session
->ns_data
.dd_mover
.addr_type
== NDMP_ADDR_TCP
)
2024 ? "remote" : "local");
2027 rv
= ((session
->ns_data
.dd_data_addr
.addr_type
== NDMP_ADDR_TCP
)
2028 ? "remote" : "local");
2031 rv
= ((session
->ns_data
.dd_data_addr
.addr_type
==
2033 (session
->ns_data
.dd_data_addr_v4
.addr_type
==
2034 NDMP_ADDR_TCP
)) ? "remote" : "local");
2038 NDMP_LOG(LOG_ERR
, "Invalid protocol version %d.",
2039 session
->ns_protocol_version
);
2045 /* *** static functions ******************************************** */
2048 * ndmpd_tar_start_backup_v2
2050 * Request handling code common to version 1 and
2051 * version 2 data_start_backup request handlers.
2054 * session (input) - session pointer.
2055 * bu_type (input) - backup type.
2056 * env_val (input) - environment variable array.
2057 * env_len (input) - length of env_val.
2060 * NDMP_NO_ERR - backup successfully started.
2061 * otherwise - error code of backup start error.
2064 ndmpd_tar_start_backup_v2(ndmpd_session_t
*session
, char *bu_type
,
2065 ndmp_pval
*env_val
, ulong_t env_len
)
2067 ndmp_data_start_backup_reply reply
;
2068 ndmpd_module_params_t
*params
;
2069 ndmp_lbr_params_t
*nlp
;
2072 if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_IDLE
) {
2073 NDMP_LOG(LOG_ERR
, "Can't start new backup in current state.");
2074 return (NDMP_ILLEGAL_STATE_ERR
);
2076 if (strcmp(bu_type
, NDMP_DUMP_TYPE
) != 0 &&
2077 strcmp(bu_type
, NDMP_TAR_TYPE
) != 0) {
2078 NDMP_LOG(LOG_ERR
, "Invalid backup type: %s.", bu_type
);
2079 NDMP_LOG(LOG_ERR
, "Supported backup types are tar and dump.");
2080 return (NDMP_ILLEGAL_ARGS_ERR
);
2082 if ((err
= ndmpd_save_env(session
, env_val
, env_len
)) != NDMP_NO_ERR
)
2085 nlp
= ndmp_get_nlp(session
);
2086 NDMP_FREE(nlp
->nlp_params
);
2087 params
= nlp
->nlp_params
= ndmp_malloc(sizeof (ndmpd_module_params_t
));
2089 return (NDMP_NO_MEM_ERR
);
2091 params
->mp_daemon_cookie
= (void *)session
;
2092 params
->mp_module_cookie
= &session
->ns_data
.dd_module
.dm_module_cookie
;
2093 params
->mp_protocol_version
= session
->ns_protocol_version
;
2094 params
->mp_operation
= NDMP_DATA_OP_BACKUP
;
2095 params
->mp_get_env_func
= ndmpd_api_get_env
;
2096 params
->mp_add_env_func
= ndmpd_api_add_env
;
2097 params
->mp_get_name_func
= ndmpd_api_get_name
;
2098 params
->mp_dispatch_func
= ndmpd_api_dispatch
;
2099 params
->mp_done_func
= ndmpd_api_done_v2
;
2100 params
->mp_log_func
= ndmpd_api_log_v2
;
2101 params
->mp_add_file_handler_func
= ndmpd_api_add_file_handler
;
2102 params
->mp_remove_file_handler_func
= ndmpd_api_remove_file_handler
;
2103 params
->mp_write_func
= ndmpd_api_write_v2
;
2104 params
->mp_read_func
= 0;
2105 params
->mp_file_recovered_func
= 0;
2106 params
->mp_stats
= &session
->ns_data
.dd_module
.dm_stats
;
2108 session
->ns_data
.dd_module
.dm_module_cookie
= 0;
2109 if (strcmp(bu_type
, NDMP_DUMP_TYPE
) == 0) {
2110 NLP_SET(nlp
, NLPF_DUMP
);
2111 params
->mp_file_history_path_func
= 0;
2112 params
->mp_file_history_dir_func
=
2113 ndmpd_api_file_history_dir_v2
;
2114 params
->mp_file_history_node_func
=
2115 ndmpd_api_file_history_node_v2
;
2116 } else if (strcmp(bu_type
, NDMP_TAR_TYPE
) == 0) {
2117 /* backup type == NDMP_TAR_TYPE */
2118 NLP_SET(nlp
, NLPF_TAR
);
2119 params
->mp_file_history_path_func
=
2120 ndmpd_api_file_history_path_v2
;
2121 params
->mp_file_history_dir_func
= 0;
2122 params
->mp_file_history_node_func
= 0;
2124 NLP_UNSET(nlp
, NLPF_DUMP
);
2125 NLP_UNSET(nlp
, NLPF_TAR
);
2128 session
->ns_data
.dd_module
.dm_start_func
= ndmpd_tar_backup_starter
;
2129 session
->ns_data
.dd_module
.dm_abort_func
= ndmpd_tar_backup_abort
;
2131 session
->ns_data
.dd_module
.dm_stats
.ms_est_bytes_remaining
= 0;
2132 session
->ns_data
.dd_module
.dm_stats
.ms_est_time_remaining
= 0;
2133 session
->ns_data
.dd_nlist
= 0;
2134 session
->ns_data
.dd_nlist_len
= 0;
2135 session
->ns_data
.dd_read_offset
= 0;
2136 session
->ns_data
.dd_read_length
= 0;
2138 if ((err
= ndmp_backup_extract_params(session
,
2139 params
)) != NDMP_NO_ERR
) {
2140 NDMP_LOG(LOG_DEBUG
, "err: %d", err
);
2141 NDMP_FREE(nlp
->nlp_params
);
2145 err
= ndmpd_mover_connect(session
, NDMP_MOVER_MODE_READ
);
2146 if (err
!= NDMP_NO_ERR
) {
2148 "mover connect err: %d", err
);
2149 NDMP_FREE(nlp
->nlp_params
);
2153 session
->ns_data
.dd_state
= NDMP_DATA_STATE_ACTIVE
;
2155 session
->ns_data
.dd_operation
= NDMP_DATA_OP_BACKUP
;
2156 session
->ns_data
.dd_abort
= FALSE
;
2158 NDMP_LOG(LOG_DEBUG
, "starting backup");
2160 reply
.error
= NDMP_NO_ERR
;
2161 if (ndmp_send_response(session
->ns_connection
, NDMP_NO_ERR
,
2163 NDMP_LOG(LOG_DEBUG
, "Sending data_start_backup reply");
2164 NDMP_FREE(nlp
->nlp_params
);
2165 if (session
->ns_data
.dd_mover
.addr_type
== NDMP_ADDR_TCP
) {
2167 * ndmpcopy: we use the same socket for the mover,
2168 * so expect to close when mover is done!
2170 if (session
->ns_data
.dd_sock
!=
2171 session
->ns_mover
.md_sock
)
2172 (void) close(session
->ns_data
.dd_sock
);
2174 session
->ns_data
.dd_sock
= -1;
2176 ndmpd_mover_error(session
,
2177 NDMP_MOVER_HALT_CONNECT_CLOSED
);
2178 return (NDMP_NO_ERR
);
2182 * perform the backup
2184 * Cannot wait for the thread to exit as we are replying to the
2185 * client request here.
2187 (void) pthread_create(NULL
, NULL
,
2188 (funct_t
)session
->ns_data
.dd_module
.dm_start_func
,
2191 return (NDMP_NO_ERR
);
2195 * ndmpd_tar_start_recover_v2
2197 * The main recover/restore function
2200 * session (input) - session pointer.
2201 * bu_type (input) - backup type.
2202 * env_val (input) - environment variable array.
2203 * env_len (input) - length of env_val.
2204 * nlist_val (input) - list of files.
2205 * nlist_len (input) - length of nlist_val.
2208 * NDMP_NO_ERR - recover successfully started.
2209 * otherwise - error code of backup start error.
2212 ndmpd_tar_start_recover_v2(ndmpd_session_t
*session
, char *bu_type
,
2213 ndmp_pval
*env_val
, ulong_t env_len
, ndmp_name
*nlist_val
,
2216 ndmp_data_start_recover_reply_v2 reply
;
2217 ndmpd_module_params_t
*params
;
2218 ndmp_lbr_params_t
*nlp
;
2221 if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_IDLE
) {
2222 NDMP_LOG(LOG_ERR
, "Can't start new recover in current state.");
2223 return (NDMP_ILLEGAL_STATE_ERR
);
2226 if (strcmp(bu_type
, NDMP_DUMP_TYPE
) != 0 &&
2227 strcmp(bu_type
, NDMP_TAR_TYPE
) != 0) {
2228 NDMP_LOG(LOG_ERR
, "Invalid backup type: %s.", bu_type
);
2229 NDMP_LOG(LOG_ERR
, "Supported backup types are tar and dump.");
2230 return (NDMP_ILLEGAL_ARGS_ERR
);
2233 reply
.error
= ndmpd_save_env(session
, env_val
, env_len
);
2234 if (reply
.error
!= NDMP_NO_ERR
)
2235 return (NDMP_NO_MEM_ERR
);
2237 reply
.error
= ndmpd_save_nlist_v2(session
, nlist_val
, nlist_len
);
2238 if (reply
.error
!= NDMP_NO_ERR
)
2239 return (NDMP_NO_MEM_ERR
);
2241 nlp
= ndmp_get_nlp(session
);
2242 NDMP_FREE(nlp
->nlp_params
);
2243 params
= nlp
->nlp_params
= ndmp_malloc(sizeof (ndmpd_module_params_t
));
2245 return (NDMP_NO_MEM_ERR
);
2248 * Setup restore parameters.
2250 params
->mp_daemon_cookie
= (void *)session
;
2251 params
->mp_module_cookie
= &session
->ns_data
.dd_module
.dm_module_cookie
;
2252 params
->mp_protocol_version
= session
->ns_protocol_version
;
2253 params
->mp_operation
= NDMP_DATA_OP_RECOVER
;
2254 params
->mp_get_env_func
= ndmpd_api_get_env
;
2255 params
->mp_add_env_func
= ndmpd_api_add_env
;
2256 params
->mp_get_name_func
= ndmpd_api_get_name
;
2257 params
->mp_dispatch_func
= ndmpd_api_dispatch
;
2258 params
->mp_done_func
= ndmpd_api_done_v2
;
2259 params
->mp_log_func
= ndmpd_api_log_v2
;
2260 params
->mp_add_file_handler_func
= ndmpd_api_add_file_handler
;
2261 params
->mp_remove_file_handler_func
= ndmpd_api_remove_file_handler
;
2262 params
->mp_write_func
= 0;
2263 params
->mp_file_history_path_func
= 0;
2264 params
->mp_file_history_dir_func
= 0;
2265 params
->mp_file_history_node_func
= 0;
2266 params
->mp_read_func
= ndmpd_api_read_v2
;
2267 params
->mp_seek_func
= ndmpd_api_seek_v2
;
2268 params
->mp_file_recovered_func
= ndmpd_api_file_recovered_v2
;
2269 params
->mp_stats
= &session
->ns_data
.dd_module
.dm_stats
;
2271 session
->ns_data
.dd_module
.dm_module_cookie
= 0;
2272 session
->ns_data
.dd_module
.dm_start_func
= ndmpd_tar_restore_starter
;
2273 session
->ns_data
.dd_module
.dm_abort_func
= ndmpd_tar_restore_abort
;
2274 session
->ns_data
.dd_module
.dm_stats
.ms_est_bytes_remaining
= 0;
2275 session
->ns_data
.dd_module
.dm_stats
.ms_est_time_remaining
= 0;
2276 session
->ns_data
.dd_read_offset
= 0;
2277 session
->ns_data
.dd_read_length
= 0;
2279 if ((err
= ndmp_restore_extract_params(session
,
2280 params
)) != NDMP_NO_ERR
) {
2281 NDMP_FREE(nlp
->nlp_params
);
2285 err
= ndmpd_mover_connect(session
, NDMP_MOVER_MODE_WRITE
);
2286 if (err
!= NDMP_NO_ERR
) {
2287 NDMP_FREE(nlp
->nlp_params
);
2291 session
->ns_data
.dd_state
= NDMP_DATA_STATE_ACTIVE
;
2292 session
->ns_data
.dd_operation
= NDMP_DATA_OP_RECOVER
;
2293 session
->ns_data
.dd_abort
= FALSE
;
2295 reply
.error
= NDMP_NO_ERR
;
2296 if (ndmp_send_response(session
->ns_connection
, NDMP_NO_ERR
,
2298 NDMP_LOG(LOG_DEBUG
, "Sending data_start_recover reply");
2299 NDMP_FREE(nlp
->nlp_params
);
2300 if (session
->ns_data
.dd_mover
.addr_type
== NDMP_ADDR_TCP
) {
2302 * ndmpcopy: we use the same socket for the mover,
2303 * so expect to close when mover is done!
2305 if (session
->ns_data
.dd_sock
!=
2306 session
->ns_mover
.md_sock
)
2307 (void) close(session
->ns_data
.dd_sock
);
2309 session
->ns_data
.dd_sock
= -1;
2311 ndmpd_mover_error(session
,
2312 NDMP_MOVER_HALT_CONNECT_CLOSED
);
2314 return (NDMP_NO_ERR
);
2319 * perform the restore
2321 * Cannot wait for the thread to exit as we are replying to the
2322 * client request here.
2324 (void) pthread_create(NULL
, NULL
,
2325 (funct_t
)session
->ns_data
.dd_module
.dm_start_func
,
2328 return (NDMP_NO_ERR
);
2332 * ndmpd_data_get_info
2334 * Return the total number of bytes processed
2337 * session (input) - session pointer.
2340 * the number of bytes processed
2343 ndmpd_data_get_info(ndmpd_session_t
*session
)
2345 ndmp_lbr_params_t
*nlp
;
2347 nlp
= ndmp_get_nlp(session
);
2349 return ((u_longlong_t
)0);
2351 if (nlp
->nlp_jstat
== NULL
)
2352 return (nlp
->nlp_bytes_total
);
2354 return ((u_longlong_t
)nlp
->nlp_jstat
->js_bytes_total
);