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