xref: /titanic_51/usr/src/cmd/ndmpd/ndmp/ndmpd_util.c (revision db3659e514c8bf3f03bcca6dd082e363bd7b466a)
1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * BSD 3 Clause License
8  *
9  * Copyright (c) 2007, The Storage Networking Industry Association.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 	- Redistributions of source code must retain the above copyright
15  *	  notice, this list of conditions and the following disclaimer.
16  *
17  * 	- Redistributions in binary form must reproduce the above copyright
18  *	  notice, this list of conditions and the following disclaimer in
19  *	  the documentation and/or other materials provided with the
20  *	  distribution.
21  *
22  *	- Neither the name of The Storage Networking Industry Association (SNIA)
23  *	  nor the names of its contributors may be used to endorse or promote
24  *	  products derived from this software without specific prior written
25  *	  permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
41 
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <assert.h>
45 #include <ctype.h>
46 #include <errno.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <strings.h>
51 #include <time.h>
52 #include <libgen.h>
53 #include "ndmpd.h"
54 #include <bitmap.h>
55 #include <sys/queue.h>
56 #include <sys/socket.h>
57 #include <netinet/in.h>
58 #include <netinet/tcp.h>
59 #include <arpa/inet.h>
60 #include <sys/socketvar.h>
61 #include <net/if.h>
62 #include <netdb.h>
63 #include <sys/filio.h>
64 #include <sys/mtio.h>
65 #include <sys/scsi/impl/uscsi.h>
66 #include <sys/scsi/scsi.h>
67 #include "tlm.h"
68 
69 /*
70  * Mutex to protect Nlp
71  */
72 mutex_t nlp_mtx;
73 
74 /*
75  * Patchable socket buffer sizes in kilobytes.
76  * ssb: send buffer size.
77  * rsb: receive buffer size.
78  */
79 int ndmp_sbs = 60;
80 int ndmp_rbs = 60;
81 
82 
83 /*
84  * Force to backup all the intermediate directories leading to an object
85  * to be backed up in 'dump' format backup.
86  */
87 boolean_t ndmp_dump_path_node = FALSE;
88 
89 
90 /*
91  * Force to backup all the intermediate directories leading to an object
92  * to be backed up in 'tar' format backup.
93  */
94 boolean_t ndmp_tar_path_node = FALSE;
95 
96 
97 /*
98  * Should the 'st_ctime' be ignored during incremental level backup?
99  */
100 boolean_t ndmp_ignore_ctime = FALSE;
101 
102 /*
103  * Should the 'st_lmtime' be included during incremental level backup?
104  */
105 boolean_t ndmp_include_lmtime = FALSE;
106 
107 /*
108  * Force to send the file history node entries along with the file history
109  * dir entries for all directories containing the changed files to the client
110  * for incremental backup.
111  *
112  * Note: This variable is added to support Bakbone Software's Netvault DMA
113  * which expects to get the FH ADD NODES for all upper directories which
114  * contain the changed files in incremental backup along with the FH ADD DIRS.
115  */
116 boolean_t ndmp_fhinode = FALSE;
117 
118 /*
119  * Maximum permitted sequence number in the token-based backup.  The
120  * value of this variable can be changed by the administrator and is
121  * saved in the NDMP configuration file.
122  */
123 static int ndmp_max_tok_seq = NDMP_MAX_TOKSEQ;
124 
125 /*
126  * Force backup directories in incremental backups.  If the
127  * directory is not modified itself, it's not backed up by
128  * default.
129  */
130 int ndmp_force_bk_dirs = 0;
131 
132 /*
133  * Keeps track of the open SCSI (including tape and robot) devices.
134  * When a SCSI device is opened its name must be added to this list and
135  * when it's closed its name must be removed from this list.  The main
136  * purpose of this list is the robot device.  If the robot devices are not
137  * attached in SASD layer, Local Backup won't see them. If they are
138  * attached and we open the robot devices, then wrong commands are sent
139  * to robot by SASD since it assumes that the robot is a tape (sequential
140  * access) device.
141  */
142 struct open_list {
143 	LIST_ENTRY(open_list) ol_q;
144 	int ol_nref;
145 	char *ol_devnm;
146 	int ol_sid;
147 	int ol_lun;
148 	int ol_fd;
149 	ndmp_connection_t *cl_conn;
150 };
151 LIST_HEAD(ol_head, open_list);
152 
153 
154 /*
155  * Head of the opened SCSI devices list.
156  */
157 static struct ol_head ol_head;
158 
159 mutex_t ol_mutex = DEFAULTMUTEX;
160 
161 
162 /*
163  * List of things to be exluded from backup.
164  */
165 static char *exls[] = {
166 	EXCL_PROC,
167 	EXCL_TMP,
168 	NULL, /* reserved for a copy of the "backup.directory" */
169 	NULL
170 };
171 
172 
173 /*
174  * The counter for creating unique names with "ndmp.%d" format.
175  */
176 #define	NDMP_RCF_BASENAME	"ndmp."
177 static int ndmp_job_cnt = 0;
178 
179 static int scsi_test_unit_ready(int dev_id);
180 
181 /*
182  * ndmpd_add_file_handler
183  *
184  * Adds a file handler to the file handler list.
185  * The file handler list is used by ndmpd_api_dispatch.
186  *
187  * Parameters:
188  *   session (input) - session pointer.
189  *   cookie  (input) - opaque data to be passed to file hander when called.
190  *   fd      (input) - file descriptor.
191  *   mode    (input) - bitmask of the following:
192  *		     1 = watch file for ready for reading
193  *		     2 = watch file for ready for writing
194  *		     4 = watch file for exception
195  *   class   (input) - handler class. (HC_CLIENT, HC_MOVER, HC_MODULE)
196  *   func    (input) - function to call when the file meets one of the
197  *		     conditions specified by mode.
198  *
199  * Returns:
200  *   0 - success.
201  *  -1 - error.
202  */
203 int
204 ndmpd_add_file_handler(ndmpd_session_t *session, void *cookie, int fd,
205     ulong_t mode, ulong_t class, ndmpd_file_handler_func_t *func)
206 {
207 	ndmpd_file_handler_t *new;
208 
209 	new = ndmp_malloc(sizeof (ndmpd_file_handler_t));
210 	if (new == 0)
211 		return (-1);
212 
213 	new->fh_cookie = cookie;
214 	new->fh_fd = fd;
215 	new->fh_mode = mode;
216 	new->fh_class = class;
217 	new->fh_func = func;
218 	new->fh_next = session->ns_file_handler_list;
219 	session->ns_file_handler_list = new;
220 	return (0);
221 }
222 
223 
224 /*
225  * ndmpd_remove_file_handler
226  *
227  * Removes a file handler from the file handler list.
228  *
229  * Parameters:
230  *   session (input) - session pointer.
231  *   fd      (input) - file descriptor.
232  *
233  * Returns:
234  *   0 - success.
235  *  -1 - error.
236  */
237 int
238 ndmpd_remove_file_handler(ndmpd_session_t *session, int fd)
239 {
240 	ndmpd_file_handler_t **last;
241 	ndmpd_file_handler_t *handler;
242 
243 	last = &session->ns_file_handler_list;
244 	while (*last != 0) {
245 		handler = *last;
246 
247 		if (handler->fh_fd == fd) {
248 			*last = handler->fh_next;
249 			(void) free(handler);
250 			return (1);
251 		}
252 		last = &handler->fh_next;
253 	}
254 
255 	return (0);
256 }
257 
258 
259 /*
260  * ndmp_connection_closed
261  *
262  * If the connection closed or not.
263  *
264  * Parameters:
265  *   fd (input) : file descriptor
266  *
267  * Returns:
268  *   0  - connection is still valid
269  *   1  - connection is not valid anymore
270  *   -1 - Internal kernel error
271  */
272 int
273 ndmp_connection_closed(int fd)
274 {
275 	fd_set fds;
276 	int closed, ret;
277 	struct timeval timeout;
278 
279 	if (fd < 0) /* We are not using the mover */
280 		return (-1);
281 
282 	timeout.tv_sec = 0;
283 	timeout.tv_usec = 1000;
284 
285 	FD_ZERO(&fds);
286 	FD_SET(fd, &fds);
287 	ret = select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
288 
289 	closed = (ret == -1 && errno == EBADF);
290 
291 	return (closed);
292 }
293 
294 /*
295  * ndmp_check_mover_state
296  *
297  * Checks the mover connection status and sends an appropriate
298  * NDMP message to client based on that.
299  *
300  * Parameters:
301  *   ndmpd_session_t *session (input) : session pointer
302  *
303  * Returns:
304  *   void.
305  */
306 void
307 ndmp_check_mover_state(ndmpd_session_t *session)
308 {
309 	int moverfd;
310 	/*
311 	 * NDMPV3 Spec (Three-way restore):
312 	 * Once all of the files have been recovered, NDMP DATA Server closes
313 	 * the connection to the mover on the NDMP TAPE Server. THEN
314 	 * The NDMP client should receive an NDMP_NOTIFY_MOVER_HALTED message
315 	 * with an NDMP_MOVER_CONNECT_CLOSED reason from the NDMP TAPE Server
316 	 */
317 	moverfd = session->ns_mover.md_sock;
318 	/* If connection is closed by the peer */
319 	if (moverfd >= 0 &&
320 	    session->ns_mover.md_mode == NDMP_MOVER_MODE_WRITE) {
321 		int closed, reason;
322 
323 		closed = ndmp_connection_closed(moverfd);
324 		if (closed) {
325 			/* Connection closed or internal error */
326 			if (closed > 0) {
327 				NDMP_LOG(LOG_DEBUG,
328 				    "ndmp mover: connection closed by peer");
329 				reason = NDMP_MOVER_HALT_CONNECT_CLOSED;
330 			} else {
331 				NDMP_LOG(LOG_DEBUG,
332 				    "ndmp mover: Internal error");
333 				reason = NDMP_MOVER_HALT_INTERNAL_ERROR;
334 			}
335 			ndmpd_mover_error(session, reason);
336 
337 		}
338 	}
339 }
340 
341 
342 /*
343  * ndmpd_select
344  *
345  * Calls select on the the set of file descriptors from the
346  * file handler list masked by the fd_class argument.
347  * Calls the file handler function for each
348  * file descriptor that is ready for I/O.
349  *
350  * Parameters:
351  *   session (input) - session pointer.
352  *   block   (input) - if TRUE, ndmpd_select waits until at least one
353  *		     file descriptor is ready for I/O. Otherwise,
354  *		     it returns immediately if no file descriptors are
355  *		     ready for I/O.
356  *   class_mask (input) - bit mask of handler classes to be examined.
357  *		     Provides for excluding some of the handlers from
358  *		     being called.
359  *
360  * Returns:
361  *  -1 - error.
362  *   0 - no handlers were called.
363  *   1 - at least one handler was called.
364  */
365 int
366 ndmpd_select(ndmpd_session_t *session, boolean_t block, ulong_t class_mask)
367 {
368 	fd_set rfds;
369 	fd_set wfds;
370 	fd_set efds;
371 	int n;
372 	ndmpd_file_handler_t *handler;
373 	struct timeval timeout;
374 
375 	nlp_event_rv_set(session, 0);
376 
377 	if (session->ns_file_handler_list == 0)
378 		return (0);
379 
380 
381 	/*
382 	 * If select should be blocked, then we poll every ten seconds.
383 	 * The reason is in case of three-way restore we should be able
384 	 * to detect if the other end closed the connection or not.
385 	 * NDMP client(DMA) does not send any information about the connection
386 	 * that was closed in the other end.
387 	 */
388 
389 	if (block == TRUE)
390 		timeout.tv_sec = 10;
391 	else
392 		timeout.tv_sec = 0;
393 	timeout.tv_usec = 0;
394 
395 	do {
396 		/* Create the fd_sets for select. */
397 		FD_ZERO(&rfds);
398 		FD_ZERO(&wfds);
399 		FD_ZERO(&efds);
400 
401 		for (handler = session->ns_file_handler_list; handler != 0;
402 		    handler = handler->fh_next) {
403 			if ((handler->fh_class & class_mask) == 0)
404 				continue;
405 
406 			if (handler->fh_mode & NDMPD_SELECT_MODE_READ)
407 				FD_SET(handler->fh_fd, &rfds);
408 			if (handler->fh_mode & NDMPD_SELECT_MODE_WRITE)
409 				FD_SET(handler->fh_fd, &wfds);
410 			if (handler->fh_mode & NDMPD_SELECT_MODE_EXCEPTION)
411 				FD_SET(handler->fh_fd, &efds);
412 		}
413 		ndmp_check_mover_state(session);
414 		n = select(FD_SETSIZE, &rfds, &wfds, &efds, &timeout);
415 	} while (n == 0 && block == TRUE);
416 
417 	if (n < 0) {
418 		int connection_fd = ndmp_get_fd(session->ns_connection);
419 
420 		if (errno == EINTR)
421 			return (0);
422 
423 		NDMP_LOG(LOG_DEBUG, "Select error: %m");
424 
425 		for (handler = session->ns_file_handler_list; handler != 0;
426 		    handler = handler->fh_next) {
427 			if ((handler->fh_class & class_mask) == 0)
428 				continue;
429 
430 			if (handler->fh_mode & NDMPD_SELECT_MODE_READ) {
431 				if (FD_ISSET(handler->fh_fd, &rfds) &&
432 				    connection_fd == handler->fh_fd)
433 					session->ns_eof = TRUE;
434 			}
435 			if (handler->fh_mode & NDMPD_SELECT_MODE_WRITE) {
436 				if (FD_ISSET(handler->fh_fd, &wfds) &&
437 				    connection_fd == handler->fh_fd)
438 					session->ns_eof = TRUE;
439 			}
440 			if (handler->fh_mode & NDMPD_SELECT_MODE_EXCEPTION) {
441 				if (FD_ISSET(handler->fh_fd, &efds) &&
442 				    connection_fd == handler->fh_fd)
443 					session->ns_eof = TRUE;
444 			}
445 		}
446 
447 		nlp_event_rv_set(session, -1);
448 		return (-1);
449 	}
450 	if (n == 0)
451 		return (0);
452 
453 	handler = session->ns_file_handler_list;
454 	while (handler != 0) {
455 		ulong_t mode = 0;
456 
457 		if ((handler->fh_class & class_mask) == 0) {
458 			handler = handler->fh_next;
459 			continue;
460 		}
461 		if (handler->fh_mode & NDMPD_SELECT_MODE_READ) {
462 			if (FD_ISSET(handler->fh_fd, &rfds)) {
463 				mode |= NDMPD_SELECT_MODE_READ;
464 				FD_CLR(handler->fh_fd, &rfds);
465 			}
466 		}
467 		if (handler->fh_mode & NDMPD_SELECT_MODE_WRITE) {
468 			if (FD_ISSET(handler->fh_fd, &wfds)) {
469 				mode |= NDMPD_SELECT_MODE_WRITE;
470 				FD_CLR(handler->fh_fd, &wfds);
471 			}
472 		}
473 		if (handler->fh_mode & NDMPD_SELECT_MODE_EXCEPTION) {
474 			if (FD_ISSET(handler->fh_fd, &efds)) {
475 				mode |= NDMPD_SELECT_MODE_EXCEPTION;
476 				FD_CLR(handler->fh_fd, &efds);
477 			}
478 		}
479 		if (mode) {
480 			(*handler->fh_func) (handler->fh_cookie,
481 			    handler->fh_fd, mode);
482 
483 			/*
484 			 * K.L. The list can be modified during the execution
485 			 * of handler->fh_func. Therefore, handler will start
486 			 * from the beginning of the handler list after
487 			 * each execution.
488 			 */
489 			handler = session->ns_file_handler_list;
490 
491 			/*
492 			 * Release the thread which is waiting for a request
493 			 * to be proccessed.
494 			 */
495 			nlp_event_nw(session);
496 		} else
497 			handler = handler->fh_next;
498 
499 	}
500 
501 	nlp_event_rv_set(session, 1);
502 	return (1);
503 }
504 
505 
506 /*
507  * ndmpd_save_env
508  *
509  * Saves a copy of the environment variable list from the data_start_backup
510  * request or data_start_recover request.
511  *
512  * Parameters:
513  *   session (input) - session pointer.
514  *   env     (input) - environment variable list to be saved.
515  *   envlen  (input) - length of variable array.
516  *
517  * Returns:
518  *   error code.
519  */
520 ndmp_error
521 ndmpd_save_env(ndmpd_session_t *session, ndmp_pval *env, ulong_t envlen)
522 {
523 	ulong_t i;
524 	char *namebuf;
525 	char *valbuf;
526 
527 	session->ns_data.dd_env_len = 0;
528 
529 	if (envlen == 0)
530 		return (NDMP_NO_ERR);
531 
532 	session->ns_data.dd_env = ndmp_malloc(sizeof (ndmp_pval) * envlen);
533 	if (session->ns_data.dd_env == 0)
534 		return (NDMP_NO_MEM_ERR);
535 
536 	for (i = 0; i < envlen; i++) {
537 		namebuf = strdup(env[i].name);
538 		if (namebuf == 0)
539 			return (NDMP_NO_MEM_ERR);
540 
541 		valbuf = strdup(env[i].value);
542 		if (valbuf == 0) {
543 			free(namebuf);
544 			return (NDMP_NO_MEM_ERR);
545 		}
546 
547 		NDMP_LOG(LOG_DEBUG, "env(%s): \"%s\"",
548 		    namebuf, valbuf);
549 
550 		(void) mutex_lock(&session->ns_lock);
551 		session->ns_data.dd_env[i].name = namebuf;
552 		session->ns_data.dd_env[i].value = valbuf;
553 		session->ns_data.dd_env_len++;
554 		(void) mutex_unlock(&session->ns_lock);
555 	}
556 
557 	return (NDMP_NO_ERR);
558 }
559 
560 
561 /*
562  * ndmpd_free_env
563  *
564  * Free the previously saved environment variable array.
565  *
566  * Parameters:
567  *   session - NDMP session pointer.
568  *
569  * Returns:
570  *   void.
571  */
572 void
573 ndmpd_free_env(ndmpd_session_t *session)
574 {
575 	ulong_t i;
576 	int count = session->ns_data.dd_env_len;
577 
578 	(void) mutex_lock(&session->ns_lock);
579 	session->ns_data.dd_env_len = 0;
580 	for (i = 0; i < count; i++) {
581 		free(session->ns_data.dd_env[i].name);
582 		free(session->ns_data.dd_env[i].value);
583 	}
584 
585 	free((char *)session->ns_data.dd_env);
586 	session->ns_data.dd_env = 0;
587 	(void) mutex_unlock(&session->ns_lock);
588 }
589 
590 
591 /*
592  * ndmpd_save_nlist_v2
593  *
594  * Save a copy of list of file names to be restored.
595  *
596  * Parameters:
597  *   nlist    (input) - name list from data_start_recover request.
598  *   nlistlen (input) - length of name list.
599  *
600  * Returns:
601  *   array of file name pointers.
602  *
603  * Notes:
604  *   free_nlist should be called to free the returned list.
605  *   A null pointer indicates the end of the list.
606  */
607 ndmp_error
608 ndmpd_save_nlist_v2(ndmpd_session_t *session, ndmp_name *nlist,
609     ulong_t nlistlen)
610 {
611 	ulong_t i;
612 	char *namebuf;
613 	char *destbuf;
614 
615 	if (nlistlen == 0)
616 		return (NDMP_NO_ERR);
617 
618 	session->ns_data.dd_nlist_len = 0;
619 	session->ns_data.dd_nlist = ndmp_malloc(sizeof (ndmp_name)*nlistlen);
620 	if (session->ns_data.dd_nlist == 0)
621 		return (NDMP_NO_MEM_ERR);
622 
623 	for (i = 0; i < nlistlen; i++) {
624 		namebuf = ndmp_malloc(strlen(nlist[i].name) + 1);
625 		if (namebuf == 0)
626 			return (NDMP_NO_MEM_ERR);
627 
628 		destbuf = ndmp_malloc(strlen(nlist[i].dest) + 1);
629 		if (destbuf == 0) {
630 			free(namebuf);
631 			return (NDMP_NO_MEM_ERR);
632 		}
633 		(void) strlcpy(namebuf, nlist[i].name,
634 		    strlen(nlist[i].name) + 1);
635 		(void) strlcpy(destbuf, nlist[i].dest,
636 		    strlen(nlist[i].dest) + 1);
637 
638 		session->ns_data.dd_nlist[i].name = namebuf;
639 		session->ns_data.dd_nlist[i].dest = destbuf;
640 		session->ns_data.dd_nlist[i].ssid = nlist[i].ssid;
641 		session->ns_data.dd_nlist[i].fh_info = nlist[i].fh_info;
642 		session->ns_data.dd_nlist_len++;
643 	}
644 
645 	return (NDMP_NO_ERR);
646 }
647 
648 
649 /*
650  * ndmpd_free_nlist_v2
651  *
652  * Free a list created by ndmpd_save_nlist_v2.
653  *
654  * Parameters:
655  *   session (input) - session pointer.
656  *
657  * Returns:
658  *   void
659  */
660 void
661 ndmpd_free_nlist_v2(ndmpd_session_t *session)
662 {
663 	ulong_t i;
664 
665 	for (i = 0; i < session->ns_data.dd_nlist_len; i++) {
666 		free(session->ns_data.dd_nlist[i].name);
667 		free(session->ns_data.dd_nlist[i].dest);
668 	}
669 
670 	if (session->ns_data.dd_nlist != NULL)
671 		free((char *)session->ns_data.dd_nlist);
672 	session->ns_data.dd_nlist = 0;
673 	session->ns_data.dd_nlist_len = 0;
674 }
675 
676 
677 /*
678  * ndmpd_free_nlist_v3
679  *
680  * Free a list created by ndmpd_save_nlist_v3.
681  *
682  * Parameters:
683  *   session (input) - session pointer.
684  *
685  * Returns:
686  *   void
687  */
688 void
689 ndmpd_free_nlist_v3(ndmpd_session_t *session)
690 {
691 	ulong_t i;
692 	mem_ndmp_name_v3_t *tp; /* destination entry */
693 
694 	tp = session->ns_data.dd_nlist_v3;
695 	for (i = 0; i < session->ns_data.dd_nlist_len; tp++, i++) {
696 		NDMP_FREE(tp->nm3_opath);
697 		NDMP_FREE(tp->nm3_dpath);
698 		NDMP_FREE(tp->nm3_newnm);
699 	}
700 
701 	NDMP_FREE(session->ns_data.dd_nlist_v3);
702 	session->ns_data.dd_nlist_len = 0;
703 }
704 
705 
706 /*
707  * ndmpd_save_nlist_v3
708  *
709  * Save a copy of list of file names to be restored.
710  *
711  * Parameters:
712  *   nlist    (input) - name list from data_start_recover request.
713  *   nlistlen (input) - length of name list.
714  *
715  * Returns:
716  *   array of file name pointers.
717  *
718  * Notes:
719  *   free_nlist should be called to free the returned list.
720  *   A null pointer indicates the end of the list.
721  */
722 ndmp_error
723 ndmpd_save_nlist_v3(ndmpd_session_t *session, ndmp_name_v3 *nlist,
724     ulong_t nlistlen)
725 {
726 	ulong_t i;
727 	ndmp_error rv;
728 	ndmp_name_v3 *sp; /* source entry */
729 	mem_ndmp_name_v3_t *tp; /* destination entry */
730 
731 	if (nlistlen == 0)
732 		return (NDMP_ILLEGAL_ARGS_ERR);
733 
734 	session->ns_data.dd_nlist_len = 0;
735 	tp = session->ns_data.dd_nlist_v3 =
736 	    ndmp_malloc(sizeof (mem_ndmp_name_v3_t) * nlistlen);
737 	if (session->ns_data.dd_nlist_v3 == 0)
738 		return (NDMP_NO_MEM_ERR);
739 
740 	rv = NDMP_NO_ERR;
741 	sp = nlist;
742 	for (i = 0; i < nlistlen; tp++, sp++, i++) {
743 		tp->nm3_opath = strdup(sp->original_path);
744 		if (!tp->nm3_opath) {
745 			rv = NDMP_NO_MEM_ERR;
746 			break;
747 		}
748 		if (!*sp->destination_dir) {
749 			tp->nm3_dpath = NULL;
750 			/* In V4 destination dir cannot be NULL */
751 			if (session->ns_protocol_version == NDMPV4) {
752 				rv = NDMP_ILLEGAL_ARGS_ERR;
753 				break;
754 			}
755 		} else if (!(tp->nm3_dpath = strdup(sp->destination_dir))) {
756 			rv = NDMP_NO_MEM_ERR;
757 			break;
758 		}
759 		if (!*sp->new_name)
760 			tp->nm3_newnm = NULL;
761 		else if (!(tp->nm3_newnm = strdup(sp->new_name))) {
762 			rv = NDMP_NO_MEM_ERR;
763 			break;
764 		}
765 
766 		tp->nm3_node = quad_to_long_long(sp->node);
767 		tp->nm3_fh_info = quad_to_long_long(sp->fh_info);
768 		tp->nm3_err = NDMP_NO_ERR;
769 		session->ns_data.dd_nlist_len++;
770 
771 		NDMP_LOG(LOG_DEBUG, "orig \"%s\"", tp->nm3_opath);
772 		NDMP_LOG(LOG_DEBUG, "dest \"%s\"", NDMP_SVAL(tp->nm3_dpath));
773 		NDMP_LOG(LOG_DEBUG, "name \"%s\"", NDMP_SVAL(tp->nm3_newnm));
774 		NDMP_LOG(LOG_DEBUG, "node %lld", tp->nm3_node);
775 		NDMP_LOG(LOG_DEBUG, "fh_info %lld", tp->nm3_fh_info);
776 	}
777 
778 	if (rv != NDMP_NO_ERR)
779 		ndmpd_free_nlist_v3(session);
780 
781 	return (rv);
782 }
783 
784 
785 /*
786  * ndmpd_free_nlist
787  *
788  * Free the recovery list based on the version
789  *
790  * Parameters:
791  *   session (input) - session pointer.
792  *
793  * Returns:
794  *   void
795  */
796 void
797 ndmpd_free_nlist(ndmpd_session_t *session)
798 {
799 	switch (session->ns_protocol_version) {
800 	case 1:
801 	case 2:
802 		ndmpd_free_nlist_v2(session);
803 		break;
804 	case 3:
805 	case 4:
806 		ndmpd_free_nlist_v3(session);
807 		break;
808 
809 	default:
810 		NDMP_LOG(LOG_DEBUG, "Unknown version %d",
811 		    session->ns_protocol_version);
812 	}
813 }
814 
815 
816 /*
817  * fh_cmpv3
818  *
819  * Comparison function used in sorting the Nlist based on their
820  * file history info (offset of the entry on the tape)
821  *
822  * Parameters:
823  *   p (input) - pointer to P
824  *   q (input) - pointer to Q
825  *
826  * Returns:
827  *  -1: P < Q
828  *   0: P = Q
829  *   1: P > Q
830  */
831 static int
832 fh_cmpv3(const void *p,
833 		const void *q)
834 {
835 #define	FH_INFOV3(p)	(((mem_ndmp_name_v3_t *)p)->nm3_fh_info)
836 
837 	if (FH_INFOV3(p) < FH_INFOV3(q))
838 		return (-1);
839 	else if (FH_INFOV3(p) == FH_INFOV3(q))
840 		return (0);
841 	else
842 		return (1);
843 
844 #undef FH_INFOV3
845 }
846 
847 
848 /*
849  * ndmp_sort_nlist_v3
850  *
851  * Sort the recovery list based on their offset on the tape
852  *
853  * Parameters:
854  *   session (input) - session pointer.
855  *
856  * Returns:
857  *   void
858  */
859 void
860 ndmp_sort_nlist_v3(ndmpd_session_t *session)
861 {
862 	if (!session || session->ns_data.dd_nlist_len == 0 ||
863 	    !session->ns_data.dd_nlist_v3)
864 		return;
865 
866 	(void) qsort(session->ns_data.dd_nlist_v3,
867 	    session->ns_data.dd_nlist_len,
868 	    sizeof (mem_ndmp_name_v3_t), fh_cmpv3);
869 }
870 
871 
872 /*
873  * ndmp_send_reply
874  *
875  * Send the reply, check for error and print the msg if any error
876  * occured when sending the reply.
877  *
878  *   Parameters:
879  *     connection (input) - connection pointer.
880  *
881  *   Return:
882  *     void
883  */
884 void
885 ndmp_send_reply(ndmp_connection_t *connection, void *reply, char *msg)
886 {
887 	if (ndmp_send_response(connection, NDMP_NO_ERR, reply) < 0)
888 		NDMP_LOG(LOG_DEBUG, "%s", msg);
889 }
890 
891 
892 /*
893  * ndmp_mtioctl
894  *
895  * Performs numerous filemark operations.
896  *
897  * Parameters:
898  * 	fd - file descriptor of the device
899  *	cmd - filemark or record command
900  * 	count - the number of operations to be performed
901  */
902 int
903 ndmp_mtioctl(int fd, int cmd, int count)
904 {
905 	struct mtop mp;
906 
907 	mp.mt_op = cmd;
908 	mp.mt_count = count;
909 	if (ioctl(fd, MTIOCTOP, &mp) < 0) {
910 		NDMP_LOG(LOG_ERR, "Failed to send command to tape: %m.");
911 		return (-1);
912 	}
913 
914 	return (0);
915 }
916 
917 
918 /*
919  * quad_to_long_long
920  *
921  * Convert type quad to longlong_t
922  */
923 u_longlong_t
924 quad_to_long_long(ndmp_u_quad q)
925 {
926 	u_longlong_t ull;
927 
928 	ull = ((u_longlong_t)q.high << 32) + q.low;
929 	return (ull);
930 }
931 
932 
933 /*
934  * long_long_to_quad
935  *
936  * Convert long long to quad type
937  */
938 ndmp_u_quad
939 long_long_to_quad(u_longlong_t ull)
940 {
941 	ndmp_u_quad q;
942 
943 	q.high = (ulong_t)(ull >> 32);
944 	q.low = (ulong_t)ull;
945 	return (q);
946 }
947 
948 
949 /*
950  * ndmp_set_socket_nodelay
951  *
952  * Set the TCP socket option to nodelay mode
953  */
954 void
955 ndmp_set_socket_nodelay(int sock)
956 {
957 	int flag = 1;
958 
959 	(void) setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof (flag));
960 }
961 
962 
963 /*
964  * ndmp_set_socket_snd_buf
965  *
966  * Set the socket send buffer size
967  */
968 void
969 ndmp_set_socket_snd_buf(int sock, int size)
970 {
971 	if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0)
972 		NDMP_LOG(LOG_DEBUG, "SO_SNDBUF failed errno=%d", errno);
973 }
974 
975 
976 /*
977  * ndmp_set_socket_rcv_buf
978  *
979  * Set the socket receive buffer size
980  */
981 void
982 ndmp_set_socket_rcv_buf(int sock, int size)
983 {
984 	if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) < 0)
985 		NDMP_LOG(LOG_DEBUG, "SO_RCVBUF failed errno=%d", errno);
986 }
987 
988 /*
989  * ndmp_get_max_tok_seq
990  *
991  * Get the maximum permitted token sequence for token-based
992  * backups.
993  *
994  * Parameters:
995  *   void
996  *
997  * Returns:
998  *   ndmp_max_tok_seq
999  */
1000 int
1001 ndmp_get_max_tok_seq(void)
1002 {
1003 	return (ndmp_max_tok_seq);
1004 }
1005 
1006 /*
1007  * ndmp_buffer_get_size
1008  *
1009  * Return the NDMP transfer buffer size
1010  *
1011  * Parameters:
1012  *   session (input) - session pointer.
1013  *
1014  * Returns:
1015  *   buffer size
1016  */
1017 long
1018 ndmp_buffer_get_size(ndmpd_session_t *session)
1019 {
1020 	long xfer_size;
1021 
1022 	if (session == NULL)
1023 		return (0);
1024 
1025 	if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
1026 		xfer_size = atoi(ndmpd_get_prop_default(NDMP_MOVER_RECSIZE,
1027 		    "60"));
1028 		if (xfer_size > 0)
1029 			xfer_size *= KILOBYTE;
1030 		else
1031 			xfer_size = REMOTE_RECORD_SIZE;
1032 		NDMP_LOG(LOG_DEBUG, "Remote operation: %d", xfer_size);
1033 	} else {
1034 		NDMP_LOG(LOG_DEBUG,
1035 		    "Local operation: %lu", session->ns_mover.md_record_size);
1036 		if ((xfer_size = session->ns_mover.md_record_size) == 0)
1037 			xfer_size = MAX_RECORD_SIZE;
1038 	}
1039 
1040 	NDMP_LOG(LOG_DEBUG, "xfer_size: %d", xfer_size);
1041 	return (xfer_size);
1042 }
1043 
1044 
1045 /*
1046  * ndmp_lbr_init
1047  *
1048  * Initialize the LBR/NDMP backup parameters
1049  *
1050  * Parameters:
1051  *   session (input) - session pointer.
1052  *
1053  * Returns:
1054  *   0: on success
1055  *  -1: otherwise
1056  */
1057 int
1058 ndmp_lbr_init(ndmpd_session_t *session)
1059 {
1060 	if (session->ns_ndmp_lbr_params != NULL) {
1061 		NDMP_LOG(LOG_DEBUG, "ndmp_lbr_params already allocated.");
1062 		return (0);
1063 	}
1064 
1065 	session->ns_ndmp_lbr_params = ndmp_malloc(sizeof (ndmp_lbr_params_t));
1066 	if (session->ns_ndmp_lbr_params == NULL)
1067 		return (-1);
1068 
1069 	session->ns_ndmp_lbr_params->nlp_bkmap = -1;
1070 	session->ns_ndmp_lbr_params->nlp_session = session;
1071 	(void) cond_init(&session->ns_ndmp_lbr_params->nlp_cv, 0, NULL);
1072 	(void) mutex_init(&session->ns_lock, 0, NULL);
1073 	session->ns_nref = 0;
1074 	return (0);
1075 }
1076 
1077 
1078 /*
1079  * ndmp_lbr_cleanup
1080  *
1081  * Deallocate and cleanup all NDMP/LBR parameters
1082  *
1083  * Parameters:
1084  *   session (input) - session pointer.
1085  *
1086  * Returns:
1087  *   0: on success
1088  *  -1: otherwise
1089  */
1090 void
1091 ndmp_lbr_cleanup(ndmpd_session_t *session)
1092 {
1093 	/*
1094 	 * If in 3-way restore, the connection close is detected after
1095 	 * check in tape_read(), the reader thread of mover may wait forever
1096 	 * for the tape to be changed.  Force the reader thread to exit.
1097 	 */
1098 	nlp_event_rv_set(session, -2);
1099 	nlp_event_nw(session);
1100 
1101 	ndmpd_abort_marking_v2(session);
1102 	ndmp_stop_buffer_worker(session);
1103 	ndmp_waitfor_op(session);
1104 	ndmp_free_reader_writer_ipc(session);
1105 	if (session->ns_ndmp_lbr_params) {
1106 		if (session->ns_ndmp_lbr_params->nlp_bkmap != -1)
1107 			(void) dbm_free(session->ns_ndmp_lbr_params->nlp_bkmap);
1108 		tlm_release_list(session->ns_ndmp_lbr_params->nlp_exl);
1109 		tlm_release_list(session->ns_ndmp_lbr_params->nlp_inc);
1110 		(void) cond_destroy(&session->ns_ndmp_lbr_params->nlp_cv);
1111 	}
1112 
1113 	NDMP_FREE(session->ns_ndmp_lbr_params);
1114 }
1115 
1116 
1117 /*
1118  * nlp_ref_nw
1119  *
1120  * Increase the references to the NDMP/LBR parameter to prevent
1121  * unwanted release
1122  *
1123  * Parameters:
1124  *   session (input) - session pointer.
1125  *
1126  * Returns:
1127  *   void
1128  */
1129 void
1130 nlp_ref_nw(ndmpd_session_t *session)
1131 {
1132 	ndmp_lbr_params_t *nlp;
1133 
1134 	(void) mutex_lock(&nlp_mtx);
1135 	if ((nlp = ndmp_get_nlp(session)) != NULL) {
1136 		nlp->nlp_nw++;
1137 		NDMP_LOG(LOG_DEBUG, "nw: %d", nlp->nlp_nw);
1138 	} else
1139 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1140 	(void) mutex_unlock(&nlp_mtx);
1141 }
1142 
1143 
1144 /*
1145  * nlp_unref_nw
1146  *
1147  * Decrease the references to the NDMP/LBR parameter before
1148  * release
1149  *
1150  * Parameters:
1151  *   session (input) - session pointer.
1152  *
1153  * Returns:
1154  *   void
1155  */
1156 void
1157 nlp_unref_nw(ndmpd_session_t *session)
1158 {
1159 	ndmp_lbr_params_t *nlp;
1160 
1161 	(void) mutex_lock(&nlp_mtx);
1162 	if ((nlp = ndmp_get_nlp(session)) != NULL) {
1163 		NDMP_LOG(LOG_DEBUG, "nw: %d", nlp->nlp_nw);
1164 		if (nlp->nlp_nw > 0)
1165 			nlp->nlp_nw--;
1166 	} else
1167 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1168 	(void) mutex_unlock(&nlp_mtx);
1169 }
1170 
1171 
1172 /*
1173  * nlp_wait_nw
1174  *
1175  * Wait for a NDMP/LBR parameter to get available
1176  *
1177  * Parameters:
1178  *   session (input) - session pointer.
1179  *
1180  * Returns:
1181  *   void
1182  */
1183 void
1184 nlp_wait_nw(ndmpd_session_t *session)
1185 {
1186 	ndmp_lbr_params_t *nlp;
1187 
1188 	(void) mutex_lock(&nlp_mtx);
1189 	if ((nlp = ndmp_get_nlp(session)) != NULL) {
1190 		NDMP_LOG(LOG_DEBUG, "nw: %d", nlp->nlp_nw);
1191 		if (nlp->nlp_nw > 0) {
1192 			NDMP_LOG(LOG_DEBUG, "Waiting");
1193 			while ((nlp->nlp_flag & NLP_READY) == 0)
1194 				(void) cond_wait(&nlp->nlp_cv, &nlp_mtx);
1195 		}
1196 	} else
1197 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1198 	(void) mutex_unlock(&nlp_mtx);
1199 }
1200 
1201 
1202 /*
1203  * nlp_event_nw
1204  *
1205  * Signal that a NDMP/LBR parameter is available to wake up the
1206  * threads waiting on that
1207  *
1208  * Parameters:
1209  *   session (input) - session pointer.
1210  *
1211  * Returns:
1212  *   void
1213  */
1214 void
1215 nlp_event_nw(ndmpd_session_t *session)
1216 {
1217 	ndmp_lbr_params_t *nlp;
1218 
1219 	(void) mutex_lock(&nlp_mtx);
1220 	if ((nlp = ndmp_get_nlp(session)) != NULL) {
1221 		if (nlp->nlp_nw > 0) {
1222 			NDMP_LOG(LOG_DEBUG, "nw: %d", nlp->nlp_nw);
1223 			nlp->nlp_flag |= NLP_READY;
1224 			(void) cond_signal(&nlp->nlp_cv);
1225 		}
1226 	} else
1227 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1228 	(void) mutex_unlock(&nlp_mtx);
1229 }
1230 
1231 
1232 /*
1233  * nlp_event_rv_get
1234  *
1235  * Get the return value for each NLP
1236  *
1237  * Parameters:
1238  *   session (input) - session pointer.
1239  *
1240  * Returns:
1241  *   return value
1242  */
1243 int
1244 nlp_event_rv_get(ndmpd_session_t *session)
1245 {
1246 	ndmp_lbr_params_t *nlp;
1247 
1248 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1249 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1250 		return (0);
1251 	}
1252 
1253 	return (nlp->nlp_rv);
1254 }
1255 
1256 
1257 /*
1258  * nlp_event_rv_set
1259  *
1260  * Set the return value for an NLP
1261  *
1262  * Parameters:
1263  *   session (input) - session pointer.
1264  *   rv (input) - return value
1265  *
1266  * Returns:
1267  *   void
1268  */
1269 void
1270 nlp_event_rv_set(ndmpd_session_t *session,
1271     int rv)
1272 {
1273 	ndmp_lbr_params_t *nlp;
1274 
1275 	(void) mutex_lock(&nlp_mtx);
1276 	if (rv != 0)
1277 		NDMP_LOG(LOG_DEBUG, "rv: %d", rv);
1278 
1279 	if ((nlp = ndmp_get_nlp(session)) != NULL)
1280 		nlp->nlp_rv = rv;
1281 	else
1282 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1283 	(void) mutex_unlock(&nlp_mtx);
1284 }
1285 
1286 /*
1287  * is_buffer_erroneous
1288  *
1289  * Run a sanity check on the buffer
1290  *
1291  * returns:
1292  *   TRUE: if the buffer seems to have error
1293  *   FALSE: if the buffer is full and has valid data.
1294  */
1295 boolean_t
1296 is_buffer_erroneous(tlm_buffer_t *buf)
1297 {
1298 	boolean_t rv;
1299 
1300 	rv = (buf == NULL || buf->tb_eot || buf->tb_eof ||
1301 	    buf->tb_errno != 0);
1302 	if (rv) {
1303 		if (buf == NULL) {
1304 			NDMP_LOG(LOG_DEBUG, "buf == NULL");
1305 		} else {
1306 			NDMP_LOG(LOG_DEBUG, "eot: %u, eof: %u, errno: %d",
1307 			    buf->tb_eot, buf->tb_eof, buf->tb_errno);
1308 		}
1309 	}
1310 
1311 	return (rv);
1312 }
1313 
1314 /*
1315  * ndmp_execute_cdb
1316  *
1317  * Main SCSI CDB execution program, this is used by message handler
1318  * for the NDMP tape/SCSI execute CDB requests. This function uses
1319  * USCSI interface to run the CDB command and sets all the CDB parameters
1320  * in the SCSI query before calling the USCSI ioctl. The result of the
1321  * CDB is returned in two places:
1322  *    cmd.uscsi_status		The status of CDB execution
1323  *    cmd.uscsi_rqstatus	The status of sense requests
1324  *    reply.error		The general errno (ioctl)
1325  *
1326  * Parameters:
1327  *   session (input) - session pointer
1328  *   adapter_name (input) - name of SCSI adapter
1329  *   sid (input) - SCSI target ID
1330  *   lun (input) - LUN number
1331  *   request (input) - NDMP client CDB request
1332  *
1333  * Returns:
1334  *   void
1335  */
1336 /*ARGSUSED*/
1337 void
1338 ndmp_execute_cdb(ndmpd_session_t *session, char *adapter_name, int sid, int lun,
1339     ndmp_execute_cdb_request *request)
1340 {
1341 	ndmp_execute_cdb_reply reply;
1342 	struct uscsi_cmd cmd;
1343 	int fd;
1344 	struct open_list *olp;
1345 	char rq_buf[255];
1346 
1347 	(void) memset((void *)&cmd, 0, sizeof (cmd));
1348 	(void) memset((void *)&reply, 0, sizeof (reply));
1349 	(void) memset((void *)rq_buf, 0, sizeof (rq_buf));
1350 
1351 	if (request->flags == NDMP_SCSI_DATA_IN) {
1352 		cmd.uscsi_flags = USCSI_READ | USCSI_RQENABLE;
1353 		if ((cmd.uscsi_bufaddr =
1354 		    ndmp_malloc(request->datain_len)) == 0) {
1355 			reply.error = NDMP_NO_MEM_ERR;
1356 			if (ndmp_send_response(session->ns_connection,
1357 			    NDMP_NO_ERR, (void *)&reply) < 0)
1358 				NDMP_LOG(LOG_DEBUG, "error sending"
1359 				    " scsi_execute_cdb reply.");
1360 			return;
1361 		}
1362 
1363 		cmd.uscsi_buflen = request->datain_len;
1364 		cmd.uscsi_rqlen = sizeof (rq_buf);
1365 		cmd.uscsi_rqbuf = rq_buf;
1366 	} else if (request->flags == NDMP_SCSI_DATA_OUT) {
1367 		cmd.uscsi_flags = USCSI_WRITE;
1368 		cmd.uscsi_bufaddr = request->dataout.dataout_val;
1369 		cmd.uscsi_buflen = request->dataout.dataout_len;
1370 	} else {
1371 		cmd.uscsi_bufaddr = 0;
1372 		cmd.uscsi_buflen = 0;
1373 		cmd.uscsi_rqlen = sizeof (rq_buf);
1374 		cmd.uscsi_rqbuf = rq_buf;
1375 	}
1376 
1377 	cmd.uscsi_timeout = (request->timeout < 1000) ?
1378 	    1 : (request->timeout / 1000);
1379 
1380 	cmd.uscsi_cdb = (caddr_t)request->cdb.cdb_val;
1381 	cmd.uscsi_cdblen = request->cdb.cdb_len;
1382 
1383 	NDMP_LOG(LOG_DEBUG, "cmd: 0x%x, len: %d, flags: %d, datain_len: %d",
1384 	    request->cdb.cdb_val[0] & 0xff, request->cdb.cdb_len,
1385 	    request->flags, request->datain_len);
1386 	NDMP_LOG(LOG_DEBUG, "dataout_len: %d, timeout: %d",
1387 	    request->dataout.dataout_len, request->timeout);
1388 
1389 	if (request->cdb.cdb_len > 12) {
1390 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1391 		ndmp_send_reply(session->ns_connection, (void *) &reply,
1392 		    "sending execute_cdb reply");
1393 		if (request->flags == NDMP_SCSI_DATA_IN)
1394 			free(cmd.uscsi_bufaddr);
1395 		return;
1396 	}
1397 
1398 	reply.error = NDMP_NO_ERR;
1399 
1400 	if ((olp = ndmp_open_list_find(adapter_name, sid, lun)) != NULL) {
1401 		fd = olp->ol_fd;
1402 	} else {
1403 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
1404 		ndmp_send_reply(session->ns_connection, (void *) &reply,
1405 		    "sending execute_cdb reply");
1406 		if (request->flags == NDMP_SCSI_DATA_IN)
1407 			free(cmd.uscsi_bufaddr);
1408 		return;
1409 	}
1410 
1411 	if (ioctl(fd, USCSICMD, &cmd) < 0) {
1412 		NDMP_LOG(LOG_ERR, "Failed to send command to device: %m");
1413 		NDMP_LOG(LOG_DEBUG, "ioctl(USCSICMD) error: %m");
1414 		if (cmd.uscsi_status == 0)
1415 			reply.error = NDMP_IO_ERR;
1416 	}
1417 
1418 	reply.status = cmd.uscsi_status;
1419 
1420 	if (request->flags == NDMP_SCSI_DATA_IN) {
1421 		reply.datain.datain_len = cmd.uscsi_buflen;
1422 		reply.datain.datain_val = cmd.uscsi_bufaddr;
1423 	} else {
1424 		reply.dataout_len = request->dataout.dataout_len;
1425 	}
1426 
1427 	reply.ext_sense.ext_sense_len = cmd.uscsi_rqlen - cmd.uscsi_rqresid;
1428 	reply.ext_sense.ext_sense_val = rq_buf;
1429 
1430 	if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1431 	    (void *)&reply) < 0)
1432 		NDMP_LOG(LOG_DEBUG, "Error sending scsi_execute_cdb reply.");
1433 
1434 	if (request->flags == NDMP_SCSI_DATA_IN)
1435 		free(cmd.uscsi_bufaddr);
1436 }
1437 
1438 
1439 /*
1440  * ndmp_stop_local_reader
1441  *
1442  * Stops a mover reader thread (for local backup only)
1443  *
1444  * Parameters:
1445  *   session (input) - session pointer
1446  *   cmds (input) - reader/writer command struct
1447  *
1448  * Returns:
1449  *   void
1450  */
1451 void
1452 ndmp_stop_local_reader(ndmpd_session_t *session, tlm_commands_t *cmds)
1453 {
1454 	if (session != NULL) {
1455 		if (session->ns_data.dd_sock == -1) {
1456 			/*
1457 			 * 2-way restore.
1458 			 */
1459 			NDMP_LOG(LOG_DEBUG, "2-way restore");
1460 			if (cmds != NULL && cmds->tcs_reader_count > 0) {
1461 				nlp_event_rv_set(session, -2);
1462 				nlp_event_nw(session);
1463 			}
1464 		}
1465 	}
1466 }
1467 
1468 
1469 /*
1470  * Stops a mover reader thread (for remote backup only)
1471  *
1472  * Parameters:
1473  *   session (input) - session pointer
1474  *   cmds (input) - reader/writer command struct
1475  *
1476  * Returns:
1477  *   void
1478  */
1479 void
1480 ndmp_stop_remote_reader(ndmpd_session_t *session)
1481 {
1482 	if (session != NULL) {
1483 		if (session->ns_data.dd_sock >= 0) {
1484 			/*
1485 			 * 3-way restore.
1486 			 */
1487 			NDMP_LOG(LOG_DEBUG,
1488 			    "data.sock: %d", session->ns_data.dd_sock);
1489 			(void) close(session->ns_data.dd_sock);
1490 			session->ns_data.dd_sock = -1;
1491 		}
1492 	}
1493 }
1494 
1495 
1496 /*
1497  * ndmp_wait_for_reader
1498  *
1499  * Wait for a reader until get done (busy wait)
1500  */
1501 void
1502 ndmp_wait_for_reader(tlm_commands_t *cmds)
1503 {
1504 	if (cmds == NULL) {
1505 		NDMP_LOG(LOG_DEBUG, "cmds == NULL");
1506 	} else {
1507 		NDMP_LOG(LOG_DEBUG,
1508 		    "reader_count: %d", cmds->tcs_reader_count);
1509 
1510 		while (cmds->tcs_reader_count > 0)
1511 			(void) sleep(1);
1512 	}
1513 }
1514 
1515 
1516 /*
1517  * ndmp_open_list_find
1518  *
1519  * Find a specific device in the open list
1520  *
1521  * Parameters:
1522  *   dev (input) - device name
1523  *   sid (input) - SCSI target ID
1524  *   lun (input) - LUN number
1525  *
1526  * Returns:
1527  *   pointer to the open list entry
1528  */
1529 struct open_list *
1530 ndmp_open_list_find(char *dev, int sid, int lun)
1531 {
1532 	struct ol_head *olhp;
1533 	struct open_list *olp;
1534 
1535 	if (dev == NULL || *dev == '\0') {
1536 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1537 		return (NULL);
1538 	}
1539 
1540 	(void) mutex_lock(&ol_mutex);
1541 	olhp = &ol_head;
1542 	for (olp = LIST_FIRST(olhp); olp != NULL; olp = LIST_NEXT(olp, ol_q))
1543 		if (strcmp(olp->ol_devnm, dev) == 0 && olp->ol_sid == sid &&
1544 		    olp->ol_lun == lun) {
1545 			(void) mutex_unlock(&ol_mutex);
1546 			return (olp);
1547 		}
1548 
1549 	(void) mutex_unlock(&ol_mutex);
1550 	return (NULL);
1551 }
1552 
1553 
1554 /*
1555  * ndmp_open_list_add
1556  *
1557  * Add a specific device to the open list
1558  *
1559  * Parameters:
1560  *   conn (input) - connection pointer
1561  *   dev (input) - device name
1562  *   sid (input) - SCSI target ID
1563  *   lun (input) - LUN number
1564  *   fd (input) - the device file descriptor
1565  *
1566  * Returns:
1567  *   errno
1568  */
1569 int
1570 ndmp_open_list_add(ndmp_connection_t *conn, char *dev, int sid, int lun, int fd)
1571 {
1572 	int err;
1573 	struct ol_head *olhp;
1574 	struct open_list *olp;
1575 
1576 	if (dev == NULL || *dev == '\0') {
1577 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1578 		return (EINVAL);
1579 	}
1580 	NDMP_LOG(LOG_DEBUG,
1581 	    "conn: 0x%08x, dev: %s, sid: %d, lun: %d", conn, dev, sid, lun);
1582 
1583 	err = 0;
1584 	olhp = &ol_head;
1585 
1586 	if ((olp = ndmp_open_list_find(dev, sid, lun)) != NULL) {
1587 		NDMP_LOG(LOG_DEBUG, "already in list");
1588 		/*
1589 		 * The adapter handle can be opened many times by the clients.
1590 		 * Only when the target is set, we must check and reject the
1591 		 * open request if the device is already being used by another
1592 		 * session.
1593 		 */
1594 		if (sid == -1)
1595 			olp->ol_nref++;
1596 		else
1597 			err = EBUSY;
1598 	} else if ((olp = ndmp_malloc(sizeof (struct open_list))) == NULL) {
1599 		err = ENOMEM;
1600 	} else if ((olp->ol_devnm = strdup(dev)) == NULL) {
1601 		NDMP_LOG(LOG_ERR, "Out of memory.");
1602 		free(olp);
1603 		err = ENOMEM;
1604 	} else {
1605 		olp->cl_conn = conn;
1606 		olp->ol_nref = 1;
1607 		olp->ol_sid = sid;
1608 		olp->ol_lun = lun;
1609 		if (fd > 0)
1610 			olp->ol_fd = fd;
1611 		else
1612 			olp->ol_fd = -1;
1613 		(void) mutex_lock(&ol_mutex);
1614 		LIST_INSERT_HEAD(olhp, olp, ol_q);
1615 		(void) mutex_unlock(&ol_mutex);
1616 	}
1617 
1618 	return (err);
1619 }
1620 
1621 
1622 /*
1623  * ndmp_open_list_del
1624  *
1625  * Delete a specific device from the open list
1626  *
1627  * Parameters:
1628  *   dev (input) - device name
1629  *   sid (input) - SCSI target ID
1630  *   lun (input) - LUN number
1631  *
1632  * Returns:
1633  *   errno
1634  */
1635 int
1636 ndmp_open_list_del(char *dev, int sid, int lun)
1637 {
1638 	struct open_list *olp;
1639 
1640 	if (dev == NULL || *dev == '\0') {
1641 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1642 		return (EINVAL);
1643 	}
1644 	if ((olp = ndmp_open_list_find(dev, sid, lun)) == NULL) {
1645 		NDMP_LOG(LOG_DEBUG, "%s not found", dev);
1646 		return (ENOENT);
1647 	}
1648 
1649 	(void) mutex_lock(&ol_mutex);
1650 	if (--olp->ol_nref <= 0) {
1651 		NDMP_LOG(LOG_DEBUG,
1652 		    "Removed dev: %s, sid: %d, lun: %d", dev, sid, lun);
1653 		LIST_REMOVE(olp, ol_q);
1654 		free(olp->ol_devnm);
1655 		free(olp);
1656 	}
1657 	(void) mutex_unlock(&ol_mutex);
1658 
1659 	return (0);
1660 }
1661 
1662 
1663 /*
1664  * ndmp_open_list_release
1665  *
1666  * Close all the resources belonging to this connection.
1667  *
1668  * Parameters:
1669  *    ndmp_connection_t *conn : connection identifier
1670  *
1671  * Returns:
1672  *   void
1673  */
1674 void
1675 ndmp_open_list_release(ndmp_connection_t *conn)
1676 {
1677 	struct ol_head *olhp = &ol_head;
1678 	struct open_list *olp;
1679 	struct open_list *next;
1680 
1681 	(void) mutex_lock(&ol_mutex);
1682 	olp = LIST_FIRST(olhp);
1683 	while (olp != NULL) {
1684 		next = LIST_NEXT(olp, ol_q);
1685 		NDMP_LOG(LOG_DEBUG, "olp->conn 0x%08x", olp->cl_conn);
1686 		if (olp->cl_conn == conn) {
1687 			NDMP_LOG(LOG_DEBUG,
1688 			    "Removed dev: %s, sid: %d, lun: %d",
1689 			    olp->ol_devnm, olp->ol_sid, olp->ol_lun);
1690 			LIST_REMOVE(olp, ol_q);
1691 			if (olp->ol_fd > 0)
1692 				(void) close(olp->ol_fd);
1693 			free(olp->ol_devnm);
1694 			free(olp);
1695 		}
1696 		olp = next;
1697 	}
1698 	(void) mutex_unlock(&ol_mutex);
1699 }
1700 
1701 
1702 /*
1703  * ndmp_stop_buffer_worker
1704  *
1705  * Stop all reader and writer threads for a specific buffer.
1706  *
1707  * Parameters:
1708  *   session (input) - session pointer
1709  *
1710  * Returns:
1711  *   void
1712  */
1713 void
1714 ndmp_stop_buffer_worker(ndmpd_session_t *session)
1715 {
1716 	ndmp_lbr_params_t *nlp;
1717 	tlm_commands_t *cmds;
1718 
1719 	session->ns_tape.td_pos = 0;
1720 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1721 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1722 	} else {
1723 		cmds = &nlp->nlp_cmds;
1724 		if (cmds->tcs_command == NULL) {
1725 			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL");
1726 		} else {
1727 			cmds->tcs_reader = cmds->tcs_writer = TLM_ABORT;
1728 			cmds->tcs_command->tc_reader = TLM_ABORT;
1729 			cmds->tcs_command->tc_writer = TLM_ABORT;
1730 			while (cmds->tcs_reader_count > 0 ||
1731 			    cmds->tcs_writer_count > 0) {
1732 				NDMP_LOG(LOG_DEBUG,
1733 				    "trying to stop buffer worker");
1734 				(void) sleep(1);
1735 			}
1736 		}
1737 	}
1738 }
1739 
1740 
1741 /*
1742  * ndmp_stop_reader_thread
1743  *
1744  * Stop only the reader threads of a specific buffer
1745  *
1746  * Parameters:
1747  *   session (input) - session pointer
1748  *
1749  * Returns:
1750  *   void
1751  */
1752 void
1753 ndmp_stop_reader_thread(ndmpd_session_t *session)
1754 {
1755 	ndmp_lbr_params_t *nlp;
1756 	tlm_commands_t *cmds;
1757 
1758 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1759 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1760 	} else {
1761 		cmds = &nlp->nlp_cmds;
1762 		if (cmds->tcs_command == NULL) {
1763 			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL");
1764 		} else {
1765 			cmds->tcs_reader = TLM_ABORT;
1766 			cmds->tcs_command->tc_reader = TLM_ABORT;
1767 			while (cmds->tcs_reader_count > 0) {
1768 				NDMP_LOG(LOG_DEBUG,
1769 				    "trying to stop reader thread");
1770 				(void) sleep(1);
1771 			}
1772 		}
1773 	}
1774 }
1775 
1776 
1777 /*
1778  * ndmp_stop_reader_thread
1779  *
1780  * Stop only the writer threads of a specific buffer
1781  *
1782  * Parameters:
1783  *   session (input) - session pointer
1784  *
1785  * Returns:
1786  *   void
1787  */
1788 void
1789 ndmp_stop_writer_thread(ndmpd_session_t *session)
1790 {
1791 	ndmp_lbr_params_t *nlp;
1792 	tlm_commands_t *cmds;
1793 
1794 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1795 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1796 	} else {
1797 		cmds = &nlp->nlp_cmds;
1798 		if (cmds->tcs_command == NULL) {
1799 			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL");
1800 		} else {
1801 			cmds->tcs_writer = TLM_ABORT;
1802 			cmds->tcs_command->tc_writer = TLM_ABORT;
1803 			while (cmds->tcs_writer_count > 0) {
1804 				NDMP_LOG(LOG_DEBUG,
1805 				    "trying to stop writer thread");
1806 				(void) sleep(1);
1807 			}
1808 		}
1809 	}
1810 }
1811 
1812 
1813 /*
1814  * ndmp_free_reader_writer_ipc
1815  *
1816  * Free and release the reader/writer buffers and the IPC structure
1817  * for reader and writer threads.
1818  *
1819  * Parameters:
1820  *   session (input) - session pointer
1821  *
1822  * Returns:
1823  *   void
1824  */
1825 void
1826 ndmp_free_reader_writer_ipc(ndmpd_session_t *session)
1827 {
1828 	ndmp_lbr_params_t *nlp;
1829 	tlm_commands_t *cmds;
1830 
1831 	if ((nlp = ndmp_get_nlp(session)) != NULL) {
1832 		cmds = &nlp->nlp_cmds;
1833 		if (cmds->tcs_command != NULL) {
1834 			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command->tc_ref: %d",
1835 			    cmds->tcs_command->tc_ref);
1836 			tlm_release_reader_writer_ipc(cmds->tcs_command);
1837 		}
1838 	}
1839 }
1840 
1841 
1842 /*
1843  * ndmp_waitfor_op
1844  *
1845  * Wait for a session reference count to drop to zero
1846  *
1847  * Parameters:
1848  *   session (input) - session pointer
1849  *
1850  * Returns:
1851  *   void
1852  */
1853 void
1854 ndmp_waitfor_op(ndmpd_session_t *session)
1855 {
1856 	if (session != NULL) {
1857 		while (session->ns_nref > 0) {
1858 			(void) sleep(1);
1859 			NDMP_LOG(LOG_DEBUG,
1860 			    "waiting for session nref: %d", session->ns_nref);
1861 		}
1862 	}
1863 }
1864 
1865 
1866 /*
1867  * ndmp_session_ref
1868  *
1869  * Increment the reference count of the session
1870  *
1871  * Parameters:
1872  *   session (input) - session pointer
1873  *
1874  * Returns:
1875  *   void
1876  */
1877 void
1878 ndmp_session_ref(ndmpd_session_t *session)
1879 {
1880 	(void) mutex_lock(&session->ns_lock);
1881 	session->ns_nref++;
1882 	(void) mutex_unlock(&session->ns_lock);
1883 }
1884 
1885 
1886 /*
1887  * ndmp_session_unref
1888  *
1889  * Decrement the reference count of the session
1890  *
1891  * Parameters:
1892  *   session (input) - session pointer
1893  *
1894  * Returns:
1895  *   void
1896  */
1897 void
1898 ndmp_session_unref(ndmpd_session_t *session)
1899 {
1900 	(void) mutex_lock(&session->ns_lock);
1901 	session->ns_nref--;
1902 	(void) mutex_unlock(&session->ns_lock);
1903 }
1904 
1905 
1906 /*
1907  * ndmp_addr2str_v3
1908  *
1909  * Convert the address type to a string
1910  *
1911  * Parameters:
1912  *   type (input) - address type
1913  *
1914  * Returns:
1915  *   type in string
1916  */
1917 char *
1918 ndmp_addr2str_v3(ndmp_addr_type type)
1919 {
1920 	char *rv;
1921 
1922 	switch (type) {
1923 	case NDMP_ADDR_LOCAL:
1924 		rv = "Local";
1925 		break;
1926 	case NDMP_ADDR_TCP:
1927 		rv = "TCP";
1928 		break;
1929 	case NDMP_ADDR_FC:
1930 		rv = "FC";
1931 		break;
1932 	case NDMP_ADDR_IPC:
1933 		rv = "IPC";
1934 		break;
1935 	default:
1936 		rv = "Unknown";
1937 	}
1938 
1939 	return (rv);
1940 }
1941 
1942 
1943 /*
1944  * ndmp_valid_v3addr_type
1945  *
1946  * Make sure that the NDMP address is from any of the
1947  * valid types
1948  *
1949  * Parameters:
1950  *   type (input) - address type
1951  *
1952  * Returns:
1953  *   1: valid
1954  *   0: invalid
1955  */
1956 boolean_t
1957 ndmp_valid_v3addr_type(ndmp_addr_type type)
1958 {
1959 	boolean_t rv;
1960 
1961 	switch (type) {
1962 	case NDMP_ADDR_LOCAL:
1963 	case NDMP_ADDR_TCP:
1964 	case NDMP_ADDR_FC:
1965 	case NDMP_ADDR_IPC:
1966 		rv = TRUE;
1967 		break;
1968 	default:
1969 		rv = FALSE;
1970 	}
1971 
1972 	return (rv);
1973 }
1974 
1975 
1976 /*
1977  * ndmp_copy_addr_v3
1978  *
1979  * Copy NDMP address from source to destination (V2 and V3 only)
1980  *
1981  * Parameters:
1982  *   dst (ouput) - destination address
1983  *   src (input) - source address
1984  *
1985  * Returns:
1986  *   void
1987  */
1988 void
1989 ndmp_copy_addr_v3(ndmp_addr_v3 *dst, ndmp_addr_v3 *src)
1990 {
1991 	dst->addr_type = src->addr_type;
1992 	switch (src->addr_type) {
1993 	case NDMP_ADDR_LOCAL:
1994 		/* nothing */
1995 		break;
1996 	case NDMP_ADDR_TCP:
1997 		dst->tcp_ip_v3 = htonl(src->tcp_ip_v3);
1998 		dst->tcp_port_v3 = src->tcp_port_v3;
1999 		break;
2000 	case NDMP_ADDR_FC:
2001 	case NDMP_ADDR_IPC:
2002 	default:
2003 		break;
2004 	}
2005 }
2006 
2007 
2008 /*
2009  * ndmp_copy_addr_v4
2010  *
2011  * Copy NDMP address from source to destination. V4 has a extra
2012  * environment list inside the address too which needs to be copied.
2013  *
2014  * Parameters:
2015  *   dst (ouput) - destination address
2016  *   src (input) - source address
2017  *
2018  * Returns:
2019  *   void
2020  */
2021 void
2022 ndmp_copy_addr_v4(ndmp_addr_v4 *dst, ndmp_addr_v4 *src)
2023 {
2024 	int i;
2025 
2026 	dst->addr_type = src->addr_type;
2027 	dst->tcp_len_v4 = src->tcp_len_v4;
2028 	switch (src->addr_type) {
2029 	case NDMP_ADDR_LOCAL:
2030 		/* nothing */
2031 		break;
2032 	case NDMP_ADDR_TCP:
2033 		dst->tcp_addr_v4 = ndmp_malloc(sizeof (ndmp_tcp_addr_v4) *
2034 		    src->tcp_len_v4);
2035 		if (dst->tcp_addr_v4 == 0)
2036 			return;
2037 
2038 		for (i = 0; i < src->tcp_len_v4; i++) {
2039 			dst->tcp_ip_v4(i) = htonl(src->tcp_ip_v4(i));
2040 			dst->tcp_port_v4(i) = src->tcp_port_v4(i);
2041 			dst->tcp_env_v4(i).addr_env_len = 0; /* Solaris */
2042 			dst->tcp_env_v4(i).addr_env_val = 0; /* Solaris */
2043 		}
2044 		break;
2045 	case NDMP_ADDR_FC:
2046 	case NDMP_ADDR_IPC:
2047 	default:
2048 		break;
2049 	}
2050 }
2051 
2052 
2053 /*
2054  * ndmp_connect_sock_v3
2055  *
2056  * Creates a socket and connects to the specified address/port
2057  *
2058  * Parameters:
2059  *   addr (input) - IP address
2060  *   port (input) - port number
2061  *
2062  * Returns:
2063  *   0: on success
2064  *  -1: otherwise
2065  */
2066 int
2067 ndmp_connect_sock_v3(ulong_t addr, ushort_t port)
2068 {
2069 	int sock;
2070 	struct sockaddr_in sin;
2071 	int flag = 1;
2072 
2073 	NDMP_LOG(LOG_DEBUG, "addr %s:%d", inet_ntoa(IN_ADDR(addr)), port);
2074 
2075 	sock = socket(AF_INET, SOCK_STREAM, 0);
2076 	if (sock < 0) {
2077 		NDMP_LOG(LOG_DEBUG, "Socket error: %m");
2078 		return (-1);
2079 	}
2080 
2081 	(void) memset((void *) &sin, 0, sizeof (sin));
2082 	sin.sin_family = AF_INET;
2083 	sin.sin_addr.s_addr = htonl(addr);
2084 	sin.sin_port = htons(port);
2085 	if (connect(sock, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
2086 		NDMP_LOG(LOG_DEBUG, "Connect error: %m");
2087 		(void) close(sock);
2088 		sock = -1;
2089 	} else {
2090 		if (ndmp_sbs > 0)
2091 			ndmp_set_socket_snd_buf(sock, ndmp_sbs*KILOBYTE);
2092 		if (ndmp_rbs > 0)
2093 			ndmp_set_socket_rcv_buf(sock, ndmp_rbs*KILOBYTE);
2094 
2095 		ndmp_set_socket_nodelay(sock);
2096 		(void) setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &flag,
2097 		    sizeof (flag));
2098 
2099 		NDMP_LOG(LOG_DEBUG, "sock %d", sock);
2100 	}
2101 
2102 	return (sock);
2103 }
2104 
2105 /*
2106  * ndmp_create_socket
2107  *
2108  * Creates a socket for listening for accepting data connections.
2109  *
2110  * Parameters:
2111  *   session (input)  - session pointer.
2112  *   addr    (output) - location to store address of socket.
2113  *   port    (output) - location to store port of socket.
2114  *
2115  * Returns:
2116  *   0 - success.
2117  *  -1 - error.
2118  */
2119 int
2120 ndmp_create_socket(ulong_t *addr, ushort_t *port)
2121 {
2122 	char *p;
2123 	int length;
2124 	int sd;
2125 	struct sockaddr_in sin;
2126 
2127 	p = ndmpd_get_prop(NDMP_MOVER_NIC);
2128 
2129 	if (!p || *p == 0)
2130 		p = gethostaddr();
2131 
2132 	if (!p) {
2133 		NDMP_LOG(LOG_ERR, "Undetermined network port.");
2134 		return (-1);
2135 	}
2136 
2137 	*addr = inet_addr(p);
2138 
2139 	sd = socket(AF_INET, SOCK_STREAM, 0);
2140 	if (sd < 0) {
2141 		NDMP_LOG(LOG_DEBUG, "Socket error: %m");
2142 		return (-1);
2143 	}
2144 	sin.sin_family = AF_INET;
2145 	sin.sin_addr.s_addr = INADDR_ANY;
2146 	sin.sin_port = 0;
2147 	length = sizeof (sin);
2148 
2149 	if (bind(sd, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
2150 		NDMP_LOG(LOG_DEBUG, "Bind error: %m");
2151 		(void) close(sd);
2152 		sd = -1;
2153 	} else if (getsockname(sd, (struct sockaddr *)&sin, &length) < 0) {
2154 		NDMP_LOG(LOG_DEBUG, "getsockname error: %m");
2155 		(void) close(sd);
2156 		sd = -1;
2157 	} else if (listen(sd, 5) < 0) {
2158 		NDMP_LOG(LOG_DEBUG, "Listen error: %m");
2159 		(void) close(sd);
2160 		sd = -1;
2161 	} else
2162 		*port = sin.sin_port;
2163 
2164 	return (sd);
2165 }
2166 
2167 
2168 /*
2169  * cctime
2170  *
2171  * Convert the specified time into a string.  It's like
2172  * ctime(), but:
2173  *     - chops the trailing '\n' of ctime.
2174  *     - and returns "the epoch" if time is 0.
2175  *
2176  * Returns:
2177  *     "": invalid argument.
2178  *     "the epoch": if time is 0.
2179  *     string format of the time.
2180  */
2181 char *
2182 cctime(time_t *t)
2183 {
2184 	char *bp, *cp;
2185 	char tbuf[BUFSIZ];
2186 
2187 	if (!t)
2188 		return ("");
2189 
2190 	if (*t == (time_t)0)
2191 		return ("the epoch");
2192 
2193 	bp = ctime_r(t, tbuf, BUFSIZ);
2194 	cp = strchr(bp, '\n');
2195 	if (cp)
2196 		*cp = '\0';
2197 
2198 	return (bp);
2199 }
2200 
2201 
2202 /*
2203  * ndmp_new_job_name
2204  *
2205  * Create a job name for each backup/restore to keep track
2206  *
2207  * Parameters:
2208  *   jname (output) - job name
2209  *
2210  * Returns:
2211  *   jname
2212  */
2213 char *
2214 ndmp_new_job_name(char *jname)
2215 {
2216 	if (jname != NULL) {
2217 		(void) snprintf(jname, TLM_MAX_BACKUP_JOB_NAME, "%s%d",
2218 		    NDMP_RCF_BASENAME, ndmp_job_cnt++);
2219 		NDMP_LOG(LOG_DEBUG, "jname: \"%s\"", jname);
2220 	}
2221 
2222 	return (jname);
2223 }
2224 
2225 
2226 /*
2227  * fs_is_valid_logvol
2228  *
2229  * Check if the log path exists
2230  *
2231  * Parameters:
2232  *   path (input) - log path
2233  *
2234  * Returns:
2235  *   FALSE: invalid
2236  *   TRUE: valid
2237  */
2238 boolean_t
2239 fs_is_valid_logvol(char *path)
2240 {
2241 	struct stat64 st;
2242 
2243 	if (stat64(path, &st) < 0)
2244 		return (FALSE);
2245 
2246 	return (TRUE);
2247 }
2248 
2249 
2250 /*
2251  * ndmpd_mk_temp
2252  *
2253  * Make a temporary file using the working directory path and the
2254  * jobname
2255  *
2256  * Parameters:
2257  *   buf (output) - the temporary file name path
2258  *
2259  * Returns:
2260  *   buf
2261  */
2262 char *
2263 ndmpd_mk_temp(char *buf)
2264 {
2265 	char fname[TLM_MAX_BACKUP_JOB_NAME];
2266 	const char *dir;
2267 	char *rv;
2268 
2269 	if (!buf)
2270 		return (NULL);
2271 
2272 	dir = ndmpd_get_prop(NDMP_DEBUG_PATH);
2273 	if (dir == 0 || *dir == '\0') {
2274 		NDMP_LOG(LOG_DEBUG, "NDMP work path not specified");
2275 		return (0);
2276 	}
2277 
2278 	if (!fs_is_valid_logvol((char *)dir)) {
2279 		NDMP_LOG(LOG_ERR,
2280 		    "Log file path cannot be on system volumes.");
2281 		return (0);
2282 	}
2283 
2284 	dir += strspn(dir, " \t");
2285 	if (!*dir) {
2286 		NDMP_LOG(LOG_DEBUG, "NDMP work path not specified");
2287 		return (0);
2288 	}
2289 
2290 	rv = buf;
2291 	(void) ndmp_new_job_name(fname);
2292 	(void) tlm_cat_path(buf, (char *)dir, fname);
2293 
2294 	return (rv);
2295 }
2296 
2297 
2298 /*
2299  * ndmpd_make_bk_dir_path
2300  *
2301  * Make a directory path for temporary files under the NDMP
2302  * working directory.
2303  *
2304  * Parameters:
2305  *   buf (output) - result path
2306  *   fname (input) - the file name
2307  *
2308  * Returns:
2309  *   buf
2310  */
2311 char *
2312 ndmpd_make_bk_dir_path(char *buf, char *fname)
2313 {
2314 	const char *p;
2315 	char *name;
2316 	char path[PATH_MAX];
2317 
2318 	if (!buf || !fname || !*fname)
2319 		return (NULL);
2320 
2321 	p = ndmpd_get_prop(NDMP_DEBUG_PATH);
2322 	if (p == NULL || *p == '\0' || !fs_is_valid_logvol((char *)p)) {
2323 		return (NULL);
2324 	}
2325 
2326 	(void) strlcpy(path, (char *)p, PATH_MAX);
2327 	(void) trim_whitespace(path);
2328 
2329 	if ((name = strrchr(fname, '/')) == 0)
2330 		name = fname;
2331 
2332 	(void) tlm_cat_path(buf, path, name);
2333 	return (buf);
2334 }
2335 
2336 
2337 /*
2338  * ndmp_is_chkpnt_root
2339  *
2340  * Is this a root checkpoint (snapshot) directory.
2341  * Note: a temporary function
2342  */
2343 boolean_t
2344 ndmp_is_chkpnt_root(char *path)
2345 {
2346 	struct stat64 st;
2347 
2348 	if (stat64(path, &st) != 0) {
2349 		NDMP_LOG(LOG_DEBUG, "Couldn't stat path \"%s\"", path);
2350 		return (TRUE);
2351 	}
2352 	return (FALSE);
2353 }
2354 
2355 
2356 /*
2357  * ndmpd_make_exc_list
2358  *
2359  * Make a list of files that should not be backed up.
2360  *
2361  * Parameters:
2362  *   void
2363  *
2364  * Returns:
2365  *   list - array of character strings
2366  */
2367 char **
2368 ndmpd_make_exc_list(void)
2369 {
2370 	char *val, **cpp;
2371 	int i, n;
2372 
2373 	n = sizeof (exls);
2374 	if ((cpp = ndmp_malloc(n)) != NULL) {
2375 		for (i = 0; exls[i] != NULL; i++)
2376 			cpp[i] = exls[i];
2377 
2378 		/*
2379 		 * If ndmpd_get_prop returns NULL, the array will be
2380 		 * null-terminated.
2381 		 */
2382 		val = ndmpd_get_prop(NDMP_DEBUG_PATH);
2383 		cpp[i] = val;
2384 	}
2385 
2386 	return (cpp);
2387 }
2388 
2389 
2390 /*
2391  * ndmp_get_bk_dir_ino
2392  *
2393  * Get the inode number of the backup directory
2394  */
2395 int
2396 ndmp_get_bk_dir_ino(ndmp_lbr_params_t *nlp)
2397 {
2398 	int rv;
2399 	struct stat64 st;
2400 
2401 	if (stat64(nlp->nlp_backup_path, &st) != 0) {
2402 		rv = -1;
2403 		NDMP_LOG(LOG_DEBUG, "Getting inode # of \"%s\"",
2404 		    nlp->nlp_backup_path);
2405 	} else {
2406 		rv = 0;
2407 		nlp->nlp_bkdirino = st.st_ino;
2408 		NDMP_LOG(LOG_DEBUG, "nlp_bkdirino: %lu",
2409 		    (uint_t)nlp->nlp_bkdirino);
2410 	}
2411 
2412 	return (rv);
2413 }
2414 
2415 
2416 /*
2417  * ndmp_check_utf8magic
2418  *
2419  * Check if the magic string for exists in the tar header. This
2420  * magic string (which also indicates that the file names are in
2421  * UTF8 format) is used as a crest to indetify our own tapes.
2422  * This checking is always done before all restores except DAR
2423  * restores.
2424  */
2425 boolean_t
2426 ndmp_check_utf8magic(tlm_cmd_t *cmd)
2427 {
2428 	char *cp;
2429 	int err, len, actual_size;
2430 
2431 	if (cmd == NULL) {
2432 		NDMP_LOG(LOG_DEBUG, "cmd == NULL");
2433 		return (FALSE);
2434 	}
2435 	if (cmd->tc_buffers == NULL) {
2436 		NDMP_LOG(LOG_DEBUG, "cmd->tc_buffers == NULL");
2437 		return (FALSE);
2438 	}
2439 
2440 	/* wait until the first buffer gets full. */
2441 	tlm_buffer_in_buf_wait(cmd->tc_buffers);
2442 
2443 	err = actual_size = 0;
2444 	cp = tlm_get_read_buffer(RECORDSIZE, &err, cmd->tc_buffers,
2445 	    &actual_size);
2446 	if (cp == NULL) {
2447 		NDMP_LOG(LOG_DEBUG, "Can't read from buffers, err: %d", err);
2448 		return (FALSE);
2449 	}
2450 	len = strlen(NDMPUTF8MAGIC);
2451 	if (actual_size < len) {
2452 		NDMP_LOG(LOG_DEBUG, "Not enough data in the buffers");
2453 		return (FALSE);
2454 	}
2455 
2456 	return ((strncmp(cp, NDMPUTF8MAGIC, len) == 0) ? TRUE : FALSE);
2457 }
2458 
2459 
2460 /*
2461  * ndmp_get_cur_bk_time
2462  *
2463  * Get the backup checkpoint time.
2464  */
2465 int
2466 ndmp_get_cur_bk_time(ndmp_lbr_params_t *nlp, time_t *tp, char *jname)
2467 {
2468 	int err;
2469 
2470 	if (!nlp || !nlp->nlp_backup_path || !tp) {
2471 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
2472 		return (-1);
2473 	}
2474 
2475 	if (!fs_is_chkpnt_enabled(nlp->nlp_backup_path)) {
2476 		NDMP_LOG(LOG_DEBUG, "Not a chkpnt volume %s",
2477 		    nlp->nlp_backup_path);
2478 		*tp = time(NULL);
2479 		return (0);
2480 	}
2481 
2482 	err = tlm_get_chkpnt_time(nlp->nlp_backup_path, !NLP_ISCHKPNTED(nlp),
2483 	    tp, jname);
2484 	if (err != 0) {
2485 		NDMP_LOG(LOG_DEBUG, "Can't checkpoint time");
2486 	} else {
2487 		NDMP_LOG(LOG_DEBUG, "%s", cctime(tp));
2488 	}
2489 
2490 	return (err);
2491 }
2492 
2493 
2494 /*
2495  * get_relative_path
2496  */
2497 char *
2498 ndmp_get_relative_path(char *base, char *fullpath)
2499 {
2500 	char *p = fullpath;
2501 
2502 	if (!base || !*base)
2503 		return (fullpath);
2504 
2505 	while (*base) {
2506 		if (*base != *p)
2507 			break;
2508 		p++; base++;
2509 	}
2510 
2511 	if (*p == '/')
2512 		p++;
2513 
2514 	return ((*base) ? fullpath : p);
2515 }
2516 
2517 
2518 /*
2519  * ndmp_get_nlp
2520  *
2521  * Get NDMP local backup parameters
2522  *
2523  * Parameter:
2524  *   session cooke
2525  *
2526  * Returns:
2527  *   LBR structure
2528  */
2529 ndmp_lbr_params_t *
2530 ndmp_get_nlp(void *cookie)
2531 {
2532 	if (cookie == NULL)
2533 		return (NULL);
2534 
2535 	return (((ndmpd_session_t *)cookie)->ns_ndmp_lbr_params);
2536 }
2537 
2538 
2539 /*
2540  * is_tape_unit_ready
2541  *
2542  * Check if the tape device is ready or not
2543  */
2544 boolean_t
2545 is_tape_unit_ready(char *adptnm, int dev_id)
2546 {
2547 	int try;
2548 	int fd = 0;
2549 
2550 	try = TUR_MAX_TRY;
2551 	if (dev_id == 0)
2552 		fd = open(adptnm, O_RDONLY | O_NDELAY);
2553 	else
2554 		fd = dev_id;
2555 	do {
2556 		if (scsi_test_unit_ready(fd) >= 0) {
2557 			NDMP_LOG(LOG_DEBUG, "Unit is ready");
2558 
2559 			if (dev_id == 0)
2560 				(void) close(fd);
2561 
2562 			return (TRUE);
2563 		}
2564 
2565 		NDMP_LOG(LOG_DEBUG, "Unit not ready");
2566 		(void) usleep(TUR_WAIT);
2567 
2568 	} while (--try > 0);
2569 
2570 	if (dev_id == 0)
2571 		(void) close(fd);
2572 
2573 	NDMP_LOG(LOG_DEBUG, "Unit didn't get ready");
2574 	return (FALSE);
2575 }
2576 
2577 
2578 /*
2579  * scsi_test_unit_ready
2580  *
2581  * This is for Test Unit Read, without this function, the only
2582  * impact is getting EBUSY's before each operation which we have
2583  * busy waiting loops checking EBUSY error code.
2584  */
2585 static int
2586 scsi_test_unit_ready(int dev_id)
2587 {
2588 	struct uscsi_cmd ucmd;
2589 	union scsi_cdb cdb;
2590 	int retval;
2591 
2592 	(void) memset(&ucmd, 0, sizeof (struct uscsi_cmd));
2593 	(void) memset(&cdb, 0, sizeof (union scsi_cdb));
2594 	cdb.scc_cmd = SCMD_TEST_UNIT_READY;
2595 	ucmd.uscsi_cdb = (caddr_t)&cdb;
2596 	ucmd.uscsi_cdblen = CDB_GROUP0;
2597 	ucmd.uscsi_flags |= USCSI_SILENT;
2598 
2599 	retval = ioctl(dev_id, USCSICMD, &ucmd);
2600 
2601 	if (retval != 0 && errno != EIO) {
2602 		NDMP_LOG(LOG_ERR,
2603 		    "Failed to send inquiry request to device: %m.");
2604 		NDMP_LOG(LOG_DEBUG, "Inquiry request failed for"
2605 		    " dev_id:%d err=%d -%m", dev_id, errno);
2606 		retval = -errno;
2607 	} else
2608 		retval = -(ucmd.uscsi_status);
2609 
2610 	return (retval);
2611 }
2612 
2613 
2614 /*
2615  * ndmp_load_params
2616  *
2617  * Load the parameters.
2618  *
2619  * Parameter:
2620  *   void
2621  *
2622  * Returns:
2623  *   void
2624  */
2625 void
2626 ndmp_load_params(void)
2627 {
2628 	struct stat64 st;
2629 
2630 	ndmp_dump_path_node = ndmpd_get_prop_yorn(NDMP_DUMP_PATHNODE_ENV) ?
2631 	    TRUE : FALSE;
2632 	ndmp_tar_path_node = ndmpd_get_prop_yorn(NDMP_TAR_PATHNODE_ENV) ?
2633 	    TRUE : FALSE;
2634 	ndmp_ignore_ctime =
2635 	    ndmpd_get_prop_yorn(NDMP_IGNCTIME_ENV) ? TRUE : FALSE;
2636 	ndmp_include_lmtime = ndmpd_get_prop_yorn(NDMP_INCLMTIME_ENV) ?
2637 	    TRUE : FALSE;
2638 	ndmp_max_tok_seq = atoi(ndmpd_get_prop_default(NDMP_MAXSEQ_ENV, "9"));
2639 
2640 	ndmp_full_restore_path = ndmpd_get_prop_yorn(NDMP_FULL_RESTORE_PATH) ?
2641 	    TRUE : FALSE;
2642 
2643 	ndmp_fhinode = ndmpd_get_prop_yorn(NDMP_FHIST_INCR_ENV) ? TRUE : FALSE;
2644 
2645 	/* Get the value from ndmp SMF property. */
2646 	ndmp_dar_support = ndmpd_get_prop_yorn(NDMP_DAR_SUPPORT);
2647 
2648 	ndmp_log_path = ndmpd_get_prop(NDMP_DEBUG_PATH);
2649 	if ((ndmp_log_path == NULL) || (*ndmp_log_path == NULL))
2650 		ndmp_log_path = "/var/ndmp";
2651 
2652 	if (lstat64(ndmp_log_path, &st) < 0) {
2653 		if (mkdirp(ndmp_log_path, 0755) < 0)
2654 			NDMP_LOG(LOG_ERR, "Could not create log path %s: %m.",
2655 			    ndmp_log_path);
2656 	}
2657 
2658 	if ((ndmp_ver = atoi(ndmpd_get_prop(NDMP_VERSION_ENV))) == 0)
2659 		ndmp_ver = NDMPVER;
2660 }
2661 
2662 /*
2663  * randomize
2664  *
2665  * Randomize the contents of a buffer
2666  *
2667  * Parameter:
2668  *   buffer (output) - destination buffer
2669  *   size (input) - buffer size
2670  *
2671  * Returns:
2672  *   void
2673  */
2674 void
2675 randomize(unsigned char *buffer, int size)
2676 {
2677 	/* LINTED improper alignment */
2678 	unsigned int *p = (unsigned int *)buffer;
2679 	unsigned int dwlen = size / sizeof (unsigned int);
2680 	unsigned int remlen = size % sizeof (unsigned int);
2681 	unsigned int tmp;
2682 	unsigned int i;
2683 
2684 	for (i = 0; i < dwlen; i++)
2685 		*p++ = random();
2686 
2687 	if (remlen) {
2688 		tmp = random();
2689 		(void) memcpy(p, &tmp, remlen);
2690 	}
2691 }
2692 
2693 /*
2694  * ndmpd_get_file_entry_type
2695  *
2696  * Converts the mode to the NDMP file type
2697  *
2698  * Parameter:
2699  *   mode (input) - file mode
2700  *   ftype (output) - file type
2701  *
2702  * Returns:
2703  *   void
2704  */
2705 void
2706 ndmpd_get_file_entry_type(int mode, ndmp_file_type *ftype)
2707 {
2708 	switch (mode & S_IFMT) {
2709 	case S_IFIFO:
2710 		*ftype = NDMP_FILE_FIFO;
2711 		break;
2712 	case S_IFCHR:
2713 		*ftype = NDMP_FILE_CSPEC;
2714 		break;
2715 	case S_IFDIR:
2716 		*ftype = NDMP_FILE_DIR;
2717 		break;
2718 	case S_IFBLK:
2719 		*ftype = NDMP_FILE_BSPEC;
2720 		break;
2721 	case S_IFREG:
2722 		*ftype = NDMP_FILE_REG;
2723 		break;
2724 	case S_IFLNK:
2725 		*ftype = NDMP_FILE_SLINK;
2726 		break;
2727 	default:
2728 		*ftype = NDMP_FILE_SOCK;
2729 		break;
2730 	}
2731 }
2732 
2733 /*
2734  * Set a private data in the plugin context
2735  */
2736 void
2737 ndmp_context_set_specific(ndmp_context_t *nctx, void *ptr)
2738 {
2739 	nctx->nc_pldata = ptr;
2740 }
2741 
2742 /*
2743  * Get a private data in the plugin context
2744  */
2745 void *
2746 ndmp_context_get_specific(ndmp_context_t *nctx)
2747 {
2748 	return (nctx->nc_pldata);
2749 }
2750