xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_util.c (revision e4d060fb4c00d44cd578713eb9a921f594b733b8)
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 		if (errno != EIO && errno != 0)
1413 			NDMP_LOG(LOG_ERR,
1414 			    "Failed to send command to device: %m");
1415 		NDMP_LOG(LOG_DEBUG, "ioctl(USCSICMD) error: %m");
1416 		if (cmd.uscsi_status == 0)
1417 			reply.error = NDMP_IO_ERR;
1418 	}
1419 
1420 	reply.status = cmd.uscsi_status;
1421 
1422 	if (request->flags == NDMP_SCSI_DATA_IN) {
1423 		reply.datain.datain_len = cmd.uscsi_buflen;
1424 		reply.datain.datain_val = cmd.uscsi_bufaddr;
1425 	} else {
1426 		reply.dataout_len = request->dataout.dataout_len;
1427 	}
1428 
1429 	reply.ext_sense.ext_sense_len = cmd.uscsi_rqlen - cmd.uscsi_rqresid;
1430 	reply.ext_sense.ext_sense_val = rq_buf;
1431 
1432 	if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1433 	    (void *)&reply) < 0)
1434 		NDMP_LOG(LOG_DEBUG, "Error sending scsi_execute_cdb reply.");
1435 
1436 	if (request->flags == NDMP_SCSI_DATA_IN)
1437 		free(cmd.uscsi_bufaddr);
1438 }
1439 
1440 
1441 /*
1442  * ndmp_stop_local_reader
1443  *
1444  * Stops a mover reader thread (for local backup only)
1445  *
1446  * Parameters:
1447  *   session (input) - session pointer
1448  *   cmds (input) - reader/writer command struct
1449  *
1450  * Returns:
1451  *   void
1452  */
1453 void
1454 ndmp_stop_local_reader(ndmpd_session_t *session, tlm_commands_t *cmds)
1455 {
1456 	if (session != NULL) {
1457 		if (session->ns_data.dd_sock == -1) {
1458 			/*
1459 			 * 2-way restore.
1460 			 */
1461 			NDMP_LOG(LOG_DEBUG, "2-way restore");
1462 			if (cmds != NULL && cmds->tcs_reader_count > 0) {
1463 				nlp_event_rv_set(session, -2);
1464 				nlp_event_nw(session);
1465 			}
1466 		}
1467 	}
1468 }
1469 
1470 
1471 /*
1472  * Stops a mover reader thread (for remote backup only)
1473  *
1474  * Parameters:
1475  *   session (input) - session pointer
1476  *   cmds (input) - reader/writer command struct
1477  *
1478  * Returns:
1479  *   void
1480  */
1481 void
1482 ndmp_stop_remote_reader(ndmpd_session_t *session)
1483 {
1484 	if (session != NULL) {
1485 		if (session->ns_data.dd_sock >= 0) {
1486 			/*
1487 			 * 3-way restore.
1488 			 */
1489 			NDMP_LOG(LOG_DEBUG,
1490 			    "data.sock: %d", session->ns_data.dd_sock);
1491 			(void) close(session->ns_data.dd_sock);
1492 			session->ns_data.dd_sock = -1;
1493 		}
1494 	}
1495 }
1496 
1497 
1498 /*
1499  * ndmp_wait_for_reader
1500  *
1501  * Wait for a reader until get done (busy wait)
1502  */
1503 void
1504 ndmp_wait_for_reader(tlm_commands_t *cmds)
1505 {
1506 	if (cmds == NULL) {
1507 		NDMP_LOG(LOG_DEBUG, "cmds == NULL");
1508 	} else {
1509 		NDMP_LOG(LOG_DEBUG,
1510 		    "reader_count: %d", cmds->tcs_reader_count);
1511 
1512 		while (cmds->tcs_reader_count > 0)
1513 			(void) sleep(1);
1514 	}
1515 }
1516 
1517 
1518 /*
1519  * ndmp_open_list_find
1520  *
1521  * Find a specific device in the open list
1522  *
1523  * Parameters:
1524  *   dev (input) - device name
1525  *   sid (input) - SCSI target ID
1526  *   lun (input) - LUN number
1527  *
1528  * Returns:
1529  *   pointer to the open list entry
1530  */
1531 struct open_list *
1532 ndmp_open_list_find(char *dev, int sid, int lun)
1533 {
1534 	struct ol_head *olhp;
1535 	struct open_list *olp;
1536 
1537 	if (dev == NULL || *dev == '\0') {
1538 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1539 		return (NULL);
1540 	}
1541 
1542 	(void) mutex_lock(&ol_mutex);
1543 	olhp = &ol_head;
1544 	for (olp = LIST_FIRST(olhp); olp != NULL; olp = LIST_NEXT(olp, ol_q))
1545 		if (strcmp(olp->ol_devnm, dev) == 0 && olp->ol_sid == sid &&
1546 		    olp->ol_lun == lun) {
1547 			(void) mutex_unlock(&ol_mutex);
1548 			return (olp);
1549 		}
1550 
1551 	(void) mutex_unlock(&ol_mutex);
1552 	return (NULL);
1553 }
1554 
1555 
1556 /*
1557  * ndmp_open_list_add
1558  *
1559  * Add a specific device to the open list
1560  *
1561  * Parameters:
1562  *   conn (input) - connection pointer
1563  *   dev (input) - device name
1564  *   sid (input) - SCSI target ID
1565  *   lun (input) - LUN number
1566  *   fd (input) - the device file descriptor
1567  *
1568  * Returns:
1569  *   errno
1570  */
1571 int
1572 ndmp_open_list_add(ndmp_connection_t *conn, char *dev, int sid, int lun, int fd)
1573 {
1574 	int err;
1575 	struct ol_head *olhp;
1576 	struct open_list *olp;
1577 
1578 	if (dev == NULL || *dev == '\0') {
1579 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1580 		return (EINVAL);
1581 	}
1582 	NDMP_LOG(LOG_DEBUG,
1583 	    "conn: 0x%08x, dev: %s, sid: %d, lun: %d", conn, dev, sid, lun);
1584 
1585 	err = 0;
1586 	olhp = &ol_head;
1587 
1588 	if ((olp = ndmp_open_list_find(dev, sid, lun)) != NULL) {
1589 		NDMP_LOG(LOG_DEBUG, "already in list");
1590 		/*
1591 		 * The adapter handle can be opened many times by the clients.
1592 		 * Only when the target is set, we must check and reject the
1593 		 * open request if the device is already being used by another
1594 		 * session.
1595 		 */
1596 		if (sid == -1)
1597 			olp->ol_nref++;
1598 		else
1599 			err = EBUSY;
1600 	} else if ((olp = ndmp_malloc(sizeof (struct open_list))) == NULL) {
1601 		err = ENOMEM;
1602 	} else if ((olp->ol_devnm = strdup(dev)) == NULL) {
1603 		NDMP_LOG(LOG_ERR, "Out of memory.");
1604 		free(olp);
1605 		err = ENOMEM;
1606 	} else {
1607 		olp->cl_conn = conn;
1608 		olp->ol_nref = 1;
1609 		olp->ol_sid = sid;
1610 		olp->ol_lun = lun;
1611 		if (fd > 0)
1612 			olp->ol_fd = fd;
1613 		else
1614 			olp->ol_fd = -1;
1615 		(void) mutex_lock(&ol_mutex);
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 		LIST_REMOVE(olp, ol_q);
1656 		free(olp->ol_devnm);
1657 		free(olp);
1658 	}
1659 	(void) mutex_unlock(&ol_mutex);
1660 
1661 	return (0);
1662 }
1663 
1664 
1665 /*
1666  * ndmp_open_list_release
1667  *
1668  * Close all the resources belonging to this connection.
1669  *
1670  * Parameters:
1671  *    ndmp_connection_t *conn : connection identifier
1672  *
1673  * Returns:
1674  *   void
1675  */
1676 void
1677 ndmp_open_list_release(ndmp_connection_t *conn)
1678 {
1679 	struct ol_head *olhp = &ol_head;
1680 	struct open_list *olp;
1681 	struct open_list *next;
1682 
1683 	(void) mutex_lock(&ol_mutex);
1684 	olp = LIST_FIRST(olhp);
1685 	while (olp != NULL) {
1686 		next = LIST_NEXT(olp, ol_q);
1687 		NDMP_LOG(LOG_DEBUG, "olp->conn 0x%08x", olp->cl_conn);
1688 		if (olp->cl_conn == conn) {
1689 			NDMP_LOG(LOG_DEBUG,
1690 			    "Removed dev: %s, sid: %d, lun: %d",
1691 			    olp->ol_devnm, olp->ol_sid, olp->ol_lun);
1692 			LIST_REMOVE(olp, ol_q);
1693 			if (olp->ol_fd > 0)
1694 				(void) close(olp->ol_fd);
1695 			free(olp->ol_devnm);
1696 			free(olp);
1697 		}
1698 		olp = next;
1699 	}
1700 	(void) mutex_unlock(&ol_mutex);
1701 }
1702 
1703 
1704 /*
1705  * ndmp_stop_buffer_worker
1706  *
1707  * Stop all reader and writer threads for a specific buffer.
1708  *
1709  * Parameters:
1710  *   session (input) - session pointer
1711  *
1712  * Returns:
1713  *   void
1714  */
1715 void
1716 ndmp_stop_buffer_worker(ndmpd_session_t *session)
1717 {
1718 	ndmp_lbr_params_t *nlp;
1719 	tlm_commands_t *cmds;
1720 
1721 	session->ns_tape.td_pos = 0;
1722 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1723 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1724 	} else {
1725 		cmds = &nlp->nlp_cmds;
1726 		if (cmds->tcs_command == NULL) {
1727 			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL");
1728 		} else {
1729 			cmds->tcs_reader = cmds->tcs_writer = TLM_ABORT;
1730 			cmds->tcs_command->tc_reader = TLM_ABORT;
1731 			cmds->tcs_command->tc_writer = TLM_ABORT;
1732 			while (cmds->tcs_reader_count > 0 ||
1733 			    cmds->tcs_writer_count > 0) {
1734 				NDMP_LOG(LOG_DEBUG,
1735 				    "trying to stop buffer worker");
1736 				(void) sleep(1);
1737 			}
1738 		}
1739 	}
1740 }
1741 
1742 
1743 /*
1744  * ndmp_stop_reader_thread
1745  *
1746  * Stop only the reader threads of a specific buffer
1747  *
1748  * Parameters:
1749  *   session (input) - session pointer
1750  *
1751  * Returns:
1752  *   void
1753  */
1754 void
1755 ndmp_stop_reader_thread(ndmpd_session_t *session)
1756 {
1757 	ndmp_lbr_params_t *nlp;
1758 	tlm_commands_t *cmds;
1759 
1760 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1761 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1762 	} else {
1763 		cmds = &nlp->nlp_cmds;
1764 		if (cmds->tcs_command == NULL) {
1765 			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL");
1766 		} else {
1767 			cmds->tcs_reader = TLM_ABORT;
1768 			cmds->tcs_command->tc_reader = TLM_ABORT;
1769 			while (cmds->tcs_reader_count > 0) {
1770 				NDMP_LOG(LOG_DEBUG,
1771 				    "trying to stop reader thread");
1772 				(void) sleep(1);
1773 			}
1774 		}
1775 	}
1776 }
1777 
1778 
1779 /*
1780  * ndmp_stop_reader_thread
1781  *
1782  * Stop only the writer threads of a specific buffer
1783  *
1784  * Parameters:
1785  *   session (input) - session pointer
1786  *
1787  * Returns:
1788  *   void
1789  */
1790 void
1791 ndmp_stop_writer_thread(ndmpd_session_t *session)
1792 {
1793 	ndmp_lbr_params_t *nlp;
1794 	tlm_commands_t *cmds;
1795 
1796 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1797 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1798 	} else {
1799 		cmds = &nlp->nlp_cmds;
1800 		if (cmds->tcs_command == NULL) {
1801 			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL");
1802 		} else {
1803 			cmds->tcs_writer = TLM_ABORT;
1804 			cmds->tcs_command->tc_writer = TLM_ABORT;
1805 			while (cmds->tcs_writer_count > 0) {
1806 				NDMP_LOG(LOG_DEBUG,
1807 				    "trying to stop writer thread");
1808 				(void) sleep(1);
1809 			}
1810 		}
1811 	}
1812 }
1813 
1814 
1815 /*
1816  * ndmp_free_reader_writer_ipc
1817  *
1818  * Free and release the reader/writer buffers and the IPC structure
1819  * for reader and writer threads.
1820  *
1821  * Parameters:
1822  *   session (input) - session pointer
1823  *
1824  * Returns:
1825  *   void
1826  */
1827 void
1828 ndmp_free_reader_writer_ipc(ndmpd_session_t *session)
1829 {
1830 	ndmp_lbr_params_t *nlp;
1831 	tlm_commands_t *cmds;
1832 
1833 	if ((nlp = ndmp_get_nlp(session)) != NULL) {
1834 		cmds = &nlp->nlp_cmds;
1835 		if (cmds->tcs_command != NULL) {
1836 			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command->tc_ref: %d",
1837 			    cmds->tcs_command->tc_ref);
1838 			tlm_release_reader_writer_ipc(cmds->tcs_command);
1839 		}
1840 	}
1841 }
1842 
1843 
1844 /*
1845  * ndmp_waitfor_op
1846  *
1847  * Wait for a session reference count to drop to zero
1848  *
1849  * Parameters:
1850  *   session (input) - session pointer
1851  *
1852  * Returns:
1853  *   void
1854  */
1855 void
1856 ndmp_waitfor_op(ndmpd_session_t *session)
1857 {
1858 	if (session != NULL) {
1859 		while (session->ns_nref > 0) {
1860 			(void) sleep(1);
1861 			NDMP_LOG(LOG_DEBUG,
1862 			    "waiting for session nref: %d", session->ns_nref);
1863 		}
1864 	}
1865 }
1866 
1867 
1868 /*
1869  * ndmp_session_ref
1870  *
1871  * Increment the reference count of the session
1872  *
1873  * Parameters:
1874  *   session (input) - session pointer
1875  *
1876  * Returns:
1877  *   void
1878  */
1879 void
1880 ndmp_session_ref(ndmpd_session_t *session)
1881 {
1882 	(void) mutex_lock(&session->ns_lock);
1883 	session->ns_nref++;
1884 	(void) mutex_unlock(&session->ns_lock);
1885 }
1886 
1887 
1888 /*
1889  * ndmp_session_unref
1890  *
1891  * Decrement the reference count of the session
1892  *
1893  * Parameters:
1894  *   session (input) - session pointer
1895  *
1896  * Returns:
1897  *   void
1898  */
1899 void
1900 ndmp_session_unref(ndmpd_session_t *session)
1901 {
1902 	(void) mutex_lock(&session->ns_lock);
1903 	session->ns_nref--;
1904 	(void) mutex_unlock(&session->ns_lock);
1905 }
1906 
1907 
1908 /*
1909  * ndmp_addr2str_v3
1910  *
1911  * Convert the address type to a string
1912  *
1913  * Parameters:
1914  *   type (input) - address type
1915  *
1916  * Returns:
1917  *   type in string
1918  */
1919 char *
1920 ndmp_addr2str_v3(ndmp_addr_type type)
1921 {
1922 	char *rv;
1923 
1924 	switch (type) {
1925 	case NDMP_ADDR_LOCAL:
1926 		rv = "Local";
1927 		break;
1928 	case NDMP_ADDR_TCP:
1929 		rv = "TCP";
1930 		break;
1931 	case NDMP_ADDR_FC:
1932 		rv = "FC";
1933 		break;
1934 	case NDMP_ADDR_IPC:
1935 		rv = "IPC";
1936 		break;
1937 	default:
1938 		rv = "Unknown";
1939 	}
1940 
1941 	return (rv);
1942 }
1943 
1944 
1945 /*
1946  * ndmp_valid_v3addr_type
1947  *
1948  * Make sure that the NDMP address is from any of the
1949  * valid types
1950  *
1951  * Parameters:
1952  *   type (input) - address type
1953  *
1954  * Returns:
1955  *   1: valid
1956  *   0: invalid
1957  */
1958 boolean_t
1959 ndmp_valid_v3addr_type(ndmp_addr_type type)
1960 {
1961 	boolean_t rv;
1962 
1963 	switch (type) {
1964 	case NDMP_ADDR_LOCAL:
1965 	case NDMP_ADDR_TCP:
1966 	case NDMP_ADDR_FC:
1967 	case NDMP_ADDR_IPC:
1968 		rv = TRUE;
1969 		break;
1970 	default:
1971 		rv = FALSE;
1972 	}
1973 
1974 	return (rv);
1975 }
1976 
1977 
1978 /*
1979  * ndmp_copy_addr_v3
1980  *
1981  * Copy NDMP address from source to destination (V2 and V3 only)
1982  *
1983  * Parameters:
1984  *   dst (ouput) - destination address
1985  *   src (input) - source address
1986  *
1987  * Returns:
1988  *   void
1989  */
1990 void
1991 ndmp_copy_addr_v3(ndmp_addr_v3 *dst, ndmp_addr_v3 *src)
1992 {
1993 	dst->addr_type = src->addr_type;
1994 	switch (src->addr_type) {
1995 	case NDMP_ADDR_LOCAL:
1996 		/* nothing */
1997 		break;
1998 	case NDMP_ADDR_TCP:
1999 		dst->tcp_ip_v3 = htonl(src->tcp_ip_v3);
2000 		dst->tcp_port_v3 = src->tcp_port_v3;
2001 		break;
2002 	case NDMP_ADDR_FC:
2003 	case NDMP_ADDR_IPC:
2004 	default:
2005 		break;
2006 	}
2007 }
2008 
2009 
2010 /*
2011  * ndmp_copy_addr_v4
2012  *
2013  * Copy NDMP address from source to destination. V4 has a extra
2014  * environment list inside the address too which needs to be copied.
2015  *
2016  * Parameters:
2017  *   dst (ouput) - destination address
2018  *   src (input) - source address
2019  *
2020  * Returns:
2021  *   void
2022  */
2023 void
2024 ndmp_copy_addr_v4(ndmp_addr_v4 *dst, ndmp_addr_v4 *src)
2025 {
2026 	int i;
2027 
2028 	dst->addr_type = src->addr_type;
2029 	dst->tcp_len_v4 = src->tcp_len_v4;
2030 	switch (src->addr_type) {
2031 	case NDMP_ADDR_LOCAL:
2032 		/* nothing */
2033 		break;
2034 	case NDMP_ADDR_TCP:
2035 		dst->tcp_addr_v4 = ndmp_malloc(sizeof (ndmp_tcp_addr_v4) *
2036 		    src->tcp_len_v4);
2037 		if (dst->tcp_addr_v4 == 0)
2038 			return;
2039 
2040 		for (i = 0; i < src->tcp_len_v4; i++) {
2041 			dst->tcp_ip_v4(i) = htonl(src->tcp_ip_v4(i));
2042 			dst->tcp_port_v4(i) = src->tcp_port_v4(i);
2043 			dst->tcp_env_v4(i).addr_env_len = 0; /* Solaris */
2044 			dst->tcp_env_v4(i).addr_env_val = 0; /* Solaris */
2045 		}
2046 		break;
2047 	case NDMP_ADDR_FC:
2048 	case NDMP_ADDR_IPC:
2049 	default:
2050 		break;
2051 	}
2052 }
2053 
2054 
2055 /*
2056  * ndmp_connect_sock_v3
2057  *
2058  * Creates a socket and connects to the specified address/port
2059  *
2060  * Parameters:
2061  *   addr (input) - IP address
2062  *   port (input) - port number
2063  *
2064  * Returns:
2065  *   0: on success
2066  *  -1: otherwise
2067  */
2068 int
2069 ndmp_connect_sock_v3(ulong_t addr, ushort_t port)
2070 {
2071 	int sock;
2072 	struct sockaddr_in sin;
2073 	int flag = 1;
2074 
2075 	NDMP_LOG(LOG_DEBUG, "addr %s:%d", inet_ntoa(IN_ADDR(addr)), port);
2076 
2077 	sock = socket(AF_INET, SOCK_STREAM, 0);
2078 	if (sock < 0) {
2079 		NDMP_LOG(LOG_DEBUG, "Socket error: %m");
2080 		return (-1);
2081 	}
2082 
2083 	(void) memset((void *) &sin, 0, sizeof (sin));
2084 	sin.sin_family = AF_INET;
2085 	sin.sin_addr.s_addr = htonl(addr);
2086 	sin.sin_port = htons(port);
2087 	if (connect(sock, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
2088 		NDMP_LOG(LOG_DEBUG, "Connect error: %m");
2089 		(void) close(sock);
2090 		sock = -1;
2091 	} else {
2092 		if (ndmp_sbs > 0)
2093 			ndmp_set_socket_snd_buf(sock, ndmp_sbs*KILOBYTE);
2094 		if (ndmp_rbs > 0)
2095 			ndmp_set_socket_rcv_buf(sock, ndmp_rbs*KILOBYTE);
2096 
2097 		ndmp_set_socket_nodelay(sock);
2098 		(void) setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &flag,
2099 		    sizeof (flag));
2100 
2101 		NDMP_LOG(LOG_DEBUG, "sock %d", sock);
2102 	}
2103 
2104 	return (sock);
2105 }
2106 
2107 /*
2108  * ndmp_create_socket
2109  *
2110  * Creates a socket for listening for accepting data connections.
2111  *
2112  * Parameters:
2113  *   session (input)  - session pointer.
2114  *   addr    (output) - location to store address of socket.
2115  *   port    (output) - location to store port of socket.
2116  *
2117  * Returns:
2118  *   0 - success.
2119  *  -1 - error.
2120  */
2121 int
2122 ndmp_create_socket(ulong_t *addr, ushort_t *port)
2123 {
2124 	char *p;
2125 	int length;
2126 	int sd;
2127 	struct sockaddr_in sin;
2128 
2129 	p = ndmpd_get_prop(NDMP_MOVER_NIC);
2130 
2131 	if (!p || *p == 0)
2132 		p = gethostaddr();
2133 
2134 	if (!p) {
2135 		NDMP_LOG(LOG_ERR, "Undetermined network port.");
2136 		return (-1);
2137 	}
2138 
2139 	*addr = inet_addr(p);
2140 
2141 	sd = socket(AF_INET, SOCK_STREAM, 0);
2142 	if (sd < 0) {
2143 		NDMP_LOG(LOG_DEBUG, "Socket error: %m");
2144 		return (-1);
2145 	}
2146 	sin.sin_family = AF_INET;
2147 	sin.sin_addr.s_addr = INADDR_ANY;
2148 	sin.sin_port = 0;
2149 	length = sizeof (sin);
2150 
2151 	if (bind(sd, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
2152 		NDMP_LOG(LOG_DEBUG, "Bind error: %m");
2153 		(void) close(sd);
2154 		sd = -1;
2155 	} else if (getsockname(sd, (struct sockaddr *)&sin, &length) < 0) {
2156 		NDMP_LOG(LOG_DEBUG, "getsockname error: %m");
2157 		(void) close(sd);
2158 		sd = -1;
2159 	} else if (listen(sd, 5) < 0) {
2160 		NDMP_LOG(LOG_DEBUG, "Listen error: %m");
2161 		(void) close(sd);
2162 		sd = -1;
2163 	} else
2164 		*port = sin.sin_port;
2165 
2166 	return (sd);
2167 }
2168 
2169 
2170 /*
2171  * cctime
2172  *
2173  * Convert the specified time into a string.  It's like
2174  * ctime(), but:
2175  *     - chops the trailing '\n' of ctime.
2176  *     - and returns "the epoch" if time is 0.
2177  *
2178  * Returns:
2179  *     "": invalid argument.
2180  *     "the epoch": if time is 0.
2181  *     string format of the time.
2182  */
2183 char *
2184 cctime(time_t *t)
2185 {
2186 	char *bp, *cp;
2187 	static char tbuf[BUFSIZ];
2188 
2189 	if (!t)
2190 		return ("");
2191 
2192 	if (*t == (time_t)0)
2193 		return ("the epoch");
2194 
2195 	if ((bp = ctime_r(t, tbuf, BUFSIZ)) == NULL)
2196 		return ("");
2197 
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 		if ((fd = open(adptnm, O_RDONLY | O_NDELAY)) < 0)
2557 			return (FALSE);
2558 	} else {
2559 		fd = dev_id;
2560 	}
2561 	do {
2562 		if (scsi_test_unit_ready(fd) >= 0) {
2563 			NDMP_LOG(LOG_DEBUG, "Unit is ready");
2564 
2565 			if (dev_id <= 0)
2566 				(void) close(fd);
2567 
2568 			return (TRUE);
2569 		}
2570 
2571 		NDMP_LOG(LOG_DEBUG, "Unit not ready");
2572 		(void) usleep(TUR_WAIT);
2573 
2574 	} while (--try > 0);
2575 
2576 	if (dev_id <= 0)
2577 		(void) close(fd);
2578 
2579 	NDMP_LOG(LOG_DEBUG, "Unit didn't get ready");
2580 	return (FALSE);
2581 }
2582 
2583 
2584 /*
2585  * scsi_test_unit_ready
2586  *
2587  * This is for Test Unit Read, without this function, the only
2588  * impact is getting EBUSY's before each operation which we have
2589  * busy waiting loops checking EBUSY error code.
2590  */
2591 static int
2592 scsi_test_unit_ready(int dev_id)
2593 {
2594 	struct uscsi_cmd ucmd;
2595 	union scsi_cdb cdb;
2596 	int retval;
2597 
2598 	(void) memset(&ucmd, 0, sizeof (struct uscsi_cmd));
2599 	(void) memset(&cdb, 0, sizeof (union scsi_cdb));
2600 	cdb.scc_cmd = SCMD_TEST_UNIT_READY;
2601 	ucmd.uscsi_cdb = (caddr_t)&cdb;
2602 	ucmd.uscsi_cdblen = CDB_GROUP0;
2603 	ucmd.uscsi_flags |= USCSI_SILENT;
2604 	ucmd.uscsi_timeout = 60;	/* Allow maximum 1 min */
2605 
2606 	retval = ioctl(dev_id, USCSICMD, &ucmd);
2607 
2608 	if (retval != 0 && errno != EIO) {
2609 		NDMP_LOG(LOG_ERR,
2610 		    "Failed to send inquiry request to device: %m.");
2611 		NDMP_LOG(LOG_DEBUG, "Inquiry request failed for"
2612 		    " dev_id:%d err=%d -%m", dev_id, errno);
2613 		retval = -errno;
2614 	} else
2615 		retval = -(ucmd.uscsi_status);
2616 
2617 	return (retval);
2618 }
2619 
2620 
2621 /*
2622  * ndmp_load_params
2623  *
2624  * Load the parameters.
2625  *
2626  * Parameter:
2627  *   void
2628  *
2629  * Returns:
2630  *   void
2631  */
2632 void
2633 ndmp_load_params(void)
2634 {
2635 	ndmp_dump_path_node = ndmpd_get_prop_yorn(NDMP_DUMP_PATHNODE_ENV) ?
2636 	    TRUE : FALSE;
2637 	ndmp_tar_path_node = ndmpd_get_prop_yorn(NDMP_TAR_PATHNODE_ENV) ?
2638 	    TRUE : FALSE;
2639 	ndmp_ignore_ctime =
2640 	    ndmpd_get_prop_yorn(NDMP_IGNCTIME_ENV) ? TRUE : FALSE;
2641 	ndmp_include_lmtime = ndmpd_get_prop_yorn(NDMP_INCLMTIME_ENV) ?
2642 	    TRUE : FALSE;
2643 	ndmp_max_tok_seq = atoi(ndmpd_get_prop_default(NDMP_MAXSEQ_ENV, "9"));
2644 
2645 	ndmp_full_restore_path = ndmpd_get_prop_yorn(NDMP_FULL_RESTORE_PATH) ?
2646 	    TRUE : FALSE;
2647 
2648 	ndmp_fhinode = ndmpd_get_prop_yorn(NDMP_FHIST_INCR_ENV) ? TRUE : FALSE;
2649 
2650 	/* Get the value from ndmp SMF property. */
2651 	ndmp_dar_support = ndmpd_get_prop_yorn(NDMP_DAR_SUPPORT);
2652 
2653 	if ((ndmp_ver = atoi(ndmpd_get_prop(NDMP_VERSION_ENV))) == 0)
2654 		ndmp_ver = NDMPVER;
2655 }
2656 
2657 /*
2658  * randomize
2659  *
2660  * Randomize the contents of a buffer
2661  *
2662  * Parameter:
2663  *   buffer (output) - destination buffer
2664  *   size (input) - buffer size
2665  *
2666  * Returns:
2667  *   void
2668  */
2669 void
2670 randomize(unsigned char *buffer, int size)
2671 {
2672 	/* LINTED improper alignment */
2673 	unsigned int *p = (unsigned int *)buffer;
2674 	unsigned int dwlen = size / sizeof (unsigned int);
2675 	unsigned int remlen = size % sizeof (unsigned int);
2676 	unsigned int tmp;
2677 	unsigned int i;
2678 
2679 	for (i = 0; i < dwlen; i++)
2680 		*p++ = random();
2681 
2682 	if (remlen) {
2683 		tmp = random();
2684 		(void) memcpy(p, &tmp, remlen);
2685 	}
2686 }
2687 
2688 /*
2689  * ndmpd_get_file_entry_type
2690  *
2691  * Converts the mode to the NDMP file type
2692  *
2693  * Parameter:
2694  *   mode (input) - file mode
2695  *   ftype (output) - file type
2696  *
2697  * Returns:
2698  *   void
2699  */
2700 void
2701 ndmpd_get_file_entry_type(int mode, ndmp_file_type *ftype)
2702 {
2703 	switch (mode & S_IFMT) {
2704 	case S_IFIFO:
2705 		*ftype = NDMP_FILE_FIFO;
2706 		break;
2707 	case S_IFCHR:
2708 		*ftype = NDMP_FILE_CSPEC;
2709 		break;
2710 	case S_IFDIR:
2711 		*ftype = NDMP_FILE_DIR;
2712 		break;
2713 	case S_IFBLK:
2714 		*ftype = NDMP_FILE_BSPEC;
2715 		break;
2716 	case S_IFREG:
2717 		*ftype = NDMP_FILE_REG;
2718 		break;
2719 	case S_IFLNK:
2720 		*ftype = NDMP_FILE_SLINK;
2721 		break;
2722 	default:
2723 		*ftype = NDMP_FILE_SOCK;
2724 		break;
2725 	}
2726 }
2727 
2728 /*
2729  * Set a private data in the plugin context
2730  */
2731 void
2732 ndmp_context_set_specific(ndmp_context_t *nctx, void *ptr)
2733 {
2734 	nctx->nc_pldata = ptr;
2735 }
2736 
2737 /*
2738  * Get a private data in the plugin context
2739  */
2740 void *
2741 ndmp_context_get_specific(ndmp_context_t *nctx)
2742 {
2743 	return (nctx->nc_pldata);
2744 }
2745