xref: /titanic_52/usr/src/cmd/ndmpd/ndmp/ndmpd_util.c (revision a73c0fe4e90b82a478f821ef3adb5cf34f6a9346)
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 		/* LINTED: E_CONSTANT_CONDITION */
1615 		LIST_INSERT_HEAD(olhp, olp, ol_q);
1616 		(void) mutex_unlock(&ol_mutex);
1617 	}
1618 
1619 	return (err);
1620 }
1621 
1622 
1623 /*
1624  * ndmp_open_list_del
1625  *
1626  * Delete a specific device from the open list
1627  *
1628  * Parameters:
1629  *   dev (input) - device name
1630  *   sid (input) - SCSI target ID
1631  *   lun (input) - LUN number
1632  *
1633  * Returns:
1634  *   errno
1635  */
1636 int
1637 ndmp_open_list_del(char *dev, int sid, int lun)
1638 {
1639 	struct open_list *olp;
1640 
1641 	if (dev == NULL || *dev == '\0') {
1642 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1643 		return (EINVAL);
1644 	}
1645 	if ((olp = ndmp_open_list_find(dev, sid, lun)) == NULL) {
1646 		NDMP_LOG(LOG_DEBUG, "%s not found", dev);
1647 		return (ENOENT);
1648 	}
1649 
1650 	(void) mutex_lock(&ol_mutex);
1651 	if (--olp->ol_nref <= 0) {
1652 		NDMP_LOG(LOG_DEBUG,
1653 		    "Removed dev: %s, sid: %d, lun: %d", dev, sid, lun);
1654 		/* LINTED: E_CONSTANT_CONDITION */
1655 		LIST_REMOVE(olp, ol_q);
1656 		free(olp->ol_devnm);
1657 		free(olp);
1658 	}
1659 	(void) mutex_unlock(&ol_mutex);
1660 
1661 	return (0);
1662 }
1663 
1664 
1665 /*
1666  * ndmp_open_list_release
1667  *
1668  * Close all the resources belonging to this connection.
1669  *
1670  * Parameters:
1671  *    ndmp_connection_t *conn : connection identifier
1672  *
1673  * Returns:
1674  *   void
1675  */
1676 void
1677 ndmp_open_list_release(ndmp_connection_t *conn)
1678 {
1679 	struct ol_head *olhp = &ol_head;
1680 	struct open_list *olp;
1681 	struct open_list *next;
1682 
1683 	(void) mutex_lock(&ol_mutex);
1684 	olp = LIST_FIRST(olhp);
1685 	while (olp != NULL) {
1686 		next = LIST_NEXT(olp, ol_q);
1687 		NDMP_LOG(LOG_DEBUG, "olp->conn 0x%08x", olp->cl_conn);
1688 		if (olp->cl_conn == conn) {
1689 			NDMP_LOG(LOG_DEBUG,
1690 			    "Removed dev: %s, sid: %d, lun: %d",
1691 			    olp->ol_devnm, olp->ol_sid, olp->ol_lun);
1692 			/* LINTED: E_CONSTANT_CONDITION */
1693 			LIST_REMOVE(olp, ol_q);
1694 			if (olp->ol_fd > 0)
1695 				(void) close(olp->ol_fd);
1696 			free(olp->ol_devnm);
1697 			free(olp);
1698 		}
1699 		olp = next;
1700 	}
1701 	(void) mutex_unlock(&ol_mutex);
1702 }
1703 
1704 
1705 /*
1706  * ndmp_stop_buffer_worker
1707  *
1708  * Stop all reader and writer threads for a specific buffer.
1709  *
1710  * Parameters:
1711  *   session (input) - session pointer
1712  *
1713  * Returns:
1714  *   void
1715  */
1716 void
1717 ndmp_stop_buffer_worker(ndmpd_session_t *session)
1718 {
1719 	ndmp_lbr_params_t *nlp;
1720 	tlm_commands_t *cmds;
1721 
1722 	session->ns_tape.td_pos = 0;
1723 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1724 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1725 	} else {
1726 		cmds = &nlp->nlp_cmds;
1727 		if (cmds->tcs_command == NULL) {
1728 			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL");
1729 		} else {
1730 			cmds->tcs_reader = cmds->tcs_writer = TLM_ABORT;
1731 			cmds->tcs_command->tc_reader = TLM_ABORT;
1732 			cmds->tcs_command->tc_writer = TLM_ABORT;
1733 			while (cmds->tcs_reader_count > 0 ||
1734 			    cmds->tcs_writer_count > 0) {
1735 				NDMP_LOG(LOG_DEBUG,
1736 				    "trying to stop buffer worker");
1737 				(void) sleep(1);
1738 			}
1739 		}
1740 	}
1741 }
1742 
1743 
1744 /*
1745  * ndmp_stop_reader_thread
1746  *
1747  * Stop only the reader threads of a specific buffer
1748  *
1749  * Parameters:
1750  *   session (input) - session pointer
1751  *
1752  * Returns:
1753  *   void
1754  */
1755 void
1756 ndmp_stop_reader_thread(ndmpd_session_t *session)
1757 {
1758 	ndmp_lbr_params_t *nlp;
1759 	tlm_commands_t *cmds;
1760 
1761 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1762 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1763 	} else {
1764 		cmds = &nlp->nlp_cmds;
1765 		if (cmds->tcs_command == NULL) {
1766 			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL");
1767 		} else {
1768 			cmds->tcs_reader = TLM_ABORT;
1769 			cmds->tcs_command->tc_reader = TLM_ABORT;
1770 			while (cmds->tcs_reader_count > 0) {
1771 				NDMP_LOG(LOG_DEBUG,
1772 				    "trying to stop reader thread");
1773 				(void) sleep(1);
1774 			}
1775 		}
1776 	}
1777 }
1778 
1779 
1780 /*
1781  * ndmp_stop_reader_thread
1782  *
1783  * Stop only the writer threads of a specific buffer
1784  *
1785  * Parameters:
1786  *   session (input) - session pointer
1787  *
1788  * Returns:
1789  *   void
1790  */
1791 void
1792 ndmp_stop_writer_thread(ndmpd_session_t *session)
1793 {
1794 	ndmp_lbr_params_t *nlp;
1795 	tlm_commands_t *cmds;
1796 
1797 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1798 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1799 	} else {
1800 		cmds = &nlp->nlp_cmds;
1801 		if (cmds->tcs_command == NULL) {
1802 			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL");
1803 		} else {
1804 			cmds->tcs_writer = TLM_ABORT;
1805 			cmds->tcs_command->tc_writer = TLM_ABORT;
1806 			while (cmds->tcs_writer_count > 0) {
1807 				NDMP_LOG(LOG_DEBUG,
1808 				    "trying to stop writer thread");
1809 				(void) sleep(1);
1810 			}
1811 		}
1812 	}
1813 }
1814 
1815 
1816 /*
1817  * ndmp_free_reader_writer_ipc
1818  *
1819  * Free and release the reader/writer buffers and the IPC structure
1820  * for reader and writer threads.
1821  *
1822  * Parameters:
1823  *   session (input) - session pointer
1824  *
1825  * Returns:
1826  *   void
1827  */
1828 void
1829 ndmp_free_reader_writer_ipc(ndmpd_session_t *session)
1830 {
1831 	ndmp_lbr_params_t *nlp;
1832 	tlm_commands_t *cmds;
1833 
1834 	if ((nlp = ndmp_get_nlp(session)) != NULL) {
1835 		cmds = &nlp->nlp_cmds;
1836 		if (cmds->tcs_command != NULL) {
1837 			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command->tc_ref: %d",
1838 			    cmds->tcs_command->tc_ref);
1839 			tlm_release_reader_writer_ipc(cmds->tcs_command);
1840 		}
1841 	}
1842 }
1843 
1844 
1845 /*
1846  * ndmp_waitfor_op
1847  *
1848  * Wait for a session reference count to drop to zero
1849  *
1850  * Parameters:
1851  *   session (input) - session pointer
1852  *
1853  * Returns:
1854  *   void
1855  */
1856 void
1857 ndmp_waitfor_op(ndmpd_session_t *session)
1858 {
1859 	if (session != NULL) {
1860 		while (session->ns_nref > 0) {
1861 			(void) sleep(1);
1862 			NDMP_LOG(LOG_DEBUG,
1863 			    "waiting for session nref: %d", session->ns_nref);
1864 		}
1865 	}
1866 }
1867 
1868 
1869 /*
1870  * ndmp_session_ref
1871  *
1872  * Increment the reference count of the session
1873  *
1874  * Parameters:
1875  *   session (input) - session pointer
1876  *
1877  * Returns:
1878  *   void
1879  */
1880 void
1881 ndmp_session_ref(ndmpd_session_t *session)
1882 {
1883 	(void) mutex_lock(&session->ns_lock);
1884 	session->ns_nref++;
1885 	(void) mutex_unlock(&session->ns_lock);
1886 }
1887 
1888 
1889 /*
1890  * ndmp_session_unref
1891  *
1892  * Decrement the reference count of the session
1893  *
1894  * Parameters:
1895  *   session (input) - session pointer
1896  *
1897  * Returns:
1898  *   void
1899  */
1900 void
1901 ndmp_session_unref(ndmpd_session_t *session)
1902 {
1903 	(void) mutex_lock(&session->ns_lock);
1904 	session->ns_nref--;
1905 	(void) mutex_unlock(&session->ns_lock);
1906 }
1907 
1908 
1909 /*
1910  * ndmp_addr2str_v3
1911  *
1912  * Convert the address type to a string
1913  *
1914  * Parameters:
1915  *   type (input) - address type
1916  *
1917  * Returns:
1918  *   type in string
1919  */
1920 char *
1921 ndmp_addr2str_v3(ndmp_addr_type type)
1922 {
1923 	char *rv;
1924 
1925 	switch (type) {
1926 	case NDMP_ADDR_LOCAL:
1927 		rv = "Local";
1928 		break;
1929 	case NDMP_ADDR_TCP:
1930 		rv = "TCP";
1931 		break;
1932 	case NDMP_ADDR_FC:
1933 		rv = "FC";
1934 		break;
1935 	case NDMP_ADDR_IPC:
1936 		rv = "IPC";
1937 		break;
1938 	default:
1939 		rv = "Unknown";
1940 	}
1941 
1942 	return (rv);
1943 }
1944 
1945 
1946 /*
1947  * ndmp_valid_v3addr_type
1948  *
1949  * Make sure that the NDMP address is from any of the
1950  * valid types
1951  *
1952  * Parameters:
1953  *   type (input) - address type
1954  *
1955  * Returns:
1956  *   1: valid
1957  *   0: invalid
1958  */
1959 boolean_t
1960 ndmp_valid_v3addr_type(ndmp_addr_type type)
1961 {
1962 	boolean_t rv;
1963 
1964 	switch (type) {
1965 	case NDMP_ADDR_LOCAL:
1966 	case NDMP_ADDR_TCP:
1967 	case NDMP_ADDR_FC:
1968 	case NDMP_ADDR_IPC:
1969 		rv = TRUE;
1970 		break;
1971 	default:
1972 		rv = FALSE;
1973 	}
1974 
1975 	return (rv);
1976 }
1977 
1978 
1979 /*
1980  * ndmp_copy_addr_v3
1981  *
1982  * Copy NDMP address from source to destination (V2 and V3 only)
1983  *
1984  * Parameters:
1985  *   dst (ouput) - destination address
1986  *   src (input) - source address
1987  *
1988  * Returns:
1989  *   void
1990  */
1991 void
1992 ndmp_copy_addr_v3(ndmp_addr_v3 *dst, ndmp_addr_v3 *src)
1993 {
1994 	dst->addr_type = src->addr_type;
1995 	switch (src->addr_type) {
1996 	case NDMP_ADDR_LOCAL:
1997 		/* nothing */
1998 		break;
1999 	case NDMP_ADDR_TCP:
2000 		dst->tcp_ip_v3 = htonl(src->tcp_ip_v3);
2001 		dst->tcp_port_v3 = src->tcp_port_v3;
2002 		break;
2003 	case NDMP_ADDR_FC:
2004 	case NDMP_ADDR_IPC:
2005 	default:
2006 		break;
2007 	}
2008 }
2009 
2010 
2011 /*
2012  * ndmp_copy_addr_v4
2013  *
2014  * Copy NDMP address from source to destination. V4 has a extra
2015  * environment list inside the address too which needs to be copied.
2016  *
2017  * Parameters:
2018  *   dst (ouput) - destination address
2019  *   src (input) - source address
2020  *
2021  * Returns:
2022  *   void
2023  */
2024 void
2025 ndmp_copy_addr_v4(ndmp_addr_v4 *dst, ndmp_addr_v4 *src)
2026 {
2027 	int i;
2028 
2029 	dst->addr_type = src->addr_type;
2030 	dst->tcp_len_v4 = src->tcp_len_v4;
2031 	switch (src->addr_type) {
2032 	case NDMP_ADDR_LOCAL:
2033 		/* nothing */
2034 		break;
2035 	case NDMP_ADDR_TCP:
2036 		dst->tcp_addr_v4 = ndmp_malloc(sizeof (ndmp_tcp_addr_v4) *
2037 		    src->tcp_len_v4);
2038 		if (dst->tcp_addr_v4 == 0)
2039 			return;
2040 
2041 		for (i = 0; i < src->tcp_len_v4; i++) {
2042 			dst->tcp_ip_v4(i) = htonl(src->tcp_ip_v4(i));
2043 			dst->tcp_port_v4(i) = src->tcp_port_v4(i);
2044 			dst->tcp_env_v4(i).addr_env_len = 0; /* Solaris */
2045 			dst->tcp_env_v4(i).addr_env_val = 0; /* Solaris */
2046 		}
2047 		break;
2048 	case NDMP_ADDR_FC:
2049 	case NDMP_ADDR_IPC:
2050 	default:
2051 		break;
2052 	}
2053 }
2054 
2055 
2056 /*
2057  * ndmp_connect_sock_v3
2058  *
2059  * Creates a socket and connects to the specified address/port
2060  *
2061  * Parameters:
2062  *   addr (input) - IP address
2063  *   port (input) - port number
2064  *
2065  * Returns:
2066  *   0: on success
2067  *  -1: otherwise
2068  */
2069 int
2070 ndmp_connect_sock_v3(ulong_t addr, ushort_t port)
2071 {
2072 	int sock;
2073 	struct sockaddr_in sin;
2074 	int flag = 1;
2075 
2076 	NDMP_LOG(LOG_DEBUG, "addr %s:%d", inet_ntoa(IN_ADDR(addr)), port);
2077 
2078 	sock = socket(AF_INET, SOCK_STREAM, 0);
2079 	if (sock < 0) {
2080 		NDMP_LOG(LOG_DEBUG, "Socket error: %m");
2081 		return (-1);
2082 	}
2083 
2084 	(void) memset((void *) &sin, 0, sizeof (sin));
2085 	sin.sin_family = AF_INET;
2086 	sin.sin_addr.s_addr = htonl(addr);
2087 	sin.sin_port = htons(port);
2088 	if (connect(sock, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
2089 		NDMP_LOG(LOG_DEBUG, "Connect error: %m");
2090 		(void) close(sock);
2091 		sock = -1;
2092 	} else {
2093 		if (ndmp_sbs > 0)
2094 			ndmp_set_socket_snd_buf(sock, ndmp_sbs*KILOBYTE);
2095 		if (ndmp_rbs > 0)
2096 			ndmp_set_socket_rcv_buf(sock, ndmp_rbs*KILOBYTE);
2097 
2098 		ndmp_set_socket_nodelay(sock);
2099 		(void) setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &flag,
2100 		    sizeof (flag));
2101 
2102 		NDMP_LOG(LOG_DEBUG, "sock %d", sock);
2103 	}
2104 
2105 	return (sock);
2106 }
2107 
2108 /*
2109  * ndmp_create_socket
2110  *
2111  * Creates a socket for listening for accepting data connections.
2112  *
2113  * Parameters:
2114  *   session (input)  - session pointer.
2115  *   addr    (output) - location to store address of socket.
2116  *   port    (output) - location to store port of socket.
2117  *
2118  * Returns:
2119  *   0 - success.
2120  *  -1 - error.
2121  */
2122 int
2123 ndmp_create_socket(ulong_t *addr, ushort_t *port)
2124 {
2125 	char *p;
2126 	int length;
2127 	int sd;
2128 	struct sockaddr_in sin;
2129 
2130 	p = ndmpd_get_prop(NDMP_MOVER_NIC);
2131 
2132 	if (!p || *p == 0)
2133 		p = gethostaddr();
2134 
2135 	if (!p) {
2136 		NDMP_LOG(LOG_ERR, "Undetermined network port.");
2137 		return (-1);
2138 	}
2139 
2140 	*addr = inet_addr(p);
2141 
2142 	sd = socket(AF_INET, SOCK_STREAM, 0);
2143 	if (sd < 0) {
2144 		NDMP_LOG(LOG_DEBUG, "Socket error: %m");
2145 		return (-1);
2146 	}
2147 	sin.sin_family = AF_INET;
2148 	sin.sin_addr.s_addr = INADDR_ANY;
2149 	sin.sin_port = 0;
2150 	length = sizeof (sin);
2151 
2152 	if (bind(sd, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
2153 		NDMP_LOG(LOG_DEBUG, "Bind error: %m");
2154 		(void) close(sd);
2155 		sd = -1;
2156 	} else if (getsockname(sd, (struct sockaddr *)&sin, &length) < 0) {
2157 		NDMP_LOG(LOG_DEBUG, "getsockname error: %m");
2158 		(void) close(sd);
2159 		sd = -1;
2160 	} else if (listen(sd, 5) < 0) {
2161 		NDMP_LOG(LOG_DEBUG, "Listen error: %m");
2162 		(void) close(sd);
2163 		sd = -1;
2164 	} else
2165 		*port = sin.sin_port;
2166 
2167 	return (sd);
2168 }
2169 
2170 
2171 /*
2172  * cctime
2173  *
2174  * Convert the specified time into a string.  It's like
2175  * ctime(), but:
2176  *     - chops the trailing '\n' of ctime.
2177  *     - and returns "the epoch" if time is 0.
2178  *
2179  * Returns:
2180  *     "": invalid argument.
2181  *     "the epoch": if time is 0.
2182  *     string format of the time.
2183  */
2184 char *
2185 cctime(time_t *t)
2186 {
2187 	char *bp, *cp;
2188 	char tbuf[BUFSIZ];
2189 
2190 	if (!t)
2191 		return ("");
2192 
2193 	if (*t == (time_t)0)
2194 		return ("the epoch");
2195 
2196 	bp = ctime_r(t, tbuf, BUFSIZ);
2197 	cp = strchr(bp, '\n');
2198 	if (cp)
2199 		*cp = '\0';
2200 
2201 	return (bp);
2202 }
2203 
2204 
2205 /*
2206  * ndmp_new_job_name
2207  *
2208  * Create a job name for each backup/restore to keep track
2209  *
2210  * Parameters:
2211  *   jname (output) - job name
2212  *
2213  * Returns:
2214  *   jname
2215  */
2216 char *
2217 ndmp_new_job_name(char *jname)
2218 {
2219 	if (jname != NULL) {
2220 		(void) snprintf(jname, TLM_MAX_BACKUP_JOB_NAME, "%s%d",
2221 		    NDMP_RCF_BASENAME, ndmp_job_cnt++);
2222 		NDMP_LOG(LOG_DEBUG, "jname: \"%s\"", jname);
2223 	}
2224 
2225 	return (jname);
2226 }
2227 
2228 
2229 /*
2230  * fs_is_valid_logvol
2231  *
2232  * Check if the log path exists
2233  *
2234  * Parameters:
2235  *   path (input) - log path
2236  *
2237  * Returns:
2238  *   FALSE: invalid
2239  *   TRUE: valid
2240  */
2241 boolean_t
2242 fs_is_valid_logvol(char *path)
2243 {
2244 	struct stat64 st;
2245 
2246 	if (stat64(path, &st) < 0)
2247 		return (FALSE);
2248 
2249 	return (TRUE);
2250 }
2251 
2252 
2253 /*
2254  * ndmpd_mk_temp
2255  *
2256  * Make a temporary file using the working directory path and the
2257  * jobname
2258  *
2259  * Parameters:
2260  *   buf (output) - the temporary file name path
2261  *
2262  * Returns:
2263  *   buf
2264  */
2265 char *
2266 ndmpd_mk_temp(char *buf)
2267 {
2268 	char fname[TLM_MAX_BACKUP_JOB_NAME];
2269 	const char *dir;
2270 	char *rv;
2271 
2272 	if (!buf)
2273 		return (NULL);
2274 
2275 	dir = ndmpd_get_prop(NDMP_DEBUG_PATH);
2276 	if (dir == 0 || *dir == '\0') {
2277 		NDMP_LOG(LOG_DEBUG, "NDMP work path not specified");
2278 		return (0);
2279 	}
2280 
2281 	if (!fs_is_valid_logvol((char *)dir)) {
2282 		NDMP_LOG(LOG_ERR,
2283 		    "Log file path cannot be on system volumes.");
2284 		return (0);
2285 	}
2286 
2287 	dir += strspn(dir, " \t");
2288 	if (!*dir) {
2289 		NDMP_LOG(LOG_DEBUG, "NDMP work path not specified");
2290 		return (0);
2291 	}
2292 
2293 	rv = buf;
2294 	(void) ndmp_new_job_name(fname);
2295 	(void) tlm_cat_path(buf, (char *)dir, fname);
2296 
2297 	return (rv);
2298 }
2299 
2300 
2301 /*
2302  * ndmpd_make_bk_dir_path
2303  *
2304  * Make a directory path for temporary files under the NDMP
2305  * working directory.
2306  *
2307  * Parameters:
2308  *   buf (output) - result path
2309  *   fname (input) - the file name
2310  *
2311  * Returns:
2312  *   buf
2313  */
2314 char *
2315 ndmpd_make_bk_dir_path(char *buf, char *fname)
2316 {
2317 	const char *p;
2318 	char *name;
2319 	char path[PATH_MAX];
2320 
2321 	if (!buf || !fname || !*fname)
2322 		return (NULL);
2323 
2324 	p = ndmpd_get_prop(NDMP_DEBUG_PATH);
2325 	if (p == NULL || *p == '\0' || !fs_is_valid_logvol((char *)p)) {
2326 		return (NULL);
2327 	}
2328 
2329 	(void) strlcpy(path, (char *)p, PATH_MAX);
2330 	(void) trim_whitespace(path);
2331 
2332 	if ((name = strrchr(fname, '/')) == 0)
2333 		name = fname;
2334 
2335 	(void) tlm_cat_path(buf, path, name);
2336 	return (buf);
2337 }
2338 
2339 
2340 /*
2341  * ndmp_is_chkpnt_root
2342  *
2343  * Is this a root checkpoint (snapshot) directory.
2344  * Note: a temporary function
2345  */
2346 boolean_t
2347 ndmp_is_chkpnt_root(char *path)
2348 {
2349 	struct stat64 st;
2350 
2351 	if (stat64(path, &st) != 0) {
2352 		NDMP_LOG(LOG_DEBUG, "Couldn't stat path \"%s\"", path);
2353 		return (TRUE);
2354 	}
2355 	return (FALSE);
2356 }
2357 
2358 
2359 /*
2360  * ndmpd_make_exc_list
2361  *
2362  * Make a list of files that should not be backed up.
2363  *
2364  * Parameters:
2365  *   void
2366  *
2367  * Returns:
2368  *   list - array of character strings
2369  */
2370 char **
2371 ndmpd_make_exc_list(void)
2372 {
2373 	char *val, **cpp;
2374 	int i, n;
2375 
2376 	n = sizeof (exls);
2377 	if ((cpp = ndmp_malloc(n)) != NULL) {
2378 		for (i = 0; exls[i] != NULL; i++)
2379 			cpp[i] = exls[i];
2380 
2381 		/*
2382 		 * If ndmpd_get_prop returns NULL, the array will be
2383 		 * null-terminated.
2384 		 */
2385 		val = ndmpd_get_prop(NDMP_DEBUG_PATH);
2386 		cpp[i] = val;
2387 	}
2388 
2389 	return (cpp);
2390 }
2391 
2392 
2393 /*
2394  * ndmp_get_bk_dir_ino
2395  *
2396  * Get the inode number of the backup directory
2397  */
2398 int
2399 ndmp_get_bk_dir_ino(ndmp_lbr_params_t *nlp)
2400 {
2401 	int rv;
2402 	struct stat64 st;
2403 
2404 	if (stat64(nlp->nlp_backup_path, &st) != 0) {
2405 		rv = -1;
2406 		NDMP_LOG(LOG_DEBUG, "Getting inode # of \"%s\"",
2407 		    nlp->nlp_backup_path);
2408 	} else {
2409 		rv = 0;
2410 		nlp->nlp_bkdirino = st.st_ino;
2411 		NDMP_LOG(LOG_DEBUG, "nlp_bkdirino: %lu",
2412 		    (uint_t)nlp->nlp_bkdirino);
2413 	}
2414 
2415 	return (rv);
2416 }
2417 
2418 
2419 /*
2420  * ndmp_check_utf8magic
2421  *
2422  * Check if the magic string for exists in the tar header. This
2423  * magic string (which also indicates that the file names are in
2424  * UTF8 format) is used as a crest to indetify our own tapes.
2425  * This checking is always done before all restores except DAR
2426  * restores.
2427  */
2428 boolean_t
2429 ndmp_check_utf8magic(tlm_cmd_t *cmd)
2430 {
2431 	char *cp;
2432 	int err, len, actual_size;
2433 
2434 	if (cmd == NULL) {
2435 		NDMP_LOG(LOG_DEBUG, "cmd == NULL");
2436 		return (FALSE);
2437 	}
2438 	if (cmd->tc_buffers == NULL) {
2439 		NDMP_LOG(LOG_DEBUG, "cmd->tc_buffers == NULL");
2440 		return (FALSE);
2441 	}
2442 
2443 	/* wait until the first buffer gets full. */
2444 	tlm_buffer_in_buf_wait(cmd->tc_buffers);
2445 
2446 	err = actual_size = 0;
2447 	cp = tlm_get_read_buffer(RECORDSIZE, &err, cmd->tc_buffers,
2448 	    &actual_size);
2449 	if (cp == NULL) {
2450 		NDMP_LOG(LOG_DEBUG, "Can't read from buffers, err: %d", err);
2451 		return (FALSE);
2452 	}
2453 	len = strlen(NDMPUTF8MAGIC);
2454 	if (actual_size < len) {
2455 		NDMP_LOG(LOG_DEBUG, "Not enough data in the buffers");
2456 		return (FALSE);
2457 	}
2458 
2459 	return ((strncmp(cp, NDMPUTF8MAGIC, len) == 0) ? TRUE : FALSE);
2460 }
2461 
2462 
2463 /*
2464  * ndmp_get_cur_bk_time
2465  *
2466  * Get the backup checkpoint time.
2467  */
2468 int
2469 ndmp_get_cur_bk_time(ndmp_lbr_params_t *nlp, time_t *tp, char *jname)
2470 {
2471 	int err;
2472 
2473 	if (!nlp || !nlp->nlp_backup_path || !tp) {
2474 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
2475 		return (-1);
2476 	}
2477 
2478 	if (!fs_is_chkpnt_enabled(nlp->nlp_backup_path)) {
2479 		NDMP_LOG(LOG_DEBUG, "Not a chkpnt volume %s",
2480 		    nlp->nlp_backup_path);
2481 		*tp = time(NULL);
2482 		return (0);
2483 	}
2484 
2485 	err = tlm_get_chkpnt_time(nlp->nlp_backup_path, !NLP_ISCHKPNTED(nlp),
2486 	    tp, jname);
2487 	if (err != 0) {
2488 		NDMP_LOG(LOG_DEBUG, "Can't checkpoint time");
2489 	} else {
2490 		NDMP_LOG(LOG_DEBUG, "%s", cctime(tp));
2491 	}
2492 
2493 	return (err);
2494 }
2495 
2496 
2497 /*
2498  * get_relative_path
2499  */
2500 char *
2501 ndmp_get_relative_path(char *base, char *fullpath)
2502 {
2503 	char *p = fullpath;
2504 
2505 	if (!base || !*base)
2506 		return (fullpath);
2507 
2508 	while (*base) {
2509 		if (*base != *p)
2510 			break;
2511 		p++; base++;
2512 	}
2513 
2514 	if (*p == '/')
2515 		p++;
2516 
2517 	return ((*base) ? fullpath : p);
2518 }
2519 
2520 
2521 /*
2522  * ndmp_get_nlp
2523  *
2524  * Get NDMP local backup parameters
2525  *
2526  * Parameter:
2527  *   session cooke
2528  *
2529  * Returns:
2530  *   LBR structure
2531  */
2532 ndmp_lbr_params_t *
2533 ndmp_get_nlp(void *cookie)
2534 {
2535 	if (cookie == NULL)
2536 		return (NULL);
2537 
2538 	return (((ndmpd_session_t *)cookie)->ns_ndmp_lbr_params);
2539 }
2540 
2541 
2542 /*
2543  * is_tape_unit_ready
2544  *
2545  * Check if the tape device is ready or not
2546  */
2547 boolean_t
2548 is_tape_unit_ready(char *adptnm, int dev_id)
2549 {
2550 	int try;
2551 	int fd = 0;
2552 
2553 	try = TUR_MAX_TRY;
2554 	if (dev_id == 0)
2555 		fd = open(adptnm, O_RDONLY | O_NDELAY);
2556 	else
2557 		fd = dev_id;
2558 	do {
2559 		if (scsi_test_unit_ready(fd) >= 0) {
2560 			NDMP_LOG(LOG_DEBUG, "Unit is ready");
2561 
2562 			if (dev_id == 0)
2563 				(void) close(fd);
2564 
2565 			return (TRUE);
2566 		}
2567 
2568 		NDMP_LOG(LOG_DEBUG, "Unit not ready");
2569 		(void) usleep(TUR_WAIT);
2570 
2571 	} while (--try > 0);
2572 
2573 	if (dev_id == 0)
2574 		(void) close(fd);
2575 
2576 	NDMP_LOG(LOG_DEBUG, "Unit didn't get ready");
2577 	return (FALSE);
2578 }
2579 
2580 
2581 /*
2582  * scsi_test_unit_ready
2583  *
2584  * This is for Test Unit Read, without this function, the only
2585  * impact is getting EBUSY's before each operation which we have
2586  * busy waiting loops checking EBUSY error code.
2587  */
2588 static int
2589 scsi_test_unit_ready(int dev_id)
2590 {
2591 	struct uscsi_cmd ucmd;
2592 	union scsi_cdb cdb;
2593 	int retval;
2594 
2595 	(void) memset(&ucmd, 0, sizeof (struct uscsi_cmd));
2596 	(void) memset(&cdb, 0, sizeof (union scsi_cdb));
2597 	cdb.scc_cmd = SCMD_TEST_UNIT_READY;
2598 	ucmd.uscsi_cdb = (caddr_t)&cdb;
2599 	ucmd.uscsi_cdblen = CDB_GROUP0;
2600 	ucmd.uscsi_flags |= USCSI_SILENT;
2601 
2602 	retval = ioctl(dev_id, USCSICMD, &ucmd);
2603 
2604 	if (retval != 0 && errno != EIO) {
2605 		NDMP_LOG(LOG_ERR,
2606 		    "Failed to send inquiry request to device: %m.");
2607 		NDMP_LOG(LOG_DEBUG, "Inquiry request failed for"
2608 		    " dev_id:%d err=%d -%m", dev_id, errno);
2609 		retval = -errno;
2610 	} else
2611 		retval = -(ucmd.uscsi_status);
2612 
2613 	return (retval);
2614 }
2615 
2616 
2617 /*
2618  * ndmp_load_params
2619  *
2620  * Load the parameters.
2621  *
2622  * Parameter:
2623  *   void
2624  *
2625  * Returns:
2626  *   void
2627  */
2628 void
2629 ndmp_load_params(void)
2630 {
2631 	struct stat64 st;
2632 
2633 	ndmp_dump_path_node = ndmpd_get_prop_yorn(NDMP_DUMP_PATHNODE_ENV) ?
2634 	    TRUE : FALSE;
2635 	ndmp_tar_path_node = ndmpd_get_prop_yorn(NDMP_TAR_PATHNODE_ENV) ?
2636 	    TRUE : FALSE;
2637 	ndmp_ignore_ctime =
2638 	    ndmpd_get_prop_yorn(NDMP_IGNCTIME_ENV) ? TRUE : FALSE;
2639 	ndmp_include_lmtime = ndmpd_get_prop_yorn(NDMP_INCLMTIME_ENV) ?
2640 	    TRUE : FALSE;
2641 	ndmp_max_tok_seq = atoi(ndmpd_get_prop_default(NDMP_MAXSEQ_ENV, "9"));
2642 
2643 	ndmp_full_restore_path = ndmpd_get_prop_yorn(NDMP_FULL_RESTORE_PATH) ?
2644 	    TRUE : FALSE;
2645 
2646 	ndmp_fhinode = ndmpd_get_prop_yorn(NDMP_FHIST_INCR_ENV) ? TRUE : FALSE;
2647 
2648 	/* Get the value from ndmp SMF property. */
2649 	ndmp_dar_support = ndmpd_get_prop_yorn(NDMP_DAR_SUPPORT);
2650 
2651 	ndmp_log_path = ndmpd_get_prop(NDMP_DEBUG_PATH);
2652 	if ((ndmp_log_path == NULL) || (*ndmp_log_path == NULL))
2653 		ndmp_log_path = "/var/ndmp";
2654 
2655 	if (lstat64(ndmp_log_path, &st) < 0) {
2656 		if (mkdirp(ndmp_log_path, 0755) < 0)
2657 			NDMP_LOG(LOG_ERR, "Could not create log path %s: %m.",
2658 			    ndmp_log_path);
2659 	}
2660 
2661 	if ((ndmp_ver = atoi(ndmpd_get_prop(NDMP_VERSION_ENV))) == 0)
2662 		ndmp_ver = NDMPVER;
2663 }
2664 
2665 /*
2666  * randomize
2667  *
2668  * Randomize the contents of a buffer
2669  *
2670  * Parameter:
2671  *   buffer (output) - destination buffer
2672  *   size (input) - buffer size
2673  *
2674  * Returns:
2675  *   void
2676  */
2677 void
2678 randomize(unsigned char *buffer, int size)
2679 {
2680 	/* LINTED improper alignment */
2681 	unsigned int *p = (unsigned int *)buffer;
2682 	unsigned int dwlen = size / sizeof (unsigned int);
2683 	unsigned int remlen = size % sizeof (unsigned int);
2684 	unsigned int tmp;
2685 	unsigned int i;
2686 
2687 	for (i = 0; i < dwlen; i++)
2688 		*p++ = random();
2689 
2690 	if (remlen) {
2691 		tmp = random();
2692 		(void) memcpy(p, &tmp, remlen);
2693 	}
2694 }
2695 
2696 /*
2697  * ndmpd_get_file_entry_type
2698  *
2699  * Converts the mode to the NDMP file type
2700  *
2701  * Parameter:
2702  *   mode (input) - file mode
2703  *   ftype (output) - file type
2704  *
2705  * Returns:
2706  *   void
2707  */
2708 void
2709 ndmpd_get_file_entry_type(int mode, ndmp_file_type *ftype)
2710 {
2711 	switch (mode & S_IFMT) {
2712 	case S_IFIFO:
2713 		*ftype = NDMP_FILE_FIFO;
2714 		break;
2715 	case S_IFCHR:
2716 		*ftype = NDMP_FILE_CSPEC;
2717 		break;
2718 	case S_IFDIR:
2719 		*ftype = NDMP_FILE_DIR;
2720 		break;
2721 	case S_IFBLK:
2722 		*ftype = NDMP_FILE_BSPEC;
2723 		break;
2724 	case S_IFREG:
2725 		*ftype = NDMP_FILE_REG;
2726 		break;
2727 	case S_IFLNK:
2728 		*ftype = NDMP_FILE_SLINK;
2729 		break;
2730 	default:
2731 		*ftype = NDMP_FILE_SOCK;
2732 		break;
2733 	}
2734 }
2735 
2736 /*
2737  * Set a private data in the plugin context
2738  */
2739 void
2740 ndmp_context_set_specific(ndmp_context_t *nctx, void *ptr)
2741 {
2742 	nctx->nc_pldata = ptr;
2743 }
2744 
2745 /*
2746  * Get a private data in the plugin context
2747  */
2748 void *
2749 ndmp_context_get_specific(ndmp_context_t *nctx)
2750 {
2751 	return (nctx->nc_pldata);
2752 }
2753