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 */
71boolean_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 */
78boolean_t ndmp_tar_path_node = FALSE;
79
80
81/*
82 * Should the 'st_ctime' be ignored during incremental level backup?
83 */
84boolean_t ndmp_ignore_ctime = FALSE;
85
86/*
87 * Should the 'st_lmtime' be included during incremental level backup?
88 */
89boolean_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 */
100boolean_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 */
107static 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 */
114int 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 */
126struct 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};
135LIST_HEAD(ol_head, open_list);
136
137
138/*
139 * Head of the opened SCSI devices list.
140 */
141static struct ol_head ol_head;
142
143mutex_t ol_mutex = DEFAULTMUTEX;
144
145
146/*
147 * List of things to be exluded from backup.
148 */
149static 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."
161static int ndmp_job_cnt = 0;
162
163static 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 */
187int
188ndmpd_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 */
221int
222ndmpd_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 */
256int
257ndmp_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 */
290void
291ndmp_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 */
349int
350ndmpd_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 */
498ndmp_error
499ndmpd_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 */
550void
551ndmpd_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 */
585ndmp_error
586ndmpd_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 */
638void
639ndmpd_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 */
666void
667ndmpd_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 */
700ndmp_error
701ndmpd_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 */
774void
775ndmpd_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 */
809static int
810fh_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 */
837void
838ndmp_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 */
862void
863ndmp_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 */
880int
881ndmp_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 */
901u_longlong_t
902quad_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 */
916ndmp_u_quad
917long_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
926void
927set_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 */
970int
971ndmp_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 */
987long
988ndmp_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 */
1027int
1028ndmp_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 */
1061void
1062ndmp_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 */
1092int
1093ndmp_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	return ((session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE) ?
1138	    0 : -1);
1139}
1140
1141/*
1142 * is_buffer_erroneous
1143 *
1144 * Run a sanity check on the buffer
1145 *
1146 * returns:
1147 *   TRUE: if the buffer seems to have error
1148 *   FALSE: if the buffer is full and has valid data.
1149 */
1150boolean_t
1151is_buffer_erroneous(tlm_buffer_t *buf)
1152{
1153	boolean_t rv;
1154
1155	rv = (buf == NULL || buf->tb_eot || buf->tb_eof ||
1156	    buf->tb_errno != 0);
1157	if (rv) {
1158		if (buf == NULL) {
1159			NDMP_LOG(LOG_DEBUG, "buf == NULL");
1160		} else {
1161			NDMP_LOG(LOG_DEBUG, "eot: %u, eof: %u, errno: %d",
1162			    buf->tb_eot, buf->tb_eof, buf->tb_errno);
1163		}
1164	}
1165
1166	return (rv);
1167}
1168
1169/*
1170 * ndmp_execute_cdb
1171 *
1172 * Main SCSI CDB execution program, this is used by message handler
1173 * for the NDMP tape/SCSI execute CDB requests. This function uses
1174 * USCSI interface to run the CDB command and sets all the CDB parameters
1175 * in the SCSI query before calling the USCSI ioctl. The result of the
1176 * CDB is returned in two places:
1177 *    cmd.uscsi_status		The status of CDB execution
1178 *    cmd.uscsi_rqstatus	The status of sense requests
1179 *    reply.error		The general errno (ioctl)
1180 *
1181 * Parameters:
1182 *   session (input) - session pointer
1183 *   adapter_name (input) - name of SCSI adapter
1184 *   sid (input) - SCSI target ID
1185 *   lun (input) - LUN number
1186 *   request (input) - NDMP client CDB request
1187 *
1188 * Returns:
1189 *   void
1190 */
1191/*ARGSUSED*/
1192void
1193ndmp_execute_cdb(ndmpd_session_t *session, char *adapter_name, int sid, int lun,
1194    ndmp_execute_cdb_request *request)
1195{
1196	ndmp_execute_cdb_reply reply;
1197	struct uscsi_cmd cmd;
1198	int fd;
1199	struct open_list *olp;
1200	char rq_buf[255];
1201
1202	(void) memset((void *)&cmd, 0, sizeof (cmd));
1203	(void) memset((void *)&reply, 0, sizeof (reply));
1204	(void) memset((void *)rq_buf, 0, sizeof (rq_buf));
1205
1206	if (request->flags == NDMP_SCSI_DATA_IN) {
1207		cmd.uscsi_flags = USCSI_READ | USCSI_RQENABLE;
1208		if ((cmd.uscsi_bufaddr =
1209		    ndmp_malloc(request->datain_len)) == 0) {
1210			reply.error = NDMP_NO_MEM_ERR;
1211			if (ndmp_send_response(session->ns_connection,
1212			    NDMP_NO_ERR, (void *)&reply) < 0)
1213				NDMP_LOG(LOG_DEBUG, "error sending"
1214				    " scsi_execute_cdb reply.");
1215			return;
1216		}
1217
1218		cmd.uscsi_buflen = request->datain_len;
1219	} else if (request->flags == NDMP_SCSI_DATA_OUT) {
1220		cmd.uscsi_flags = USCSI_WRITE | USCSI_RQENABLE;
1221		cmd.uscsi_bufaddr = request->dataout.dataout_val;
1222		cmd.uscsi_buflen = request->dataout.dataout_len;
1223	} else {
1224		cmd.uscsi_flags = USCSI_RQENABLE;
1225		cmd.uscsi_bufaddr = 0;
1226		cmd.uscsi_buflen = 0;
1227	}
1228	cmd.uscsi_rqlen = sizeof (rq_buf);
1229	cmd.uscsi_rqbuf = rq_buf;
1230
1231	cmd.uscsi_timeout = (request->timeout < 1000) ?
1232	    1 : (request->timeout / 1000);
1233
1234	cmd.uscsi_cdb = (caddr_t)request->cdb.cdb_val;
1235	cmd.uscsi_cdblen = request->cdb.cdb_len;
1236
1237	NDMP_LOG(LOG_DEBUG, "cmd: 0x%x, len: %d, flags: %d, datain_len: %d",
1238	    request->cdb.cdb_val[0] & 0xff, request->cdb.cdb_len,
1239	    request->flags, request->datain_len);
1240	NDMP_LOG(LOG_DEBUG, "dataout_len: %d, timeout: %d",
1241	    request->dataout.dataout_len, request->timeout);
1242
1243	if (request->cdb.cdb_len > 12) {
1244		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1245		ndmp_send_reply(session->ns_connection, (void *) &reply,
1246		    "sending execute_cdb reply");
1247		if (request->flags == NDMP_SCSI_DATA_IN)
1248			free(cmd.uscsi_bufaddr);
1249		return;
1250	}
1251
1252	reply.error = NDMP_NO_ERR;
1253
1254	if ((olp = ndmp_open_list_find(adapter_name, sid, lun)) != NULL) {
1255		fd = olp->ol_fd;
1256	} else {
1257		reply.error = NDMP_DEV_NOT_OPEN_ERR;
1258		ndmp_send_reply(session->ns_connection, (void *) &reply,
1259		    "sending execute_cdb reply");
1260		if (request->flags == NDMP_SCSI_DATA_IN)
1261			free(cmd.uscsi_bufaddr);
1262		return;
1263	}
1264
1265	if (ioctl(fd, USCSICMD, &cmd) < 0) {
1266		if (errno != EIO && errno != 0)
1267			NDMP_LOG(LOG_ERR,
1268			    "Failed to send command to device: %m");
1269		NDMP_LOG(LOG_DEBUG, "ioctl(USCSICMD) error: %m");
1270		if (cmd.uscsi_status == 0)
1271			reply.error = NDMP_IO_ERR;
1272	}
1273
1274	reply.status = cmd.uscsi_status;
1275
1276	if (request->flags == NDMP_SCSI_DATA_IN) {
1277		reply.datain.datain_len = cmd.uscsi_buflen;
1278		reply.datain.datain_val = cmd.uscsi_bufaddr;
1279	} else {
1280		reply.dataout_len = request->dataout.dataout_len;
1281	}
1282
1283	reply.ext_sense.ext_sense_len = cmd.uscsi_rqlen - cmd.uscsi_rqresid;
1284	reply.ext_sense.ext_sense_val = rq_buf;
1285
1286	if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1287	    (void *)&reply) < 0)
1288		NDMP_LOG(LOG_DEBUG, "Error sending scsi_execute_cdb reply.");
1289
1290	if (request->flags == NDMP_SCSI_DATA_IN)
1291		free(cmd.uscsi_bufaddr);
1292}
1293
1294
1295/*
1296 * ndmp_stop_local_reader
1297 *
1298 * Stops a mover reader thread (for local backup only)
1299 *
1300 * Parameters:
1301 *   session (input) - session pointer
1302 *   cmds (input) - reader/writer command struct
1303 *
1304 * Returns:
1305 *   void
1306 */
1307void
1308ndmp_stop_local_reader(ndmpd_session_t *session, tlm_commands_t *cmds)
1309{
1310	ndmp_lbr_params_t *nlp;
1311
1312	if (session != NULL && session->ns_data.dd_sock == -1) {
1313		/* 2-way restore */
1314		if (cmds != NULL && cmds->tcs_reader_count > 0) {
1315			if ((nlp = ndmp_get_nlp(session)) != NULL) {
1316				(void) mutex_lock(&nlp->nlp_mtx);
1317				cmds->tcs_command->tc_reader = TLM_STOP;
1318				(void) cond_broadcast(&nlp->nlp_cv);
1319				(void) mutex_unlock(&nlp->nlp_mtx);
1320			}
1321		}
1322	}
1323}
1324
1325
1326/*
1327 * Stops a mover reader thread (for remote backup only)
1328 *
1329 * Parameters:
1330 *   session (input) - session pointer
1331 *   cmds (input) - reader/writer command struct
1332 *
1333 * Returns:
1334 *   void
1335 */
1336void
1337ndmp_stop_remote_reader(ndmpd_session_t *session)
1338{
1339	if (session != NULL) {
1340		if (session->ns_data.dd_sock >= 0) {
1341			/*
1342			 * 3-way restore.
1343			 */
1344			NDMP_LOG(LOG_DEBUG,
1345			    "data.sock: %d", session->ns_data.dd_sock);
1346			(void) close(session->ns_data.dd_sock);
1347			session->ns_data.dd_sock = -1;
1348		}
1349	}
1350}
1351
1352
1353/*
1354 * ndmp_wait_for_reader
1355 *
1356 * Wait for a reader until get done (busy wait)
1357 */
1358void
1359ndmp_wait_for_reader(tlm_commands_t *cmds)
1360{
1361	if (cmds == NULL) {
1362		NDMP_LOG(LOG_DEBUG, "cmds == NULL");
1363	} else {
1364		NDMP_LOG(LOG_DEBUG,
1365		    "reader_count: %d", cmds->tcs_reader_count);
1366
1367		while (cmds->tcs_reader_count > 0)
1368			(void) sleep(1);
1369	}
1370}
1371
1372
1373/*
1374 * ndmp_open_list_find
1375 *
1376 * Find a specific device in the open list
1377 *
1378 * Parameters:
1379 *   dev (input) - device name
1380 *   sid (input) - SCSI target ID
1381 *   lun (input) - LUN number
1382 *
1383 * Returns:
1384 *   pointer to the open list entry
1385 */
1386struct open_list *
1387ndmp_open_list_find(char *dev, int sid, int lun)
1388{
1389	struct ol_head *olhp;
1390	struct open_list *olp;
1391
1392	if (dev == NULL || *dev == '\0') {
1393		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1394		return (NULL);
1395	}
1396
1397	(void) mutex_lock(&ol_mutex);
1398	olhp = &ol_head;
1399	for (olp = LIST_FIRST(olhp); olp != NULL; olp = LIST_NEXT(olp, ol_q))
1400		if (strcmp(olp->ol_devnm, dev) == 0 && olp->ol_sid == sid &&
1401		    olp->ol_lun == lun) {
1402			(void) mutex_unlock(&ol_mutex);
1403			return (olp);
1404		}
1405
1406	(void) mutex_unlock(&ol_mutex);
1407	return (NULL);
1408}
1409
1410
1411/*
1412 * ndmp_open_list_add
1413 *
1414 * Add a specific device to the open list
1415 *
1416 * Parameters:
1417 *   conn (input) - connection pointer
1418 *   dev (input) - device name
1419 *   sid (input) - SCSI target ID
1420 *   lun (input) - LUN number
1421 *   fd (input) - the device file descriptor
1422 *
1423 * Returns:
1424 *   errno
1425 */
1426int
1427ndmp_open_list_add(ndmp_connection_t *conn, char *dev, int sid, int lun, int fd)
1428{
1429	int err;
1430	struct ol_head *olhp;
1431	struct open_list *olp;
1432
1433	if (dev == NULL || *dev == '\0') {
1434		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1435		return (EINVAL);
1436	}
1437	NDMP_LOG(LOG_DEBUG,
1438	    "conn: 0x%08x, dev: %s, sid: %d, lun: %d", conn, dev, sid, lun);
1439
1440	err = 0;
1441	olhp = &ol_head;
1442
1443	if ((olp = ndmp_open_list_find(dev, sid, lun)) != NULL) {
1444		NDMP_LOG(LOG_DEBUG, "already in list");
1445		/*
1446		 * The adapter handle can be opened many times by the clients.
1447		 * Only when the target is set, we must check and reject the
1448		 * open request if the device is already being used by another
1449		 * session.
1450		 */
1451		if (sid == -1)
1452			olp->ol_nref++;
1453		else
1454			err = EBUSY;
1455	} else if ((olp = ndmp_malloc(sizeof (struct open_list))) == NULL) {
1456		err = ENOMEM;
1457	} else if ((olp->ol_devnm = strdup(dev)) == NULL) {
1458		NDMP_LOG(LOG_ERR, "Out of memory.");
1459		free(olp);
1460		err = ENOMEM;
1461	} else {
1462		olp->cl_conn = conn;
1463		olp->ol_nref = 1;
1464		olp->ol_sid = sid;
1465		olp->ol_lun = lun;
1466		if (fd > 0)
1467			olp->ol_fd = fd;
1468		else
1469			olp->ol_fd = -1;
1470		(void) mutex_lock(&ol_mutex);
1471		LIST_INSERT_HEAD(olhp, olp, ol_q);
1472		(void) mutex_unlock(&ol_mutex);
1473	}
1474
1475	return (err);
1476}
1477
1478
1479/*
1480 * ndmp_open_list_del
1481 *
1482 * Delete a specific device from the open list
1483 *
1484 * Parameters:
1485 *   dev (input) - device name
1486 *   sid (input) - SCSI target ID
1487 *   lun (input) - LUN number
1488 *
1489 * Returns:
1490 *   errno
1491 */
1492int
1493ndmp_open_list_del(char *dev, int sid, int lun)
1494{
1495	struct open_list *olp;
1496
1497	if (dev == NULL || *dev == '\0') {
1498		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1499		return (EINVAL);
1500	}
1501	if ((olp = ndmp_open_list_find(dev, sid, lun)) == NULL) {
1502		NDMP_LOG(LOG_DEBUG, "%s not found", dev);
1503		return (ENOENT);
1504	}
1505
1506	(void) mutex_lock(&ol_mutex);
1507	if (--olp->ol_nref <= 0) {
1508		NDMP_LOG(LOG_DEBUG,
1509		    "Removed dev: %s, sid: %d, lun: %d", dev, sid, lun);
1510		LIST_REMOVE(olp, ol_q);
1511		free(olp->ol_devnm);
1512		free(olp);
1513	}
1514	(void) mutex_unlock(&ol_mutex);
1515
1516	return (0);
1517}
1518
1519
1520/*
1521 * ndmp_open_list_release
1522 *
1523 * Close all the resources belonging to this connection.
1524 *
1525 * Parameters:
1526 *    ndmp_connection_t *conn : connection identifier
1527 *
1528 * Returns:
1529 *   void
1530 */
1531void
1532ndmp_open_list_release(ndmp_connection_t *conn)
1533{
1534	struct ol_head *olhp = &ol_head;
1535	struct open_list *olp;
1536	struct open_list *next;
1537
1538	(void) mutex_lock(&ol_mutex);
1539	olp = LIST_FIRST(olhp);
1540	while (olp != NULL) {
1541		next = LIST_NEXT(olp, ol_q);
1542		NDMP_LOG(LOG_DEBUG, "olp->conn 0x%08x", olp->cl_conn);
1543		if (olp->cl_conn == conn) {
1544			NDMP_LOG(LOG_DEBUG,
1545			    "Removed dev: %s, sid: %d, lun: %d",
1546			    olp->ol_devnm, olp->ol_sid, olp->ol_lun);
1547			LIST_REMOVE(olp, ol_q);
1548			if (olp->ol_fd > 0)
1549				(void) close(olp->ol_fd);
1550			free(olp->ol_devnm);
1551			free(olp);
1552		}
1553		olp = next;
1554	}
1555	(void) mutex_unlock(&ol_mutex);
1556}
1557
1558
1559/*
1560 * ndmp_stop_buffer_worker
1561 *
1562 * Stop all reader and writer threads for a specific buffer.
1563 *
1564 * Parameters:
1565 *   session (input) - session pointer
1566 *
1567 * Returns:
1568 *   void
1569 */
1570void
1571ndmp_stop_buffer_worker(ndmpd_session_t *session)
1572{
1573	ndmp_lbr_params_t *nlp;
1574	tlm_commands_t *cmds;
1575
1576	session->ns_tape.td_pos = 0;
1577	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1578		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1579	} else {
1580		cmds = &nlp->nlp_cmds;
1581		if (cmds->tcs_command == NULL) {
1582			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL");
1583		} else {
1584			cmds->tcs_reader = cmds->tcs_writer = TLM_ABORT;
1585			cmds->tcs_command->tc_reader = TLM_ABORT;
1586			cmds->tcs_command->tc_writer = TLM_ABORT;
1587			while (cmds->tcs_reader_count > 0 ||
1588			    cmds->tcs_writer_count > 0) {
1589				NDMP_LOG(LOG_DEBUG,
1590				    "trying to stop buffer worker");
1591				(void) sleep(1);
1592			}
1593		}
1594	}
1595}
1596
1597
1598/*
1599 * ndmp_stop_reader_thread
1600 *
1601 * Stop only the reader threads of a specific buffer
1602 *
1603 * Parameters:
1604 *   session (input) - session pointer
1605 *
1606 * Returns:
1607 *   void
1608 */
1609void
1610ndmp_stop_reader_thread(ndmpd_session_t *session)
1611{
1612	ndmp_lbr_params_t *nlp;
1613	tlm_commands_t *cmds;
1614
1615	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1616		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1617	} else {
1618		cmds = &nlp->nlp_cmds;
1619		if (cmds->tcs_command == NULL) {
1620			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL");
1621		} else {
1622			cmds->tcs_reader = TLM_ABORT;
1623			cmds->tcs_command->tc_reader = TLM_ABORT;
1624			while (cmds->tcs_reader_count > 0) {
1625				NDMP_LOG(LOG_DEBUG,
1626				    "trying to stop reader thread");
1627				(void) sleep(1);
1628			}
1629		}
1630	}
1631}
1632
1633
1634/*
1635 * ndmp_stop_reader_thread
1636 *
1637 * Stop only the writer threads of a specific buffer
1638 *
1639 * Parameters:
1640 *   session (input) - session pointer
1641 *
1642 * Returns:
1643 *   void
1644 */
1645void
1646ndmp_stop_writer_thread(ndmpd_session_t *session)
1647{
1648	ndmp_lbr_params_t *nlp;
1649	tlm_commands_t *cmds;
1650
1651	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1652		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1653	} else {
1654		cmds = &nlp->nlp_cmds;
1655		if (cmds->tcs_command == NULL) {
1656			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL");
1657		} else {
1658			(void) mutex_lock(&nlp->nlp_mtx);
1659			cmds->tcs_writer = TLM_ABORT;
1660			cmds->tcs_command->tc_writer = TLM_ABORT;
1661			(void) cond_broadcast(&nlp->nlp_cv);
1662			(void) mutex_unlock(&nlp->nlp_mtx);
1663			while (cmds->tcs_writer_count > 0) {
1664				NDMP_LOG(LOG_DEBUG,
1665				    "trying to stop writer thread");
1666				(void) sleep(1);
1667			}
1668		}
1669	}
1670}
1671
1672
1673/*
1674 * ndmp_free_reader_writer_ipc
1675 *
1676 * Free and release the reader/writer buffers and the IPC structure
1677 * for reader and writer threads.
1678 *
1679 * Parameters:
1680 *   session (input) - session pointer
1681 *
1682 * Returns:
1683 *   void
1684 */
1685void
1686ndmp_free_reader_writer_ipc(ndmpd_session_t *session)
1687{
1688	ndmp_lbr_params_t *nlp;
1689	tlm_commands_t *cmds;
1690
1691	if ((nlp = ndmp_get_nlp(session)) != NULL) {
1692		cmds = &nlp->nlp_cmds;
1693		if (cmds->tcs_command != NULL) {
1694			NDMP_LOG(LOG_DEBUG, "cmds->tcs_command->tc_ref: %d",
1695			    cmds->tcs_command->tc_ref);
1696			tlm_release_reader_writer_ipc(cmds->tcs_command);
1697		}
1698	}
1699}
1700
1701
1702/*
1703 * ndmp_waitfor_op
1704 *
1705 * Wait for a session reference count to drop to zero
1706 *
1707 * Parameters:
1708 *   session (input) - session pointer
1709 *
1710 * Returns:
1711 *   void
1712 */
1713void
1714ndmp_waitfor_op(ndmpd_session_t *session)
1715{
1716	if (session != NULL) {
1717		while (session->ns_nref > 0) {
1718			(void) sleep(1);
1719			NDMP_LOG(LOG_DEBUG,
1720			    "waiting for session nref: %d", session->ns_nref);
1721		}
1722	}
1723}
1724
1725
1726/*
1727 * ndmp_session_ref
1728 *
1729 * Increment the reference count of the session
1730 *
1731 * Parameters:
1732 *   session (input) - session pointer
1733 *
1734 * Returns:
1735 *   void
1736 */
1737void
1738ndmp_session_ref(ndmpd_session_t *session)
1739{
1740	(void) mutex_lock(&session->ns_lock);
1741	session->ns_nref++;
1742	(void) mutex_unlock(&session->ns_lock);
1743}
1744
1745
1746/*
1747 * ndmp_session_unref
1748 *
1749 * Decrement the reference count of the session
1750 *
1751 * Parameters:
1752 *   session (input) - session pointer
1753 *
1754 * Returns:
1755 *   void
1756 */
1757void
1758ndmp_session_unref(ndmpd_session_t *session)
1759{
1760	(void) mutex_lock(&session->ns_lock);
1761	session->ns_nref--;
1762	(void) mutex_unlock(&session->ns_lock);
1763}
1764
1765
1766/*
1767 * ndmp_addr2str_v3
1768 *
1769 * Convert the address type to a string
1770 *
1771 * Parameters:
1772 *   type (input) - address type
1773 *
1774 * Returns:
1775 *   type in string
1776 */
1777char *
1778ndmp_addr2str_v3(ndmp_addr_type type)
1779{
1780	char *rv;
1781
1782	switch (type) {
1783	case NDMP_ADDR_LOCAL:
1784		rv = "Local";
1785		break;
1786	case NDMP_ADDR_TCP:
1787		rv = "TCP";
1788		break;
1789	case NDMP_ADDR_FC:
1790		rv = "FC";
1791		break;
1792	case NDMP_ADDR_IPC:
1793		rv = "IPC";
1794		break;
1795	default:
1796		rv = "Unknown";
1797	}
1798
1799	return (rv);
1800}
1801
1802
1803/*
1804 * ndmp_valid_v3addr_type
1805 *
1806 * Make sure that the NDMP address is from any of the
1807 * valid types
1808 *
1809 * Parameters:
1810 *   type (input) - address type
1811 *
1812 * Returns:
1813 *   1: valid
1814 *   0: invalid
1815 */
1816boolean_t
1817ndmp_valid_v3addr_type(ndmp_addr_type type)
1818{
1819	boolean_t rv;
1820
1821	switch (type) {
1822	case NDMP_ADDR_LOCAL:
1823	case NDMP_ADDR_TCP:
1824	case NDMP_ADDR_FC:
1825	case NDMP_ADDR_IPC:
1826		rv = TRUE;
1827		break;
1828	default:
1829		rv = FALSE;
1830	}
1831
1832	return (rv);
1833}
1834
1835
1836/*
1837 * ndmp_copy_addr_v3
1838 *
1839 * Copy NDMP address from source to destination (V2 and V3 only)
1840 *
1841 * Parameters:
1842 *   dst (ouput) - destination address
1843 *   src (input) - source address
1844 *
1845 * Returns:
1846 *   void
1847 */
1848void
1849ndmp_copy_addr_v3(ndmp_addr_v3 *dst, ndmp_addr_v3 *src)
1850{
1851	dst->addr_type = src->addr_type;
1852	switch (src->addr_type) {
1853	case NDMP_ADDR_LOCAL:
1854		/* nothing */
1855		break;
1856	case NDMP_ADDR_TCP:
1857		dst->tcp_ip_v3 = htonl(src->tcp_ip_v3);
1858		dst->tcp_port_v3 = src->tcp_port_v3;
1859		break;
1860	case NDMP_ADDR_FC:
1861	case NDMP_ADDR_IPC:
1862	default:
1863		break;
1864	}
1865}
1866
1867
1868/*
1869 * ndmp_copy_addr_v4
1870 *
1871 * Copy NDMP address from source to destination. V4 has a extra
1872 * environment list inside the address too which needs to be copied.
1873 *
1874 * Parameters:
1875 *   dst (ouput) - destination address
1876 *   src (input) - source address
1877 *
1878 * Returns:
1879 *   void
1880 */
1881void
1882ndmp_copy_addr_v4(ndmp_addr_v4 *dst, ndmp_addr_v4 *src)
1883{
1884	int i;
1885
1886	dst->addr_type = src->addr_type;
1887	dst->tcp_len_v4 = src->tcp_len_v4;
1888	switch (src->addr_type) {
1889	case NDMP_ADDR_LOCAL:
1890		/* nothing */
1891		break;
1892	case NDMP_ADDR_TCP:
1893		dst->tcp_addr_v4 = ndmp_malloc(sizeof (ndmp_tcp_addr_v4) *
1894		    src->tcp_len_v4);
1895		if (dst->tcp_addr_v4 == 0)
1896			return;
1897
1898		for (i = 0; i < src->tcp_len_v4; i++) {
1899			dst->tcp_ip_v4(i) = htonl(src->tcp_ip_v4(i));
1900			dst->tcp_port_v4(i) = src->tcp_port_v4(i);
1901			dst->tcp_env_v4(i).addr_env_len = 0; /* Solaris */
1902			dst->tcp_env_v4(i).addr_env_val = 0; /* Solaris */
1903		}
1904		break;
1905	case NDMP_ADDR_FC:
1906	case NDMP_ADDR_IPC:
1907	default:
1908		break;
1909	}
1910}
1911
1912
1913/*
1914 * ndmp_connect_sock_v3
1915 *
1916 * Creates a socket and connects to the specified address/port
1917 *
1918 * Parameters:
1919 *   addr (input) - IP address
1920 *   port (input) - port number
1921 *
1922 * Returns:
1923 *   0: on success
1924 *  -1: otherwise
1925 */
1926int
1927ndmp_connect_sock_v3(ulong_t addr, ushort_t port)
1928{
1929	int sock;
1930	struct sockaddr_in sin;
1931
1932	NDMP_LOG(LOG_DEBUG, "addr %s:%d", inet_ntoa(IN_ADDR(addr)), port);
1933
1934	sock = socket(AF_INET, SOCK_STREAM, 0);
1935	if (sock < 0) {
1936		NDMP_LOG(LOG_DEBUG, "Socket error: %m");
1937		return (-1);
1938	}
1939
1940	(void) memset((void *) &sin, 0, sizeof (sin));
1941	sin.sin_family = AF_INET;
1942	sin.sin_addr.s_addr = htonl(addr);
1943	sin.sin_port = htons(port);
1944	if (connect(sock, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
1945		NDMP_LOG(LOG_DEBUG, "Connect error: %m");
1946		(void) close(sock);
1947		return (-1);
1948	}
1949
1950	set_socket_options(sock);
1951	NDMP_LOG(LOG_DEBUG, "sock %d", sock);
1952
1953	return (sock);
1954}
1955
1956/*
1957 * ndmp_create_socket
1958 *
1959 * Creates a socket for listening for accepting data connections.
1960 *
1961 * Parameters:
1962 *   session (input)  - session pointer.
1963 *   addr    (output) - location to store address of socket.
1964 *   port    (output) - location to store port of socket.
1965 *
1966 * Returns:
1967 *   0 - success.
1968 *  -1 - error.
1969 */
1970int
1971ndmp_create_socket(ulong_t *addr, ushort_t *port)
1972{
1973	char *p;
1974	int length;
1975	int sd;
1976	struct sockaddr_in sin;
1977
1978	/* Try the user's prefered NIC IP address */
1979	p = ndmpd_get_prop(NDMP_MOVER_NIC);
1980
1981	/* Try host's IP address */
1982	if (!p || *p == 0)
1983		p = gethostaddr();
1984
1985	/* Try default NIC's IP address (if DNS failed) */
1986	if (!p)
1987		p = get_default_nic_addr();
1988
1989	/* Fail if no IP can be obtained */
1990	if (!p) {
1991		NDMP_LOG(LOG_ERR, "Undetermined network port.");
1992		return (-1);
1993	}
1994
1995	*addr = inet_addr(p);
1996
1997	sd = socket(AF_INET, SOCK_STREAM, 0);
1998	if (sd < 0) {
1999		NDMP_LOG(LOG_DEBUG, "Socket error: %m");
2000		return (-1);
2001	}
2002	sin.sin_family = AF_INET;
2003	sin.sin_addr.s_addr = INADDR_ANY;
2004	sin.sin_port = 0;
2005	length = sizeof (sin);
2006
2007	if (bind(sd, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
2008		NDMP_LOG(LOG_DEBUG, "Bind error: %m");
2009		(void) close(sd);
2010		sd = -1;
2011	} else if (getsockname(sd, (struct sockaddr *)&sin, &length) < 0) {
2012		NDMP_LOG(LOG_DEBUG, "getsockname error: %m");
2013		(void) close(sd);
2014		sd = -1;
2015	} else if (listen(sd, 5) < 0) {
2016		NDMP_LOG(LOG_DEBUG, "Listen error: %m");
2017		(void) close(sd);
2018		sd = -1;
2019	} else
2020		*port = sin.sin_port;
2021
2022	return (sd);
2023}
2024
2025
2026/*
2027 * cctime
2028 *
2029 * Convert the specified time into a string.  It's like
2030 * ctime(), but:
2031 *     - chops the trailing '\n' of ctime.
2032 *     - and returns "the epoch" if time is 0.
2033 *
2034 * Returns:
2035 *     "": invalid argument.
2036 *     "the epoch": if time is 0.
2037 *     string format of the time.
2038 */
2039char *
2040cctime(time_t *t)
2041{
2042	char *bp, *cp;
2043	static char tbuf[BUFSIZ];
2044
2045	if (!t)
2046		return ("");
2047
2048	if (*t == (time_t)0)
2049		return ("the epoch");
2050
2051	if ((bp = ctime_r(t, tbuf, BUFSIZ)) == NULL)
2052		return ("");
2053
2054	cp = strchr(bp, '\n');
2055	if (cp)
2056		*cp = '\0';
2057
2058	return (bp);
2059}
2060
2061
2062/*
2063 * ndmp_new_job_name
2064 *
2065 * Create a job name for each backup/restore to keep track
2066 *
2067 * Parameters:
2068 *   jname (output) - job name
2069 *
2070 * Returns:
2071 *   jname
2072 */
2073char *
2074ndmp_new_job_name(char *jname)
2075{
2076	if (jname != NULL) {
2077		(void) snprintf(jname, TLM_MAX_BACKUP_JOB_NAME, "%s%d",
2078		    NDMP_RCF_BASENAME, ndmp_job_cnt++);
2079		NDMP_LOG(LOG_DEBUG, "jname: \"%s\"", jname);
2080	}
2081
2082	return (jname);
2083}
2084
2085
2086/*
2087 * fs_is_valid_logvol
2088 *
2089 * Check if the log path exists
2090 *
2091 * Parameters:
2092 *   path (input) - log path
2093 *
2094 * Returns:
2095 *   FALSE: invalid
2096 *   TRUE: valid
2097 */
2098boolean_t
2099fs_is_valid_logvol(char *path)
2100{
2101	struct stat64 st;
2102
2103	if (stat64(path, &st) < 0)
2104		return (FALSE);
2105
2106	return (TRUE);
2107}
2108
2109
2110/*
2111 * ndmpd_mk_temp
2112 *
2113 * Make a temporary file using the working directory path and the
2114 * jobname
2115 *
2116 * Parameters:
2117 *   buf (output) - the temporary file name path
2118 *
2119 * Returns:
2120 *   buf
2121 */
2122char *
2123ndmpd_mk_temp(char *buf)
2124{
2125	char fname[TLM_MAX_BACKUP_JOB_NAME];
2126	const char *dir;
2127	char *rv;
2128
2129	if (!buf)
2130		return (NULL);
2131
2132	dir = ndmpd_get_prop(NDMP_DEBUG_PATH);
2133	if (dir == 0 || *dir == '\0') {
2134		NDMP_LOG(LOG_DEBUG, "NDMP work path not specified");
2135		return (0);
2136	}
2137
2138	if (!fs_is_valid_logvol((char *)dir)) {
2139		NDMP_LOG(LOG_ERR,
2140		    "Log file path cannot be on system volumes.");
2141		return (0);
2142	}
2143
2144	dir += strspn(dir, " \t");
2145	if (!*dir) {
2146		NDMP_LOG(LOG_DEBUG, "NDMP work path not specified");
2147		return (0);
2148	}
2149
2150	rv = buf;
2151	(void) ndmp_new_job_name(fname);
2152	(void) tlm_cat_path(buf, (char *)dir, fname);
2153
2154	return (rv);
2155}
2156
2157
2158/*
2159 * ndmpd_make_bk_dir_path
2160 *
2161 * Make a directory path for temporary files under the NDMP
2162 * working directory.
2163 *
2164 * Parameters:
2165 *   buf (output) - result path
2166 *   fname (input) - the file name
2167 *
2168 * Returns:
2169 *   buf
2170 */
2171char *
2172ndmpd_make_bk_dir_path(char *buf, char *fname)
2173{
2174	const char *p;
2175	char *name;
2176	char path[PATH_MAX];
2177
2178	if (!buf || !fname || !*fname)
2179		return (NULL);
2180
2181	p = ndmpd_get_prop(NDMP_DEBUG_PATH);
2182	if (p == NULL || *p == '\0' || !fs_is_valid_logvol((char *)p)) {
2183		return (NULL);
2184	}
2185
2186	(void) strlcpy(path, (char *)p, PATH_MAX);
2187	(void) trim_whitespace(path);
2188
2189	if ((name = strrchr(fname, '/')) == 0)
2190		name = fname;
2191
2192	(void) tlm_cat_path(buf, path, name);
2193	return (buf);
2194}
2195
2196
2197/*
2198 * ndmp_is_chkpnt_root
2199 *
2200 * Is this a root checkpoint (snapshot) directory.
2201 * Note: a temporary function
2202 */
2203boolean_t
2204ndmp_is_chkpnt_root(char *path)
2205{
2206	struct stat64 st;
2207
2208	if (stat64(path, &st) != 0) {
2209		NDMP_LOG(LOG_DEBUG, "Couldn't stat path \"%s\"", path);
2210		return (TRUE);
2211	}
2212	return (FALSE);
2213}
2214
2215
2216/*
2217 * ndmpd_make_exc_list
2218 *
2219 * Make a list of files that should not be backed up.
2220 *
2221 * Parameters:
2222 *   void
2223 *
2224 * Returns:
2225 *   list - array of character strings
2226 */
2227char **
2228ndmpd_make_exc_list(void)
2229{
2230	char *val, **cpp;
2231	int i, n;
2232
2233	n = sizeof (exls);
2234	if ((cpp = ndmp_malloc(n)) != NULL) {
2235		for (i = 0; exls[i] != NULL; i++)
2236			cpp[i] = exls[i];
2237
2238		/*
2239		 * If ndmpd_get_prop returns NULL, the array will be
2240		 * null-terminated.
2241		 */
2242		val = ndmpd_get_prop(NDMP_DEBUG_PATH);
2243		cpp[i] = val;
2244	}
2245
2246	return (cpp);
2247}
2248
2249
2250/*
2251 * ndmp_get_bk_dir_ino
2252 *
2253 * Get the inode number of the backup directory
2254 */
2255int
2256ndmp_get_bk_dir_ino(ndmp_lbr_params_t *nlp)
2257{
2258	int rv;
2259	struct stat64 st;
2260
2261	if (stat64(nlp->nlp_backup_path, &st) != 0) {
2262		rv = -1;
2263		NDMP_LOG(LOG_DEBUG, "Getting inode # of \"%s\"",
2264		    nlp->nlp_backup_path);
2265	} else {
2266		rv = 0;
2267		nlp->nlp_bkdirino = st.st_ino;
2268		NDMP_LOG(LOG_DEBUG, "nlp_bkdirino: %lu",
2269		    (uint_t)nlp->nlp_bkdirino);
2270	}
2271
2272	return (rv);
2273}
2274
2275
2276/*
2277 * ndmp_check_utf8magic
2278 *
2279 * Check if the magic string for exists in the tar header. This
2280 * magic string (which also indicates that the file names are in
2281 * UTF8 format) is used as a crest to indetify our own tapes.
2282 * This checking is always done before all restores except DAR
2283 * restores.
2284 */
2285boolean_t
2286ndmp_check_utf8magic(tlm_cmd_t *cmd)
2287{
2288	char *cp;
2289	int err, len, actual_size;
2290
2291	if (cmd == NULL) {
2292		NDMP_LOG(LOG_DEBUG, "cmd == NULL");
2293		return (FALSE);
2294	}
2295	if (cmd->tc_buffers == NULL) {
2296		NDMP_LOG(LOG_DEBUG, "cmd->tc_buffers == NULL");
2297		return (FALSE);
2298	}
2299
2300	/* wait until the first buffer gets full. */
2301	tlm_buffer_in_buf_wait(cmd->tc_buffers);
2302
2303	err = actual_size = 0;
2304	cp = tlm_get_read_buffer(RECORDSIZE, &err, cmd->tc_buffers,
2305	    &actual_size);
2306	if (cp == NULL) {
2307		NDMP_LOG(LOG_DEBUG, "Can't read from buffers, err: %d", err);
2308		return (FALSE);
2309	}
2310	len = strlen(NDMPUTF8MAGIC);
2311	if (actual_size < len) {
2312		NDMP_LOG(LOG_DEBUG, "Not enough data in the buffers");
2313		return (FALSE);
2314	}
2315
2316	return ((strncmp(cp, NDMPUTF8MAGIC, len) == 0) ? TRUE : FALSE);
2317}
2318
2319
2320/*
2321 * ndmp_get_cur_bk_time
2322 *
2323 * Get the backup checkpoint time.
2324 */
2325int
2326ndmp_get_cur_bk_time(ndmp_lbr_params_t *nlp, time_t *tp, char *jname)
2327{
2328	int err;
2329
2330	if (!nlp || !nlp->nlp_backup_path || !tp) {
2331		NDMP_LOG(LOG_DEBUG, "Invalid argument");
2332		return (-1);
2333	}
2334
2335	if (!fs_is_chkpnt_enabled(nlp->nlp_backup_path)) {
2336		NDMP_LOG(LOG_DEBUG, "Not a chkpnt volume %s",
2337		    nlp->nlp_backup_path);
2338		*tp = time(NULL);
2339		return (0);
2340	}
2341
2342	err = tlm_get_chkpnt_time(nlp->nlp_backup_path, !NLP_ISCHKPNTED(nlp),
2343	    tp, jname);
2344	if (err != 0) {
2345		NDMP_LOG(LOG_DEBUG, "Can't checkpoint time");
2346	} else {
2347		NDMP_LOG(LOG_DEBUG, "%s", cctime(tp));
2348	}
2349
2350	return (err);
2351}
2352
2353
2354/*
2355 * get_relative_path
2356 */
2357char *
2358ndmp_get_relative_path(char *base, char *fullpath)
2359{
2360	char *p = fullpath;
2361
2362	if (!base || !*base)
2363		return (fullpath);
2364
2365	while (*base) {
2366		if (*base != *p)
2367			break;
2368		p++; base++;
2369	}
2370
2371	if (*p == '/')
2372		p++;
2373
2374	return ((*base) ? fullpath : p);
2375}
2376
2377
2378/*
2379 * ndmp_get_nlp
2380 *
2381 * Get NDMP local backup parameters
2382 *
2383 * Parameter:
2384 *   session cooke
2385 *
2386 * Returns:
2387 *   LBR structure
2388 */
2389ndmp_lbr_params_t *
2390ndmp_get_nlp(void *cookie)
2391{
2392	if (cookie == NULL)
2393		return (NULL);
2394
2395	return (((ndmpd_session_t *)cookie)->ns_ndmp_lbr_params);
2396}
2397
2398
2399/*
2400 * is_tape_unit_ready
2401 *
2402 * Check if the tape device is ready or not
2403 */
2404boolean_t
2405is_tape_unit_ready(char *adptnm, int dev_id)
2406{
2407	int try;
2408	int fd = 0;
2409
2410	try = TUR_MAX_TRY;
2411	if (dev_id <= 0) {
2412		if ((fd = open(adptnm, O_RDONLY | O_NDELAY)) < 0)
2413			return (FALSE);
2414	} else {
2415		fd = dev_id;
2416	}
2417	do {
2418		if (scsi_test_unit_ready(fd) >= 0) {
2419			NDMP_LOG(LOG_DEBUG, "Unit is ready");
2420
2421			if (dev_id <= 0)
2422				(void) close(fd);
2423
2424			return (TRUE);
2425		}
2426
2427		NDMP_LOG(LOG_DEBUG, "Unit not ready");
2428		(void) usleep(TUR_WAIT);
2429
2430	} while (--try > 0);
2431
2432	if (dev_id <= 0)
2433		(void) close(fd);
2434
2435	NDMP_LOG(LOG_DEBUG, "Unit didn't get ready");
2436	return (FALSE);
2437}
2438
2439
2440/*
2441 * scsi_test_unit_ready
2442 *
2443 * This is for Test Unit Read, without this function, the only
2444 * impact is getting EBUSY's before each operation which we have
2445 * busy waiting loops checking EBUSY error code.
2446 */
2447static int
2448scsi_test_unit_ready(int dev_id)
2449{
2450	struct uscsi_cmd ucmd;
2451	union scsi_cdb cdb;
2452	int retval;
2453
2454	(void) memset(&ucmd, 0, sizeof (struct uscsi_cmd));
2455	(void) memset(&cdb, 0, sizeof (union scsi_cdb));
2456	cdb.scc_cmd = SCMD_TEST_UNIT_READY;
2457	ucmd.uscsi_cdb = (caddr_t)&cdb;
2458	ucmd.uscsi_cdblen = CDB_GROUP0;
2459	ucmd.uscsi_flags |= USCSI_SILENT;
2460	ucmd.uscsi_timeout = 60;	/* Allow maximum 1 min */
2461
2462	retval = ioctl(dev_id, USCSICMD, &ucmd);
2463
2464	if (retval != 0 && errno != EIO) {
2465		NDMP_LOG(LOG_ERR,
2466		    "Failed to send inquiry request to device: %m.");
2467		NDMP_LOG(LOG_DEBUG, "Inquiry request failed for"
2468		    " dev_id:%d err=%d -%m", dev_id, errno);
2469		retval = -errno;
2470	} else
2471		retval = -(ucmd.uscsi_status);
2472
2473	return (retval);
2474}
2475
2476
2477/*
2478 * ndmp_load_params
2479 *
2480 * Load the parameters.
2481 *
2482 * Parameter:
2483 *   void
2484 *
2485 * Returns:
2486 *   void
2487 */
2488void
2489ndmp_load_params(void)
2490{
2491	ndmp_dump_path_node = ndmpd_get_prop_yorn(NDMP_DUMP_PATHNODE_ENV) ?
2492	    TRUE : FALSE;
2493	ndmp_tar_path_node = ndmpd_get_prop_yorn(NDMP_TAR_PATHNODE_ENV) ?
2494	    TRUE : FALSE;
2495	ndmp_ignore_ctime =
2496	    ndmpd_get_prop_yorn(NDMP_IGNCTIME_ENV) ? TRUE : FALSE;
2497	ndmp_include_lmtime = ndmpd_get_prop_yorn(NDMP_INCLMTIME_ENV) ?
2498	    TRUE : FALSE;
2499	ndmp_max_tok_seq = atoi(ndmpd_get_prop_default(NDMP_MAXSEQ_ENV, "9"));
2500
2501	ndmp_full_restore_path = ndmpd_get_prop_yorn(NDMP_FULL_RESTORE_PATH) ?
2502	    TRUE : FALSE;
2503
2504	ndmp_fhinode = ndmpd_get_prop_yorn(NDMP_FHIST_INCR_ENV) ? TRUE : FALSE;
2505
2506	/* Get the value from ndmp SMF property. */
2507	ndmp_dar_support = ndmpd_get_prop_yorn(NDMP_DAR_SUPPORT);
2508
2509	if ((ndmp_ver = atoi(ndmpd_get_prop(NDMP_VERSION_ENV))) == 0)
2510		ndmp_ver = NDMPVER;
2511}
2512
2513/*
2514 * randomize
2515 *
2516 * Randomize the contents of a buffer
2517 *
2518 * Parameter:
2519 *   buffer (output) - destination buffer
2520 *   size (input) - buffer size
2521 *
2522 * Returns:
2523 *   void
2524 */
2525void
2526randomize(unsigned char *buffer, int size)
2527{
2528	/* LINTED improper alignment */
2529	unsigned int *p = (unsigned int *)buffer;
2530	unsigned int dwlen = size / sizeof (unsigned int);
2531	unsigned int remlen = size % sizeof (unsigned int);
2532	unsigned int tmp;
2533	unsigned int i;
2534
2535	for (i = 0; i < dwlen; i++)
2536		*p++ = random();
2537
2538	if (remlen) {
2539		tmp = random();
2540		(void) memcpy(p, &tmp, remlen);
2541	}
2542}
2543
2544/*
2545 * ndmpd_get_file_entry_type
2546 *
2547 * Converts the mode to the NDMP file type
2548 *
2549 * Parameter:
2550 *   mode (input) - file mode
2551 *   ftype (output) - file type
2552 *
2553 * Returns:
2554 *   void
2555 */
2556void
2557ndmpd_get_file_entry_type(int mode, ndmp_file_type *ftype)
2558{
2559	switch (mode & S_IFMT) {
2560	case S_IFIFO:
2561		*ftype = NDMP_FILE_FIFO;
2562		break;
2563	case S_IFCHR:
2564		*ftype = NDMP_FILE_CSPEC;
2565		break;
2566	case S_IFDIR:
2567		*ftype = NDMP_FILE_DIR;
2568		break;
2569	case S_IFBLK:
2570		*ftype = NDMP_FILE_BSPEC;
2571		break;
2572	case S_IFREG:
2573		*ftype = NDMP_FILE_REG;
2574		break;
2575	case S_IFLNK:
2576		*ftype = NDMP_FILE_SLINK;
2577		break;
2578	default:
2579		*ftype = NDMP_FILE_SOCK;
2580		break;
2581	}
2582}
2583
2584/*
2585 * Set a private data in the plugin context
2586 */
2587void
2588ndmp_context_set_specific(ndmp_context_t *nctx, void *ptr)
2589{
2590	nctx->nc_pldata = ptr;
2591}
2592
2593/*
2594 * Get a private data in the plugin context
2595 */
2596void *
2597ndmp_context_get_specific(ndmp_context_t *nctx)
2598{
2599	return (nctx->nc_pldata);
2600}
2601
2602ndmpd_backup_type_t
2603ndmp_get_backup_type(ndmp_context_t *ctx)
2604{
2605	ndmpd_session_t *session = (ndmpd_session_t *)ctx->nc_ddata;
2606
2607	return (session->ns_butype);
2608}
2609