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