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