xref: /titanic_51/usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c (revision bb1fad37c75defa7a6ae25f00c1d4b356713b734)
1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * BSD 3 Clause License
8  *
9  * Copyright (c) 2007, The Storage Networking Industry Association.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 	- Redistributions of source code must retain the above copyright
15  *	  notice, this list of conditions and the following disclaimer.
16  *
17  * 	- Redistributions in binary form must reproduce the above copyright
18  *	  notice, this list of conditions and the following disclaimer in
19  *	  the documentation and/or other materials provided with the
20  *	  distribution.
21  *
22  *	- Neither the name of The Storage Networking Industry Association (SNIA)
23  *	  nor the names of its contributors may be used to endorse or promote
24  *	  products derived from this software without specific prior written
25  *	  permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <sys/time.h>
42 #include <ctype.h>
43 #include <sys/socket.h>
44 #include <sys/acl.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <errno.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <time.h>
51 #include <cstack.h>
52 #include "ndmp.h"
53 #include "ndmpd.h"
54 #include <bitmap.h>
55 #include <traverse.h>
56 
57 
58 /*
59  * Maximum length of the string-representation of u_longlong_t type.
60  */
61 #define	QUAD_DECIMAL_LEN	20
62 
63 
64 /* Is Y=yes or T=true */
65 #define	IS_YORT(c)	(strchr("YT", toupper(c)))
66 
67 /* Is F=file format (vs D=node-dir format) */
68 #define	IS_F(c)		(toupper(c) == 'F')
69 
70 /*
71  * If path is defined.
72  */
73 #define	ISDEFINED(cp)	((cp) && *(cp))
74 #define	SHOULD_LBRBK(bpp)	(!((bpp)->bp_opr & TLM_OP_CHOOSE_ARCHIVE))
75 
76 /*
77  * Component boundary means end of path or on a '/'.  At this
78  * point both paths should be on component boundary.
79  */
80 #define	COMPBNDRY(p)	(!*(p) || (*p) == '/')
81 
82 typedef struct bk_param_v3 {
83 	ndmpd_session_t *bp_session;
84 	ndmp_lbr_params_t *bp_nlp;
85 	tlm_job_stats_t *bp_js;
86 	tlm_cmd_t *bp_lcmd;
87 	tlm_commands_t *bp_cmds;
88 	tlm_acls_t *bp_tlmacl;
89 	int bp_opr;
90 	char *bp_tmp;
91 	char *bp_chkpnm;
92 	char **bp_excls;
93 	char *bp_unchkpnm;
94 } bk_param_v3_t;
95 
96 
97 /*
98  * Multiple destination restore mode
99  */
100 #define	MULTIPLE_DEST_DIRS 128
101 
102 int multiple_dest_restore = 0;
103 
104 /*
105  * Plug-in module ops
106  */
107 ndmp_plugin_t *ndmp_pl;
108 
109 /*
110  * NDMP exclusion list
111  */
112 char **ndmp_excl_list = NULL;
113 
114 /*
115  * split_env
116  *
117  * Splits the string into list of sections separated by the
118  * sep character.
119  *
120  * Parameters:
121  *   envp (input) - the environment variable that should be broken
122  *   sep (input) - the separator character
123  *
124  * Returns:
125  *   Array of character pointers: On success.  The array is allocated
126  *	as well as all its entries.  They all should be freed by the
127  *	caller.
128  *   NULL: on error
129  */
130 static char **
131 split_env(char *envp, char sep)
132 {
133 	char *bp, *cp, *ep;
134 	char *save;
135 	char **cpp;
136 	int n;
137 
138 	if (!envp)
139 		return (NULL);
140 
141 	while (isspace(*envp))
142 		envp++;
143 
144 	if (!*envp)
145 		return (NULL);
146 
147 	bp = save = strdup(envp);
148 	if (!bp)
149 		return (NULL);
150 
151 	/*
152 	 * Since the env variable is not empty, it contains at least one
153 	 * component
154 	 */
155 	n = 1;
156 	while ((cp = strchr(bp, sep))) {
157 		if (cp > save && *(cp-1) != '\\')
158 			n++;
159 
160 		bp = cp + 1;
161 	}
162 
163 	n++; /* for the terminating NULL pointer */
164 	cpp = ndmp_malloc(sizeof (char *) * n);
165 	if (!cpp) {
166 		free(save);
167 		return (NULL);
168 	}
169 
170 	(void) memset(cpp, 0, n * sizeof (char *));
171 	n = 0;
172 	cp = bp = ep = save;
173 	while (*cp)
174 		if (*cp == sep) {
175 			*ep = '\0';
176 			if (strlen(bp) > 0) {
177 				cpp[n] = strdup(bp);
178 				if (!cpp[n++]) {
179 					tlm_release_list(cpp);
180 					cpp = NULL;
181 					break;
182 				}
183 			}
184 			ep = bp = ++cp;
185 		} else if (*cp == '\\') {
186 			++cp;
187 			if (*cp == 'n') {	/* "\n" */
188 				*ep++ = '\n';
189 				cp++;
190 			} else if (*cp == 't') {	/* "\t" */
191 				*ep++ = '\t';
192 				cp++;
193 			} else
194 				*ep++ = *cp++;
195 		} else
196 			*ep++ = *cp++;
197 
198 	*ep = '\0';
199 	if (cpp) {
200 		if (strlen(bp) > 0) {
201 			cpp[n] = strdup(bp);
202 			if (!cpp[n++]) {
203 				tlm_release_list(cpp);
204 				cpp = NULL;
205 			} else
206 				cpp[n] = NULL;
207 		}
208 
209 		if (n == 0 && cpp != NULL) {
210 			tlm_release_list(cpp);
211 			cpp = NULL;
212 		}
213 	}
214 
215 	free(save);
216 	return (cpp);
217 }
218 
219 
220 /*
221  * prl
222  *
223  * Print the array of character pointers passed to it.  This is
224  * used for debugging purpose.
225  *
226  * Parameters:
227  *   lpp (input) - pointer to the array of strings
228  *
229  * Returns:
230  *   void
231  */
232 static void
233 prl(char **lpp)
234 {
235 	if (!lpp) {
236 		NDMP_LOG(LOG_DEBUG, "empty");
237 		return;
238 	}
239 
240 	while (*lpp)
241 		NDMP_LOG(LOG_DEBUG, "\"%s\"", *lpp++);
242 }
243 
244 
245 /*
246  * inlist
247  *
248  * Looks through all the strings of the array to see if the ent
249  * matches any of the strings.  The strings are patterns.
250  *
251  * Parameters:
252  *   lpp (input) - pointer to the array of strings
253  *   ent (input) - the entry to be matched
254  *
255  * Returns:
256  *   TRUE: if there is a match
257  *   FALSE: invalid argument or no match
258  */
259 static boolean_t
260 inlist(char **lpp, char *ent)
261 {
262 	if (!lpp || !ent) {
263 		NDMP_LOG(LOG_DEBUG, "empty list");
264 		return (FALSE);
265 	}
266 
267 	while (*lpp) {
268 		/*
269 		 * Fixing the sync_sort NDMPV3 problem, it sends the inclusion
270 		 * like "./" which we should skip the "./"
271 		 */
272 		char *pattern = *lpp;
273 		if (strncmp(pattern, "./", 2) == 0)
274 			pattern += 2;
275 
276 		NDMP_LOG(LOG_DEBUG, "pattern %s, ent %s", pattern, ent);
277 
278 		if (match(pattern, ent)) {
279 			NDMP_LOG(LOG_DEBUG, "match(%s,%s)", pattern, ent);
280 			return (TRUE);
281 		}
282 		lpp++;
283 	}
284 
285 	NDMP_LOG(LOG_DEBUG, "no match");
286 	return (FALSE);
287 }
288 
289 
290 /*
291  * inexl
292  *
293  * Checks if the entry is in the list.  This is used for exclusion
294  * list.  If the exclusion list is empty, FALSE should be returned
295  * showing that nothing should be excluded by default.
296  *
297  * Parameters:
298  *   lpp (input) - pointer to the array of strings
299  *   ent (input) - the entry to be matched
300  *
301  * Returns:
302  *   TRUE: if there is a match
303  *   FALSE: invalid argument or no match
304  *
305  */
306 static boolean_t
307 inexl(char **lpp, char *ent)
308 {
309 	if (!lpp || !ent)
310 		return (FALSE);
311 
312 	return (inlist(lpp, ent));
313 }
314 
315 
316 /*
317  * ininc
318  *
319  * Checks if the entry is in the list.  This is used for inclusion
320  * list.  If the inclusion list is empty, TRUE should be returned
321  * showing that everything should be included by default.
322  *
323  * Parameters:
324  *   lpp (input) - pointer to the array of strings
325  *   ent (input) - the entry to be matched
326  *
327  * Returns:
328  *   TRUE: if there is a match or the list is empty
329  *   FALSE: no match
330  */
331 static boolean_t
332 ininc(char **lpp, char *ent)
333 {
334 	if (!lpp || !ent || !*ent)
335 		return (TRUE);
336 
337 	return (inlist(lpp, ent));
338 }
339 
340 
341 /*
342  * setupsels
343  *
344  * Set up the selection list for Local B/R functions.  A new array of
345  * "char *" is created and the pointers point to the original paths of
346  * the Nlist.
347  *
348  * Parameters:
349  *   session (input) - pointer to the session
350  *   params (input) - pointer to the parameters structure
351  *   nlp (input) - pointer to the nlp structure
352  *   index(input) - If not zero is the DAR entry position
353  *
354  * Returns:
355  *   list pointer: on success
356  *   NULL: on error
357  */
358 /*ARGSUSED*/
359 char **
360 setupsels(ndmpd_session_t *session, ndmpd_module_params_t *params,
361     ndmp_lbr_params_t *nlp, int index)
362 {
363 	char **lpp, **save;
364 	int i, n;
365 	int len;
366 	int start, end;
367 	mem_ndmp_name_v3_t *ep;
368 
369 	n = session->ns_data.dd_nlist_len;
370 
371 	save = lpp = ndmp_malloc(sizeof (char *) * (n + 1));
372 	if (!lpp) {
373 		MOD_LOGV3(params, NDMP_LOG_ERROR, "Insufficient memory.\n");
374 		return (NULL);
375 	}
376 
377 	if (index) { /* DAR, just one entry */
378 		/*
379 		 * We have to setup a list of strings that will not match any
380 		 * file. One DAR entry will be added in the right position later
381 		 * in this function.
382 		 * When the match is called from tar_getdir the
383 		 * location of the selection that matches the entry is
384 		 * important
385 		 */
386 		for (i = 0; i < n; ++i)
387 			*(lpp+i) = " ";
388 		n = 1;
389 		start = index-1;
390 		end = start+1;
391 		lpp += start; /* Next selection entry will be in lpp[start] */
392 	} else {
393 		start = 0;
394 		end = n;
395 	}
396 
397 	for (i = start; i < end; i++) {
398 		ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
399 		if (!ep)
400 			continue;
401 
402 		/*
403 		 * Check for clients that send original path as "."(like
404 		 * CA products). In this situation opath is something like
405 		 * "/v1/." and we should change it to "/v1/"
406 		 */
407 		len = strlen(ep->nm3_opath);
408 		if (len > 1 && ep->nm3_opath[len-2] == '/' &&
409 		    ep->nm3_opath[len-1] == '.') {
410 			ep->nm3_opath[len-1] = '\0';
411 			NDMP_LOG(LOG_DEBUG,
412 			    "nm3_opath changed from %s. to %s",
413 			    ep->nm3_opath, ep->nm3_opath);
414 		}
415 		*lpp++ = ep->nm3_opath;
416 	}
417 
418 	/* list termination indicator is a null pointer */
419 	*lpp = NULL;
420 
421 	return (save);
422 }
423 
424 
425 /*
426  * mkrsp
427  *
428  * Make Restore Path.
429  * It gets a path, a selection (with which the path has matched) a new
430  * name and makes a new name for the path.
431  * All the components of the path and the selection are skipped as long
432  * as they are the same.  If either of the path or selection are not on
433  * a component boundary, the match was reported falsefully and no new name
434  * is generated(Except the situation in which both path and selection
435  * end with trailing '/' and selection is the prefix of the path).
436  * Otherwise, the remaining of the path is appended to the
437  * new name.  The result is saved in the buffer passed.
438  *
439  * Parameters:
440  *   bp (output) - pointer to the result buffer
441  *   pp (input) - pointer to the path
442  *   sp (input) - pointer to the selection
443  *   np (input) - pointer to the new name
444  *
445  * Returns:
446  *   pointer to the bp: on success
447  *   NULL: otherwise
448  */
449 char *
450 mkrsp(char *bp, char *pp, char *sp, char *np)
451 {
452 	if (!bp || !pp)
453 		return (NULL);
454 
455 
456 	pp += strspn(pp, "/");
457 	if (sp) {
458 		sp += strspn(sp, "/");
459 
460 		/* skip as much as match */
461 		while (*sp && *pp && *sp == *pp) {
462 			sp++;
463 			pp++;
464 		}
465 
466 		if (!COMPBNDRY(pp) || !COMPBNDRY(sp))
467 			/* An exception to the boundary rule */
468 			/* (!(!*sp && (*(pp - 1)) == '/')) */
469 			if (*sp || (*(pp - 1)) != '/')
470 				return (NULL);
471 
472 		/* if pp shorter than sp, it should not be restored */
473 		if (!*pp && *sp) {
474 			sp += strspn(sp, "/");
475 			if (strlen(sp) > 0)
476 				return (NULL);
477 		}
478 	}
479 
480 	if (np)
481 		np += strspn(np, "/");
482 	else
483 		np = "";
484 
485 	if (!tlm_cat_path(bp, np, pp)) {
486 		NDMP_LOG(LOG_ERR, "Restore path too long %s/%s.", np, pp);
487 		return (NULL);
488 	}
489 
490 	return (bp);
491 }
492 
493 
494 /*
495  * mknewname
496  *
497  * This is used as callback for creating the restore path. This function
498  * can handle both single destination and multiple restore paths.
499  *
500  * Make up the restore destination path for a particular file/directory, path,
501  * based on nm3_opath and nm3_dpath.  path should have matched nm3_opath
502  * in some way.
503  */
504 char *
505 mknewname(struct rs_name_maker *rnp, char *buf, int idx, char *path)
506 {
507 	char *rv;
508 	ndmp_lbr_params_t *nlp;
509 	mem_ndmp_name_v3_t *ep;
510 
511 	rv = NULL;
512 	if (!buf) {
513 		NDMP_LOG(LOG_DEBUG, "buf is NULL");
514 	} else if (!path) {
515 		NDMP_LOG(LOG_DEBUG, "path is NULL");
516 	} else if ((nlp = rnp->rn_nlp) == 0) {
517 		NDMP_LOG(LOG_DEBUG, "rnp->rn_nlp is NULL");
518 	} else if (!nlp->nlp_params) {
519 		NDMP_LOG(LOG_DEBUG, "nlp->nlp_params is NULL");
520 	} else
521 		if (!ndmp_full_restore_path) {
522 			if (idx < 0 || idx >= (int)nlp->nlp_nfiles) {
523 				NDMP_LOG(LOG_DEBUG,
524 				    "Invalid idx %d range (0, %d)",
525 				    idx, nlp->nlp_nfiles);
526 			} else if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(
527 			    nlp->nlp_params, idx))) {
528 				NDMP_LOG(LOG_DEBUG,
529 				    "nlist entry %d is NULL", idx);
530 			} else {
531 				rv = mkrsp(buf, path, ep->nm3_opath,
532 				    ep->nm3_dpath);
533 
534 				NDMP_LOG(LOG_DEBUG,
535 				    "idx %d org \"%s\" dst \"%s\"",
536 				    idx, ep->nm3_opath, ep->nm3_dpath);
537 				if (rv) {
538 					NDMP_LOG(LOG_DEBUG,
539 					    "path \"%s\": \"%s\"", path, rv);
540 				} else {
541 					NDMP_LOG(LOG_DEBUG,
542 					    "path \"%s\": NULL", path);
543 				}
544 			}
545 		} else {
546 			if (!tlm_cat_path(buf, nlp->nlp_restore_path, path)) {
547 				NDMP_LOG(LOG_ERR, "Path too long %s/%s.",
548 				    nlp->nlp_restore_path, path);
549 				rv = NULL;
550 			} else {
551 				rv = buf;
552 				NDMP_LOG(LOG_DEBUG,
553 				    "path \"%s\": \"%s\"", path, rv);
554 			}
555 		}
556 
557 	return (rv);
558 }
559 
560 
561 /*
562  * chopslash
563  *
564  * Remove the slash from the end of the given path
565  */
566 static void
567 chopslash(char *cp)
568 {
569 	int ln;
570 
571 	if (!cp || !*cp)
572 		return;
573 
574 	ln = strlen(cp);
575 	cp += ln - 1; /* end of the string */
576 	while (ln > 0 && *cp == '/') {
577 		*cp-- = '\0';
578 		ln--;
579 	}
580 }
581 
582 
583 /*
584  * joinpath
585  *
586  * Join two given paths
587  */
588 static char *
589 joinpath(char *bp, char *pp, char *np)
590 {
591 	if (pp && *pp) {
592 		if (np && *np)
593 			(void) tlm_cat_path(bp, pp, np);
594 		else
595 			(void) strlcpy(bp, pp, TLM_MAX_PATH_NAME);
596 	} else {
597 		if (np && *np)
598 			(void) strlcpy(bp, np, TLM_MAX_PATH_NAME);
599 		else
600 			bp = NULL;
601 	}
602 
603 	return (bp);
604 }
605 
606 
607 /*
608  * voliswr
609  *
610  * Is the volume writable?
611  */
612 static int
613 voliswr(char *path)
614 {
615 	int rv;
616 
617 	if (!path)
618 		return (0);
619 
620 	rv = !fs_is_rdonly(path) && !fs_is_chkpntvol(path);
621 	NDMP_LOG(LOG_DEBUG, "%d path \"%s\"", rv, path);
622 	return (rv);
623 
624 }
625 
626 
627 /*
628  * get_bk_path_v3
629  *
630  * Get the backup path from the NDMP environment variables.
631  *
632  * Parameters:
633  *   params (input) - pointer to the parameters structure.
634  *
635  * Returns:
636  *   The backup path: if anything is specified
637  *   NULL: Otherwise
638  */
639 char *
640 get_bk_path_v3(ndmpd_module_params_t *params)
641 {
642 	char *bkpath;
643 
644 	bkpath = MOD_GETENV(params, "PREFIX");
645 	if (!bkpath)
646 		bkpath = MOD_GETENV(params, "FILESYSTEM");
647 
648 
649 	if (!bkpath) {
650 		MOD_LOGV3(params, NDMP_LOG_ERROR,
651 		    "Backup path not defined.\n");
652 	} else {
653 		NDMP_LOG(LOG_DEBUG, "bkpath: \"%s\"", bkpath);
654 	}
655 
656 	return (bkpath);
657 }
658 
659 
660 /*
661  * is_valid_backup_dir_v3
662  *
663  * Checks the validity of the backup path.  Backup path should
664  * have the following characteristics to be valid:
665  *	1) It should be an absolute path.
666  *	2) It should be a directory.
667  *	3) It should not be checkpoint root directory
668  *	4) If the file system is read-only, the backup path
669  *	    should be a checkpointed path.  Checkpoint cannot
670  *	    be created on a read-only file system.
671  *
672  * Parameters:
673  *   params (input) - pointer to the parameters structure.
674  *   bkpath (input) - the backup path
675  *
676  * Returns:
677  *   TRUE: if everything's OK
678  *   FALSE: otherwise.
679  */
680 static boolean_t
681 is_valid_backup_dir_v3(ndmpd_module_params_t *params, char *bkpath)
682 {
683 	char *msg;
684 	struct stat64 st;
685 
686 	if (*bkpath != '/') {
687 		MOD_LOGV3(params, NDMP_LOG_ERROR,
688 		    "Relative backup path not allowed \"%s\".\n", bkpath);
689 		return (FALSE);
690 	}
691 	if (stat64(bkpath, &st) < 0) {
692 		msg = strerror(errno);
693 		MOD_LOGV3(params, NDMP_LOG_ERROR, "\"%s\" %s.\n",
694 		    bkpath, msg);
695 		return (FALSE);
696 	}
697 	if (!S_ISDIR(st.st_mode)) {
698 		/* only directories can be specified as the backup path */
699 		MOD_LOGV3(params, NDMP_LOG_ERROR,
700 		    "\"%s\" is not a directory.\n", bkpath);
701 		return (FALSE);
702 	}
703 	if (ndmp_is_chkpnt_root(bkpath)) {
704 		/* it is the chkpnt root directory */
705 		MOD_LOGV3(params, NDMP_LOG_ERROR,
706 		    "\"%s\" is a checkpoint root directory.\n", bkpath);
707 		return (FALSE);
708 	}
709 	if (fs_is_rdonly(bkpath) && !fs_is_chkpntvol(bkpath) &&
710 	    fs_is_chkpnt_enabled(bkpath)) {
711 		/* it is not a chkpnted path */
712 		MOD_LOGV3(params, NDMP_LOG_ERROR,
713 		    "\"%s\" is not a checkpointed path.\n", bkpath);
714 		return (FALSE);
715 	}
716 
717 	return (TRUE);
718 }
719 
720 
721 /*
722  * log_date_token_v3
723  *
724  * Log the token sequence number and also the date of the
725  * last backup for token-based backup in the system log
726  * and also send them as normal log to the client.
727  *
728  * Parameters:
729  *   params (input) - pointer to the parameters structure
730  *   nlp (input) - pointer to the nlp structure
731  *
732  * Returns:
733  *   void
734  */
735 static void
736 log_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
737 {
738 	MOD_LOGV3(params, NDMP_LOG_NORMAL, "Token sequence counter: %d.\n",
739 	    nlp->nlp_tokseq);
740 
741 	MOD_LOGV3(params, NDMP_LOG_NORMAL, "Date of the last backup: %s.\n",
742 	    cctime(&nlp->nlp_tokdate));
743 
744 	if (nlp->nlp_dmpnm) {
745 		MOD_LOGV3(params, NDMP_LOG_NORMAL,
746 		    "Backup date log file name: \"%s\".\n", nlp->nlp_dmpnm);
747 	}
748 }
749 
750 
751 /*
752  * log_lbr_bk_v3
753  *
754  * Log the backup level and data of the backup for LBR-type
755  * backup in the system log and also send them as normal log
756  * to the client.
757  *
758  * Parameters:
759  *   params (input) - pointer to the parameters structure
760  *   nlp (input) - pointer to the nlp structure
761  *
762  * Returns:
763  *   void
764  */
765 static void
766 log_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
767 {
768 	MOD_LOGV3(params, NDMP_LOG_NORMAL,
769 	    "Date of this level '%c': %s.\n", nlp->nlp_clevel,
770 	    cctime(&nlp->nlp_cdate));
771 
772 	if (nlp->nlp_dmpnm) {
773 		MOD_LOGV3(params, NDMP_LOG_NORMAL,
774 		    "Backup date log file name: \"%s\".\n", nlp->nlp_dmpnm);
775 	}
776 }
777 
778 
779 /*
780  * log_level_v3
781  *
782  * Log the backup level and date of the last and the current
783  * backup for level-type backup in the system log and also
784  * send them as normal log to the client.
785  *
786  * Parameters:
787  *   params (input) - pointer to the parameters structure
788  *   nlp (input) - pointer to the nlp structure
789  *
790  * Returns:
791  *   void
792  */
793 static void
794 log_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
795 {
796 	MOD_LOGV3(params, NDMP_LOG_NORMAL,
797 	    "Date of the last level '%u': %s.\n", nlp->nlp_llevel,
798 	    cctime(&nlp->nlp_ldate));
799 
800 	MOD_LOGV3(params, NDMP_LOG_NORMAL,
801 	    "Date of this level '%u': %s.\n", nlp->nlp_clevel,
802 	    cctime(&nlp->nlp_cdate));
803 
804 	MOD_LOGV3(params, NDMP_LOG_NORMAL, "Update: %s.\n",
805 	    NDMP_TORF(NLP_ISSET(nlp, NLPF_UPDATE)));
806 }
807 
808 
809 /*
810  * log_bk_params_v3
811  *
812  * Dispatcher function which calls the appropriate function
813  * for logging the backup date and level in the system log
814  * and also send them as normal log message to the client.
815  *
816  * Parameters:
817  *   session (input) - pointer to the session
818  *   params (input) - pointer to the parameters structure
819  *   nlp (input) - pointer to the nlp structure
820  *
821  * Returns:
822  *   void
823  */
824 static void
825 log_bk_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
826     ndmp_lbr_params_t *nlp)
827 {
828 	MOD_LOGV3(params, NDMP_LOG_NORMAL, "Backing up \"%s\".\n",
829 	    nlp->nlp_backup_path);
830 
831 	if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_LOCAL)
832 		MOD_LOGV3(params, NDMP_LOG_NORMAL,
833 		    "Tape record size: %d.\n",
834 		    session->ns_mover.md_record_size);
835 
836 	MOD_LOGV3(params, NDMP_LOG_NORMAL, "File history: %c.\n",
837 	    NDMP_YORN(NLP_ISSET(nlp, NLPF_FH)));
838 
839 	if (NLP_ISSET(nlp, NLPF_TOKENBK))
840 		log_date_token_v3(params, nlp);
841 	else if (NLP_ISSET(nlp, NLPF_LBRBK))
842 		log_lbr_bk_v3(params, nlp);
843 	else if (NLP_ISSET(nlp, NLPF_LEVELBK))
844 		log_level_v3(params, nlp);
845 	else {
846 		MOD_LOGV3(params, NDMP_LOG_ERROR,
847 		    "Internal error: backup level not defined for \"%s\".\n",
848 		    nlp->nlp_backup_path);
849 	}
850 }
851 
852 
853 /*
854  * get_update_env_v3
855  *
856  * Is the UPDATE environment variable specified?  If it is
857  * the corresponding flag is set in the flags field of the
858  * nlp structure, otherwise the flag is cleared.
859  *
860  * Parameters:
861  *   params (input) - pointer to the parameters structure
862  *   nlp (input) - pointer to the nlp structure
863  *
864  * Returns:
865  *   void
866  */
867 static void
868 get_update_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
869 {
870 	char *envp;
871 
872 	envp = MOD_GETENV(params, "UPDATE");
873 	if (!envp) {
874 		NLP_SET(nlp, NLPF_UPDATE);
875 		NDMP_LOG(LOG_DEBUG,
876 		    "env(UPDATE) not defined, default to TRUE");
877 	} else {
878 		NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp);
879 		if (IS_YORT(*envp))
880 			NLP_SET(nlp, NLPF_UPDATE);
881 		else
882 			NLP_UNSET(nlp, NLPF_UPDATE);
883 	}
884 }
885 
886 
887 /*
888  * get_hist_env_v3
889  *
890  * Is backup history requested?  If it is, the corresponding
891  * flag is set in the flags field of the nlp structure, otherwise
892  * the flag is cleared.
893  *
894  * Parameters:
895  *   params (input) - pointer to the parameters structure
896  *   nlp (input) - pointer to the nlp structure
897  *
898  * Returns:
899  *   void
900  */
901 static void
902 get_hist_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
903 {
904 	char *envp;
905 
906 	envp = MOD_GETENV(params, "HIST");
907 	if (!envp) {
908 		NDMP_LOG(LOG_DEBUG, "env(HIST) not defined");
909 		NLP_UNSET(nlp, NLPF_FH);
910 	} else {
911 		NDMP_LOG(LOG_DEBUG, "env(HIST): \"%s\"", envp);
912 		if (IS_YORT(*envp) || IS_F(*envp))
913 			NLP_SET(nlp, NLPF_FH);
914 		else
915 			NLP_UNSET(nlp, NLPF_FH);
916 
917 		/* Force file format if specified */
918 		if (IS_F(*envp)) {
919 			params->mp_file_history_path_func =
920 			    ndmpd_api_file_history_file_v3;
921 			params->mp_file_history_dir_func = 0;
922 			params->mp_file_history_node_func = 0;
923 		}
924 	}
925 }
926 
927 
928 /*
929  * get_exc_env_v3
930  *
931  * Gets the EXCLUDE environment variable and breaks it
932  * into strings.  The separator of the EXCLUDE environment
933  * variable is the ',' character.
934  *
935  * Parameters:
936  *   params (input) - pointer to the parameters structure
937  *   nlp (input) - pointer to the nlp structure
938  *
939  * Returns:
940  *   void
941  */
942 static void
943 get_exc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
944 {
945 	char *envp;
946 
947 	envp = MOD_GETENV(params, "EXCLUDE");
948 	if (!envp) {
949 		NDMP_LOG(LOG_DEBUG, "env(EXCLUDE) not defined");
950 		nlp->nlp_exl = NULL;
951 	} else {
952 		NDMP_LOG(LOG_DEBUG, "env(EXCLUDE): \"%s\"", envp);
953 		nlp->nlp_exl = split_env(envp, ',');
954 		prl(nlp->nlp_exl);
955 	}
956 }
957 
958 
959 /*
960  * get_inc_env_v3
961  *
962  * Gets the FILES environment variable that shows which files
963  * should be backed up, and breaks it into strings.  The
964  * separator of the FILES environment variable is the space
965  * character.
966  *
967  * Parameters:
968  *   params (input) - pointer to the parameters structure
969  *   nlp (input) - pointer to the nlp structure
970  *
971  * Returns:
972  *   void
973  */
974 static void
975 get_inc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
976 {
977 	char *envp;
978 
979 	envp = MOD_GETENV(params, "FILES");
980 	if (!envp) {
981 		NDMP_LOG(LOG_DEBUG, "env(FILES) not defined");
982 		nlp->nlp_inc = NULL;
983 	} else {
984 		NDMP_LOG(LOG_DEBUG, "env(FILES): \"%s\"", envp);
985 		nlp->nlp_inc = split_env(envp, ' ');
986 		prl(nlp->nlp_inc);
987 	}
988 }
989 
990 
991 /*
992  * get_direct_env_v3
993  *
994  * Gets the DIRECT environment variable that shows if the fh_info should
995  * be sent to the client or not.
996  *
997  * Parameters:
998  *   params (input) - pointer to the parameters structure
999  *   nlp (input) - pointer to the nlp structure
1000  *
1001  * Returns:
1002  *   void
1003  */
1004 static void
1005 get_direct_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1006 {
1007 	char *envp;
1008 
1009 	/*
1010 	 * We should send the fh_info to the DMA, unless it is specified
1011 	 * in the request that we should not send fh_info.
1012 	 * At the moment we do not support DAR on directories, so if the user
1013 	 * needs to restore a directory they should disable the DAR.
1014 	 */
1015 	if (params->mp_operation == NDMP_DATA_OP_RECOVER && !ndmp_dar_support) {
1016 		NDMP_LOG(LOG_DEBUG, "Direct Access Restore Disabled");
1017 		NLP_UNSET(nlp, NLPF_DIRECT);
1018 		MOD_LOGV3(params, NDMP_LOG_NORMAL,
1019 		    "DAR is disabled. Running Restore without DAR");
1020 		return;
1021 	}
1022 
1023 	/*
1024 	 * Regardless of whether DIRECT is defined at backup time we send
1025 	 * back the fh_info, for some clients do not use get_backup_attrs.
1026 	 * If operation is restore we have to unset the DIRECT, for
1027 	 * some clients do not set the MOVER window.
1028 	 */
1029 	if (params->mp_operation == NDMP_DATA_OP_BACKUP) {
1030 		NDMP_LOG(LOG_DEBUG, "backup default env(DIRECT): YES");
1031 		NLP_SET(nlp, NLPF_DIRECT);
1032 	} else {
1033 
1034 		envp = MOD_GETENV(params, "DIRECT");
1035 		if (!envp) {
1036 			NDMP_LOG(LOG_DEBUG, "env(DIRECT) not defined");
1037 			NLP_UNSET(nlp, NLPF_DIRECT);
1038 		} else {
1039 			NDMP_LOG(LOG_DEBUG, "env(DIRECT): \"%s\"", envp);
1040 			if (IS_YORT(*envp)) {
1041 				NLP_SET(nlp, NLPF_DIRECT);
1042 				NDMP_LOG(LOG_DEBUG,
1043 				    "Direct Access Restore Enabled");
1044 			} else {
1045 				NLP_UNSET(nlp, NLPF_DIRECT);
1046 				NDMP_LOG(LOG_DEBUG,
1047 				    "Direct Access Restore Disabled");
1048 			}
1049 		}
1050 	}
1051 
1052 	if (NLP_ISSET(nlp, NLPF_DIRECT)) {
1053 		if (params->mp_operation == NDMP_DATA_OP_BACKUP)
1054 			MOD_LOGV3(params, NDMP_LOG_NORMAL,
1055 			    "Direct Access Restore information is supported");
1056 		else
1057 			MOD_LOGV3(params, NDMP_LOG_NORMAL,
1058 			    "Running Restore with Direct Access Restore");
1059 	} else {
1060 		if (params->mp_operation == NDMP_DATA_OP_BACKUP)
1061 			MOD_LOGV3(params, NDMP_LOG_NORMAL,
1062 			    "Direct Access Restore is not supported");
1063 		else
1064 			MOD_LOGV3(params, NDMP_LOG_NORMAL,
1065 			    "Running Restore without Direct Access Restore");
1066 	}
1067 }
1068 
1069 
1070 /*
1071  * get_date_token_v3
1072  *
1073  * Parse the token passed as the argument.  Evaluate it and
1074  * issue any warning or error if needed.  Save the date and
1075  * token sequence in the nlp structure fields.  The sequence
1076  * number in the token should be less than hard-limit.  If
1077  * it's between soft and hard limit, a warning is issued.
1078  * There is a configurable limit which should be less than
1079  * the soft-limit saved in ndmp_max_tok_seq variable.
1080  *
1081  * The NLPF_TOKENBK flag is set in the nlp flags field to
1082  * show that the backup type is token-based.
1083  *
1084  * Parameters:
1085  *   params (input) - pointer to the parameters structure
1086  *   nlp (input) - pointer to the nlp structure
1087  *   basedate (input) - the value of the BASE_DATE environment
1088  *	variable.
1089  *
1090  * Returns:
1091  *   NDMP_NO_ERR: on success
1092  *   != NDMP_NO_ERR: Otherwise
1093  *
1094  */
1095 static ndmp_error
1096 get_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp,
1097     char *basedate)
1098 {
1099 	char *endp;
1100 	uint_t seq;
1101 	ndmp_error rv;
1102 	time_t tstamp;
1103 	u_longlong_t tok;
1104 
1105 	if (!params || !nlp || !basedate || !*basedate)
1106 		return (NDMP_ILLEGAL_ARGS_ERR);
1107 
1108 	if (MOD_GETENV(params, "LEVEL")) {
1109 		MOD_LOGV3(params, NDMP_LOG_WARNING,
1110 		    "Both BASE_DATE and LEVEL environment variables "
1111 		    "defined.\n");
1112 		MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
1113 		    "BASE_DATE is being used for this backup.\n");
1114 	}
1115 
1116 	tok = strtoll(basedate, &endp, 10);
1117 	if (endp == basedate) {
1118 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1119 		    "Invalid BASE_DATE environment variable: \"%s\".\n",
1120 		    basedate);
1121 		return (NDMP_ILLEGAL_ARGS_ERR);
1122 	}
1123 
1124 	tstamp = tok & 0xffffffff;
1125 	seq = (tok >> 32) & 0xffffffff;
1126 	NDMP_LOG(LOG_DEBUG, "basedate \"%s\" %lld seq %u tstamp %u",
1127 	    basedate, tok, seq, tstamp);
1128 
1129 	if ((int)seq > ndmp_get_max_tok_seq()) {
1130 		rv = NDMP_ILLEGAL_ARGS_ERR;
1131 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1132 		    "The sequence counter of the token exceeds the "
1133 		    "maximum permitted value.\n");
1134 		MOD_LOGCONTV3(params, NDMP_LOG_ERROR,
1135 		    "Token sequence: %u, maxiumum value: %u.\n",
1136 		    seq, ndmp_get_max_tok_seq());
1137 	} else if (seq >= NDMP_TOKSEQ_HLIMIT) {
1138 		rv = NDMP_ILLEGAL_ARGS_ERR;
1139 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1140 		    "The sequence counter the of token exceeds the "
1141 		    "hard-limit.\n");
1142 		MOD_LOGCONTV3(params, NDMP_LOG_ERROR,
1143 		    "Token sequence: %u, hard-limit: %u.\n",
1144 		    seq, NDMP_TOKSEQ_HLIMIT);
1145 	} else {
1146 		rv = NDMP_NO_ERR;
1147 		/*
1148 		 * Issue a warning if the seq is equal to the maximum
1149 		 * permitted seq number or equal to the soft-limit.
1150 		 */
1151 		if (seq == NDMP_TOKSEQ_SLIMIT) {
1152 			MOD_LOGV3(params, NDMP_LOG_WARNING,
1153 			    "The sequence counter of the token has reached "
1154 			    "the soft-limit.\n");
1155 			MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
1156 			    "Token sequence: %u, soft-limit: %u.\n",
1157 			    seq, NDMP_TOKSEQ_SLIMIT);
1158 		} else if ((int)seq == ndmp_get_max_tok_seq()) {
1159 			MOD_LOGV3(params, NDMP_LOG_WARNING,
1160 			    "The sequence counter of the token has reached "
1161 			    "the maximum permitted value.\n");
1162 			MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
1163 			    "Token sequence: %u, maxiumum value: %u.\n",
1164 			    seq, ndmp_get_max_tok_seq());
1165 		}
1166 
1167 		/*
1168 		 * The current seq is equal to the seq field of the
1169 		 * token.  It will be increased after successful backup
1170 		 * before setting the DUMP_DATE environment variable.
1171 		 */
1172 		nlp->nlp_dmpnm = MOD_GETENV(params, "DMP_NAME");
1173 		NLP_SET(nlp, NLPF_TOKENBK);
1174 		NLP_UNSET(nlp, NLPF_LEVELBK);
1175 		NLP_UNSET(nlp, NLPF_LBRBK);
1176 		nlp->nlp_tokseq = seq;
1177 		nlp->nlp_tokdate = tstamp;
1178 		/*
1179 		 * The value of nlp_cdate will be set to the checkpoint
1180 		 * creation time after it is created.
1181 		 */
1182 	}
1183 
1184 	return (rv);
1185 }
1186 
1187 
1188 /*
1189  * get_lbr_bk_v3
1190  *
1191  * Sets the level fields of the nlp structures for
1192  * LBR-type backup.  The NLPF_LBRBK flag of the
1193  * nlp flags is also set to show the backup type.
1194  *
1195  * Parameters:
1196  *   params (input) - pointer to the parameters structure
1197  *   nlp (input) - pointer to the nlp structure
1198  *   type (input) - the backup level: 'F', 'A', 'I', 'D' or
1199  *	their lower-case values.
1200  *
1201  * Returns:
1202  *   NDMP_NO_ERR: on success
1203  *   != NDMP_NO_ERR: Otherwise
1204  */
1205 static ndmp_error
1206 get_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, char *type)
1207 {
1208 	if (!params || !nlp || !type || !*type)
1209 		return (NDMP_ILLEGAL_ARGS_ERR);
1210 
1211 	NLP_SET(nlp, NLPF_LBRBK);
1212 	NLP_UNSET(nlp, NLPF_TOKENBK);
1213 	NLP_UNSET(nlp, NLPF_LEVELBK);
1214 	nlp->nlp_dmpnm = MOD_GETENV(params, "DMP_NAME");
1215 	nlp->nlp_llevel = toupper(*type);
1216 	nlp->nlp_ldate = (time_t)0;
1217 	nlp->nlp_clevel = nlp->nlp_llevel;
1218 	(void) time(&nlp->nlp_cdate);
1219 
1220 	return (NDMP_NO_ERR);
1221 }
1222 
1223 
1224 /*
1225  * get_backup_level_v3
1226  *
1227  * Gets the backup level from the environment variables.  If
1228  * BASE_DATE is specified, it will be used, otherwise LEVEL
1229  * will be used.  If neither is specified, LEVEL = '0' is
1230  * assumed.
1231  *
1232  * Parameters:
1233  *   params (input) - pointer to the parameters structure
1234  *   nlp (input) - pointer to the nlp structure
1235  *
1236  * Returns:
1237  *   NDMP_NO_ERR: on success
1238  *   != NDMP_NO_ERR: Otherwise
1239  */
1240 static ndmp_error
1241 get_backup_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1242 {
1243 	char *envp;
1244 	ndmp_error rv;
1245 
1246 	/*
1247 	 * If the BASE_DATE env variable is specified use it, otherwise
1248 	 * look to see if LEVEL is specified.  If LEVEL is not
1249 	 * specified either, backup level '0' must be made. Level backup
1250 	 * does not clear the archive bit.
1251 	 *
1252 	 * If LEVEL environment varaible is specified, values for
1253 	 * 'F', 'D', 'I' and 'A' (for 'Full', 'Differential',
1254 	 * 'Incremental', and 'Archive' is checked first.  Then
1255 	 * level '0' to '9' will be checked.
1256 	 *
1257 	 * LEVEL environment variable can hold only one character.
1258 	 * If its length is longer than 1, an error is returned.
1259 	 */
1260 	envp = MOD_GETENV(params, "BASE_DATE");
1261 	if (envp)
1262 		return (get_date_token_v3(params, nlp, envp));
1263 
1264 
1265 	envp = MOD_GETENV(params, "LEVEL");
1266 	if (!envp) {
1267 		NDMP_LOG(LOG_DEBUG, "env(LEVEL) not defined, default to 0");
1268 		NLP_SET(nlp, NLPF_LEVELBK);
1269 		NLP_UNSET(nlp, NLPF_LBRBK);
1270 		NLP_UNSET(nlp, NLPF_TOKENBK);
1271 		nlp->nlp_llevel = 0;
1272 		nlp->nlp_ldate = 0;
1273 		nlp->nlp_clevel = 0;
1274 		/*
1275 		 * The value of nlp_cdate will be set to the checkpoint
1276 		 * creation time after it is created.
1277 		 */
1278 		return (NDMP_NO_ERR);
1279 	}
1280 
1281 	if (*(envp+1) != '\0') {
1282 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1283 		    "Invalid backup level \"%s\".\n", envp);
1284 		return (NDMP_ILLEGAL_ARGS_ERR);
1285 	}
1286 
1287 	if (IS_LBR_BKTYPE(*envp))
1288 		return (get_lbr_bk_v3(params, nlp, envp));
1289 
1290 	if (!isdigit(*envp)) {
1291 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1292 		    "Invalid backup level \"%s\".\n", envp);
1293 		return (NDMP_ILLEGAL_ARGS_ERR);
1294 	}
1295 
1296 	NLP_SET(nlp, NLPF_LEVELBK);
1297 	NLP_UNSET(nlp, NLPF_LBRBK);
1298 	NLP_UNSET(nlp, NLPF_TOKENBK);
1299 	nlp->nlp_llevel = *envp - '0';
1300 	nlp->nlp_ldate = 0;
1301 	nlp->nlp_clevel = nlp->nlp_llevel;
1302 	/*
1303 	 * The value of nlp_cdate will be set to the checkpoint
1304 	 * creation time after it is created.
1305 	 */
1306 	if (ndmpd_get_dumptime(nlp->nlp_backup_path, &nlp->nlp_llevel,
1307 	    &nlp->nlp_ldate) < 0) {
1308 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1309 		    "Getting dumpdates for %s level '%c'.\n",
1310 		    nlp->nlp_backup_path, *envp);
1311 		return (NDMP_NO_MEM_ERR);
1312 	} else {
1313 		get_update_env_v3(params, nlp);
1314 		rv = NDMP_NO_ERR;
1315 	}
1316 
1317 	return (rv);
1318 }
1319 
1320 
1321 /*
1322  * save_date_token_v3
1323  *
1324  * Make the value of DUMP_DATE env variable and append the values
1325  * of the current backup in the file specified with the DMP_NAME
1326  * env variable if any file is specified.  The file will be
1327  * relative name in the backup directory path.
1328  *
1329  * Parameters:
1330  *   params (input) - pointer to the parameters structure
1331  *   nlp (input) - pointer to the nlp structure
1332  *
1333  * Returns:
1334  *   void
1335  */
1336 static void
1337 save_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1338 {
1339 	char val[QUAD_DECIMAL_LEN];
1340 	u_longlong_t tok;
1341 
1342 	if (!params || !nlp)
1343 		return;
1344 
1345 	nlp->nlp_tokseq++;
1346 	tok = ((u_longlong_t)nlp->nlp_tokseq << 32) | nlp->nlp_cdate;
1347 	(void) snprintf(val, sizeof (val), "%llu", tok);
1348 
1349 	NDMP_LOG(LOG_DEBUG, "tok: %lld %s", tok, val);
1350 
1351 	if (MOD_SETENV(params, "DUMP_DATE", val) != 0) {
1352 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1353 		    "Could not set DUMP_DATE to %s", val);
1354 	} else if (!nlp->nlp_dmpnm) {
1355 		NDMP_LOG(LOG_DEBUG, "No log file defined");
1356 	} else if (ndmpd_append_dumptime(nlp->nlp_dmpnm, nlp->nlp_backup_path,
1357 	    nlp->nlp_tokseq, nlp->nlp_tokdate) < 0) {
1358 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1359 		    "Saving backup date for \"%s\" in \"%s\".\n",
1360 		    nlp->nlp_backup_path, nlp->nlp_dmpnm);
1361 	}
1362 }
1363 
1364 
1365 /*
1366  * save_lbr_bk_v3
1367  *
1368  * Append the backup type and date in the DMP_NAME file for
1369  * LBR-type backup if any file is specified.
1370  *
1371  * Parameters:
1372  *   params (input) - pointer to the parameters structure
1373  *   nlp (input) - pointer to the nlp structure
1374  *
1375  * Returns:
1376  *   void
1377  */
1378 static void
1379 save_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1380 {
1381 	if (!params || !nlp)
1382 		return;
1383 
1384 	if (!nlp->nlp_dmpnm) {
1385 		NDMP_LOG(LOG_DEBUG, "No log file defined");
1386 	} else if (ndmpd_append_dumptime(nlp->nlp_dmpnm, nlp->nlp_backup_path,
1387 	    nlp->nlp_clevel, nlp->nlp_cdate) < 0) {
1388 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1389 		    "Saving backup date for \"%s\" in \"%s\".\n",
1390 		    nlp->nlp_backup_path, nlp->nlp_dmpnm);
1391 	}
1392 }
1393 
1394 
1395 /*
1396  * save_level_v3
1397  *
1398  * Save the date and level of the current backup in the dumpdates
1399  * file.
1400  *
1401  * Parameters:
1402  *   params (input) - pointer to the parameters structure
1403  *   nlp (input) - pointer to the nlp structure
1404  *
1405  * Returns:
1406  *   void
1407  */
1408 static void
1409 save_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1410 {
1411 	if (!params || !nlp)
1412 		return;
1413 
1414 	if (!NLP_SHOULD_UPDATE(nlp)) {
1415 		NDMP_LOG(LOG_DEBUG, "update not requested");
1416 	} else if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel,
1417 	    nlp->nlp_cdate) < 0) {
1418 		MOD_LOGV3(params, NDMP_LOG_ERROR, "Logging backup date.\n");
1419 	}
1420 }
1421 
1422 
1423 /*
1424  * save_backup_date_v3
1425  *
1426  * A dispatcher function to call the corresponding save function
1427  * based on the backup type.
1428  *
1429  * Parameters:
1430  *   params (input) - pointer to the parameters structure
1431  *   nlp (input) - pointer to the nlp structure
1432  *
1433  * Returns:
1434  *   void
1435  */
1436 static void
1437 save_backup_date_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1438 {
1439 	if (!params || !nlp)
1440 		return;
1441 
1442 	if (NLP_ISSET(nlp, NLPF_TOKENBK))
1443 		save_date_token_v3(params, nlp);
1444 	else if (NLP_ISSET(nlp, NLPF_LBRBK))
1445 		save_lbr_bk_v3(params, nlp);
1446 	else if (NLP_ISSET(nlp, NLPF_LEVELBK))
1447 		save_level_v3(params, nlp);
1448 	else {
1449 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1450 		    "Internal error: lost backup level type for \"%s\".\n",
1451 		    nlp->nlp_backup_path);
1452 	}
1453 }
1454 
1455 
1456 /*
1457  * backup_alloc_structs_v3
1458  *
1459  * Create the structures for V3 backup.  This includes:
1460  *	Job stats
1461  *	Reader writer IPC
1462  *	File history callback structure
1463  *
1464  * Parameters:
1465  *   session (input) - pointer to the session
1466  *   jname (input) - name assigned to the current backup for
1467  *	job stats strucure
1468  *
1469  * Returns:
1470  *   0: on success
1471  *   -1: otherwise
1472  */
1473 static int
1474 backup_alloc_structs_v3(ndmpd_session_t *session, char *jname)
1475 {
1476 	int n;
1477 	long xfer_size;
1478 	ndmp_lbr_params_t *nlp;
1479 	tlm_commands_t *cmds;
1480 
1481 	nlp = ndmp_get_nlp(session);
1482 	if (!nlp) {
1483 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1484 		return (-1);
1485 	}
1486 
1487 	nlp->nlp_jstat = tlm_new_job_stats(jname);
1488 	if (!nlp->nlp_jstat) {
1489 		NDMP_LOG(LOG_DEBUG, "Creating job stats");
1490 		return (-1);
1491 	}
1492 
1493 	cmds = &nlp->nlp_cmds;
1494 	(void) memset(cmds, 0, sizeof (*cmds));
1495 
1496 	xfer_size = ndmp_buffer_get_size(session);
1497 	if (xfer_size < 512*KILOBYTE) {
1498 		/*
1499 		 * Read multiple of mover_record_size near to 512K.  This
1500 		 * will prevent the data being copied in the mover buffer
1501 		 * when we write the data.
1502 		 */
1503 		n = 512 * KILOBYTE / xfer_size;
1504 		if (n <= 0)
1505 			n = 1;
1506 		xfer_size *= n;
1507 		NDMP_LOG(LOG_DEBUG, "Adjusted read size: %d",
1508 		    xfer_size);
1509 	}
1510 
1511 	cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, xfer_size);
1512 	if (!cmds->tcs_command) {
1513 		tlm_un_ref_job_stats(jname);
1514 		return (-1);
1515 	}
1516 
1517 	nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
1518 	    ndmpd_fhpath_v3_cb, ndmpd_fhdir_v3_cb, ndmpd_fhnode_v3_cb);
1519 	if (!nlp->nlp_logcallbacks) {
1520 		tlm_release_reader_writer_ipc(cmds->tcs_command);
1521 		tlm_un_ref_job_stats(jname);
1522 		return (-1);
1523 	}
1524 	nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
1525 	nlp->nlp_restored = NULL;
1526 
1527 	return (0);
1528 }
1529 
1530 
1531 /*
1532  * restore_alloc_structs_v3
1533  *
1534  * Create the structures for V3 Restore.  This includes:
1535  *	Job stats
1536  *	Reader writer IPC
1537  *	File recovery callback structure
1538  *
1539  * Parameters:
1540  *   session (input) - pointer to the session
1541  *   jname (input) - name assigned to the current backup for
1542  *	job stats strucure
1543  *
1544  * Returns:
1545  *   0: on success
1546  *   -1: otherwise
1547  */
1548 int
1549 restore_alloc_structs_v3(ndmpd_session_t *session, char *jname)
1550 {
1551 	long xfer_size;
1552 	ndmp_lbr_params_t *nlp;
1553 	tlm_commands_t *cmds;
1554 
1555 	nlp = ndmp_get_nlp(session);
1556 	if (!nlp) {
1557 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1558 		return (-1);
1559 	}
1560 
1561 	/* this is used in ndmpd_path_restored_v3() */
1562 	nlp->nlp_lastidx = -1;
1563 
1564 	nlp->nlp_jstat = tlm_new_job_stats(jname);
1565 	if (!nlp->nlp_jstat) {
1566 		NDMP_LOG(LOG_DEBUG, "Creating job stats");
1567 		return (-1);
1568 	}
1569 
1570 	cmds = &nlp->nlp_cmds;
1571 	(void) memset(cmds, 0, sizeof (*cmds));
1572 
1573 	xfer_size = ndmp_buffer_get_size(session);
1574 	cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
1575 	if (!cmds->tcs_command) {
1576 		tlm_un_ref_job_stats(jname);
1577 		return (-1);
1578 	}
1579 
1580 	nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
1581 	    ndmpd_path_restored_v3, NULL, NULL);
1582 	if (!nlp->nlp_logcallbacks) {
1583 		tlm_release_reader_writer_ipc(cmds->tcs_command);
1584 		tlm_un_ref_job_stats(jname);
1585 		return (-1);
1586 	}
1587 	nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
1588 
1589 	nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0);
1590 	if (nlp->nlp_rsbm < 0) {
1591 		NDMP_LOG(LOG_ERR, "Out of memory.");
1592 		lbrlog_callbacks_done(nlp->nlp_logcallbacks);
1593 		tlm_release_reader_writer_ipc(cmds->tcs_command);
1594 		tlm_un_ref_job_stats(jname);
1595 		return (-1);
1596 	}
1597 
1598 	return (0);
1599 }
1600 
1601 
1602 /*
1603  * free_structs_v3
1604  *
1605  * Release the resources allocated by backup_alloc_structs_v3
1606  * function.
1607  *
1608  * Parameters:
1609  *   session (input) - pointer to the session
1610  *   jname (input) - name assigned to the current backup for
1611  *	job stats strucure
1612  *
1613  * Returns:
1614  *   void
1615  */
1616 /*ARGSUSED*/
1617 static void
1618 free_structs_v3(ndmpd_session_t *session, char *jname)
1619 {
1620 	ndmp_lbr_params_t *nlp;
1621 	tlm_commands_t *cmds;
1622 
1623 	nlp = ndmp_get_nlp(session);
1624 	if (!nlp) {
1625 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1626 		return;
1627 	}
1628 	cmds = &nlp->nlp_cmds;
1629 	if (!cmds) {
1630 		NDMP_LOG(LOG_DEBUG, "cmds == NULL");
1631 		return;
1632 	}
1633 
1634 	if (nlp->nlp_logcallbacks) {
1635 		lbrlog_callbacks_done(nlp->nlp_logcallbacks);
1636 		nlp->nlp_logcallbacks = NULL;
1637 	} else
1638 		NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL");
1639 
1640 	if (cmds->tcs_command) {
1641 		if (cmds->tcs_command->tc_buffers != NULL)
1642 			tlm_release_reader_writer_ipc(cmds->tcs_command);
1643 		else
1644 			NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL");
1645 		cmds->tcs_command = NULL;
1646 	} else
1647 		NDMP_LOG(LOG_DEBUG, "COMMAND == NULL");
1648 
1649 	if (nlp->nlp_bkmap >= 0) {
1650 		(void) dbm_free(nlp->nlp_bkmap);
1651 		nlp->nlp_bkmap = -1;
1652 	}
1653 
1654 	if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) {
1655 		if (nlp->nlp_rsbm < 0) {
1656 			NDMP_LOG(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm);
1657 		} else {
1658 			(void) bm_free(nlp->nlp_rsbm);
1659 			nlp->nlp_rsbm = -1;
1660 		}
1661 	}
1662 }
1663 
1664 
1665 /*
1666  * backup_dirv3
1667  *
1668  * Backup a directory and update the bytes processed field of the
1669  * data server.
1670  *
1671  * Parameters:
1672  *   bpp (input) - pointer to the backup parameters structure
1673  *   pnp (input) - pointer to the path node
1674  *   enp (input) - pointer to the entry node
1675  *
1676  * Returns:
1677  *   0: on success
1678  *   != 0: otherwise
1679  */
1680 static int
1681 backup_dirv3(bk_param_v3_t *bpp, fst_node_t *pnp,
1682     fst_node_t *enp)
1683 {
1684 	longlong_t apos, bpos;
1685 	acl_t *aclp = NULL;
1686 	char *acltp;
1687 	struct stat64 st;
1688 	char fullpath[TLM_MAX_PATH_NAME];
1689 	char *p;
1690 
1691 	if (!bpp || !pnp || !enp) {
1692 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1693 		return (-1);
1694 	}
1695 
1696 	NDMP_LOG(LOG_DEBUG, "d(%s)", bpp->bp_tmp);
1697 
1698 	if (lstat64(bpp->bp_tmp, &st) != 0)
1699 		return (0);
1700 
1701 	if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) {
1702 		NDMP_LOG(LOG_DEBUG, "acl_get error errno=%d", errno);
1703 		return (-1);
1704 	}
1705 	if (aclp && (acltp = acl_totext(aclp,
1706 	    ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
1707 		(void) strlcpy(bpp->bp_tlmacl->acl_info.attr_info,
1708 		    acltp, TLM_MAX_ACL_TXT);
1709 		acl_free(aclp);
1710 		free(acltp);
1711 	} else {
1712 		*bpp->bp_tlmacl->acl_info.attr_info = '\0';
1713 	}
1714 
1715 	bpos = tlm_get_data_offset(bpp->bp_lcmd);
1716 
1717 	p = bpp->bp_tmp + strlen(bpp->bp_chkpnm);
1718 	if (*p == '/')
1719 		(void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s%s",
1720 		    bpp->bp_unchkpnm, p);
1721 	else
1722 		(void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s",
1723 		    bpp->bp_unchkpnm, p);
1724 
1725 	if (tm_tar_ops.tm_putdir != NULL)
1726 		(void) (tm_tar_ops.tm_putdir)(fullpath, bpp->bp_tlmacl,
1727 		    bpp->bp_lcmd, bpp->bp_js);
1728 
1729 	apos = tlm_get_data_offset(bpp->bp_lcmd);
1730 	bpp->bp_session->ns_data.dd_module.dm_stats.ms_bytes_processed +=
1731 	    apos - bpos;
1732 
1733 	return (0);
1734 }
1735 
1736 
1737 /*
1738  * backup_filev3
1739  *
1740  * Backup a file and update the bytes processed field of the
1741  * data server.
1742  *
1743  * Parameters:
1744  *   bpp (input) - pointer to the backup parameters structure
1745  *   pnp (input) - pointer to the path node
1746  *   enp (input) - pointer to the entry node
1747  *
1748  * Returns:
1749  *   0: on success
1750  *   != 0: otherwise
1751  */
1752 static int
1753 backup_filev3(bk_param_v3_t *bpp, fst_node_t *pnp,
1754     fst_node_t *enp)
1755 {
1756 	char *ent;
1757 	longlong_t rv;
1758 	longlong_t apos, bpos;
1759 	acl_t *aclp = NULL;
1760 	char *acltp;
1761 	struct stat64 st;
1762 	char fullpath[TLM_MAX_PATH_NAME];
1763 	char *p;
1764 
1765 	if (!bpp || !pnp || !enp) {
1766 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1767 		return (-1);
1768 	}
1769 
1770 	NDMP_LOG(LOG_DEBUG, "f(%s)", bpp->bp_tmp);
1771 
1772 	if (lstat64(bpp->bp_tmp, &st) != 0)
1773 		return (0);
1774 
1775 	if (!S_ISLNK(bpp->bp_tlmacl->acl_attr.st_mode)) {
1776 		if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) {
1777 			NDMP_LOG(LOG_DEBUG, "acl_get error");
1778 			return (-1);
1779 		}
1780 
1781 		if (aclp &&
1782 		    (acltp = acl_totext(aclp,
1783 		    ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
1784 			(void) strlcpy(bpp->bp_tlmacl->acl_info.attr_info,
1785 			    acltp, TLM_MAX_ACL_TXT);
1786 			acl_free(aclp);
1787 			free(acltp);
1788 		} else {
1789 			*bpp->bp_tlmacl->acl_info.attr_info = '\0';
1790 		}
1791 	}
1792 
1793 	bpos = tlm_get_data_offset(bpp->bp_lcmd);
1794 	ent = enp->tn_path ? enp->tn_path : "";
1795 
1796 	p = pnp->tn_path + strlen(bpp->bp_chkpnm);
1797 	if (*p == '/')
1798 		(void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s%s",
1799 		    bpp->bp_unchkpnm, p);
1800 	else
1801 		(void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s",
1802 		    bpp->bp_unchkpnm, p);
1803 
1804 	if (tm_tar_ops.tm_putfile != NULL)
1805 		rv = (tm_tar_ops.tm_putfile)(fullpath, ent, pnp->tn_path,
1806 		    bpp->bp_tlmacl, bpp->bp_cmds, bpp->bp_lcmd, bpp->bp_js,
1807 		    bpp->bp_session->hardlink_q);
1808 
1809 	apos = tlm_get_data_offset(bpp->bp_lcmd);
1810 	bpp->bp_session->ns_data.dd_module.dm_stats.ms_bytes_processed +=
1811 	    apos - bpos;
1812 
1813 	return (rv < 0 ? rv : 0);
1814 }
1815 
1816 
1817 /*
1818  * check_bk_args
1819  *
1820  * Check the argument of the bpp.  This is shared function between
1821  * timebk_v3 and lbrbk_v3 functions.  The checks include:
1822  *	- The bpp itself.
1823  *	- If the session pointer of the bpp is valid.
1824  *	- If the session connection to the DMA is closed.
1825  *	- If the nlp pointer of the bpp is valid.
1826  *	- If the backup is aborted.
1827  *
1828  * Parameters:
1829  *   bpp (input) - pointer to the backup parameters structure
1830  *
1831  * Returns:
1832  *   0: if everything's OK
1833  *   != 0: otherwise
1834  */
1835 static int
1836 check_bk_args(bk_param_v3_t *bpp)
1837 {
1838 	int rv;
1839 
1840 	if (!bpp) {
1841 		rv = -1;
1842 		NDMP_LOG(LOG_DEBUG, "Lost bpp");
1843 	} else if (!bpp->bp_session) {
1844 		rv = -1;
1845 		NDMP_LOG(LOG_DEBUG, "Session is NULL");
1846 	} else if (bpp->bp_session->ns_eof) {
1847 		rv = -1;
1848 		NDMP_LOG(LOG_INFO,
1849 		    "Connection client is closed for backup \"%s\"",
1850 		    bpp->bp_nlp->nlp_backup_path);
1851 	} else if (!bpp->bp_nlp) {
1852 		NDMP_LOG(LOG_DEBUG, "Lost nlp");
1853 		return (-1);
1854 	} else if (bpp->bp_session->ns_data.dd_abort) {
1855 		rv = -1;
1856 		NDMP_LOG(LOG_INFO, "Backup aborted \"%s\"",
1857 		    bpp->bp_nlp->nlp_backup_path);
1858 	} else
1859 		rv = 0;
1860 
1861 	return (rv);
1862 }
1863 
1864 
1865 /*
1866  * shouldskip
1867  *
1868  * Determines if the current entry should be skipped or it
1869  * should be backed up.
1870  *
1871  * Parameters:
1872  *   bpp (input) - pointer to the backup parameters structure
1873  *   pnp (input) - pointer to the path node
1874  *   enp (input) - pointer to the entry node
1875  *   errp (output) - pointer to the error value that should be
1876  *	returned by the caller
1877  *
1878  * Returns:
1879  *   TRUE: if the entry should not be backed up
1880  *   FALSE: otherwise
1881  */
1882 static boolean_t
1883 shouldskip(bk_param_v3_t *bpp, fst_node_t *pnp,
1884     fst_node_t *enp, int *errp)
1885 {
1886 	char *ent;
1887 	boolean_t rv;
1888 	struct stat64 *estp;
1889 
1890 	if (!bpp || !pnp || !enp || !errp) {
1891 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1892 		return (TRUE);
1893 	}
1894 
1895 	if (!enp->tn_path) {
1896 		ent = "";
1897 		estp = pnp->tn_st;
1898 	} else {
1899 		ent = enp->tn_path;
1900 		estp = enp->tn_st;
1901 	}
1902 
1903 	/*
1904 	 * When excluding or skipping entries, FST_SKIP should be
1905 	 * returned, otherwise, 0 should be returned to
1906 	 * get other entries in the directory of this entry.
1907 	 */
1908 	if (!dbm_getone(bpp->bp_nlp->nlp_bkmap, (u_longlong_t)estp->st_ino)) {
1909 		rv = TRUE;
1910 		*errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;
1911 		NDMP_LOG(LOG_DEBUG, "Skipping %d %s/%s",
1912 		    *errp, pnp->tn_path, ent);
1913 	} else if (tlm_is_excluded(pnp->tn_path, ent, bpp->bp_excls)) {
1914 		rv = TRUE;
1915 		*errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;
1916 		NDMP_LOG(LOG_DEBUG, "excl %d \"%s/%s\"",
1917 		    *errp, pnp->tn_path, ent);
1918 	} else if (inexl(bpp->bp_nlp->nlp_exl, ent)) {
1919 		rv = TRUE;
1920 		*errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;
1921 		NDMP_LOG(LOG_DEBUG, "out %d \"%s/%s\"",
1922 		    *errp, pnp->tn_path, ent);
1923 	} else if (!S_ISDIR(estp->st_mode) &&
1924 	    !ininc(bpp->bp_nlp->nlp_inc, ent)) {
1925 		rv = TRUE;
1926 		*errp = 0;
1927 		NDMP_LOG(LOG_DEBUG, "!in \"%s/%s\"", pnp->tn_path, ent);
1928 	} else
1929 		rv = FALSE;
1930 
1931 	return (rv);
1932 }
1933 
1934 
1935 /*
1936  * ischngd
1937  *
1938  * Check if the object specified should be backed up or not.
1939  * If stp belongs to a directory and if it is marked in the
1940  * bitmap vector, it shows that either the directory itself is
1941  * modified or there is something below it that will be backed
1942  * up.
1943  *
1944  * By setting ndmp_force_bk_dirs global variable to a non-zero
1945  * value, directories are backed up anyways.
1946  *
1947  * Backing up the directories unconditionally helps
1948  * restoring the metadata of directories as well, when one
1949  * of the objects below them are being restored.
1950  *
1951  * For non-directory objects, if the modification or change
1952  * time of the object is after the date specified by the
1953  * bk_selector_t, the the object must be backed up.
1954  */
1955 static boolean_t
1956 ischngd(struct stat64 *stp, time_t t, ndmp_lbr_params_t *nlp)
1957 {
1958 	boolean_t rv;
1959 
1960 	if (!stp) {
1961 		rv = FALSE;
1962 		NDMP_LOG(LOG_DEBUG, "stp is NULL");
1963 	} else if (!nlp) {
1964 		rv = FALSE;
1965 		NDMP_LOG(LOG_DEBUG, "nlp is NULL");
1966 	} else if (t == 0) {
1967 		/*
1968 		 * if we are doing base backup then we do not need to
1969 		 * check the time, for we should backup everything.
1970 		 */
1971 		rv = TRUE;
1972 		NDMP_LOG(LOG_DEBUG, "Base Backup");
1973 	} else if (S_ISDIR(stp->st_mode) && ndmp_force_bk_dirs) {
1974 		rv = TRUE;
1975 		NDMP_LOG(LOG_DEBUG, "d(%lu)", (uint_t)stp->st_ino);
1976 	} else if (S_ISDIR(stp->st_mode) &&
1977 	    dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino) &&
1978 	    ((NLP_ISDUMP(nlp) && ndmp_dump_path_node) ||
1979 	    (NLP_ISTAR(nlp) && ndmp_tar_path_node))) {
1980 		/*
1981 		 * If the object is a directory and it leads to a modified
1982 		 * object (that should be backed up) and for that type of
1983 		 * backup the path nodes should be backed up, then return
1984 		 * TRUE.
1985 		 *
1986 		 * This is required by some DMAs like Backup Express, which
1987 		 * needs to receive ADD_NODE (for dump) or ADD_PATH (for tar)
1988 		 * for the intermediate directories of a modified object.
1989 		 * Other DMAs, like net_backup and net_worker, do not have such
1990 		 * requirement.  This requirement makes sense for dump format
1991 		 * but for 'tar' format, it does not.  In provision to the
1992 		 * NDMP-v4 spec, for 'tar' format the intermediate directories
1993 		 * need not to be reported.
1994 		 */
1995 		rv = TRUE;
1996 		NDMP_LOG(LOG_DEBUG, "p(%lu)", (u_longlong_t)stp->st_ino);
1997 	} else if (stp->st_mtime > t) {
1998 		rv = TRUE;
1999 		NDMP_LOG(LOG_DEBUG, "m(%lu): %lu > %lu",
2000 		    (uint_t)stp->st_ino, (uint_t)stp->st_mtime, (uint_t)t);
2001 	} else if (stp->st_ctime > t) {
2002 		if (NLP_IGNCTIME(nlp)) {
2003 			rv = FALSE;
2004 			NDMP_LOG(LOG_DEBUG, "ign c(%lu): %lu > %lu",
2005 			    (uint_t)stp->st_ino, (uint_t)stp->st_ctime,
2006 			    (uint_t)t);
2007 		} else {
2008 			rv = TRUE;
2009 			NDMP_LOG(LOG_DEBUG, "c(%lu): %lu > %lu",
2010 			    (uint_t)stp->st_ino, (uint_t)stp->st_ctime,
2011 			    (uint_t)t);
2012 		}
2013 	} else {
2014 		rv = FALSE;
2015 		NDMP_LOG(LOG_DEBUG, "mc(%lu): (%lu,%lu) < %lu",
2016 		    (uint_t)stp->st_ino, (uint_t)stp->st_mtime,
2017 		    (uint_t)stp->st_ctime, (uint_t)t);
2018 	}
2019 
2020 	return (rv);
2021 }
2022 
2023 
2024 /*
2025  * iscreated
2026  *
2027  * This function is used to check last mtime (currently inside the ACL
2028  * structure) instead of ctime for checking if the file is to be backed up
2029  * or not. See option "inc.lmtime" for more details
2030  */
2031 /*ARGSUSED*/
2032 int iscreated(ndmp_lbr_params_t *nlp, char *name, tlm_acls_t *tacl,
2033     time_t t)
2034 {
2035 	int ret;
2036 	acl_t *aclp = NULL;
2037 	char *acltp;
2038 
2039 	NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
2040 	if (NLP_INCLMTIME(nlp) == FALSE)
2041 		return (0);
2042 
2043 	ret = acl_get(name, ACL_NO_TRIVIAL, &aclp);
2044 	if (ret != 0) {
2045 		NDMP_LOG(LOG_DEBUG,
2046 		    "Error getting the acl information: err %d", ret);
2047 		return (0);
2048 	}
2049 	if (aclp && (acltp = acl_totext(aclp,
2050 	    ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
2051 		(void) strlcpy(tacl->acl_info.attr_info, acltp,
2052 		    TLM_MAX_ACL_TXT);
2053 		acl_free(aclp);
2054 		free(acltp);
2055 	}
2056 
2057 	/* Need to add support for last mtime */
2058 
2059 	return (0);
2060 }
2061 
2062 /*
2063  * size_cb
2064  *
2065  * The callback function for calculating the size of
2066  * the backup path. This is used to get an estimate
2067  * of the progress of backup during NDMP backup
2068  */
2069 static int
2070 size_cb(void *arg, fst_node_t *pnp, fst_node_t *enp)
2071 {
2072 	struct stat64 *stp;
2073 
2074 	stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2075 	*((u_longlong_t *)arg) += stp->st_size;
2076 
2077 	return (0);
2078 }
2079 
2080 /*
2081  * timebk_v3
2082  *
2083  * The callback function for backing up objects based on
2084  * their time stamp.  This is shared between token-based
2085  * and level-based backup, which look at the time stamps
2086  * of the objects to determine if they should be backed
2087  * up.
2088  *
2089  * Parameters:
2090  *   arg (input) - pointer to the backup parameters structure
2091  *   pnp (input) - pointer to the path node
2092  *   enp (input) - pointer to the entry node
2093  *
2094  * Returns:
2095  *   0: if backup should continue
2096  *   -1: if the backup should be stopped
2097  *   FST_SKIP: if backing up the current directory is enough
2098  */
2099 static int
2100 timebk_v3(void *arg, fst_node_t *pnp, fst_node_t *enp)
2101 {
2102 	char *ent;
2103 	int rv;
2104 	time_t t;
2105 	bk_param_v3_t *bpp;
2106 	struct stat64 *stp;
2107 	fs_fhandle_t *fhp;
2108 
2109 	bpp = (bk_param_v3_t *)arg;
2110 
2111 	rv = check_bk_args(bpp);
2112 	if (rv != 0)
2113 		return (rv);
2114 
2115 	stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2116 	if (shouldskip(bpp, pnp, enp, &rv))
2117 		return (rv);
2118 
2119 	if (enp->tn_path) {
2120 		ent = enp->tn_path;
2121 		stp = enp->tn_st;
2122 		fhp = enp->tn_fh;
2123 	} else {
2124 		ent = "";
2125 		stp = pnp->tn_st;
2126 		fhp = pnp->tn_fh;
2127 	}
2128 
2129 
2130 	if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) {
2131 		NDMP_LOG(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent);
2132 		return (FST_SKIP);
2133 	}
2134 	if (NLP_ISSET(bpp->bp_nlp, NLPF_TOKENBK))
2135 		t = bpp->bp_nlp->nlp_tokdate;
2136 	else if (NLP_ISSET(bpp->bp_nlp, NLPF_LEVELBK)) {
2137 		t = bpp->bp_nlp->nlp_ldate;
2138 	} else {
2139 		NDMP_LOG(LOG_DEBUG, "Unknown backup type on \"%s/%s\"",
2140 		    pnp->tn_path, ent);
2141 		return (-1);
2142 	}
2143 
2144 	if (S_ISDIR(stp->st_mode)) {
2145 		bpp->bp_tlmacl->acl_dir_fh = *fhp;
2146 		(void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks,
2147 		    bpp->bp_tmp, stp);
2148 
2149 		if (ischngd(stp, t, bpp->bp_nlp)) {
2150 			(void) memcpy(&bpp->bp_tlmacl->acl_attr, stp,
2151 			    sizeof (struct stat64));
2152 			rv = backup_dirv3(bpp, pnp, enp);
2153 		}
2154 	} else {
2155 		if (ischngd(stp, t, bpp->bp_nlp) ||
2156 		    iscreated(bpp->bp_nlp, bpp->bp_tmp, bpp->bp_tlmacl, t)) {
2157 			rv = 0;
2158 			(void) memcpy(&bpp->bp_tlmacl->acl_attr, stp,
2159 			    sizeof (struct stat64));
2160 			bpp->bp_tlmacl->acl_fil_fh = *fhp;
2161 			(void) backup_filev3(bpp, pnp, enp);
2162 		}
2163 	}
2164 
2165 	return (rv);
2166 }
2167 
2168 
2169 /*
2170  * lbrbk_v3
2171  *
2172  * The callback function for backing up objects based on
2173  * their archive directory bit.  This is used in LBR-type
2174  * backup.  In which the objects are backed up if their
2175  * archive bit is set.
2176  *
2177  * Parameters:
2178  *   arg (input) - pointer to the backup parameters structure
2179  *   pnp (input) - pointer to the path node
2180  *   enp (input) - pointer to the entry node
2181  *
2182  * Returns:
2183  *   0: if backup should continue
2184  *   -1: if the backup should be stopped
2185  *   FST_SKIP: if backing up the current directory is enough
2186  */
2187 static int
2188 lbrbk_v3(void *arg, fst_node_t *pnp, fst_node_t *enp)
2189 {
2190 	char *ent;
2191 	int rv;
2192 	bk_param_v3_t *bpp;
2193 	struct stat64 *stp;
2194 	fs_fhandle_t *fhp;
2195 
2196 	bpp = (bk_param_v3_t *)arg;
2197 	rv = check_bk_args(bpp);
2198 	if (rv != 0)
2199 		return (rv);
2200 
2201 	stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2202 	if (shouldskip(bpp, pnp, enp, &rv))
2203 		return (rv);
2204 
2205 	if (enp->tn_path) {
2206 		ent = enp->tn_path;
2207 		stp = enp->tn_st;
2208 		fhp = enp->tn_fh;
2209 	} else {
2210 		ent = "";
2211 		stp = pnp->tn_st;
2212 		fhp = pnp->tn_fh;
2213 	}
2214 
2215 	if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) {
2216 		NDMP_LOG(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent);
2217 		return (FST_SKIP);
2218 	}
2219 	if (!NLP_ISSET(bpp->bp_nlp, NLPF_LBRBK)) {
2220 		NDMP_LOG(LOG_DEBUG, "!NLPF_LBRBK");
2221 		return (-1);
2222 	}
2223 
2224 	if (S_ISDIR(stp->st_mode)) {
2225 		bpp->bp_tlmacl->acl_dir_fh = *fhp;
2226 		(void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks,
2227 		    bpp->bp_tmp, stp);
2228 
2229 		if (SHOULD_LBRBK(bpp)) {
2230 			bpp->bp_tlmacl->acl_attr = *stp;
2231 			rv = backup_dirv3(bpp, pnp, enp);
2232 		}
2233 	} else if (SHOULD_LBRBK(bpp)) {
2234 		rv = 0;
2235 		bpp->bp_tlmacl->acl_attr = *stp;
2236 		bpp->bp_tlmacl->acl_fil_fh = *fhp;
2237 		(void) backup_filev3(bpp, pnp, enp);
2238 	}
2239 
2240 	return (rv);
2241 }
2242 
2243 
2244 /*
2245  * backup_reader_v3
2246  *
2247  * The reader thread for the backup.  It sets up the callback
2248  * parameters and traverses the backup hierarchy in level-order
2249  * way.
2250  *
2251  * Parameters:
2252  *   jname (input) - name assigned to the current backup for
2253  *	job stats strucure
2254  *   nlp (input) - pointer to the nlp structure
2255  *   cmds (input) - pointer to the tlm_commands_t structure
2256  *
2257  * Returns:
2258  *   0: on success
2259  *   != 0: otherwise
2260  */
2261 static int
2262 backup_reader_v3(backup_reader_arg_t *argp)
2263 {
2264 	int rv;
2265 	tlm_cmd_t *lcmd;
2266 	tlm_acls_t tlm_acls;
2267 	longlong_t bpos, n;
2268 	bk_param_v3_t bp;
2269 	fs_traverse_t ft;
2270 	char *jname;
2271 	ndmp_lbr_params_t *nlp;
2272 	tlm_commands_t *cmds;
2273 
2274 	if (!argp)
2275 		return (-1);
2276 
2277 	jname = argp->br_jname;
2278 	nlp = argp->br_nlp;
2279 	cmds = argp->br_cmds;
2280 
2281 	rv = 0;
2282 	lcmd = cmds->tcs_command;
2283 	lcmd->tc_ref++;
2284 	cmds->tcs_reader_count++;
2285 
2286 	(void) memset(&tlm_acls, 0, sizeof (tlm_acls));
2287 
2288 	/* NDMP parameters */
2289 	bp.bp_session = nlp->nlp_session;
2290 	bp.bp_nlp = nlp;
2291 
2292 	/* LBR-related parameters  */
2293 	bp.bp_js = tlm_ref_job_stats(jname);
2294 	bp.bp_cmds = cmds;
2295 	bp.bp_lcmd = lcmd;
2296 	bp.bp_tlmacl = &tlm_acls;
2297 	bp.bp_opr = 0;
2298 
2299 	/* release the parent thread, after referencing the job stats */
2300 	(void) pthread_barrier_wait(&argp->br_barrier);
2301 
2302 	bp.bp_tmp = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
2303 	if (!bp.bp_tmp)
2304 		return (-1);
2305 
2306 	/*
2307 	 * Make the checkpointed paths for traversing the
2308 	 * backup hierarchy, if we make the checkpoint.
2309 	 */
2310 	bp.bp_unchkpnm = nlp->nlp_backup_path;
2311 	if (!NLP_ISCHKPNTED(nlp)) {
2312 		tlm_acls.acl_checkpointed = TRUE;
2313 		bp.bp_chkpnm = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
2314 		if (!bp.bp_chkpnm) {
2315 			NDMP_FREE(bp.bp_tmp);
2316 			return (-1);
2317 		}
2318 		(void) tlm_build_snapshot_name(nlp->nlp_backup_path,
2319 		    bp.bp_chkpnm, nlp->nlp_jstat->js_job_name);
2320 	} else {
2321 		tlm_acls.acl_checkpointed = FALSE;
2322 		bp.bp_chkpnm = nlp->nlp_backup_path;
2323 	}
2324 	bp.bp_excls = ndmpd_make_exc_list();
2325 
2326 	/* set traversing arguments */
2327 	ft.ft_path = nlp->nlp_backup_path;
2328 	ft.ft_lpath = bp.bp_chkpnm;
2329 
2330 	NDMP_LOG(LOG_DEBUG, "path %s lpath %s", ft.ft_path, ft.ft_lpath);
2331 	if (NLP_ISSET(nlp, NLPF_TOKENBK) || NLP_ISSET(nlp, NLPF_LEVELBK)) {
2332 		ft.ft_callbk = timebk_v3;
2333 		tlm_acls.acl_clear_archive = FALSE;
2334 	} else if (NLP_ISSET(nlp, NLPF_LBRBK)) {
2335 		ft.ft_callbk = lbrbk_v3;
2336 		tlm_acls.acl_clear_archive = FALSE;
2337 
2338 		NDMP_LOG(LOG_DEBUG, "bp_opr %x clr_arc %c",
2339 		    bp.bp_opr, NDMP_YORN(tlm_acls.acl_clear_archive));
2340 	} else {
2341 		rv = -1;
2342 		MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR,
2343 		    "Unknow backup type.\n");
2344 	}
2345 	ft.ft_arg = &bp;
2346 	ft.ft_logfp = (ft_log_t)ndmp_log;
2347 	ft.ft_flags = FST_VERBOSE;	/* Solaris */
2348 
2349 	/* take into account the header written to the stream so far */
2350 	n = tlm_get_data_offset(lcmd);
2351 	nlp->nlp_session->ns_data.dd_module.dm_stats.ms_bytes_processed = n;
2352 
2353 	if (rv == 0) {
2354 		/* start traversing the hierarchy and actual backup */
2355 		rv = traverse_level(&ft);
2356 		if (rv == 0) {
2357 			/* write the trailer and update the bytes processed */
2358 			bpos = tlm_get_data_offset(lcmd);
2359 			(void) write_tar_eof(lcmd);
2360 			n = tlm_get_data_offset(lcmd) - bpos;
2361 			nlp->nlp_session->
2362 			    ns_data.dd_module.dm_stats.ms_bytes_processed += n;
2363 		}
2364 	}
2365 
2366 	if (!NLP_ISCHKPNTED(nlp))
2367 		NDMP_FREE(bp.bp_chkpnm);
2368 	NDMP_FREE(bp.bp_tmp);
2369 	NDMP_FREE(bp.bp_excls);
2370 
2371 	cmds->tcs_reader_count--;
2372 	lcmd->tc_writer = TLM_STOP;
2373 	tlm_release_reader_writer_ipc(lcmd);
2374 	tlm_un_ref_job_stats(jname);
2375 	return (rv);
2376 
2377 }
2378 
2379 
2380 /*
2381  * tar_backup_v3
2382  *
2383  * Traverse the backup hierarchy if needed and make the bitmap.
2384  * Then launch reader and writer threads to do the actual backup.
2385  *
2386  * Parameters:
2387  *   session (input) - pointer to the session
2388  *   params (input) - pointer to the parameters structure
2389  *   nlp (input) - pointer to the nlp structure
2390  *   jname (input) - job name
2391  *
2392  * Returns:
2393  *   0: on success
2394  *   != 0: otherwise
2395  */
2396 static int
2397 tar_backup_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
2398     ndmp_lbr_params_t *nlp, char *jname)
2399 {
2400 	tlm_commands_t *cmds;
2401 	backup_reader_arg_t arg;
2402 	pthread_t rdtp;
2403 	char info[256];
2404 	int result;
2405 	ndmp_context_t nctx;
2406 	int err;
2407 
2408 	if (ndmp_get_bk_dir_ino(nlp))
2409 		return (-1);
2410 
2411 	result = err = 0;
2412 
2413 	/* exit as if there was an internal error */
2414 	if (session->ns_eof)
2415 		return (-1);
2416 
2417 	if (!session->ns_data.dd_abort) {
2418 		if (backup_alloc_structs_v3(session, jname) < 0) {
2419 			nlp->nlp_bkmap = -1;
2420 			return (-1);
2421 		}
2422 
2423 		if (ndmpd_mark_inodes_v3(session, nlp) != 0) {
2424 			if (nlp->nlp_bkmap != -1) {
2425 				(void) dbm_free(nlp->nlp_bkmap);
2426 				nlp->nlp_bkmap = -1;
2427 			}
2428 			free_structs_v3(session, jname);
2429 			return (-1);
2430 		}
2431 
2432 		nlp->nlp_jstat->js_start_ltime = time(NULL);
2433 		nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
2434 		nlp->nlp_jstat->js_chkpnt_time = nlp->nlp_cdate;
2435 
2436 		cmds = &nlp->nlp_cmds;
2437 		cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
2438 		cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
2439 		cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
2440 
2441 		if (ndmp_write_utf8magic(cmds->tcs_command) < 0) {
2442 			free_structs_v3(session, jname);
2443 			return (-1);
2444 		}
2445 
2446 		NDMP_LOG(LOG_DEBUG,
2447 		    "Backing up \"%s\" started.", nlp->nlp_backup_path);
2448 
2449 		/* Plug-in module */
2450 		if (ndmp_pl != NULL &&
2451 		    ndmp_pl->np_pre_backup != NULL) {
2452 			(void) memset(&nctx, 0, sizeof (ndmp_context_t));
2453 			nctx.nc_plversion = ndmp_pl->np_plversion;
2454 			nctx.nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
2455 			nctx.nc_cmds = cmds;
2456 			nctx.nc_params = params;
2457 			if ((err = ndmp_pl->np_pre_backup(ndmp_pl, &nctx,
2458 			    nlp->nlp_backup_path)) != 0) {
2459 				NDMP_LOG(LOG_ERR, "Pre-backup plug-in: %m");
2460 				goto backup_out;
2461 			}
2462 		}
2463 
2464 		(void) memset(&arg, 0, sizeof (backup_reader_arg_t));
2465 		arg.br_jname = jname;
2466 		arg.br_nlp = nlp;
2467 		arg.br_cmds = cmds;
2468 
2469 		(void) pthread_barrier_init(&arg.br_barrier, 0, 2);
2470 
2471 		err = pthread_create(&rdtp, NULL, (funct_t)backup_reader_v3,
2472 		    (void *)&arg);
2473 		if (err == 0) {
2474 			(void) pthread_barrier_wait(&arg.br_barrier);
2475 			(void) pthread_barrier_destroy(&arg.br_barrier);
2476 		} else {
2477 			(void) pthread_barrier_destroy(&arg.br_barrier);
2478 			free_structs_v3(session, jname);
2479 			NDMP_LOG(LOG_DEBUG, "Launch backup_reader_v3: %m");
2480 			return (-1);
2481 		}
2482 
2483 		if ((err = ndmp_tar_writer(session, params, cmds)) != 0)
2484 			result = EIO;
2485 
2486 		nlp->nlp_jstat->js_stop_time = time(NULL);
2487 
2488 		(void) snprintf(info, sizeof (info),
2489 		    "Runtime [%s] %llu bytes (%llu): %d seconds\n",
2490 		    nlp->nlp_backup_path,
2491 		    session->ns_data.dd_module.dm_stats.ms_bytes_processed,
2492 		    session->ns_data.dd_module.dm_stats.ms_bytes_processed,
2493 		    nlp->nlp_jstat->js_stop_time -
2494 		    nlp->nlp_jstat->js_start_ltime);
2495 		MOD_LOGV3(params, NDMP_LOG_NORMAL, info);
2496 
2497 		ndmp_wait_for_reader(cmds);
2498 		(void) pthread_join(rdtp, NULL);
2499 
2500 		/* exit as if there was an internal error */
2501 		if (session->ns_eof) {
2502 			result = EPIPE;
2503 			err = -1;
2504 		}
2505 		if (!session->ns_data.dd_abort) {
2506 			ndmpd_audit_backup(session->ns_connection,
2507 			    nlp->nlp_backup_path,
2508 			    session->ns_data.dd_data_addr.addr_type,
2509 			    session->ns_tape.td_adapter_name, result);
2510 			NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" Finished.",
2511 			    nlp->nlp_backup_path);
2512 		}
2513 	}
2514 
2515 	if (session->ns_data.dd_abort) {
2516 		ndmpd_audit_backup(session->ns_connection,
2517 		    nlp->nlp_backup_path,
2518 		    session->ns_data.dd_data_addr.addr_type,
2519 		    session->ns_tape.td_adapter_name, EINTR);
2520 		NDMP_LOG(LOG_DEBUG,
2521 		    "Backing up \"%s\" aborted.", nlp->nlp_backup_path);
2522 		err = -1;
2523 	} else {
2524 
2525 backup_out:
2526 		/* Plug-in module */
2527 		if (ndmp_pl != NULL &&
2528 		    ndmp_pl->np_post_backup != NULL &&
2529 		    ndmp_pl->np_post_backup(ndmp_pl, &nctx, err) == -1) {
2530 			NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m");
2531 			return (-1);
2532 		}
2533 	}
2534 
2535 	free_structs_v3(session, jname);
2536 	return (err);
2537 }
2538 
2539 /*
2540  * get_backup_size
2541  *
2542  * Find the estimate of backup size. This is used to get an estimate
2543  * of the progress of backup during NDMP backup.
2544  */
2545 void
2546 get_backup_size(ndmp_bkup_size_arg_t *sarg)
2547 {
2548 	fs_traverse_t ft;
2549 	u_longlong_t bk_size;
2550 	char spath[PATH_MAX];
2551 	int rv;
2552 
2553 	bk_size = 0;
2554 	if (fs_is_chkpntvol(sarg->bs_path)) {
2555 		ft.ft_path = sarg->bs_path;
2556 	} else {
2557 		(void) tlm_build_snapshot_name(sarg->bs_path,
2558 		    spath, sarg->bs_jname);
2559 		ft.ft_path = spath;
2560 	}
2561 
2562 	ft.ft_lpath = ft.ft_path;
2563 	ft.ft_callbk = size_cb;
2564 	ft.ft_arg = &bk_size;
2565 	ft.ft_logfp = (ft_log_t)ndmp_log;
2566 	ft.ft_flags = FST_VERBOSE;
2567 
2568 	if ((rv = traverse_level(&ft)) != 0) {
2569 		NDMP_LOG(LOG_DEBUG, "bksize err=%d", rv);
2570 		bk_size = 0;
2571 	} else {
2572 		NDMP_LOG(LOG_DEBUG, "bksize %lld, %lldKB, %lldMB\n",
2573 		    bk_size, bk_size / 1024, bk_size /(1024 * 1024));
2574 	}
2575 	sarg->bs_session->ns_data.dd_data_size = bk_size;
2576 }
2577 
2578 /*
2579  * get_rs_path_v3
2580  *
2581  * Find the restore path
2582  */
2583 ndmp_error
2584 get_rs_path_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
2585 {
2586 	char *dp;
2587 	ndmp_error rv;
2588 	mem_ndmp_name_v3_t *ep;
2589 	int i, nm_cnt;
2590 	char *nm_dpath_list[MULTIPLE_DEST_DIRS];
2591 	static char mdest_buf[256];
2592 
2593 	*mdest_buf = 0;
2594 	*nm_dpath_list = "";
2595 	for (i = 0, nm_cnt = 0; i < (int)nlp->nlp_nfiles; i++) {
2596 		ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
2597 		if (!ep) {
2598 			NDMP_LOG(LOG_DEBUG, "Can't get Nlist[%d]", i);
2599 			return (NDMP_ILLEGAL_ARGS_ERR);
2600 		}
2601 		if (strcmp(nm_dpath_list[nm_cnt], ep->nm3_dpath) != 0 &&
2602 		    nm_cnt < MULTIPLE_DEST_DIRS - 1)
2603 			nm_dpath_list[++nm_cnt] = ep->nm3_dpath;
2604 	}
2605 
2606 	multiple_dest_restore = (nm_cnt > 1);
2607 	nlp->nlp_restore_path = mdest_buf;
2608 
2609 	for (i = 1; i < nm_cnt + 1; i++) {
2610 		if (ISDEFINED(nm_dpath_list[i]))
2611 			dp = nm_dpath_list[i];
2612 		else
2613 			/* the default destination path is backup directory */
2614 			dp = nlp->nlp_backup_path;
2615 
2616 		/* check the destination directory exists and is writable */
2617 		if (!fs_volexist(dp)) {
2618 			rv = NDMP_ILLEGAL_ARGS_ERR;
2619 			MOD_LOGV3(params, NDMP_LOG_ERROR,
2620 			    "Invalid destination path volume \"%s\".\n", dp);
2621 		} else if (!voliswr(dp)) {
2622 			rv = NDMP_ILLEGAL_ARGS_ERR;
2623 			MOD_LOGV3(params, NDMP_LOG_ERROR,
2624 			    "The destination path volume"
2625 			    " is not writable \"%s\".\n", dp);
2626 		} else {
2627 			rv = NDMP_NO_ERR;
2628 			(void) strlcat(nlp->nlp_restore_path, dp,
2629 			    sizeof (mdest_buf));
2630 			NDMP_LOG(LOG_DEBUG, "rspath: \"%s\"", dp);
2631 		}
2632 
2633 		/*
2634 		 * Exit if there is an error or it is not a multiple
2635 		 * destination restore mode
2636 		 */
2637 		if (rv != NDMP_NO_ERR || !multiple_dest_restore)
2638 			break;
2639 
2640 		if (i < nm_cnt)
2641 			(void) strlcat(nlp->nlp_restore_path, ", ",
2642 			    sizeof (mdest_buf));
2643 	}
2644 
2645 	return (rv);
2646 }
2647 
2648 
2649 /*
2650  * fix_nlist_v3
2651  *
2652  * Check if the recovery list is valid and fix it if there are some
2653  * unspecified entries in it. It checks for original, destination
2654  * and new path for all NDMP names provided inside the list.
2655  *
2656  * V3: dpath is the destination directory.  If newnm is not NULL, the
2657  * destination path is dpath/newnm.  Otherwise the destination path is
2658  * dpath/opath_last_node, where opath_last_node is the last node in opath.
2659  *
2660  * V4: If newnm is not NULL, dpath is the destination directory, and
2661  * dpath/newnm is the destination path.  If newnm is NULL, dpath is
2662  * the destination path (opath is not involved in forming destination path).
2663  */
2664 ndmp_error
2665 fix_nlist_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
2666     ndmp_lbr_params_t *nlp)
2667 {
2668 	char *cp, *buf, *bp;
2669 	int i, n;
2670 	int iswrbk;
2671 	int bvexists;
2672 	ndmp_error rv;
2673 	mem_ndmp_name_v3_t *ep;
2674 	char *dp;
2675 	char *nm;
2676 	int existsvol;
2677 	int isrwdst;
2678 
2679 	buf = ndmp_malloc(TLM_MAX_PATH_NAME);
2680 	if (!buf) {
2681 		MOD_LOGV3(params, NDMP_LOG_ERROR, "Insufficient memory.\n");
2682 		return (NDMP_NO_MEM_ERR);
2683 	}
2684 
2685 	bvexists = fs_volexist(nlp->nlp_backup_path);
2686 	iswrbk = voliswr(nlp->nlp_backup_path);
2687 
2688 	rv = NDMP_NO_ERR;
2689 	n = session->ns_data.dd_nlist_len;
2690 	for (i = 0; i < n; i++) {
2691 		ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
2692 		if (!ep)
2693 			continue;
2694 
2695 		/* chop off the trailing slashes */
2696 		chopslash(ep->nm3_opath);
2697 
2698 		chopslash(ep->nm3_dpath);
2699 		chopslash(ep->nm3_newnm);
2700 
2701 		/* existing and non-empty destination path */
2702 		if (ISDEFINED(ep->nm3_dpath)) {
2703 			dp = ep->nm3_dpath;
2704 			existsvol = fs_volexist(dp);
2705 			isrwdst = voliswr(dp);
2706 		} else {
2707 			/* the default destination path is backup directory */
2708 			dp = nlp->nlp_backup_path;
2709 			existsvol = bvexists;
2710 			isrwdst = iswrbk;
2711 		}
2712 
2713 		/* check the destination directory exists and is writable */
2714 		if (!existsvol) {
2715 			rv = NDMP_ILLEGAL_ARGS_ERR;
2716 			MOD_LOGV3(params, NDMP_LOG_ERROR,
2717 			    "Invalid destination path volume "
2718 			    "\"%s\".\n", dp);
2719 			break;
2720 		}
2721 		if (!isrwdst) {
2722 			rv = NDMP_ILLEGAL_ARGS_ERR;
2723 			MOD_LOGV3(params, NDMP_LOG_ERROR,
2724 			    "The destination path volume is not "
2725 			    "writable \"%s\".\n", dp);
2726 			break;
2727 		}
2728 
2729 		/*
2730 		 * If new name is not specified, the default new name is
2731 		 * the last component of the original path, if any
2732 		 * (except in V4).
2733 		 */
2734 		if (session->ns_protocol_version == NDMPV4) {
2735 			nm = ep->nm3_newnm;
2736 		} else {
2737 			if (ISDEFINED(ep->nm3_newnm)) {
2738 				nm = ep->nm3_newnm;
2739 			} else {
2740 				/*
2741 				 * Find the last component of nm3_opath.
2742 				 * nm3_opath has no trailing '/'.
2743 				 */
2744 				char *p = strrchr(ep->nm3_opath, '/');
2745 				nm = p? p : ep->nm3_opath;
2746 			}
2747 		}
2748 
2749 		bp = joinpath(buf, dp, nm);
2750 		if (!bp) {
2751 			/*
2752 			 * Note: What should be done with this entry?
2753 			 * We leave it untouched for now, hence no path in
2754 			 * the backup image matches with this entry and will
2755 			 * be reported as not found.
2756 			 */
2757 			MOD_LOGV3(params, NDMP_LOG_ERROR,
2758 			    "Destination path too long(%s/%s)", dp, nm);
2759 			continue;
2760 		}
2761 		cp = strdup(bp);
2762 		if (!cp) {
2763 			MOD_LOGV3(params, NDMP_LOG_ERROR,
2764 			    "Insufficient memory.\n");
2765 			rv = NDMP_NO_MEM_ERR;
2766 			break;
2767 		}
2768 		free(ep->nm3_dpath);
2769 		ep->nm3_dpath = cp;
2770 		NDMP_FREE(ep->nm3_newnm);
2771 
2772 		bp = joinpath(buf, nlp->nlp_backup_path, ep->nm3_opath);
2773 		if (!bp) {
2774 			/*
2775 			 * Note: The same problem of above with long path.
2776 			 */
2777 			MOD_LOGV3(params, NDMP_LOG_ERROR,
2778 			    "Path too long(%s/%s)",
2779 			    nlp->nlp_backup_path, ep->nm3_opath);
2780 			continue;
2781 		}
2782 		cp = strdup(bp);
2783 		if (!cp) {
2784 			MOD_LOGV3(params, NDMP_LOG_ERROR,
2785 			    "Insufficient memory.\n");
2786 			rv = NDMP_NO_MEM_ERR;
2787 			break;
2788 		}
2789 		NDMP_FREE(ep->nm3_opath);
2790 		ep->nm3_opath = cp;
2791 
2792 		NDMP_LOG(LOG_DEBUG, "orig[%d]: \"%s\"", i, ep->nm3_opath);
2793 		if (ep->nm3_dpath) {
2794 			NDMP_LOG(LOG_DEBUG,
2795 			    "dest[%d]: \"%s\"", i, ep->nm3_dpath);
2796 		} else {
2797 			NDMP_LOG(LOG_DEBUG, "dest[%d]: \"%s\"", i, "NULL");
2798 		}
2799 	}
2800 
2801 	free(buf);
2802 
2803 	return (rv);
2804 }
2805 
2806 
2807 /*
2808  * allvalidfh
2809  *
2810  * Run a sanity check on the file history info. The file history
2811  * info is the offset of the record starting the entry on the tape
2812  * and is used in DAR (direct access restore mode).
2813  */
2814 static boolean_t
2815 allvalidfh(ndmpd_session_t *session, ndmpd_module_params_t *params)
2816 {
2817 	int i, n;
2818 	boolean_t rv;
2819 	mem_ndmp_name_v3_t *ep;
2820 
2821 	rv = TRUE;
2822 	n = session->ns_data.dd_nlist_len;
2823 	for (i = 0; i < n; i++) {
2824 		ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
2825 		if (!ep)
2826 			continue;
2827 		/*
2828 		 * The fh_info's sent from the client are multiples
2829 		 * of RECORDSIZE which is 512 bytes.
2830 		 *
2831 		 * All our fh_info's are at the RECORDSIZE boundary.  If there
2832 		 * is any fh_info that is less than RECORDSIZE (this covers 0
2833 		 * and -1 values too), then the result is that DAR cannot be
2834 		 * done.
2835 		 */
2836 		if (ep->nm3_fh_info < RECORDSIZE ||
2837 		    ep->nm3_fh_info % RECORDSIZE != 0) {
2838 			rv = FALSE;
2839 			break;
2840 		}
2841 	}
2842 
2843 	return (rv);
2844 }
2845 
2846 
2847 /*
2848  * log_rs_params_v3
2849  *
2850  * Log a copy of all values of the restore parameters
2851  */
2852 void
2853 log_rs_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
2854     ndmp_lbr_params_t *nlp)
2855 {
2856 	MOD_LOGV3(params, NDMP_LOG_NORMAL, "Restoring to \"%s\".\n",
2857 	    (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
2858 
2859 	if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) {
2860 		MOD_LOGV3(params, NDMP_LOG_NORMAL, "Tape server: local.\n");
2861 		MOD_LOGV3(params, NDMP_LOG_NORMAL,
2862 		    "Tape record size: %d.\n",
2863 		    session->ns_mover.md_record_size);
2864 	} else if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP)
2865 		MOD_LOGV3(params, NDMP_LOG_NORMAL,
2866 		    "Tape server: remote at %s:%d.\n",
2867 		    inet_ntoa(IN_ADDR(session->ns_data.dd_data_addr.tcp_ip_v3)),
2868 		    session->ns_data.dd_data_addr.tcp_port_v3);
2869 	else
2870 		MOD_LOGV3(params, NDMP_LOG_ERROR,
2871 		    "Unknown tape server address type.\n");
2872 
2873 	if (NLP_ISSET(nlp, NLPF_DIRECT))
2874 		MOD_LOGV3(params, NDMP_LOG_NORMAL,
2875 		    "Direct Access Restore.\n");
2876 }
2877 
2878 
2879 /*
2880  * send_unrecovered_list_v3
2881  *
2882  * Create the list of files that were in restore list but
2883  * not recovered due to some errors.
2884  */
2885 int
2886 send_unrecovered_list_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
2887 {
2888 	int i, rv;
2889 	int err;
2890 
2891 	if (!params) {
2892 		NDMP_LOG(LOG_DEBUG, "params == NULL");
2893 		return (-1);
2894 	}
2895 	if (!nlp) {
2896 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2897 		return (-1);
2898 	}
2899 
2900 	if (nlp->nlp_lastidx != -1) {
2901 		if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)nlp->nlp_lastidx))
2902 			err = ENOENT;
2903 		else
2904 			err = 0;
2905 		(void) ndmp_send_recovery_stat_v3(params, nlp,
2906 		    nlp->nlp_lastidx, err);
2907 		nlp->nlp_lastidx = -1;
2908 	}
2909 
2910 	rv = 0;
2911 	for (i = 0; i < (int)nlp->nlp_nfiles; i++) {
2912 		if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)i)) {
2913 			rv = ndmp_send_recovery_stat_v3(params, nlp, i, ENOENT);
2914 			if (rv < 0)
2915 				break;
2916 		}
2917 	}
2918 
2919 	return (rv);
2920 }
2921 
2922 
2923 
2924 /*
2925  * restore_dar_alloc_structs_v3
2926  *
2927  * Allocates the necessary structures for running DAR restore.
2928  * It just creates the reader writer IPC.
2929  * This function is called for each entry in the restore entry list.
2930  *
2931  * Parameters:
2932  *   session (input) - pointer to the session
2933  *   jname (input) - Job name
2934  *
2935  * Returns:
2936  *    0: on success
2937  *   -1: on error
2938  */
2939 int
2940 restore_dar_alloc_structs_v3(ndmpd_session_t *session, char *jname)
2941 {
2942 	long xfer_size;
2943 	ndmp_lbr_params_t *nlp;
2944 	tlm_commands_t *cmds;
2945 
2946 	nlp = ndmp_get_nlp(session);
2947 	if (!nlp) {
2948 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2949 		return (-1);
2950 	}
2951 
2952 	cmds = &nlp->nlp_cmds;
2953 	(void) memset(cmds, 0, sizeof (*cmds));
2954 
2955 	xfer_size = ndmp_buffer_get_size(session);
2956 	cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
2957 	if (!cmds->tcs_command) {
2958 		tlm_un_ref_job_stats(jname);
2959 		return (-1);
2960 	}
2961 
2962 	return (0);
2963 }
2964 
2965 
2966 /*
2967  * free_dar_structs_v3
2968  *
2969  * To free the structures were created by restore_dar_alloc_structs_v3.
2970  * This funnction is called for each entry in restore entry list.
2971  *
2972  * Parameters:
2973  *   session (input) - pointer to the session
2974  *   jname (input) - job name
2975  *
2976  * Returns:
2977  *	NONE
2978  */
2979 /*ARGSUSED*/
2980 static void
2981 free_dar_structs_v3(ndmpd_session_t *session, char *jname)
2982 {
2983 	ndmp_lbr_params_t *nlp;
2984 	tlm_commands_t *cmds;
2985 
2986 	nlp = ndmp_get_nlp(session);
2987 	if (!nlp) {
2988 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2989 		return;
2990 	}
2991 	cmds = &nlp->nlp_cmds;
2992 	if (!cmds) {
2993 		NDMP_LOG(LOG_DEBUG, "cmds == NULL");
2994 		return;
2995 	}
2996 
2997 	if (cmds->tcs_command) {
2998 		if (cmds->tcs_command->tc_buffers != NULL)
2999 			tlm_release_reader_writer_ipc(cmds->tcs_command);
3000 		else
3001 			NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL");
3002 		cmds->tcs_command = NULL;
3003 	} else
3004 		NDMP_LOG(LOG_DEBUG, "COMMAND == NULL");
3005 }
3006 
3007 
3008 /*
3009  * ndmp_dar_tar_init_v3
3010  *
3011  * Constructor for the DAR restore. Creates job name, allocates structures
3012  * needed for keeping the statistics, and reports the start of restore action.
3013  * It is called once for each DAR restore request.
3014  *
3015  * Parameters:
3016  *   session (input) - pointer to the session
3017  *   nlp (input) - pointer to the nlp structure
3018  *
3019  * Returns:
3020  *   char pointer: on success
3021  *   NULL: on error
3022  */
3023 static char *ndmpd_dar_tar_init_v3(ndmpd_session_t *session,
3024     ndmp_lbr_params_t *nlp)
3025 {
3026 	char *jname;
3027 
3028 	jname = ndmp_malloc(TLM_MAX_BACKUP_JOB_NAME);
3029 
3030 	if (!jname)
3031 		return (NULL);
3032 
3033 	(void) ndmp_new_job_name(jname);
3034 
3035 	if (!nlp) {
3036 		free(jname);
3037 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3038 		return (NULL);
3039 	}
3040 
3041 	nlp->nlp_jstat = tlm_new_job_stats(jname);
3042 	if (!nlp->nlp_jstat) {
3043 		free(jname);
3044 		NDMP_LOG(LOG_DEBUG, "Creating job stats");
3045 		return (NULL);
3046 	}
3047 
3048 	nlp->nlp_jstat->js_start_ltime = time(NULL);
3049 	nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
3050 
3051 	nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
3052 	    ndmpd_path_restored_v3, NULL, NULL);
3053 	if (!nlp->nlp_logcallbacks) {
3054 		tlm_un_ref_job_stats(jname);
3055 		free(jname);
3056 		return (NULL);
3057 	}
3058 	nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
3059 
3060 	nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0);
3061 	if (nlp->nlp_rsbm < 0) {
3062 		NDMP_LOG(LOG_ERR, "Out of memory.");
3063 		lbrlog_callbacks_done(nlp->nlp_logcallbacks);
3064 		tlm_un_ref_job_stats(jname);
3065 		free(jname);
3066 		return (NULL);
3067 	}
3068 
3069 	/* this is used in ndmpd_path_restored_v3() */
3070 	nlp->nlp_lastidx = -1;
3071 
3072 	NDMP_LOG(LOG_DEBUG, "Restoring from %s tape(s).",
3073 	    ndmp_data_get_mover_mode(session));
3074 
3075 	return (jname);
3076 }
3077 
3078 /*
3079  * ndmpd_dar_tar_end_v3
3080  *
3081  * Deconstructor for the DAR restore. This function is called once per
3082  * DAR request. It deallocates memories allocated by ndmpd_dar_tar_init_v3.
3083  *
3084  * Parameters:
3085  *   session (input) - pointer to the session
3086  *   params (input) - pointer to the parameters structure
3087  *   nlp (input) - pointer to the nlp structure
3088  *   jname(input) - job name
3089  *
3090  * Returns:
3091  *   0: on success
3092  *   -1: on error
3093  */
3094 static int ndmpd_dar_tar_end_v3(ndmpd_session_t *session,
3095     ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, char *jname)
3096 {
3097 	int err = 0;
3098 
3099 
3100 	NDMP_LOG(LOG_DEBUG, "lastidx %d", nlp->nlp_lastidx);
3101 
3102 	/* nothing restored. */
3103 	(void) send_unrecovered_list_v3(params, nlp);
3104 
3105 	if (nlp->nlp_jstat) {
3106 		nlp->nlp_bytes_total =
3107 		    (u_longlong_t)nlp->nlp_jstat->js_bytes_total;
3108 		tlm_un_ref_job_stats(jname);
3109 		nlp->nlp_jstat = NULL;
3110 	} else {
3111 		NDMP_LOG(LOG_DEBUG, "JSTAT == NULL");
3112 	}
3113 
3114 	if (nlp->nlp_logcallbacks) {
3115 		lbrlog_callbacks_done(nlp->nlp_logcallbacks);
3116 		nlp->nlp_logcallbacks = NULL;
3117 	} else {
3118 		NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL");
3119 	}
3120 
3121 	if (session->ns_data.dd_abort) {
3122 		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
3123 		    (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3124 		err = EINTR;
3125 	} else {
3126 		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
3127 		    (nlp->nlp_restore_path) ? nlp->nlp_restore_path :
3128 		    "NULL", err);
3129 	}
3130 
3131 	if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) {
3132 		if (nlp->nlp_rsbm < 0) {
3133 			NDMP_LOG(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm);
3134 		} else {
3135 			(void) bm_free(nlp->nlp_rsbm);
3136 			nlp->nlp_rsbm = -1;
3137 		}
3138 	}
3139 
3140 	free(jname);
3141 
3142 	return (err);
3143 }
3144 
3145 
3146 /*
3147  * ndmpd_dar_tar_v3
3148  *
3149  * This function is called for each entry in DAR entry list. The window
3150  * is already located and we should be in the right position to read
3151  * the data from the tape.
3152  * For each entry we setup selection list; so that, if the file name from
3153  * tape is not as the name client asked for, error be returned.
3154  *
3155  * Parameters:
3156  *   session (input) - pointer to the session
3157  *   params (input) - pointer to the parameters structure
3158  *   nlp (input) - pointer to the nlp structure
3159  *   jname (input) - job name
3160  *   dar_index(input) - Index of this entry in the restore list
3161  *
3162  * Returns:
3163  *   0: on success
3164  *   -1: on error
3165  */
3166 static int
3167 ndmpd_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3168     ndmp_lbr_params_t *nlp, char *jname, int dar_index)
3169 {
3170 	char *excl;
3171 	char **sels;
3172 	int flags;
3173 	int err;
3174 	tlm_commands_t *cmds;
3175 	struct rs_name_maker rn;
3176 	int data_addr_type = session->ns_data.dd_data_addr.addr_type;
3177 	ndmp_tar_reader_arg_t arg;
3178 	pthread_t rdtp;
3179 	ndmp_context_t nctx;
3180 	mem_ndmp_name_v3_t *ep;
3181 
3182 	err = 0;
3183 
3184 	/*
3185 	 * We have to allocate and deallocate buffers every time we
3186 	 * run the restore, for we need to flush the buffers.
3187 	 */
3188 	if (restore_dar_alloc_structs_v3(session, jname) < 0)
3189 		return (-1);
3190 
3191 	sels = setupsels(session, params, nlp, dar_index);
3192 	if (!sels) {
3193 		free_dar_structs_v3(session, jname);
3194 		return (-1);
3195 	}
3196 	excl = NULL;
3197 	flags = RSFLG_OVR_ALWAYS;
3198 	rn.rn_nlp = nlp;
3199 	rn.rn_fp = mknewname;
3200 
3201 	if (!session->ns_data.dd_abort) {
3202 		cmds = &nlp->nlp_cmds;
3203 		cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
3204 		cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
3205 		cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
3206 
3207 		arg.tr_session = session;
3208 		arg.tr_mod_params = params;
3209 		arg.tr_cmds = cmds;
3210 
3211 		err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
3212 		    (void *)&arg);
3213 		if (err == 0) {
3214 			tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
3215 		} else {
3216 			NDMP_LOG(LOG_DEBUG, "launch ndmp_tar_reader: %m");
3217 			return (-1);
3218 		}
3219 
3220 		cmds->tcs_command->tc_ref++;
3221 		cmds->tcs_writer_count++;
3222 
3223 		/* Plug-in module */
3224 		if (ndmp_pl != NULL &&
3225 		    ndmp_pl->np_pre_restore != NULL) {
3226 			nctx.nc_cmds = cmds;
3227 			nctx.nc_params = params;
3228 			ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params,
3229 			    dar_index - 1);
3230 
3231 			if ((err = ndmp_pl->np_pre_restore(ndmp_pl, &nctx,
3232 			    ep->nm3_opath, ep->nm3_dpath))
3233 			    != 0) {
3234 				NDMP_LOG(LOG_ERR, "Pre-restore plug-in: %m");
3235 				cmds->tcs_command->tc_reader = TLM_STOP;
3236 				ndmp_stop_local_reader(session, cmds);
3237 				ndmp_wait_for_reader(cmds);
3238 				(void) pthread_join(rdtp, NULL);
3239 				ndmp_stop_remote_reader(session);
3240 				goto restore_out;
3241 			}
3242 		}
3243 
3244 		if (tm_tar_ops.tm_getdir != NULL) {
3245 			err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
3246 			    nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags,
3247 			    dar_index, session->hardlink_q);
3248 		}
3249 
3250 		cmds->tcs_writer_count--;
3251 		cmds->tcs_command->tc_ref--;
3252 		cmds->tcs_command->tc_reader = TLM_STOP;
3253 
3254 
3255 		/*
3256 		 * If it is a two-way restore then we stop the reader.
3257 		 */
3258 		NDMP_LOG(LOG_DEBUG, "stop local reader.");
3259 		ndmp_stop_local_reader(session, cmds);
3260 
3261 		ndmp_wait_for_reader(cmds);
3262 		(void) pthread_join(rdtp, NULL);
3263 
3264 		/*
3265 		 * If this is the last DAR entry and it is a three-way
3266 		 * restore then we should close the connection.
3267 		 */
3268 		if ((data_addr_type == NDMP_ADDR_TCP) &&
3269 		    (dar_index == (int)session->ns_data.dd_nlist_len)) {
3270 			NDMP_LOG(LOG_DEBUG, "stop remote reader.");
3271 			ndmp_stop_remote_reader(session);
3272 		}
3273 
3274 		/* exit as if there was an internal error */
3275 		if (session->ns_eof)
3276 			err = -1;
3277 restore_out:
3278 		/* Plug-in module */
3279 		if (ndmp_pl != NULL &&
3280 		    ndmp_pl->np_post_restore != NULL &&
3281 		    ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) {
3282 			NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
3283 			err = -1;
3284 		}
3285 	}
3286 
3287 	NDMP_FREE(sels);
3288 
3289 	free_dar_structs_v3(session, jname);
3290 
3291 	return (err);
3292 }
3293 
3294 /*
3295  * ndmpd_dar_locate_windwos_v3
3296  *
3297  * Locating the right window in which the requested file is backed up.
3298  * We should go through windows to find the exact location, for the
3299  * file can be located in for example 10th window after the current window.
3300  *
3301  * Parameters:
3302  *   session (input) - pointer to the session
3303  *   params (input) - pointer to the parameters structure
3304  *   fh_info (input) - index from the beginning of the backup stream
3305  *   len (input) - Length of the mover window
3306  *
3307  * Returns:
3308  *   0: on success
3309  *   -1: on error
3310  */
3311 static int
3312 ndmpd_dar_locate_window_v3(ndmpd_session_t *session,
3313     ndmpd_module_params_t *params, u_longlong_t fh_info, u_longlong_t len)
3314 {
3315 	int ret = 0;
3316 
3317 
3318 	for (; ; ) {
3319 		ret = (*params->mp_seek_func)(session, fh_info, len);
3320 
3321 		NDMP_LOG(LOG_DEBUG, "ret %d", ret);
3322 		if (ret == 0) /* Seek was done successfully */
3323 			break;
3324 		else if (ret < 0) {
3325 			NDMP_LOG(LOG_DEBUG, "Seek error");
3326 			break;
3327 		}
3328 
3329 		/*
3330 		 * DMA moved to a new window.
3331 		 * If we are reading the remainig of the file from
3332 		 * new window, seek is handled by ndmpd_local_read_v3.
3333 		 * Here we should continue the seek inside the new
3334 		 * window.
3335 		 */
3336 		continue;
3337 	}
3338 	return (ret);
3339 }
3340 
3341 /*
3342  * ndmpd_rs_dar_tar_v3
3343  *
3344  * Main DAR function. It calls the constructor, then for each entry it
3345  * calls the locate_window_v3 to find the exact position of the file. Then
3346  * it restores the file.
3347  * When all restore requests are done it calls the deconstructor to clean
3348  * everything up.
3349  *
3350  * Parameters:
3351  *   session (input) - pointer to the session
3352  *   params (input) - pointer to the parameters structure
3353  *   nlp (input) - pointer to the nlp structure
3354  *
3355  * Returns:
3356  *   0: on success
3357  *   -1: on error
3358  */
3359 static int
3360 ndmpd_rs_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3361     ndmp_lbr_params_t *nlp)
3362 {
3363 	mem_ndmp_name_v3_t *ep;
3364 	u_longlong_t len;
3365 	char *jname;
3366 	int n = session->ns_data.dd_nlist_len;
3367 	int i, ret = 0;
3368 	int result = 0;
3369 
3370 	jname = ndmpd_dar_tar_init_v3(session, nlp);
3371 
3372 	if (!jname)
3373 		return (-1);
3374 
3375 	/*
3376 	 * We set the length = sizeof (tlm_tar_hdr_t)
3377 	 * This is important for three-way DAR restore, for we should
3378 	 * read the header first (If we ask for more data then we have
3379 	 * to read and discard the remaining data in the socket)
3380 	 */
3381 	len = tlm_tarhdr_size();
3382 
3383 	for (i = 0; i < n; ++i) {
3384 		ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
3385 		if (!ep) {
3386 			NDMP_LOG(LOG_DEBUG, "ep NULL, i %d", i);
3387 			continue;
3388 		}
3389 		NDMP_LOG(LOG_DEBUG,
3390 		    "restoring opath %s, dpath %s, fh_info %lld",
3391 		    ep->nm3_opath ? ep->nm3_opath : "NULL",
3392 		    ep->nm3_dpath ? ep->nm3_dpath : "NULL",
3393 		    ep->nm3_fh_info);
3394 
3395 		/*
3396 		 * We should seek till finding the window in which file
3397 		 * is located.
3398 		 */
3399 		ret = ndmpd_dar_locate_window_v3(session, params,
3400 		    ep->nm3_fh_info, len);
3401 
3402 		if (ret < 0) /* If seek fails, restore should be aborted */
3403 			break;
3404 		/*
3405 		 * We are inside the target window.
3406 		 * for each restore we will use one entry as selection list
3407 		 */
3408 		if ((ret = ndmpd_dar_tar_v3(session, params, nlp, jname, i+1))
3409 		    != 0)
3410 			result = EIO;
3411 		ndmpd_audit_restore(session->ns_connection,
3412 		    ep->nm3_opath ? ep->nm3_opath : "NULL",
3413 		    session->ns_data.dd_data_addr.addr_type,
3414 		    session->ns_tape.td_adapter_name, result);
3415 	}
3416 
3417 	NDMP_LOG(LOG_DEBUG, "End of restore list");
3418 
3419 	(void) ndmpd_dar_tar_end_v3(session, params, nlp, jname);
3420 
3421 	return (ret);
3422 }
3423 
3424 /*
3425  * ndmp_plugin_pre_restore
3426  *
3427  * Wrapper for pre-restore callback with multiple path
3428  */
3429 static int
3430 ndmp_plugin_pre_restore(ndmp_context_t *ctxp, ndmpd_module_params_t *params,
3431     int ncount)
3432 {
3433 	mem_ndmp_name_v3_t *ep;
3434 	int err;
3435 	int i;
3436 
3437 	for (i = 0; i < ncount; i++) {
3438 		if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i)))
3439 			continue;
3440 		if ((err = ndmp_pl->np_pre_restore(ndmp_pl, ctxp,
3441 		    ep->nm3_opath, ep->nm3_dpath)) != 0)
3442 			return (err);
3443 	}
3444 
3445 	return (0);
3446 }
3447 
3448 /*
3449  * Expands the format string and logs the resulting message to the
3450  * remote DMA
3451  */
3452 void
3453 ndmp_log_dma(ndmp_context_t *nctx, ndmp_log_dma_type_t lt, const char *fmt, ...)
3454 {
3455 	va_list ap;
3456 	char buf[256];
3457 	ndmpd_module_params_t *params;
3458 
3459 	if (nctx == NULL ||
3460 	    (params = (ndmpd_module_params_t *)nctx->nc_params) == NULL)
3461 		return;
3462 
3463 	va_start(ap, fmt);
3464 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
3465 	va_end(ap);
3466 
3467 	MOD_LOGV3(params, (ndmp_log_type)lt, "%s", buf);
3468 }
3469 
3470 
3471 /*
3472  * ndmpd_rs_sar_tar_v3
3473  *
3474  * Main non-DAR restore function. It will try to restore all the entries
3475  * that have been backed up.
3476  *
3477  * Parameters:
3478  *   session (input) - pointer to the session
3479  *   params (input) - pointer to the parameters structure
3480  *   nlp (input) - pointer to the nlp structure
3481  *
3482  * Returns:
3483  *   0: on success
3484  *   -1: on error
3485  */
3486 static int
3487 ndmpd_rs_sar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3488     ndmp_lbr_params_t *nlp)
3489 {
3490 	char jname[TLM_MAX_BACKUP_JOB_NAME];
3491 	char *excl;
3492 	char **sels;
3493 	int flags;
3494 	int err;
3495 	tlm_commands_t *cmds;
3496 	struct rs_name_maker rn;
3497 	ndmp_tar_reader_arg_t arg;
3498 	pthread_t rdtp;
3499 	int result;
3500 	ndmp_context_t nctx;
3501 
3502 	result = err = 0;
3503 	(void) ndmp_new_job_name(jname);
3504 	if (restore_alloc_structs_v3(session, jname) < 0)
3505 		return (-1);
3506 
3507 	sels = setupsels(session, params, nlp, 0);
3508 	if (!sels) {
3509 		free_structs_v3(session, jname);
3510 		return (-1);
3511 	}
3512 	excl = NULL;
3513 	flags = RSFLG_OVR_ALWAYS;
3514 	rn.rn_nlp = nlp;
3515 	rn.rn_fp = mknewname;
3516 
3517 	nlp->nlp_jstat->js_start_ltime = time(NULL);
3518 	nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
3519 
3520 	if (!session->ns_data.dd_abort && !session->ns_data.dd_abort) {
3521 		cmds = &nlp->nlp_cmds;
3522 		cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
3523 		cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
3524 		cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
3525 
3526 		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" started.",
3527 		    (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3528 
3529 		arg.tr_session = session;
3530 		arg.tr_mod_params = params;
3531 		arg.tr_cmds = cmds;
3532 		err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
3533 		    (void *)&arg);
3534 		if (err == 0) {
3535 			tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
3536 		} else {
3537 			NDMP_LOG(LOG_DEBUG, "Launch ndmp_tar_reader: %m");
3538 			free_structs_v3(session, jname);
3539 			return (-1);
3540 		}
3541 
3542 		if (!ndmp_check_utf8magic(cmds->tcs_command)) {
3543 			NDMP_LOG(LOG_DEBUG, "UTF8Magic not found!");
3544 		} else {
3545 			NDMP_LOG(LOG_DEBUG, "UTF8Magic found");
3546 		}
3547 
3548 		/* Plug-in module */
3549 		if (ndmp_pl != NULL &&
3550 		    ndmp_pl->np_pre_restore != NULL) {
3551 			nctx.nc_cmds = cmds;
3552 			nctx.nc_params = params;
3553 			if ((err = ndmp_plugin_pre_restore(&nctx, params,
3554 			    nlp->nlp_nfiles))
3555 			    != 0) {
3556 				NDMP_LOG(LOG_ERR, "Pre-restore plug-in: %m");
3557 				cmds->tcs_command->tc_reader = TLM_STOP;
3558 				ndmp_stop_local_reader(session, cmds);
3559 				ndmp_wait_for_reader(cmds);
3560 				(void) pthread_join(rdtp, NULL);
3561 				ndmp_stop_remote_reader(session);
3562 				goto restore_out;
3563 			}
3564 		}
3565 
3566 		cmds->tcs_command->tc_ref++;
3567 		cmds->tcs_writer_count++;
3568 
3569 		if (tm_tar_ops.tm_getdir != NULL)
3570 			err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
3571 			    nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags, 0,
3572 			    session->hardlink_q);
3573 
3574 		cmds->tcs_writer_count--;
3575 		cmds->tcs_command->tc_ref--;
3576 		cmds->tcs_command->tc_reader = TLM_STOP;
3577 		nlp->nlp_jstat->js_stop_time = time(NULL);
3578 
3579 		/* Send the list of un-recovered files/dirs to the client.  */
3580 		(void) send_unrecovered_list_v3(params, nlp);
3581 
3582 		ndmp_stop_local_reader(session, cmds);
3583 		ndmp_wait_for_reader(cmds);
3584 		(void) pthread_join(rdtp, NULL);
3585 
3586 		ndmp_stop_remote_reader(session);
3587 
3588 		/* exit as if there was an internal error */
3589 		if (session->ns_eof)
3590 			err = -1;
3591 		if (err == -1)
3592 			result = EIO;
3593 	}
3594 
3595 	(void) send_unrecovered_list_v3(params, nlp); /* nothing restored. */
3596 	if (session->ns_data.dd_abort) {
3597 		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
3598 		    (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3599 		result = EINTR;
3600 		ndmpd_audit_restore(session->ns_connection,
3601 		    nlp->nlp_restore_path,
3602 		    session->ns_data.dd_data_addr.addr_type,
3603 		    session->ns_tape.td_adapter_name, result);
3604 		err = -1;
3605 	} else {
3606 		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
3607 		    (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL",
3608 		    err);
3609 		ndmpd_audit_restore(session->ns_connection,
3610 		    nlp->nlp_restore_path,
3611 		    session->ns_data.dd_data_addr.addr_type,
3612 		    session->ns_tape.td_adapter_name, result);
3613 
3614 restore_out:
3615 		/* Plug-in module */
3616 		if (ndmp_pl != NULL &&
3617 		    ndmp_pl->np_post_restore != NULL &&
3618 		    ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) {
3619 			NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
3620 			err = -1;
3621 		}
3622 	}
3623 
3624 	NDMP_FREE(sels);
3625 	free_structs_v3(session, jname);
3626 
3627 	return (err);
3628 }
3629 
3630 
3631 /*
3632  * ndmp_backup_get_params_v3
3633  *
3634  * Get the backup parameters from the NDMP env variables
3635  * and log them in the system log and as normal messages
3636  * to the DMA.
3637  *
3638  * Parameters:
3639  *   session (input) - pointer to the session
3640  *   params (input) - pointer to the parameters structure
3641  *
3642  * Returns:
3643  *   NDMP_NO_ERR: on success
3644  *   != NDMP_NO_ERR: otherwise
3645  */
3646 ndmp_error
3647 ndmp_backup_get_params_v3(ndmpd_session_t *session,
3648     ndmpd_module_params_t *params)
3649 {
3650 	ndmp_error rv;
3651 	ndmp_lbr_params_t *nlp;
3652 
3653 	if (!session || !params)
3654 		return (NDMP_ILLEGAL_ARGS_ERR);
3655 
3656 	rv = NDMP_NO_ERR;
3657 	nlp = ndmp_get_nlp(session);
3658 	if (!nlp) {
3659 		MOD_LOGV3(params, NDMP_LOG_ERROR,
3660 		    "Internal error: NULL nlp.\n");
3661 		rv = NDMP_ILLEGAL_ARGS_ERR;
3662 	} else {
3663 		if (!(nlp->nlp_backup_path = get_bk_path_v3(params)))
3664 			rv = NDMP_FILE_NOT_FOUND_ERR;
3665 		else if (!is_valid_backup_dir_v3(params, nlp->nlp_backup_path))
3666 			rv = NDMP_ILLEGAL_ARGS_ERR;
3667 	}
3668 
3669 	if (rv != NDMP_NO_ERR)
3670 		return (rv);
3671 
3672 	if (fs_is_chkpntvol(nlp->nlp_backup_path) ||
3673 	    fs_is_rdonly(nlp->nlp_backup_path) ||
3674 	    !fs_is_chkpnt_enabled(nlp->nlp_backup_path))
3675 		NLP_SET(nlp, NLPF_CHKPNTED_PATH);
3676 	else
3677 		NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
3678 
3679 	/* Should the st_ctime be ignored when backing up? */
3680 	if (ndmp_ignore_ctime) {
3681 		NDMP_LOG(LOG_DEBUG, "ignoring st_ctime");
3682 		NLP_SET(nlp, NLPF_IGNCTIME);
3683 	} else {
3684 		NLP_UNSET(nlp, NLPF_IGNCTIME);
3685 	}
3686 
3687 	if (ndmp_include_lmtime == TRUE) {
3688 		NDMP_LOG(LOG_DEBUG, "including st_lmtime");
3689 		NLP_SET(nlp, NLPF_INCLMTIME);
3690 	} else {
3691 		NLP_UNSET(nlp, NLPF_INCLMTIME);
3692 	}
3693 
3694 	NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
3695 
3696 	get_hist_env_v3(params, nlp);
3697 	get_exc_env_v3(params, nlp);
3698 	get_inc_env_v3(params, nlp);
3699 	get_direct_env_v3(params, nlp);
3700 	rv = get_backup_level_v3(params, nlp);
3701 
3702 	return (rv);
3703 }
3704 
3705 
3706 /*
3707  * ndmpd_tar_backup_starter_v3
3708  *
3709  * Create the checkpoint for the backup and do the backup,
3710  * then remove the backup checkpoint if we created it.
3711  * Save the backup time information based on the backup
3712  * type and stop the data server.
3713  *
3714  * Parameters:
3715  *   params (input) - pointer to the parameters structure
3716  *
3717  * Returns:
3718  *   0: on success
3719  *   != 0: otherwise
3720  */
3721 int
3722 ndmpd_tar_backup_starter_v3(ndmpd_module_params_t *params)
3723 {
3724 	int err;
3725 	ndmpd_session_t *session;
3726 	ndmp_lbr_params_t *nlp;
3727 	char jname[TLM_MAX_BACKUP_JOB_NAME];
3728 	ndmp_bkup_size_arg_t sarg;
3729 	pthread_t tid;
3730 
3731 	session = (ndmpd_session_t *)(params->mp_daemon_cookie);
3732 	*(params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
3733 	ndmp_session_ref(session);
3734 	(void) ndmp_new_job_name(jname);
3735 
3736 	err = 0;
3737 	if (!NLP_ISCHKPNTED(nlp) &&
3738 	    ndmp_start_check_point(nlp->nlp_backup_path, jname) < 0) {
3739 		MOD_LOGV3(params, NDMP_LOG_ERROR,
3740 		    "Creating checkpoint on \"%s\".\n",
3741 		    nlp->nlp_backup_path);
3742 		err = -1;
3743 	}
3744 
3745 	NDMP_LOG(LOG_DEBUG, "err %d, chkpnted %c",
3746 	    err, NDMP_YORN(NLP_ISCHKPNTED(nlp)));
3747 
3748 	if (err == 0) {
3749 		sarg.bs_session = session;
3750 		sarg.bs_jname = jname;
3751 		sarg.bs_path = nlp->nlp_backup_path;
3752 
3753 		/* Get an estimate of the data size */
3754 		if (pthread_create(&tid, NULL, (funct_t)get_backup_size,
3755 		    (void *)&sarg) == 0)
3756 			(void) pthread_detach(tid);
3757 
3758 		err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate, jname);
3759 		if (err != 0) {
3760 			NDMP_LOG(LOG_DEBUG, "err %d", err);
3761 		} else {
3762 			log_bk_params_v3(session, params, nlp);
3763 			err = tar_backup_v3(session, params, nlp, jname);
3764 		}
3765 	}
3766 
3767 	if (!NLP_ISCHKPNTED(nlp))
3768 		(void) ndmp_release_check_point(nlp->nlp_backup_path, jname);
3769 
3770 	NDMP_LOG(LOG_DEBUG, "err %d, update %c",
3771 	    err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
3772 
3773 	if (err == 0)
3774 		save_backup_date_v3(params, nlp);
3775 
3776 	MOD_DONE(params, err);
3777 
3778 	/* nlp_params is allocated in start_backup_v3() */
3779 	NDMP_FREE(nlp->nlp_params);
3780 
3781 	NS_DEC(nbk);
3782 	ndmp_session_unref(session);
3783 	return (err);
3784 
3785 }
3786 
3787 
3788 /*
3789  * ndmpd_tar_backup_abort_v3
3790  *
3791  * Abort the backup operation and stop the reader thread.
3792  *
3793  * Parameters:
3794  *   module_cookie (input) - pointer to the nlp structure
3795  *
3796  * Returns:
3797  *   0: always
3798  */
3799 int
3800 ndmpd_tar_backup_abort_v3(void *module_cookie)
3801 {
3802 	ndmp_lbr_params_t *nlp;
3803 
3804 	nlp = (ndmp_lbr_params_t *)module_cookie;
3805 	if (nlp && nlp->nlp_session) {
3806 		if (nlp->nlp_session->ns_data.dd_data_addr.addr_type ==
3807 		    NDMP_ADDR_TCP &&
3808 		    nlp->nlp_session->ns_data.dd_sock != -1) {
3809 			(void) close(nlp->nlp_session->ns_data.dd_sock);
3810 			nlp->nlp_session->ns_data.dd_sock = -1;
3811 		}
3812 		ndmp_stop_reader_thread(nlp->nlp_session);
3813 	}
3814 
3815 	return (0);
3816 }
3817 
3818 
3819 /*
3820  * ndmp_restore_get_params_v3
3821  *
3822  * Get the parameters specified for recovery such as restore path, type
3823  * of restore (DAR, non-DAR) etc
3824  *
3825  * Parameters:
3826  *   session (input) - pointer to the session
3827  *   params (input) - pointer to the parameters structure
3828  *
3829  * Returns:
3830  *   NDMP_NO_ERR: on success
3831  *   != NDMP_NO_ERR: otherwise
3832  */
3833 ndmp_error
3834 ndmp_restore_get_params_v3(ndmpd_session_t *session,
3835     ndmpd_module_params_t *params)
3836 {
3837 	ndmp_error rv;
3838 	ndmp_lbr_params_t *nlp;
3839 
3840 	if (!(nlp = ndmp_get_nlp(session))) {
3841 		NDMP_LOG(LOG_DEBUG, "nlp is NULL");
3842 		rv = NDMP_ILLEGAL_ARGS_ERR;
3843 	} else if (!(nlp->nlp_backup_path = get_bk_path_v3(params)))
3844 		rv = NDMP_ILLEGAL_ARGS_ERR;
3845 	else if ((nlp->nlp_nfiles = session->ns_data.dd_nlist_len) == 0) {
3846 		NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
3847 		rv = NDMP_ILLEGAL_ARGS_ERR;
3848 	} else if (get_rs_path_v3(params, nlp) != NDMP_NO_ERR) {
3849 		rv = NDMP_ILLEGAL_ARGS_ERR;
3850 	} else if ((rv = fix_nlist_v3(session, params, nlp)) != NDMP_NO_ERR) {
3851 		NDMP_LOG(LOG_DEBUG, "fix_nlist_v3: %d", rv);
3852 	} else {
3853 		rv = NDMP_NO_ERR;
3854 		get_direct_env_v3(params, nlp);
3855 		if (NLP_ISSET(nlp, NLPF_DIRECT)) {
3856 			if (NLP_ISSET(nlp, NLPF_RECURSIVE)) {
3857 				/* Currently we dont support DAR on directory */
3858 				NDMP_LOG(LOG_DEBUG,
3859 				    "Can't have RECURSIVE and DIRECT together");
3860 				rv = NDMP_ILLEGAL_ARGS_ERR;
3861 				return (rv);
3862 			}
3863 
3864 			/*
3865 			 * DAR can be done if all the fh_info's are valid.
3866 			 */
3867 			if (allvalidfh(session, params)) {
3868 				ndmp_sort_nlist_v3(session);
3869 			} else {
3870 				MOD_LOGV3(params, NDMP_LOG_WARNING,
3871 				    "Cannot do direct access recovery. "
3872 				    "Some 'fh_info'es are not valid.\n");
3873 				NLP_UNSET(nlp, NLPF_DIRECT);
3874 			}
3875 		}
3876 
3877 		log_rs_params_v3(session, params, nlp);
3878 	}
3879 
3880 	return (rv);
3881 }
3882 
3883 
3884 /*
3885  * ndmpd_tar_restore_starter_v3
3886  *
3887  * The main restore starter function. It will start a DAR or
3888  * non-DAR recovery based on the parameters. (V3 and V4 only)
3889  *
3890  * Parameters:
3891  *   params (input) - pointer to the parameters structure
3892  *
3893  * Returns:
3894  *   NDMP_NO_ERR: on success
3895  *   != NDMP_NO_ERR: otherwise
3896  */
3897 int
3898 ndmpd_tar_restore_starter_v3(ndmpd_module_params_t *params)
3899 {
3900 	int err;
3901 	ndmpd_session_t *session;
3902 	ndmp_lbr_params_t *nlp;
3903 
3904 
3905 	session = (ndmpd_session_t *)(params->mp_daemon_cookie);
3906 	*(params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
3907 	ndmp_session_ref(session);
3908 
3909 	if (NLP_ISSET(nlp, NLPF_DIRECT))
3910 		err = ndmpd_rs_dar_tar_v3(session, params, nlp);
3911 	else
3912 		err = ndmpd_rs_sar_tar_v3(session, params, nlp);
3913 
3914 	MOD_DONE(params, err);
3915 
3916 	NS_DEC(nrs);
3917 	/* nlp_params is allocated in start_recover() */
3918 	NDMP_FREE(nlp->nlp_params);
3919 	ndmp_session_unref(session);
3920 	return (err);
3921 
3922 }
3923 
3924 
3925 /*
3926  * ndmp_tar_restore_abort_v3
3927  *
3928  * Restore abort function (V3 and V4 only)
3929  *
3930  * Parameters:
3931  *   module_cookie (input) - pointer to nlp
3932  *
3933  * Returns:
3934  *   0
3935  */
3936 int
3937 ndmpd_tar_restore_abort_v3(void *module_cookie)
3938 {
3939 	ndmp_lbr_params_t *nlp;
3940 
3941 	nlp = (ndmp_lbr_params_t *)module_cookie;
3942 	if (nlp != NULL && nlp->nlp_session != NULL) {
3943 		if (nlp->nlp_session->ns_data.dd_mover.addr_type ==
3944 		    NDMP_ADDR_TCP &&
3945 		    nlp->nlp_session->ns_data.dd_sock != -1) {
3946 			(void) close(nlp->nlp_session->ns_data.dd_sock);
3947 			nlp->nlp_session->ns_data.dd_sock = -1;
3948 		}
3949 		nlp_event_nw(nlp->nlp_session);
3950 		ndmp_stop_writer_thread(nlp->nlp_session);
3951 	}
3952 
3953 
3954 	return (0);
3955 
3956 }
3957