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