2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
8 * Copyright (c) 2007, The Storage Networking Industry Association.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
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
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
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.
38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40 /* Copyright 2014 Nexenta Systems, Inc. All rights reserved. */
42 #include <sys/types.h>
53 #include <sys/queue.h>
54 #include <sys/socket.h>
55 #include <netinet/in.h>
56 #include <netinet/tcp.h>
57 #include <arpa/inet.h>
58 #include <sys/socketvar.h>
61 #include <sys/filio.h>
63 #include <sys/scsi/impl/uscsi.h>
64 #include <sys/scsi/scsi.h>
68 * Force to backup all the intermediate directories leading to an object
69 * to be backed up in 'dump' format backup.
71 boolean_t ndmp_dump_path_node
= FALSE
;
75 * Force to backup all the intermediate directories leading to an object
76 * to be backed up in 'tar' format backup.
78 boolean_t ndmp_tar_path_node
= FALSE
;
82 * Should the 'st_ctime' be ignored during incremental level backup?
84 boolean_t ndmp_ignore_ctime
= FALSE
;
87 * Should the 'st_lmtime' be included during incremental level backup?
89 boolean_t ndmp_include_lmtime
= FALSE
;
92 * Force to send the file history node entries along with the file history
93 * dir entries for all directories containing the changed files to the client
94 * for incremental backup.
96 * Note: This variable is added to support Bakbone Software's Netvault DMA
97 * which expects to get the FH ADD NODES for all upper directories which
98 * contain the changed files in incremental backup along with the FH ADD DIRS.
100 boolean_t ndmp_fhinode
= FALSE
;
103 * Maximum permitted sequence number in the token-based backup. The
104 * value of this variable can be changed by the administrator and is
105 * saved in the NDMP configuration file.
107 static int ndmp_max_tok_seq
= NDMP_MAX_TOKSEQ
;
110 * Force backup directories in incremental backups. If the
111 * directory is not modified itself, it's not backed up by
114 int ndmp_force_bk_dirs
= 0;
117 * Keeps track of the open SCSI (including tape and robot) devices.
118 * When a SCSI device is opened its name must be added to this list and
119 * when it's closed its name must be removed from this list. The main
120 * purpose of this list is the robot device. If the robot devices are not
121 * attached in SASD layer, Local Backup won't see them. If they are
122 * attached and we open the robot devices, then wrong commands are sent
123 * to robot by SASD since it assumes that the robot is a tape (sequential
127 LIST_ENTRY(open_list
) ol_q
;
133 ndmp_connection_t
*cl_conn
;
135 LIST_HEAD(ol_head
, open_list
);
139 * Head of the opened SCSI devices list.
141 static struct ol_head ol_head
;
143 mutex_t ol_mutex
= DEFAULTMUTEX
;
147 * List of things to be exluded from backup.
149 static char *exls
[] = {
152 NULL
, /* reserved for a copy of the "backup.directory" */
158 * The counter for creating unique names with "ndmp.%d" format.
160 #define NDMP_RCF_BASENAME "ndmp."
161 static int ndmp_job_cnt
= 0;
163 static int scsi_test_unit_ready(int dev_id
);
166 * ndmpd_add_file_handler
168 * Adds a file handler to the file handler list.
169 * The file handler list is used by ndmpd_api_dispatch.
172 * session (input) - session pointer.
173 * cookie (input) - opaque data to be passed to file hander when called.
174 * fd (input) - file descriptor.
175 * mode (input) - bitmask of the following:
176 * 1 = watch file for ready for reading
177 * 2 = watch file for ready for writing
178 * 4 = watch file for exception
179 * class (input) - handler class. (HC_CLIENT, HC_MOVER, HC_MODULE)
180 * func (input) - function to call when the file meets one of the
181 * conditions specified by mode.
188 ndmpd_add_file_handler(ndmpd_session_t
*session
, void *cookie
, int fd
,
189 ulong_t mode
, ulong_t
class, ndmpd_file_handler_func_t
*func
)
191 ndmpd_file_handler_t
*new;
193 new = ndmp_malloc(sizeof (ndmpd_file_handler_t
));
197 new->fh_cookie
= cookie
;
200 new->fh_class
= class;
202 new->fh_next
= session
->ns_file_handler_list
;
203 session
->ns_file_handler_list
= new;
209 * ndmpd_remove_file_handler
211 * Removes a file handler from the file handler list.
214 * session (input) - session pointer.
215 * fd (input) - file descriptor.
222 ndmpd_remove_file_handler(ndmpd_session_t
*session
, int fd
)
224 ndmpd_file_handler_t
**last
;
225 ndmpd_file_handler_t
*handler
;
227 last
= &session
->ns_file_handler_list
;
231 if (handler
->fh_fd
== fd
) {
232 *last
= handler
->fh_next
;
233 (void) free(handler
);
236 last
= &handler
->fh_next
;
244 * ndmp_connection_closed
246 * If the connection closed or not.
249 * fd (input) : file descriptor
252 * 0 - connection is still valid
253 * 1 - connection is not valid anymore
254 * -1 - Internal kernel error
257 ndmp_connection_closed(int fd
)
261 struct timeval timeout
;
263 if (fd
< 0) /* We are not using the mover */
267 timeout
.tv_usec
= 1000;
271 ret
= select(FD_SETSIZE
, &fds
, NULL
, NULL
, &timeout
);
273 closed
= (ret
== -1 && errno
== EBADF
);
279 * ndmp_check_mover_state
281 * Checks the mover connection status and sends an appropriate
282 * NDMP message to client based on that.
285 * ndmpd_session_t *session (input) : session pointer
291 ndmp_check_mover_state(ndmpd_session_t
*session
)
295 * NDMPV3 Spec (Three-way restore):
296 * Once all of the files have been recovered, NDMP DATA Server closes
297 * the connection to the mover on the NDMP TAPE Server. THEN
298 * The NDMP client should receive an NDMP_NOTIFY_MOVER_HALTED message
299 * with an NDMP_MOVER_CONNECT_CLOSED reason from the NDMP TAPE Server
301 moverfd
= session
->ns_mover
.md_sock
;
302 /* If connection is closed by the peer */
304 session
->ns_mover
.md_mode
== NDMP_MOVER_MODE_WRITE
) {
307 closed
= ndmp_connection_closed(moverfd
);
309 /* Connection closed or internal error */
312 "ndmp mover: connection closed by peer");
313 reason
= NDMP_MOVER_HALT_CONNECT_CLOSED
;
316 "ndmp mover: Internal error");
317 reason
= NDMP_MOVER_HALT_INTERNAL_ERROR
;
319 ndmpd_mover_error(session
, reason
);
329 * Calls select on the the set of file descriptors from the
330 * file handler list masked by the fd_class argument.
331 * Calls the file handler function for each
332 * file descriptor that is ready for I/O.
335 * session (input) - session pointer.
336 * block (input) - if TRUE, ndmpd_select waits until at least one
337 * file descriptor is ready for I/O. Otherwise,
338 * it returns immediately if no file descriptors are
340 * class_mask (input) - bit mask of handler classes to be examined.
341 * Provides for excluding some of the handlers from
346 * 0 - no handlers were called.
347 * 1 - at least one handler was called.
350 ndmpd_select(ndmpd_session_t
*session
, boolean_t block
, ulong_t class_mask
)
356 ndmpd_file_handler_t
*handler
;
357 struct timeval timeout
;
358 ndmp_lbr_params_t
*nlp
;
360 if (session
->ns_file_handler_list
== 0)
365 * If select should be blocked, then we poll every ten seconds.
366 * The reason is in case of three-way restore we should be able
367 * to detect if the other end closed the connection or not.
368 * NDMP client(DMA) does not send any information about the connection
369 * that was closed in the other end.
379 /* Create the fd_sets for select. */
384 for (handler
= session
->ns_file_handler_list
; handler
!= 0;
385 handler
= handler
->fh_next
) {
386 if ((handler
->fh_class
& class_mask
) == 0)
389 if (handler
->fh_mode
& NDMPD_SELECT_MODE_READ
)
390 FD_SET(handler
->fh_fd
, &rfds
);
391 if (handler
->fh_mode
& NDMPD_SELECT_MODE_WRITE
)
392 FD_SET(handler
->fh_fd
, &wfds
);
393 if (handler
->fh_mode
& NDMPD_SELECT_MODE_EXCEPTION
)
394 FD_SET(handler
->fh_fd
, &efds
);
396 ndmp_check_mover_state(session
);
397 n
= select(FD_SETSIZE
, &rfds
, &wfds
, &efds
, &timeout
);
398 } while (n
== 0 && block
== TRUE
);
401 int connection_fd
= ndmp_get_fd(session
->ns_connection
);
406 NDMP_LOG(LOG_DEBUG
, "Select error: %m");
408 nlp
= ndmp_get_nlp(session
);
409 (void) mutex_lock(&nlp
->nlp_mtx
);
410 for (handler
= session
->ns_file_handler_list
; handler
!= 0;
411 handler
= handler
->fh_next
) {
412 if ((handler
->fh_class
& class_mask
) == 0)
415 if (handler
->fh_mode
& NDMPD_SELECT_MODE_READ
) {
416 if (FD_ISSET(handler
->fh_fd
, &rfds
) &&
417 connection_fd
== handler
->fh_fd
)
418 session
->ns_eof
= TRUE
;
420 if (handler
->fh_mode
& NDMPD_SELECT_MODE_WRITE
) {
421 if (FD_ISSET(handler
->fh_fd
, &wfds
) &&
422 connection_fd
== handler
->fh_fd
)
423 session
->ns_eof
= TRUE
;
425 if (handler
->fh_mode
& NDMPD_SELECT_MODE_EXCEPTION
) {
426 if (FD_ISSET(handler
->fh_fd
, &efds
) &&
427 connection_fd
== handler
->fh_fd
)
428 session
->ns_eof
= TRUE
;
431 (void) cond_broadcast(&nlp
->nlp_cv
);
432 (void) mutex_unlock(&nlp
->nlp_mtx
);
438 handler
= session
->ns_file_handler_list
;
439 while (handler
!= 0) {
442 if ((handler
->fh_class
& class_mask
) == 0) {
443 handler
= handler
->fh_next
;
446 if (handler
->fh_mode
& NDMPD_SELECT_MODE_READ
) {
447 if (FD_ISSET(handler
->fh_fd
, &rfds
)) {
448 mode
|= NDMPD_SELECT_MODE_READ
;
449 FD_CLR(handler
->fh_fd
, &rfds
);
452 if (handler
->fh_mode
& NDMPD_SELECT_MODE_WRITE
) {
453 if (FD_ISSET(handler
->fh_fd
, &wfds
)) {
454 mode
|= NDMPD_SELECT_MODE_WRITE
;
455 FD_CLR(handler
->fh_fd
, &wfds
);
458 if (handler
->fh_mode
& NDMPD_SELECT_MODE_EXCEPTION
) {
459 if (FD_ISSET(handler
->fh_fd
, &efds
)) {
460 mode
|= NDMPD_SELECT_MODE_EXCEPTION
;
461 FD_CLR(handler
->fh_fd
, &efds
);
465 (*handler
->fh_func
) (handler
->fh_cookie
,
466 handler
->fh_fd
, mode
);
469 * K.L. The list can be modified during the execution
470 * of handler->fh_func. Therefore, handler will start
471 * from the beginning of the handler list after
474 handler
= session
->ns_file_handler_list
;
476 handler
= handler
->fh_next
;
487 * Saves a copy of the environment variable list from the data_start_backup
488 * request or data_start_recover request.
491 * session (input) - session pointer.
492 * env (input) - environment variable list to be saved.
493 * envlen (input) - length of variable array.
499 ndmpd_save_env(ndmpd_session_t
*session
, ndmp_pval
*env
, ulong_t envlen
)
505 session
->ns_data
.dd_env_len
= 0;
508 return (NDMP_NO_ERR
);
510 session
->ns_data
.dd_env
= ndmp_malloc(sizeof (ndmp_pval
) * envlen
);
511 if (session
->ns_data
.dd_env
== 0)
512 return (NDMP_NO_MEM_ERR
);
514 for (i
= 0; i
< envlen
; i
++) {
515 namebuf
= strdup(env
[i
].name
);
517 return (NDMP_NO_MEM_ERR
);
519 valbuf
= strdup(env
[i
].value
);
522 return (NDMP_NO_MEM_ERR
);
525 NDMP_LOG(LOG_DEBUG
, "env(%s): \"%s\"",
528 (void) mutex_lock(&session
->ns_lock
);
529 session
->ns_data
.dd_env
[i
].name
= namebuf
;
530 session
->ns_data
.dd_env
[i
].value
= valbuf
;
531 session
->ns_data
.dd_env_len
++;
532 (void) mutex_unlock(&session
->ns_lock
);
535 return (NDMP_NO_ERR
);
542 * Free the previously saved environment variable array.
545 * session - NDMP session pointer.
551 ndmpd_free_env(ndmpd_session_t
*session
)
554 int count
= session
->ns_data
.dd_env_len
;
556 (void) mutex_lock(&session
->ns_lock
);
557 session
->ns_data
.dd_env_len
= 0;
558 for (i
= 0; i
< count
; i
++) {
559 free(session
->ns_data
.dd_env
[i
].name
);
560 free(session
->ns_data
.dd_env
[i
].value
);
563 free((char *)session
->ns_data
.dd_env
);
564 session
->ns_data
.dd_env
= 0;
565 (void) mutex_unlock(&session
->ns_lock
);
570 * ndmpd_save_nlist_v2
572 * Save a copy of list of file names to be restored.
575 * nlist (input) - name list from data_start_recover request.
576 * nlistlen (input) - length of name list.
579 * array of file name pointers.
582 * free_nlist should be called to free the returned list.
583 * A null pointer indicates the end of the list.
586 ndmpd_save_nlist_v2(ndmpd_session_t
*session
, ndmp_name
*nlist
,
594 return (NDMP_NO_ERR
);
596 session
->ns_data
.dd_nlist_len
= 0;
597 session
->ns_data
.dd_nlist
= ndmp_malloc(sizeof (ndmp_name
)*nlistlen
);
598 if (session
->ns_data
.dd_nlist
== 0)
599 return (NDMP_NO_MEM_ERR
);
601 for (i
= 0; i
< nlistlen
; i
++) {
602 namebuf
= ndmp_malloc(strlen(nlist
[i
].name
) + 1);
604 return (NDMP_NO_MEM_ERR
);
606 destbuf
= ndmp_malloc(strlen(nlist
[i
].dest
) + 1);
609 return (NDMP_NO_MEM_ERR
);
611 (void) strlcpy(namebuf
, nlist
[i
].name
,
612 strlen(nlist
[i
].name
) + 1);
613 (void) strlcpy(destbuf
, nlist
[i
].dest
,
614 strlen(nlist
[i
].dest
) + 1);
616 session
->ns_data
.dd_nlist
[i
].name
= namebuf
;
617 session
->ns_data
.dd_nlist
[i
].dest
= destbuf
;
618 session
->ns_data
.dd_nlist
[i
].ssid
= nlist
[i
].ssid
;
619 session
->ns_data
.dd_nlist
[i
].fh_info
= nlist
[i
].fh_info
;
620 session
->ns_data
.dd_nlist_len
++;
623 return (NDMP_NO_ERR
);
628 * ndmpd_free_nlist_v2
630 * Free a list created by ndmpd_save_nlist_v2.
633 * session (input) - session pointer.
639 ndmpd_free_nlist_v2(ndmpd_session_t
*session
)
643 for (i
= 0; i
< session
->ns_data
.dd_nlist_len
; i
++) {
644 free(session
->ns_data
.dd_nlist
[i
].name
);
645 free(session
->ns_data
.dd_nlist
[i
].dest
);
648 if (session
->ns_data
.dd_nlist
!= NULL
)
649 free((char *)session
->ns_data
.dd_nlist
);
650 session
->ns_data
.dd_nlist
= 0;
651 session
->ns_data
.dd_nlist_len
= 0;
656 * ndmpd_free_nlist_v3
658 * Free a list created by ndmpd_save_nlist_v3.
661 * session (input) - session pointer.
667 ndmpd_free_nlist_v3(ndmpd_session_t
*session
)
670 mem_ndmp_name_v3_t
*tp
; /* destination entry */
672 tp
= session
->ns_data
.dd_nlist_v3
;
673 for (i
= 0; i
< session
->ns_data
.dd_nlist_len
; tp
++, i
++) {
674 NDMP_FREE(tp
->nm3_opath
);
675 NDMP_FREE(tp
->nm3_dpath
);
676 NDMP_FREE(tp
->nm3_newnm
);
679 NDMP_FREE(session
->ns_data
.dd_nlist_v3
);
680 session
->ns_data
.dd_nlist_len
= 0;
685 * ndmpd_save_nlist_v3
687 * Save a copy of list of file names to be restored.
690 * nlist (input) - name list from data_start_recover request.
691 * nlistlen (input) - length of name list.
694 * array of file name pointers.
697 * free_nlist should be called to free the returned list.
698 * A null pointer indicates the end of the list.
701 ndmpd_save_nlist_v3(ndmpd_session_t
*session
, ndmp_name_v3
*nlist
,
706 ndmp_name_v3
*sp
; /* source entry */
707 mem_ndmp_name_v3_t
*tp
; /* destination entry */
710 return (NDMP_ILLEGAL_ARGS_ERR
);
712 session
->ns_data
.dd_nlist_len
= 0;
713 tp
= session
->ns_data
.dd_nlist_v3
=
714 ndmp_malloc(sizeof (mem_ndmp_name_v3_t
) * nlistlen
);
715 if (session
->ns_data
.dd_nlist_v3
== 0)
716 return (NDMP_NO_MEM_ERR
);
720 for (i
= 0; i
< nlistlen
; tp
++, sp
++, i
++) {
721 tp
->nm3_opath
= strdup(sp
->original_path
);
722 if (!tp
->nm3_opath
) {
723 rv
= NDMP_NO_MEM_ERR
;
726 if (!*sp
->destination_dir
) {
727 tp
->nm3_dpath
= NULL
;
728 /* In V4 destination dir cannot be NULL */
729 if (session
->ns_protocol_version
== NDMPV4
) {
730 rv
= NDMP_ILLEGAL_ARGS_ERR
;
733 } else if (!(tp
->nm3_dpath
= strdup(sp
->destination_dir
))) {
734 rv
= NDMP_NO_MEM_ERR
;
738 tp
->nm3_newnm
= NULL
;
739 else if (!(tp
->nm3_newnm
= strdup(sp
->new_name
))) {
740 rv
= NDMP_NO_MEM_ERR
;
744 tp
->nm3_node
= quad_to_long_long(sp
->node
);
745 tp
->nm3_fh_info
= quad_to_long_long(sp
->fh_info
);
746 tp
->nm3_err
= NDMP_NO_ERR
;
747 session
->ns_data
.dd_nlist_len
++;
749 NDMP_LOG(LOG_DEBUG
, "orig \"%s\"", tp
->nm3_opath
);
750 NDMP_LOG(LOG_DEBUG
, "dest \"%s\"", NDMP_SVAL(tp
->nm3_dpath
));
751 NDMP_LOG(LOG_DEBUG
, "name \"%s\"", NDMP_SVAL(tp
->nm3_newnm
));
752 NDMP_LOG(LOG_DEBUG
, "node %lld", tp
->nm3_node
);
753 NDMP_LOG(LOG_DEBUG
, "fh_info %lld", tp
->nm3_fh_info
);
756 if (rv
!= NDMP_NO_ERR
)
757 ndmpd_free_nlist_v3(session
);
766 * Free the recovery list based on the version
769 * session (input) - session pointer.
775 ndmpd_free_nlist(ndmpd_session_t
*session
)
777 switch (session
->ns_protocol_version
) {
780 ndmpd_free_nlist_v2(session
);
784 ndmpd_free_nlist_v3(session
);
788 NDMP_LOG(LOG_DEBUG
, "Unknown version %d",
789 session
->ns_protocol_version
);
797 * Comparison function used in sorting the Nlist based on their
798 * file history info (offset of the entry on the tape)
801 * p (input) - pointer to P
802 * q (input) - pointer to Q
810 fh_cmpv3(const void *p
,
813 #define FH_INFOV3(p) (((mem_ndmp_name_v3_t *)p)->nm3_fh_info)
815 if (FH_INFOV3(p
) < FH_INFOV3(q
))
817 else if (FH_INFOV3(p
) == FH_INFOV3(q
))
829 * Sort the recovery list based on their offset on the tape
832 * session (input) - session pointer.
838 ndmp_sort_nlist_v3(ndmpd_session_t
*session
)
840 if (!session
|| session
->ns_data
.dd_nlist_len
== 0 ||
841 !session
->ns_data
.dd_nlist_v3
)
844 (void) qsort(session
->ns_data
.dd_nlist_v3
,
845 session
->ns_data
.dd_nlist_len
,
846 sizeof (mem_ndmp_name_v3_t
), fh_cmpv3
);
853 * Send the reply, check for error and print the msg if any error
854 * occured when sending the reply.
857 * connection (input) - connection pointer.
863 ndmp_send_reply(ndmp_connection_t
*connection
, void *reply
, char *msg
)
865 if (ndmp_send_response(connection
, NDMP_NO_ERR
, reply
) < 0)
866 NDMP_LOG(LOG_DEBUG
, "%s", msg
);
873 * Performs numerous filemark operations.
876 * fd - file descriptor of the device
877 * cmd - filemark or record command
878 * count - the number of operations to be performed
881 ndmp_mtioctl(int fd
, int cmd
, int count
)
887 if (ioctl(fd
, MTIOCTOP
, &mp
) < 0) {
888 NDMP_LOG(LOG_ERR
, "Failed to send command to tape: %m.");
899 * Convert type quad to longlong_t
902 quad_to_long_long(ndmp_u_quad q
)
906 ull
= ((u_longlong_t
)q
.high
<< 32) + q
.low
;
914 * Convert long long to quad type
917 long_long_to_quad(u_longlong_t ull
)
921 q
.high
= (ulong_t
)(ull
>> 32);
922 q
.low
= (ulong_t
)ull
;
927 set_socket_options(int sock
)
931 /* set send buffer size */
932 val
= atoi((const char *)ndmpd_get_prop_default(NDMP_SOCKET_CSS
, "60"));
935 val
<<= 10; /* convert the value from kilobytes to bytes */
936 if (setsockopt(sock
, SOL_SOCKET
, SO_SNDBUF
, &val
, sizeof (val
)) < 0)
937 NDMP_LOG(LOG_ERR
, "SO_SNDBUF failed: %m");
939 /* set receive buffer size */
940 val
= atoi((const char *)ndmpd_get_prop_default(NDMP_SOCKET_CRS
, "60"));
943 val
<<= 10; /* convert the value from kilobytes to bytes */
944 if (setsockopt(sock
, SOL_SOCKET
, SO_RCVBUF
, &val
, sizeof (val
)) < 0)
945 NDMP_LOG(LOG_ERR
, "SO_RCVBUF failed: %m");
947 /* don't wait to group tcp data */
949 if (setsockopt(sock
, IPPROTO_TCP
, TCP_NODELAY
, &val
, sizeof (val
)) != 0)
950 NDMP_LOG(LOG_ERR
, "TCP_NODELAY failed: %m");
954 if (setsockopt(sock
, SOL_SOCKET
, SO_KEEPALIVE
, &val
, sizeof (val
)) != 0)
955 NDMP_LOG(LOG_ERR
, "SO_KEEPALIVE failed: %m");
959 * ndmp_get_max_tok_seq
961 * Get the maximum permitted token sequence for token-based
971 ndmp_get_max_tok_seq(void)
973 return (ndmp_max_tok_seq
);
977 * ndmp_buffer_get_size
979 * Return the NDMP transfer buffer size
982 * session (input) - session pointer.
988 ndmp_buffer_get_size(ndmpd_session_t
*session
)
995 if (session
->ns_data
.dd_mover
.addr_type
== NDMP_ADDR_TCP
) {
996 xfer_size
= atoi(ndmpd_get_prop_default(NDMP_MOVER_RECSIZE
,
999 xfer_size
*= KILOBYTE
;
1001 xfer_size
= REMOTE_RECORD_SIZE
;
1002 NDMP_LOG(LOG_DEBUG
, "Remote operation: %d", xfer_size
);
1005 "Local operation: %lu", session
->ns_mover
.md_record_size
);
1006 if ((xfer_size
= session
->ns_mover
.md_record_size
) == 0)
1007 xfer_size
= MAX_RECORD_SIZE
;
1010 NDMP_LOG(LOG_DEBUG
, "xfer_size: %d", xfer_size
);
1018 * Initialize the LBR/NDMP backup parameters
1021 * session (input) - session pointer.
1028 ndmp_lbr_init(ndmpd_session_t
*session
)
1030 if (session
->ns_ndmp_lbr_params
!= NULL
) {
1031 NDMP_LOG(LOG_DEBUG
, "ndmp_lbr_params already allocated.");
1035 session
->ns_ndmp_lbr_params
= ndmp_malloc(sizeof (ndmp_lbr_params_t
));
1036 if (session
->ns_ndmp_lbr_params
== NULL
)
1039 session
->ns_ndmp_lbr_params
->nlp_bkmap
= -1;
1040 session
->ns_ndmp_lbr_params
->nlp_session
= session
;
1041 (void) cond_init(&session
->ns_ndmp_lbr_params
->nlp_cv
, 0, NULL
);
1042 (void) mutex_init(&session
->ns_ndmp_lbr_params
->nlp_mtx
, 0, NULL
);
1043 (void) mutex_init(&session
->ns_lock
, 0, NULL
);
1044 session
->ns_nref
= 0;
1052 * Deallocate and cleanup all NDMP/LBR parameters
1055 * session (input) - session pointer.
1062 ndmp_lbr_cleanup(ndmpd_session_t
*session
)
1064 ndmpd_abort_marking_v2(session
);
1065 ndmp_stop_buffer_worker(session
);
1066 ndmp_waitfor_op(session
);
1067 ndmp_free_reader_writer_ipc(session
);
1068 if (session
->ns_ndmp_lbr_params
) {
1069 if (session
->ns_ndmp_lbr_params
->nlp_bkmap
!= -1)
1070 (void) dbm_free(session
->ns_ndmp_lbr_params
->nlp_bkmap
);
1071 tlm_release_list(session
->ns_ndmp_lbr_params
->nlp_exl
);
1072 tlm_release_list(session
->ns_ndmp_lbr_params
->nlp_inc
);
1073 (void) cond_destroy(&session
->ns_ndmp_lbr_params
->nlp_cv
);
1074 (void) mutex_destroy(&session
->ns_ndmp_lbr_params
->nlp_mtx
);
1077 NDMP_FREE(session
->ns_ndmp_lbr_params
);
1081 * ndmp_wait_for_mover
1083 * Wait for a mover to become active. Waiting is interrupted if session is
1084 * aborted or mover gets to unexpected state.
1087 * session (input) - session pointer.
1090 * 0 if success, -1 if failure.
1093 ndmp_wait_for_mover(ndmpd_session_t
*session
)
1095 ndmp_lbr_params_t
*nlp
;
1098 if ((nlp
= ndmp_get_nlp(session
)) == NULL
)
1101 (void) mutex_lock(&nlp
->nlp_mtx
);
1102 while (session
->ns_mover
.md_state
== NDMP_MOVER_STATE_PAUSED
) {
1103 if (session
->ns_eof
) {
1104 NDMP_LOG(LOG_ERR
, "EOF detected");
1107 if (session
->ns_data
.dd_abort
) {
1108 NDMP_LOG(LOG_DEBUG
, "Received data abort");
1111 if (session
->ns_data
.dd_mover
.addr_type
== NDMP_ADDR_TCP
) {
1112 /* remote backup/restore error */
1113 if (session
->ns_mover
.md_sock
== -1 &&
1114 session
->ns_mover
.md_listen_sock
== -1) {
1116 "Remote data connection terminated");
1120 /* local backup/restore error */
1121 if ((lcmd
= nlp
->nlp_cmds
.tcs_command
) != NULL
) {
1122 if (lcmd
->tc_reader
== TLM_STOP
||
1123 lcmd
->tc_reader
== TLM_ABORT
||
1124 lcmd
->tc_writer
== TLM_STOP
||
1125 lcmd
->tc_writer
== TLM_ABORT
) {
1127 "Local data connection terminated");
1133 (void) cond_wait(&nlp
->nlp_cv
, &nlp
->nlp_mtx
);
1135 (void) mutex_unlock(&nlp
->nlp_mtx
);
1137 return ((session
->ns_mover
.md_state
== NDMP_MOVER_STATE_ACTIVE
) ?
1142 * is_buffer_erroneous
1144 * Run a sanity check on the buffer
1147 * TRUE: if the buffer seems to have error
1148 * FALSE: if the buffer is full and has valid data.
1151 is_buffer_erroneous(tlm_buffer_t
*buf
)
1155 rv
= (buf
== NULL
|| buf
->tb_eot
|| buf
->tb_eof
||
1156 buf
->tb_errno
!= 0);
1159 NDMP_LOG(LOG_DEBUG
, "buf == NULL");
1161 NDMP_LOG(LOG_DEBUG
, "eot: %u, eof: %u, errno: %d",
1162 buf
->tb_eot
, buf
->tb_eof
, buf
->tb_errno
);
1172 * Main SCSI CDB execution program, this is used by message handler
1173 * for the NDMP tape/SCSI execute CDB requests. This function uses
1174 * USCSI interface to run the CDB command and sets all the CDB parameters
1175 * in the SCSI query before calling the USCSI ioctl. The result of the
1176 * CDB is returned in two places:
1177 * cmd.uscsi_status The status of CDB execution
1178 * cmd.uscsi_rqstatus The status of sense requests
1179 * reply.error The general errno (ioctl)
1182 * session (input) - session pointer
1183 * adapter_name (input) - name of SCSI adapter
1184 * sid (input) - SCSI target ID
1185 * lun (input) - LUN number
1186 * request (input) - NDMP client CDB request
1193 ndmp_execute_cdb(ndmpd_session_t
*session
, char *adapter_name
, int sid
, int lun
,
1194 ndmp_execute_cdb_request
*request
)
1196 ndmp_execute_cdb_reply reply
;
1197 struct uscsi_cmd cmd
;
1199 struct open_list
*olp
;
1202 (void) memset((void *)&cmd
, 0, sizeof (cmd
));
1203 (void) memset((void *)&reply
, 0, sizeof (reply
));
1204 (void) memset((void *)rq_buf
, 0, sizeof (rq_buf
));
1206 if (request
->flags
== NDMP_SCSI_DATA_IN
) {
1207 cmd
.uscsi_flags
= USCSI_READ
| USCSI_RQENABLE
;
1208 if ((cmd
.uscsi_bufaddr
=
1209 ndmp_malloc(request
->datain_len
)) == 0) {
1210 reply
.error
= NDMP_NO_MEM_ERR
;
1211 if (ndmp_send_response(session
->ns_connection
,
1212 NDMP_NO_ERR
, (void *)&reply
) < 0)
1213 NDMP_LOG(LOG_DEBUG
, "error sending"
1214 " scsi_execute_cdb reply.");
1218 cmd
.uscsi_buflen
= request
->datain_len
;
1219 } else if (request
->flags
== NDMP_SCSI_DATA_OUT
) {
1220 cmd
.uscsi_flags
= USCSI_WRITE
| USCSI_RQENABLE
;
1221 cmd
.uscsi_bufaddr
= request
->dataout
.dataout_val
;
1222 cmd
.uscsi_buflen
= request
->dataout
.dataout_len
;
1224 cmd
.uscsi_flags
= USCSI_RQENABLE
;
1225 cmd
.uscsi_bufaddr
= 0;
1226 cmd
.uscsi_buflen
= 0;
1228 cmd
.uscsi_rqlen
= sizeof (rq_buf
);
1229 cmd
.uscsi_rqbuf
= rq_buf
;
1231 cmd
.uscsi_timeout
= (request
->timeout
< 1000) ?
1232 1 : (request
->timeout
/ 1000);
1234 cmd
.uscsi_cdb
= (caddr_t
)request
->cdb
.cdb_val
;
1235 cmd
.uscsi_cdblen
= request
->cdb
.cdb_len
;
1237 NDMP_LOG(LOG_DEBUG
, "cmd: 0x%x, len: %d, flags: %d, datain_len: %d",
1238 request
->cdb
.cdb_val
[0] & 0xff, request
->cdb
.cdb_len
,
1239 request
->flags
, request
->datain_len
);
1240 NDMP_LOG(LOG_DEBUG
, "dataout_len: %d, timeout: %d",
1241 request
->dataout
.dataout_len
, request
->timeout
);
1243 if (request
->cdb
.cdb_len
> 12) {
1244 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
1245 ndmp_send_reply(session
->ns_connection
, (void *) &reply
,
1246 "sending execute_cdb reply");
1247 if (request
->flags
== NDMP_SCSI_DATA_IN
)
1248 free(cmd
.uscsi_bufaddr
);
1252 reply
.error
= NDMP_NO_ERR
;
1254 if ((olp
= ndmp_open_list_find(adapter_name
, sid
, lun
)) != NULL
) {
1257 reply
.error
= NDMP_DEV_NOT_OPEN_ERR
;
1258 ndmp_send_reply(session
->ns_connection
, (void *) &reply
,
1259 "sending execute_cdb reply");
1260 if (request
->flags
== NDMP_SCSI_DATA_IN
)
1261 free(cmd
.uscsi_bufaddr
);
1265 if (ioctl(fd
, USCSICMD
, &cmd
) < 0) {
1266 if (errno
!= EIO
&& errno
!= 0)
1268 "Failed to send command to device: %m");
1269 NDMP_LOG(LOG_DEBUG
, "ioctl(USCSICMD) error: %m");
1270 if (cmd
.uscsi_status
== 0)
1271 reply
.error
= NDMP_IO_ERR
;
1274 reply
.status
= cmd
.uscsi_status
;
1276 if (request
->flags
== NDMP_SCSI_DATA_IN
) {
1277 reply
.datain
.datain_len
= cmd
.uscsi_buflen
;
1278 reply
.datain
.datain_val
= cmd
.uscsi_bufaddr
;
1280 reply
.dataout_len
= request
->dataout
.dataout_len
;
1283 reply
.ext_sense
.ext_sense_len
= cmd
.uscsi_rqlen
- cmd
.uscsi_rqresid
;
1284 reply
.ext_sense
.ext_sense_val
= rq_buf
;
1286 if (ndmp_send_response(session
->ns_connection
, NDMP_NO_ERR
,
1287 (void *)&reply
) < 0)
1288 NDMP_LOG(LOG_DEBUG
, "Error sending scsi_execute_cdb reply.");
1290 if (request
->flags
== NDMP_SCSI_DATA_IN
)
1291 free(cmd
.uscsi_bufaddr
);
1296 * ndmp_stop_local_reader
1298 * Stops a mover reader thread (for local backup only)
1301 * session (input) - session pointer
1302 * cmds (input) - reader/writer command struct
1308 ndmp_stop_local_reader(ndmpd_session_t
*session
, tlm_commands_t
*cmds
)
1310 ndmp_lbr_params_t
*nlp
;
1312 if (session
!= NULL
&& session
->ns_data
.dd_sock
== -1) {
1314 if (cmds
!= NULL
&& cmds
->tcs_reader_count
> 0) {
1315 if ((nlp
= ndmp_get_nlp(session
)) != NULL
) {
1316 (void) mutex_lock(&nlp
->nlp_mtx
);
1317 cmds
->tcs_command
->tc_reader
= TLM_STOP
;
1318 (void) cond_broadcast(&nlp
->nlp_cv
);
1319 (void) mutex_unlock(&nlp
->nlp_mtx
);
1327 * Stops a mover reader thread (for remote backup only)
1330 * session (input) - session pointer
1331 * cmds (input) - reader/writer command struct
1337 ndmp_stop_remote_reader(ndmpd_session_t
*session
)
1339 if (session
!= NULL
) {
1340 if (session
->ns_data
.dd_sock
>= 0) {
1345 "data.sock: %d", session
->ns_data
.dd_sock
);
1346 (void) close(session
->ns_data
.dd_sock
);
1347 session
->ns_data
.dd_sock
= -1;
1354 * ndmp_wait_for_reader
1356 * Wait for a reader until get done (busy wait)
1359 ndmp_wait_for_reader(tlm_commands_t
*cmds
)
1362 NDMP_LOG(LOG_DEBUG
, "cmds == NULL");
1365 "reader_count: %d", cmds
->tcs_reader_count
);
1367 while (cmds
->tcs_reader_count
> 0)
1374 * ndmp_open_list_find
1376 * Find a specific device in the open list
1379 * dev (input) - device name
1380 * sid (input) - SCSI target ID
1381 * lun (input) - LUN number
1384 * pointer to the open list entry
1387 ndmp_open_list_find(char *dev
, int sid
, int lun
)
1389 struct ol_head
*olhp
;
1390 struct open_list
*olp
;
1392 if (dev
== NULL
|| *dev
== '\0') {
1393 NDMP_LOG(LOG_DEBUG
, "Invalid argument");
1397 (void) mutex_lock(&ol_mutex
);
1399 for (olp
= LIST_FIRST(olhp
); olp
!= NULL
; olp
= LIST_NEXT(olp
, ol_q
))
1400 if (strcmp(olp
->ol_devnm
, dev
) == 0 && olp
->ol_sid
== sid
&&
1401 olp
->ol_lun
== lun
) {
1402 (void) mutex_unlock(&ol_mutex
);
1406 (void) mutex_unlock(&ol_mutex
);
1412 * ndmp_open_list_add
1414 * Add a specific device to the open list
1417 * conn (input) - connection pointer
1418 * dev (input) - device name
1419 * sid (input) - SCSI target ID
1420 * lun (input) - LUN number
1421 * fd (input) - the device file descriptor
1427 ndmp_open_list_add(ndmp_connection_t
*conn
, char *dev
, int sid
, int lun
, int fd
)
1430 struct ol_head
*olhp
;
1431 struct open_list
*olp
;
1433 if (dev
== NULL
|| *dev
== '\0') {
1434 NDMP_LOG(LOG_DEBUG
, "Invalid argument");
1438 "conn: 0x%08x, dev: %s, sid: %d, lun: %d", conn
, dev
, sid
, lun
);
1443 if ((olp
= ndmp_open_list_find(dev
, sid
, lun
)) != NULL
) {
1444 NDMP_LOG(LOG_DEBUG
, "already in list");
1446 * The adapter handle can be opened many times by the clients.
1447 * Only when the target is set, we must check and reject the
1448 * open request if the device is already being used by another
1455 } else if ((olp
= ndmp_malloc(sizeof (struct open_list
))) == NULL
) {
1457 } else if ((olp
->ol_devnm
= strdup(dev
)) == NULL
) {
1458 NDMP_LOG(LOG_ERR
, "Out of memory.");
1462 olp
->cl_conn
= conn
;
1470 (void) mutex_lock(&ol_mutex
);
1471 LIST_INSERT_HEAD(olhp
, olp
, ol_q
);
1472 (void) mutex_unlock(&ol_mutex
);
1480 * ndmp_open_list_del
1482 * Delete a specific device from the open list
1485 * dev (input) - device name
1486 * sid (input) - SCSI target ID
1487 * lun (input) - LUN number
1493 ndmp_open_list_del(char *dev
, int sid
, int lun
)
1495 struct open_list
*olp
;
1497 if (dev
== NULL
|| *dev
== '\0') {
1498 NDMP_LOG(LOG_DEBUG
, "Invalid argument");
1501 if ((olp
= ndmp_open_list_find(dev
, sid
, lun
)) == NULL
) {
1502 NDMP_LOG(LOG_DEBUG
, "%s not found", dev
);
1506 (void) mutex_lock(&ol_mutex
);
1507 if (--olp
->ol_nref
<= 0) {
1509 "Removed dev: %s, sid: %d, lun: %d", dev
, sid
, lun
);
1510 LIST_REMOVE(olp
, ol_q
);
1511 free(olp
->ol_devnm
);
1514 (void) mutex_unlock(&ol_mutex
);
1521 * ndmp_open_list_release
1523 * Close all the resources belonging to this connection.
1526 * ndmp_connection_t *conn : connection identifier
1532 ndmp_open_list_release(ndmp_connection_t
*conn
)
1534 struct ol_head
*olhp
= &ol_head
;
1535 struct open_list
*olp
;
1536 struct open_list
*next
;
1538 (void) mutex_lock(&ol_mutex
);
1539 olp
= LIST_FIRST(olhp
);
1540 while (olp
!= NULL
) {
1541 next
= LIST_NEXT(olp
, ol_q
);
1542 NDMP_LOG(LOG_DEBUG
, "olp->conn 0x%08x", olp
->cl_conn
);
1543 if (olp
->cl_conn
== conn
) {
1545 "Removed dev: %s, sid: %d, lun: %d",
1546 olp
->ol_devnm
, olp
->ol_sid
, olp
->ol_lun
);
1547 LIST_REMOVE(olp
, ol_q
);
1549 (void) close(olp
->ol_fd
);
1550 free(olp
->ol_devnm
);
1555 (void) mutex_unlock(&ol_mutex
);
1560 * ndmp_stop_buffer_worker
1562 * Stop all reader and writer threads for a specific buffer.
1565 * session (input) - session pointer
1571 ndmp_stop_buffer_worker(ndmpd_session_t
*session
)
1573 ndmp_lbr_params_t
*nlp
;
1574 tlm_commands_t
*cmds
;
1576 session
->ns_tape
.td_pos
= 0;
1577 if ((nlp
= ndmp_get_nlp(session
)) == NULL
) {
1578 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
1580 cmds
= &nlp
->nlp_cmds
;
1581 if (cmds
->tcs_command
== NULL
) {
1582 NDMP_LOG(LOG_DEBUG
, "cmds->tcs_command == NULL");
1584 cmds
->tcs_reader
= cmds
->tcs_writer
= TLM_ABORT
;
1585 cmds
->tcs_command
->tc_reader
= TLM_ABORT
;
1586 cmds
->tcs_command
->tc_writer
= TLM_ABORT
;
1587 while (cmds
->tcs_reader_count
> 0 ||
1588 cmds
->tcs_writer_count
> 0) {
1590 "trying to stop buffer worker");
1599 * ndmp_stop_reader_thread
1601 * Stop only the reader threads of a specific buffer
1604 * session (input) - session pointer
1610 ndmp_stop_reader_thread(ndmpd_session_t
*session
)
1612 ndmp_lbr_params_t
*nlp
;
1613 tlm_commands_t
*cmds
;
1615 if ((nlp
= ndmp_get_nlp(session
)) == NULL
) {
1616 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
1618 cmds
= &nlp
->nlp_cmds
;
1619 if (cmds
->tcs_command
== NULL
) {
1620 NDMP_LOG(LOG_DEBUG
, "cmds->tcs_command == NULL");
1622 cmds
->tcs_reader
= TLM_ABORT
;
1623 cmds
->tcs_command
->tc_reader
= TLM_ABORT
;
1624 while (cmds
->tcs_reader_count
> 0) {
1626 "trying to stop reader thread");
1635 * ndmp_stop_reader_thread
1637 * Stop only the writer threads of a specific buffer
1640 * session (input) - session pointer
1646 ndmp_stop_writer_thread(ndmpd_session_t
*session
)
1648 ndmp_lbr_params_t
*nlp
;
1649 tlm_commands_t
*cmds
;
1651 if ((nlp
= ndmp_get_nlp(session
)) == NULL
) {
1652 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
1654 cmds
= &nlp
->nlp_cmds
;
1655 if (cmds
->tcs_command
== NULL
) {
1656 NDMP_LOG(LOG_DEBUG
, "cmds->tcs_command == NULL");
1658 (void) mutex_lock(&nlp
->nlp_mtx
);
1659 cmds
->tcs_writer
= TLM_ABORT
;
1660 cmds
->tcs_command
->tc_writer
= TLM_ABORT
;
1661 (void) cond_broadcast(&nlp
->nlp_cv
);
1662 (void) mutex_unlock(&nlp
->nlp_mtx
);
1663 while (cmds
->tcs_writer_count
> 0) {
1665 "trying to stop writer thread");
1674 * ndmp_free_reader_writer_ipc
1676 * Free and release the reader/writer buffers and the IPC structure
1677 * for reader and writer threads.
1680 * session (input) - session pointer
1686 ndmp_free_reader_writer_ipc(ndmpd_session_t
*session
)
1688 ndmp_lbr_params_t
*nlp
;
1689 tlm_commands_t
*cmds
;
1691 if ((nlp
= ndmp_get_nlp(session
)) != NULL
) {
1692 cmds
= &nlp
->nlp_cmds
;
1693 if (cmds
->tcs_command
!= NULL
) {
1694 NDMP_LOG(LOG_DEBUG
, "cmds->tcs_command->tc_ref: %d",
1695 cmds
->tcs_command
->tc_ref
);
1696 tlm_release_reader_writer_ipc(cmds
->tcs_command
);
1705 * Wait for a session reference count to drop to zero
1708 * session (input) - session pointer
1714 ndmp_waitfor_op(ndmpd_session_t
*session
)
1716 if (session
!= NULL
) {
1717 while (session
->ns_nref
> 0) {
1720 "waiting for session nref: %d", session
->ns_nref
);
1729 * Increment the reference count of the session
1732 * session (input) - session pointer
1738 ndmp_session_ref(ndmpd_session_t
*session
)
1740 (void) mutex_lock(&session
->ns_lock
);
1742 (void) mutex_unlock(&session
->ns_lock
);
1747 * ndmp_session_unref
1749 * Decrement the reference count of the session
1752 * session (input) - session pointer
1758 ndmp_session_unref(ndmpd_session_t
*session
)
1760 (void) mutex_lock(&session
->ns_lock
);
1762 (void) mutex_unlock(&session
->ns_lock
);
1769 * Convert the address type to a string
1772 * type (input) - address type
1778 ndmp_addr2str_v3(ndmp_addr_type type
)
1783 case NDMP_ADDR_LOCAL
:
1804 * ndmp_valid_v3addr_type
1806 * Make sure that the NDMP address is from any of the
1810 * type (input) - address type
1817 ndmp_valid_v3addr_type(ndmp_addr_type type
)
1822 case NDMP_ADDR_LOCAL
:
1839 * Copy NDMP address from source to destination (V2 and V3 only)
1842 * dst (ouput) - destination address
1843 * src (input) - source address
1849 ndmp_copy_addr_v3(ndmp_addr_v3
*dst
, ndmp_addr_v3
*src
)
1851 dst
->addr_type
= src
->addr_type
;
1852 switch (src
->addr_type
) {
1853 case NDMP_ADDR_LOCAL
:
1857 dst
->tcp_ip_v3
= htonl(src
->tcp_ip_v3
);
1858 dst
->tcp_port_v3
= src
->tcp_port_v3
;
1871 * Copy NDMP address from source to destination. V4 has a extra
1872 * environment list inside the address too which needs to be copied.
1875 * dst (ouput) - destination address
1876 * src (input) - source address
1882 ndmp_copy_addr_v4(ndmp_addr_v4
*dst
, ndmp_addr_v4
*src
)
1886 dst
->addr_type
= src
->addr_type
;
1887 dst
->tcp_len_v4
= src
->tcp_len_v4
;
1888 switch (src
->addr_type
) {
1889 case NDMP_ADDR_LOCAL
:
1893 dst
->tcp_addr_v4
= ndmp_malloc(sizeof (ndmp_tcp_addr_v4
) *
1895 if (dst
->tcp_addr_v4
== 0)
1898 for (i
= 0; i
< src
->tcp_len_v4
; i
++) {
1899 dst
->tcp_ip_v4(i
) = htonl(src
->tcp_ip_v4(i
));
1900 dst
->tcp_port_v4(i
) = src
->tcp_port_v4(i
);
1901 dst
->tcp_env_v4(i
).addr_env_len
= 0; /* Solaris */
1902 dst
->tcp_env_v4(i
).addr_env_val
= 0; /* Solaris */
1914 * ndmp_connect_sock_v3
1916 * Creates a socket and connects to the specified address/port
1919 * addr (input) - IP address
1920 * port (input) - port number
1927 ndmp_connect_sock_v3(ulong_t addr
, ushort_t port
)
1930 struct sockaddr_in sin
;
1932 NDMP_LOG(LOG_DEBUG
, "addr %s:%d", inet_ntoa(IN_ADDR(addr
)), port
);
1934 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
1936 NDMP_LOG(LOG_DEBUG
, "Socket error: %m");
1940 (void) memset((void *) &sin
, 0, sizeof (sin
));
1941 sin
.sin_family
= AF_INET
;
1942 sin
.sin_addr
.s_addr
= htonl(addr
);
1943 sin
.sin_port
= htons(port
);
1944 if (connect(sock
, (struct sockaddr
*)&sin
, sizeof (sin
)) < 0) {
1945 NDMP_LOG(LOG_DEBUG
, "Connect error: %m");
1950 set_socket_options(sock
);
1951 NDMP_LOG(LOG_DEBUG
, "sock %d", sock
);
1957 * ndmp_create_socket
1959 * Creates a socket for listening for accepting data connections.
1962 * session (input) - session pointer.
1963 * addr (output) - location to store address of socket.
1964 * port (output) - location to store port of socket.
1971 ndmp_create_socket(ulong_t
*addr
, ushort_t
*port
)
1976 struct sockaddr_in sin
;
1978 /* Try the user's prefered NIC IP address */
1979 p
= ndmpd_get_prop(NDMP_MOVER_NIC
);
1981 /* Try host's IP address */
1985 /* Try default NIC's IP address (if DNS failed) */
1987 p
= get_default_nic_addr();
1989 /* Fail if no IP can be obtained */
1991 NDMP_LOG(LOG_ERR
, "Undetermined network port.");
1995 *addr
= inet_addr(p
);
1997 sd
= socket(AF_INET
, SOCK_STREAM
, 0);
1999 NDMP_LOG(LOG_DEBUG
, "Socket error: %m");
2002 sin
.sin_family
= AF_INET
;
2003 sin
.sin_addr
.s_addr
= INADDR_ANY
;
2005 length
= sizeof (sin
);
2007 if (bind(sd
, (struct sockaddr
*)&sin
, sizeof (sin
)) < 0) {
2008 NDMP_LOG(LOG_DEBUG
, "Bind error: %m");
2011 } else if (getsockname(sd
, (struct sockaddr
*)&sin
, &length
) < 0) {
2012 NDMP_LOG(LOG_DEBUG
, "getsockname error: %m");
2015 } else if (listen(sd
, 5) < 0) {
2016 NDMP_LOG(LOG_DEBUG
, "Listen error: %m");
2020 *port
= sin
.sin_port
;
2029 * Convert the specified time into a string. It's like
2031 * - chops the trailing '\n' of ctime.
2032 * - and returns "the epoch" if time is 0.
2035 * "": invalid argument.
2036 * "the epoch": if time is 0.
2037 * string format of the time.
2043 static char tbuf
[BUFSIZ
];
2048 if (*t
== (time_t)0)
2049 return ("the epoch");
2051 if ((bp
= ctime_r(t
, tbuf
, BUFSIZ
)) == NULL
)
2054 cp
= strchr(bp
, '\n');
2065 * Create a job name for each backup/restore to keep track
2068 * jname (output) - job name
2074 ndmp_new_job_name(char *jname
)
2076 if (jname
!= NULL
) {
2077 (void) snprintf(jname
, TLM_MAX_BACKUP_JOB_NAME
, "%s%d",
2078 NDMP_RCF_BASENAME
, ndmp_job_cnt
++);
2079 NDMP_LOG(LOG_DEBUG
, "jname: \"%s\"", jname
);
2087 * fs_is_valid_logvol
2089 * Check if the log path exists
2092 * path (input) - log path
2099 fs_is_valid_logvol(char *path
)
2103 if (stat64(path
, &st
) < 0)
2113 * Make a temporary file using the working directory path and the
2117 * buf (output) - the temporary file name path
2123 ndmpd_mk_temp(char *buf
)
2125 char fname
[TLM_MAX_BACKUP_JOB_NAME
];
2132 dir
= ndmpd_get_prop(NDMP_DEBUG_PATH
);
2133 if (dir
== 0 || *dir
== '\0') {
2134 NDMP_LOG(LOG_DEBUG
, "NDMP work path not specified");
2138 if (!fs_is_valid_logvol((char *)dir
)) {
2140 "Log file path cannot be on system volumes.");
2144 dir
+= strspn(dir
, " \t");
2146 NDMP_LOG(LOG_DEBUG
, "NDMP work path not specified");
2151 (void) ndmp_new_job_name(fname
);
2152 (void) tlm_cat_path(buf
, (char *)dir
, fname
);
2159 * ndmpd_make_bk_dir_path
2161 * Make a directory path for temporary files under the NDMP
2162 * working directory.
2165 * buf (output) - result path
2166 * fname (input) - the file name
2172 ndmpd_make_bk_dir_path(char *buf
, char *fname
)
2176 char path
[PATH_MAX
];
2178 if (!buf
|| !fname
|| !*fname
)
2181 p
= ndmpd_get_prop(NDMP_DEBUG_PATH
);
2182 if (p
== NULL
|| *p
== '\0' || !fs_is_valid_logvol((char *)p
)) {
2186 (void) strlcpy(path
, (char *)p
, PATH_MAX
);
2187 (void) trim_whitespace(path
);
2189 if ((name
= strrchr(fname
, '/')) == 0)
2192 (void) tlm_cat_path(buf
, path
, name
);
2198 * ndmp_is_chkpnt_root
2200 * Is this a root checkpoint (snapshot) directory.
2201 * Note: a temporary function
2204 ndmp_is_chkpnt_root(char *path
)
2208 if (stat64(path
, &st
) != 0) {
2209 NDMP_LOG(LOG_DEBUG
, "Couldn't stat path \"%s\"", path
);
2217 * ndmpd_make_exc_list
2219 * Make a list of files that should not be backed up.
2225 * list - array of character strings
2228 ndmpd_make_exc_list(void)
2234 if ((cpp
= ndmp_malloc(n
)) != NULL
) {
2235 for (i
= 0; exls
[i
] != NULL
; i
++)
2239 * If ndmpd_get_prop returns NULL, the array will be
2242 val
= ndmpd_get_prop(NDMP_DEBUG_PATH
);
2251 * ndmp_get_bk_dir_ino
2253 * Get the inode number of the backup directory
2256 ndmp_get_bk_dir_ino(ndmp_lbr_params_t
*nlp
)
2261 if (stat64(nlp
->nlp_backup_path
, &st
) != 0) {
2263 NDMP_LOG(LOG_DEBUG
, "Getting inode # of \"%s\"",
2264 nlp
->nlp_backup_path
);
2267 nlp
->nlp_bkdirino
= st
.st_ino
;
2268 NDMP_LOG(LOG_DEBUG
, "nlp_bkdirino: %lu",
2269 (uint_t
)nlp
->nlp_bkdirino
);
2277 * ndmp_check_utf8magic
2279 * Check if the magic string for exists in the tar header. This
2280 * magic string (which also indicates that the file names are in
2281 * UTF8 format) is used as a crest to indetify our own tapes.
2282 * This checking is always done before all restores except DAR
2286 ndmp_check_utf8magic(tlm_cmd_t
*cmd
)
2289 int err
, len
, actual_size
;
2292 NDMP_LOG(LOG_DEBUG
, "cmd == NULL");
2295 if (cmd
->tc_buffers
== NULL
) {
2296 NDMP_LOG(LOG_DEBUG
, "cmd->tc_buffers == NULL");
2300 /* wait until the first buffer gets full. */
2301 tlm_buffer_in_buf_wait(cmd
->tc_buffers
);
2303 err
= actual_size
= 0;
2304 cp
= tlm_get_read_buffer(RECORDSIZE
, &err
, cmd
->tc_buffers
,
2307 NDMP_LOG(LOG_DEBUG
, "Can't read from buffers, err: %d", err
);
2310 len
= strlen(NDMPUTF8MAGIC
);
2311 if (actual_size
< len
) {
2312 NDMP_LOG(LOG_DEBUG
, "Not enough data in the buffers");
2316 return ((strncmp(cp
, NDMPUTF8MAGIC
, len
) == 0) ? TRUE
: FALSE
);
2321 * ndmp_get_cur_bk_time
2323 * Get the backup checkpoint time.
2326 ndmp_get_cur_bk_time(ndmp_lbr_params_t
*nlp
, time_t *tp
, char *jname
)
2330 if (!nlp
|| !nlp
->nlp_backup_path
|| !tp
) {
2331 NDMP_LOG(LOG_DEBUG
, "Invalid argument");
2335 if (!fs_is_chkpnt_enabled(nlp
->nlp_backup_path
)) {
2336 NDMP_LOG(LOG_DEBUG
, "Not a chkpnt volume %s",
2337 nlp
->nlp_backup_path
);
2342 err
= tlm_get_chkpnt_time(nlp
->nlp_backup_path
, !NLP_ISCHKPNTED(nlp
),
2345 NDMP_LOG(LOG_DEBUG
, "Can't checkpoint time");
2347 NDMP_LOG(LOG_DEBUG
, "%s", cctime(tp
));
2358 ndmp_get_relative_path(char *base
, char *fullpath
)
2362 if (!base
|| !*base
)
2374 return ((*base
) ? fullpath
: p
);
2381 * Get NDMP local backup parameters
2390 ndmp_get_nlp(void *cookie
)
2395 return (((ndmpd_session_t
*)cookie
)->ns_ndmp_lbr_params
);
2400 * is_tape_unit_ready
2402 * Check if the tape device is ready or not
2405 is_tape_unit_ready(char *adptnm
, int dev_id
)
2412 if ((fd
= open(adptnm
, O_RDONLY
| O_NDELAY
)) < 0)
2418 if (scsi_test_unit_ready(fd
) >= 0) {
2419 NDMP_LOG(LOG_DEBUG
, "Unit is ready");
2427 NDMP_LOG(LOG_DEBUG
, "Unit not ready");
2428 (void) usleep(TUR_WAIT
);
2430 } while (--try > 0);
2435 NDMP_LOG(LOG_DEBUG
, "Unit didn't get ready");
2441 * scsi_test_unit_ready
2443 * This is for Test Unit Read, without this function, the only
2444 * impact is getting EBUSY's before each operation which we have
2445 * busy waiting loops checking EBUSY error code.
2448 scsi_test_unit_ready(int dev_id
)
2450 struct uscsi_cmd ucmd
;
2454 (void) memset(&ucmd
, 0, sizeof (struct uscsi_cmd
));
2455 (void) memset(&cdb
, 0, sizeof (union scsi_cdb
));
2456 cdb
.scc_cmd
= SCMD_TEST_UNIT_READY
;
2457 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
2458 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
2459 ucmd
.uscsi_flags
|= USCSI_SILENT
;
2460 ucmd
.uscsi_timeout
= 60; /* Allow maximum 1 min */
2462 retval
= ioctl(dev_id
, USCSICMD
, &ucmd
);
2464 if (retval
!= 0 && errno
!= EIO
) {
2466 "Failed to send inquiry request to device: %m.");
2467 NDMP_LOG(LOG_DEBUG
, "Inquiry request failed for"
2468 " dev_id:%d err=%d -%m", dev_id
, errno
);
2471 retval
= -(ucmd
.uscsi_status
);
2480 * Load the parameters.
2489 ndmp_load_params(void)
2491 ndmp_dump_path_node
= ndmpd_get_prop_yorn(NDMP_DUMP_PATHNODE_ENV
) ?
2493 ndmp_tar_path_node
= ndmpd_get_prop_yorn(NDMP_TAR_PATHNODE_ENV
) ?
2496 ndmpd_get_prop_yorn(NDMP_IGNCTIME_ENV
) ? TRUE
: FALSE
;
2497 ndmp_include_lmtime
= ndmpd_get_prop_yorn(NDMP_INCLMTIME_ENV
) ?
2499 ndmp_max_tok_seq
= atoi(ndmpd_get_prop_default(NDMP_MAXSEQ_ENV
, "9"));
2501 ndmp_full_restore_path
= ndmpd_get_prop_yorn(NDMP_FULL_RESTORE_PATH
) ?
2504 ndmp_fhinode
= ndmpd_get_prop_yorn(NDMP_FHIST_INCR_ENV
) ? TRUE
: FALSE
;
2506 /* Get the value from ndmp SMF property. */
2507 ndmp_dar_support
= ndmpd_get_prop_yorn(NDMP_DAR_SUPPORT
);
2509 if ((ndmp_ver
= atoi(ndmpd_get_prop(NDMP_VERSION_ENV
))) == 0)
2516 * Randomize the contents of a buffer
2519 * buffer (output) - destination buffer
2520 * size (input) - buffer size
2526 randomize(unsigned char *buffer
, int size
)
2528 /* LINTED improper alignment */
2529 unsigned int *p
= (unsigned int *)buffer
;
2530 unsigned int dwlen
= size
/ sizeof (unsigned int);
2531 unsigned int remlen
= size
% sizeof (unsigned int);
2535 for (i
= 0; i
< dwlen
; i
++)
2540 (void) memcpy(p
, &tmp
, remlen
);
2545 * ndmpd_get_file_entry_type
2547 * Converts the mode to the NDMP file type
2550 * mode (input) - file mode
2551 * ftype (output) - file type
2557 ndmpd_get_file_entry_type(int mode
, ndmp_file_type
*ftype
)
2559 switch (mode
& S_IFMT
) {
2561 *ftype
= NDMP_FILE_FIFO
;
2564 *ftype
= NDMP_FILE_CSPEC
;
2567 *ftype
= NDMP_FILE_DIR
;
2570 *ftype
= NDMP_FILE_BSPEC
;
2573 *ftype
= NDMP_FILE_REG
;
2576 *ftype
= NDMP_FILE_SLINK
;
2579 *ftype
= NDMP_FILE_SOCK
;
2585 * Set a private data in the plugin context
2588 ndmp_context_set_specific(ndmp_context_t
*nctx
, void *ptr
)
2590 nctx
->nc_pldata
= ptr
;
2594 * Get a private data in the plugin context
2597 ndmp_context_get_specific(ndmp_context_t
*nctx
)
2599 return (nctx
->nc_pldata
);
2603 ndmp_get_backup_type(ndmp_context_t
*ctx
)
2605 ndmpd_session_t
*session
= (ndmpd_session_t
*)ctx
->nc_ddata
;
2607 return (session
->ns_butype
);