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