xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c (revision c9fd6b31f4fa1345ad799549dc0f1101b9cef127)
1 /*
2  * Copyright 2010 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 (ISDEFINED(ep->nm3_newnm)) {
2735 			nm = ep->nm3_newnm;
2736 		} else {
2737 			char *p, *q;
2738 
2739 			/*
2740 			 * Find the last component of nm3_opath.
2741 			 * nm3_opath has no trailing '/'.
2742 			 */
2743 			p = strrchr(ep->nm3_opath, '/');
2744 			nm = p ? p + 1 : ep->nm3_opath;
2745 
2746 			/*
2747 			 * In DDAR the last component could
2748 			 * be repeated in nm3_dpath
2749 			 */
2750 			q = strrchr(ep->nm3_dpath, '/');
2751 			q = q ? q + 1 : ep->nm3_dpath;
2752 			if (strcmp(nm, q) == 0)
2753 				nm = NULL;
2754 
2755 		}
2756 
2757 		bp = joinpath(buf, dp, nm);
2758 		if (!bp) {
2759 			/*
2760 			 * Note: What should be done with this entry?
2761 			 * We leave it untouched for now, hence no path in
2762 			 * the backup image matches with this entry and will
2763 			 * be reported as not found.
2764 			 */
2765 			MOD_LOGV3(params, NDMP_LOG_ERROR,
2766 			    "Destination path too long(%s/%s)", dp, nm);
2767 			continue;
2768 		}
2769 		cp = strdup(bp);
2770 		if (!cp) {
2771 			MOD_LOGV3(params, NDMP_LOG_ERROR,
2772 			    "Insufficient memory.\n");
2773 			rv = NDMP_NO_MEM_ERR;
2774 			break;
2775 		}
2776 		free(ep->nm3_dpath);
2777 		ep->nm3_dpath = cp;
2778 		NDMP_FREE(ep->nm3_newnm);
2779 
2780 		bp = joinpath(buf, nlp->nlp_backup_path, ep->nm3_opath);
2781 		if (!bp) {
2782 			/*
2783 			 * Note: The same problem of above with long path.
2784 			 */
2785 			MOD_LOGV3(params, NDMP_LOG_ERROR,
2786 			    "Path too long(%s/%s)",
2787 			    nlp->nlp_backup_path, ep->nm3_opath);
2788 			continue;
2789 		}
2790 		cp = strdup(bp);
2791 		if (!cp) {
2792 			MOD_LOGV3(params, NDMP_LOG_ERROR,
2793 			    "Insufficient memory.\n");
2794 			rv = NDMP_NO_MEM_ERR;
2795 			break;
2796 		}
2797 		NDMP_FREE(ep->nm3_opath);
2798 		ep->nm3_opath = cp;
2799 
2800 		NDMP_LOG(LOG_DEBUG, "orig[%d]: \"%s\"", i, ep->nm3_opath);
2801 		if (ep->nm3_dpath) {
2802 			NDMP_LOG(LOG_DEBUG,
2803 			    "dest[%d]: \"%s\"", i, ep->nm3_dpath);
2804 		} else {
2805 			NDMP_LOG(LOG_DEBUG, "dest[%d]: \"%s\"", i, "NULL");
2806 		}
2807 	}
2808 
2809 	free(buf);
2810 
2811 	return (rv);
2812 }
2813 
2814 
2815 /*
2816  * allvalidfh
2817  *
2818  * Run a sanity check on the file history info. The file history
2819  * info is the offset of the record starting the entry on the tape
2820  * and is used in DAR (direct access restore mode).
2821  */
2822 static boolean_t
2823 allvalidfh(ndmpd_session_t *session, ndmpd_module_params_t *params)
2824 {
2825 	int i, n;
2826 	boolean_t rv;
2827 	mem_ndmp_name_v3_t *ep;
2828 
2829 	rv = TRUE;
2830 	n = session->ns_data.dd_nlist_len;
2831 	for (i = 0; i < n; i++) {
2832 		ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
2833 		if (!ep)
2834 			continue;
2835 		/*
2836 		 * The fh_info's sent from the client are multiples
2837 		 * of RECORDSIZE which is 512 bytes.
2838 		 *
2839 		 * All our fh_info's are at the RECORDSIZE boundary.  If there
2840 		 * is any fh_info that is less than RECORDSIZE (this covers 0
2841 		 * and -1 values too), then the result is that DAR cannot be
2842 		 * done.
2843 		 */
2844 		if (ep->nm3_fh_info < RECORDSIZE ||
2845 		    ep->nm3_fh_info % RECORDSIZE != 0) {
2846 			rv = FALSE;
2847 			break;
2848 		}
2849 	}
2850 
2851 	return (rv);
2852 }
2853 
2854 
2855 /*
2856  * log_rs_params_v3
2857  *
2858  * Log a copy of all values of the restore parameters
2859  */
2860 void
2861 log_rs_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
2862     ndmp_lbr_params_t *nlp)
2863 {
2864 	MOD_LOGV3(params, NDMP_LOG_NORMAL, "Restoring to \"%s\".\n",
2865 	    (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
2866 
2867 	if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) {
2868 		MOD_LOGV3(params, NDMP_LOG_NORMAL, "Tape server: local.\n");
2869 		MOD_LOGV3(params, NDMP_LOG_NORMAL,
2870 		    "Tape record size: %d.\n",
2871 		    session->ns_mover.md_record_size);
2872 	} else if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP)
2873 		MOD_LOGV3(params, NDMP_LOG_NORMAL,
2874 		    "Tape server: remote at %s:%d.\n",
2875 		    inet_ntoa(IN_ADDR(session->ns_data.dd_data_addr.tcp_ip_v3)),
2876 		    session->ns_data.dd_data_addr.tcp_port_v3);
2877 	else
2878 		MOD_LOGV3(params, NDMP_LOG_ERROR,
2879 		    "Unknown tape server address type.\n");
2880 
2881 	if (NLP_ISSET(nlp, NLPF_DIRECT))
2882 		MOD_LOGV3(params, NDMP_LOG_NORMAL,
2883 		    "Direct Access Restore.\n");
2884 }
2885 
2886 
2887 /*
2888  * send_unrecovered_list_v3
2889  *
2890  * Create the list of files that were in restore list but
2891  * not recovered due to some errors.
2892  */
2893 int
2894 send_unrecovered_list_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
2895 {
2896 	int i, rv;
2897 	int err;
2898 
2899 	if (!params) {
2900 		NDMP_LOG(LOG_DEBUG, "params == NULL");
2901 		return (-1);
2902 	}
2903 	if (!nlp) {
2904 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2905 		return (-1);
2906 	}
2907 
2908 	if (nlp->nlp_lastidx != -1) {
2909 		if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)nlp->nlp_lastidx))
2910 			err = ENOENT;
2911 		else
2912 			err = 0;
2913 		(void) ndmp_send_recovery_stat_v3(params, nlp,
2914 		    nlp->nlp_lastidx, err);
2915 		nlp->nlp_lastidx = -1;
2916 	}
2917 
2918 	rv = 0;
2919 	for (i = 0; i < (int)nlp->nlp_nfiles; i++) {
2920 		if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)i)) {
2921 			rv = ndmp_send_recovery_stat_v3(params, nlp, i, ENOENT);
2922 			if (rv < 0)
2923 				break;
2924 		}
2925 	}
2926 
2927 	return (rv);
2928 }
2929 
2930 
2931 
2932 /*
2933  * restore_dar_alloc_structs_v3
2934  *
2935  * Allocates the necessary structures for running DAR restore.
2936  * It just creates the reader writer IPC.
2937  * This function is called for each entry in the restore entry list.
2938  *
2939  * Parameters:
2940  *   session (input) - pointer to the session
2941  *   jname (input) - Job name
2942  *
2943  * Returns:
2944  *    0: on success
2945  *   -1: on error
2946  */
2947 int
2948 restore_dar_alloc_structs_v3(ndmpd_session_t *session, char *jname)
2949 {
2950 	long xfer_size;
2951 	ndmp_lbr_params_t *nlp;
2952 	tlm_commands_t *cmds;
2953 
2954 	nlp = ndmp_get_nlp(session);
2955 	if (!nlp) {
2956 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2957 		return (-1);
2958 	}
2959 
2960 	cmds = &nlp->nlp_cmds;
2961 	(void) memset(cmds, 0, sizeof (*cmds));
2962 
2963 	xfer_size = ndmp_buffer_get_size(session);
2964 	cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
2965 	if (!cmds->tcs_command) {
2966 		tlm_un_ref_job_stats(jname);
2967 		return (-1);
2968 	}
2969 
2970 	return (0);
2971 }
2972 
2973 
2974 /*
2975  * free_dar_structs_v3
2976  *
2977  * To free the structures were created by restore_dar_alloc_structs_v3.
2978  * This funnction is called for each entry in restore entry list.
2979  *
2980  * Parameters:
2981  *   session (input) - pointer to the session
2982  *   jname (input) - job name
2983  *
2984  * Returns:
2985  *	NONE
2986  */
2987 /*ARGSUSED*/
2988 static void
2989 free_dar_structs_v3(ndmpd_session_t *session, char *jname)
2990 {
2991 	ndmp_lbr_params_t *nlp;
2992 	tlm_commands_t *cmds;
2993 
2994 	nlp = ndmp_get_nlp(session);
2995 	if (!nlp) {
2996 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2997 		return;
2998 	}
2999 	cmds = &nlp->nlp_cmds;
3000 	if (!cmds) {
3001 		NDMP_LOG(LOG_DEBUG, "cmds == NULL");
3002 		return;
3003 	}
3004 
3005 	if (cmds->tcs_command) {
3006 		if (cmds->tcs_command->tc_buffers != NULL)
3007 			tlm_release_reader_writer_ipc(cmds->tcs_command);
3008 		else
3009 			NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL");
3010 		cmds->tcs_command = NULL;
3011 	} else
3012 		NDMP_LOG(LOG_DEBUG, "COMMAND == NULL");
3013 }
3014 
3015 
3016 /*
3017  * ndmp_dar_tar_init_v3
3018  *
3019  * Constructor for the DAR restore. Creates job name, allocates structures
3020  * needed for keeping the statistics, and reports the start of restore action.
3021  * It is called once for each DAR restore request.
3022  *
3023  * Parameters:
3024  *   session (input) - pointer to the session
3025  *   nlp (input) - pointer to the nlp structure
3026  *
3027  * Returns:
3028  *   char pointer: on success
3029  *   NULL: on error
3030  */
3031 static char *ndmpd_dar_tar_init_v3(ndmpd_session_t *session,
3032     ndmp_lbr_params_t *nlp)
3033 {
3034 	char *jname;
3035 
3036 	jname = ndmp_malloc(TLM_MAX_BACKUP_JOB_NAME);
3037 
3038 	if (!jname)
3039 		return (NULL);
3040 
3041 	(void) ndmp_new_job_name(jname);
3042 
3043 	if (!nlp) {
3044 		free(jname);
3045 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3046 		return (NULL);
3047 	}
3048 
3049 	nlp->nlp_jstat = tlm_new_job_stats(jname);
3050 	if (!nlp->nlp_jstat) {
3051 		free(jname);
3052 		NDMP_LOG(LOG_DEBUG, "Creating job stats");
3053 		return (NULL);
3054 	}
3055 
3056 	nlp->nlp_jstat->js_start_ltime = time(NULL);
3057 	nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
3058 
3059 	nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
3060 	    ndmpd_path_restored_v3, NULL, NULL);
3061 	if (!nlp->nlp_logcallbacks) {
3062 		tlm_un_ref_job_stats(jname);
3063 		free(jname);
3064 		return (NULL);
3065 	}
3066 	nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
3067 
3068 	nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0);
3069 	if (nlp->nlp_rsbm < 0) {
3070 		NDMP_LOG(LOG_ERR, "Out of memory.");
3071 		lbrlog_callbacks_done(nlp->nlp_logcallbacks);
3072 		tlm_un_ref_job_stats(jname);
3073 		free(jname);
3074 		return (NULL);
3075 	}
3076 
3077 	/* this is used in ndmpd_path_restored_v3() */
3078 	nlp->nlp_lastidx = -1;
3079 
3080 	NDMP_LOG(LOG_DEBUG, "Restoring from %s tape(s).",
3081 	    ndmp_data_get_mover_mode(session));
3082 
3083 	return (jname);
3084 }
3085 
3086 /*
3087  * ndmpd_dar_tar_end_v3
3088  *
3089  * Deconstructor for the DAR restore. This function is called once per
3090  * DAR request. It deallocates memories allocated by ndmpd_dar_tar_init_v3.
3091  *
3092  * Parameters:
3093  *   session (input) - pointer to the session
3094  *   params (input) - pointer to the parameters structure
3095  *   nlp (input) - pointer to the nlp structure
3096  *   jname(input) - job name
3097  *
3098  * Returns:
3099  *   0: on success
3100  *   -1: on error
3101  */
3102 static int ndmpd_dar_tar_end_v3(ndmpd_session_t *session,
3103     ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, char *jname)
3104 {
3105 	int err = 0;
3106 
3107 
3108 	NDMP_LOG(LOG_DEBUG, "lastidx %d", nlp->nlp_lastidx);
3109 
3110 	/* nothing restored. */
3111 	(void) send_unrecovered_list_v3(params, nlp);
3112 
3113 	if (nlp->nlp_jstat) {
3114 		nlp->nlp_bytes_total =
3115 		    (u_longlong_t)nlp->nlp_jstat->js_bytes_total;
3116 		tlm_un_ref_job_stats(jname);
3117 		nlp->nlp_jstat = NULL;
3118 	} else {
3119 		NDMP_LOG(LOG_DEBUG, "JSTAT == NULL");
3120 	}
3121 
3122 	if (nlp->nlp_logcallbacks) {
3123 		lbrlog_callbacks_done(nlp->nlp_logcallbacks);
3124 		nlp->nlp_logcallbacks = NULL;
3125 	} else {
3126 		NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL");
3127 	}
3128 
3129 	if (session->ns_data.dd_abort) {
3130 		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
3131 		    (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3132 		err = EINTR;
3133 	} else {
3134 		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
3135 		    (nlp->nlp_restore_path) ? nlp->nlp_restore_path :
3136 		    "NULL", err);
3137 	}
3138 
3139 	if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) {
3140 		if (nlp->nlp_rsbm < 0) {
3141 			NDMP_LOG(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm);
3142 		} else {
3143 			(void) bm_free(nlp->nlp_rsbm);
3144 			nlp->nlp_rsbm = -1;
3145 		}
3146 	}
3147 
3148 	free(jname);
3149 
3150 	return (err);
3151 }
3152 
3153 
3154 /*
3155  * ndmpd_dar_tar_v3
3156  *
3157  * This function is called for each entry in DAR entry list. The window
3158  * is already located and we should be in the right position to read
3159  * the data from the tape.
3160  * For each entry we setup selection list; so that, if the file name from
3161  * tape is not as the name client asked for, error be returned.
3162  *
3163  * Parameters:
3164  *   session (input) - pointer to the session
3165  *   params (input) - pointer to the parameters structure
3166  *   nlp (input) - pointer to the nlp structure
3167  *   jname (input) - job name
3168  *   dar_index(input) - Index of this entry in the restore list
3169  *
3170  * Returns:
3171  *   0: on success
3172  *   -1: on error
3173  */
3174 static int
3175 ndmpd_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3176     ndmp_lbr_params_t *nlp, char *jname, int dar_index)
3177 {
3178 	char *excl;
3179 	char **sels;
3180 	int flags;
3181 	int err;
3182 	tlm_commands_t *cmds;
3183 	struct rs_name_maker rn;
3184 	int data_addr_type = session->ns_data.dd_data_addr.addr_type;
3185 	ndmp_tar_reader_arg_t arg;
3186 	pthread_t rdtp;
3187 	ndmp_context_t nctx;
3188 	mem_ndmp_name_v3_t *ep;
3189 
3190 	err = 0;
3191 
3192 	/*
3193 	 * We have to allocate and deallocate buffers every time we
3194 	 * run the restore, for we need to flush the buffers.
3195 	 */
3196 	if (restore_dar_alloc_structs_v3(session, jname) < 0)
3197 		return (-1);
3198 
3199 	sels = setupsels(session, params, nlp, dar_index);
3200 	if (!sels) {
3201 		free_dar_structs_v3(session, jname);
3202 		return (-1);
3203 	}
3204 	excl = NULL;
3205 	flags = RSFLG_OVR_ALWAYS;
3206 	rn.rn_nlp = nlp;
3207 	rn.rn_fp = mknewname;
3208 
3209 	if (!session->ns_data.dd_abort) {
3210 		cmds = &nlp->nlp_cmds;
3211 		cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
3212 		cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
3213 		cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
3214 
3215 		arg.tr_session = session;
3216 		arg.tr_mod_params = params;
3217 		arg.tr_cmds = cmds;
3218 
3219 		err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
3220 		    (void *)&arg);
3221 		if (err == 0) {
3222 			tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
3223 		} else {
3224 			NDMP_LOG(LOG_DEBUG, "launch ndmp_tar_reader: %m");
3225 			return (-1);
3226 		}
3227 
3228 		cmds->tcs_command->tc_ref++;
3229 		cmds->tcs_writer_count++;
3230 
3231 		/* Plug-in module */
3232 		if (ndmp_pl != NULL &&
3233 		    ndmp_pl->np_pre_restore != NULL) {
3234 			nctx.nc_cmds = cmds;
3235 			nctx.nc_params = params;
3236 			ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params,
3237 			    dar_index - 1);
3238 
3239 			if ((err = ndmp_pl->np_pre_restore(ndmp_pl, &nctx,
3240 			    ep->nm3_opath, ep->nm3_dpath))
3241 			    != 0) {
3242 				NDMP_LOG(LOG_ERR, "Pre-restore plug-in: %m");
3243 				cmds->tcs_command->tc_reader = TLM_STOP;
3244 				ndmp_stop_local_reader(session, cmds);
3245 				ndmp_wait_for_reader(cmds);
3246 				(void) pthread_join(rdtp, NULL);
3247 				ndmp_stop_remote_reader(session);
3248 				goto restore_out;
3249 			}
3250 		}
3251 
3252 		if (tm_tar_ops.tm_getdir != NULL) {
3253 			err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
3254 			    nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags,
3255 			    dar_index, nlp->nlp_backup_path,
3256 			    session->hardlink_q);
3257 		}
3258 
3259 		cmds->tcs_writer_count--;
3260 		cmds->tcs_command->tc_ref--;
3261 		cmds->tcs_command->tc_reader = TLM_STOP;
3262 
3263 
3264 		/*
3265 		 * If it is a two-way restore then we stop the reader.
3266 		 */
3267 		NDMP_LOG(LOG_DEBUG, "stop local reader.");
3268 		ndmp_stop_local_reader(session, cmds);
3269 
3270 		ndmp_wait_for_reader(cmds);
3271 		(void) pthread_join(rdtp, NULL);
3272 
3273 		/*
3274 		 * If this is the last DAR entry and it is a three-way
3275 		 * restore then we should close the connection.
3276 		 */
3277 		if ((data_addr_type == NDMP_ADDR_TCP) &&
3278 		    (dar_index == (int)session->ns_data.dd_nlist_len)) {
3279 			NDMP_LOG(LOG_DEBUG, "stop remote reader.");
3280 			ndmp_stop_remote_reader(session);
3281 		}
3282 
3283 		/* exit as if there was an internal error */
3284 		if (session->ns_eof)
3285 			err = -1;
3286 restore_out:
3287 		/* Plug-in module */
3288 		if (ndmp_pl != NULL &&
3289 		    ndmp_pl->np_post_restore != NULL &&
3290 		    ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) {
3291 			NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
3292 			err = -1;
3293 		}
3294 	}
3295 
3296 	NDMP_FREE(sels);
3297 
3298 	free_dar_structs_v3(session, jname);
3299 
3300 	return (err);
3301 }
3302 
3303 /*
3304  * ndmpd_dar_locate_windwos_v3
3305  *
3306  * Locating the right window in which the requested file is backed up.
3307  * We should go through windows to find the exact location, for the
3308  * file can be located in for example 10th window after the current window.
3309  *
3310  * Parameters:
3311  *   session (input) - pointer to the session
3312  *   params (input) - pointer to the parameters structure
3313  *   fh_info (input) - index from the beginning of the backup stream
3314  *   len (input) - Length of the mover window
3315  *
3316  * Returns:
3317  *   0: on success
3318  *   -1: on error
3319  */
3320 static int
3321 ndmpd_dar_locate_window_v3(ndmpd_session_t *session,
3322     ndmpd_module_params_t *params, u_longlong_t fh_info, u_longlong_t len)
3323 {
3324 	int ret = 0;
3325 
3326 
3327 	for (; ; ) {
3328 		ret = (*params->mp_seek_func)(session, fh_info, len);
3329 
3330 		NDMP_LOG(LOG_DEBUG, "ret %d", ret);
3331 		if (ret == 0) /* Seek was done successfully */
3332 			break;
3333 		else if (ret < 0) {
3334 			NDMP_LOG(LOG_DEBUG, "Seek error");
3335 			break;
3336 		}
3337 
3338 		/*
3339 		 * DMA moved to a new window.
3340 		 * If we are reading the remainig of the file from
3341 		 * new window, seek is handled by ndmpd_local_read_v3.
3342 		 * Here we should continue the seek inside the new
3343 		 * window.
3344 		 */
3345 		continue;
3346 	}
3347 	return (ret);
3348 }
3349 
3350 /*
3351  * ndmpd_rs_dar_tar_v3
3352  *
3353  * Main DAR function. It calls the constructor, then for each entry it
3354  * calls the locate_window_v3 to find the exact position of the file. Then
3355  * it restores the file.
3356  * When all restore requests are done it calls the deconstructor to clean
3357  * everything up.
3358  *
3359  * Parameters:
3360  *   session (input) - pointer to the session
3361  *   params (input) - pointer to the parameters structure
3362  *   nlp (input) - pointer to the nlp structure
3363  *
3364  * Returns:
3365  *   0: on success
3366  *   -1: on error
3367  */
3368 static int
3369 ndmpd_rs_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3370     ndmp_lbr_params_t *nlp)
3371 {
3372 	mem_ndmp_name_v3_t *ep;
3373 	u_longlong_t len;
3374 	char *jname;
3375 	int n = session->ns_data.dd_nlist_len;
3376 	int i, ret = 0;
3377 	int result = 0;
3378 
3379 	jname = ndmpd_dar_tar_init_v3(session, nlp);
3380 
3381 	if (!jname)
3382 		return (-1);
3383 
3384 	/*
3385 	 * We set the length = sizeof (tlm_tar_hdr_t)
3386 	 * This is important for three-way DAR restore, for we should
3387 	 * read the header first (If we ask for more data then we have
3388 	 * to read and discard the remaining data in the socket)
3389 	 */
3390 	len = tlm_tarhdr_size();
3391 
3392 	for (i = 0; i < n; ++i) {
3393 		ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
3394 		if (!ep) {
3395 			NDMP_LOG(LOG_DEBUG, "ep NULL, i %d", i);
3396 			continue;
3397 		}
3398 		NDMP_LOG(LOG_DEBUG,
3399 		    "restoring opath %s, dpath %s, fh_info %lld",
3400 		    ep->nm3_opath ? ep->nm3_opath : "NULL",
3401 		    ep->nm3_dpath ? ep->nm3_dpath : "NULL",
3402 		    ep->nm3_fh_info);
3403 
3404 		/*
3405 		 * We should seek till finding the window in which file
3406 		 * is located.
3407 		 */
3408 		ret = ndmpd_dar_locate_window_v3(session, params,
3409 		    ep->nm3_fh_info, len);
3410 
3411 		if (ret < 0) /* If seek fails, restore should be aborted */
3412 			break;
3413 		/*
3414 		 * We are inside the target window.
3415 		 * for each restore we will use one entry as selection list
3416 		 */
3417 		if ((ret = ndmpd_dar_tar_v3(session, params, nlp, jname, i+1))
3418 		    != 0)
3419 			result = EIO;
3420 		ndmpd_audit_restore(session->ns_connection,
3421 		    ep->nm3_opath ? ep->nm3_opath : "NULL",
3422 		    session->ns_data.dd_data_addr.addr_type,
3423 		    session->ns_tape.td_adapter_name, result);
3424 	}
3425 
3426 	NDMP_LOG(LOG_DEBUG, "End of restore list");
3427 
3428 	(void) ndmpd_dar_tar_end_v3(session, params, nlp, jname);
3429 
3430 	return (ret);
3431 }
3432 
3433 /*
3434  * ndmp_plugin_pre_restore
3435  *
3436  * Wrapper for pre-restore callback with multiple path
3437  */
3438 static int
3439 ndmp_plugin_pre_restore(ndmp_context_t *ctxp, ndmpd_module_params_t *params,
3440     int ncount)
3441 {
3442 	mem_ndmp_name_v3_t *ep;
3443 	int err;
3444 	int i;
3445 
3446 	for (i = 0; i < ncount; i++) {
3447 		if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i)))
3448 			continue;
3449 		if ((err = ndmp_pl->np_pre_restore(ndmp_pl, ctxp,
3450 		    ep->nm3_opath, ep->nm3_dpath)) != 0)
3451 			return (err);
3452 	}
3453 
3454 	return (0);
3455 }
3456 
3457 /*
3458  * get_absolute_path
3459  *
3460  * Get resolved path name which does not involve ".", ".." or extra
3461  * "/" or symbolic links.
3462  *
3463  * e.g.
3464  *
3465  * /backup/path/ -> /backup/path
3466  * /backup/path/. -> /backup/path
3467  * /backup/path/../path/ -> /backup/path
3468  * /link-to-backup-path -> /backup/path
3469  *
3470  * Returns:
3471  * 	Pointer to the new path (allocated)
3472  * 	NULL if the path doesnt exist
3473  */
3474 static char *
3475 get_absolute_path(const char *bkpath)
3476 {
3477 	char *pbuf;
3478 	char *rv;
3479 
3480 	if (!(pbuf = ndmp_malloc(TLM_MAX_PATH_NAME)))
3481 		return (NULL);
3482 
3483 	if ((rv = realpath(bkpath, pbuf)) == NULL) {
3484 		NDMP_LOG(LOG_DEBUG, "Invalid path [%s] err=%d",
3485 		    bkpath, errno);
3486 	}
3487 	return (rv);
3488 }
3489 
3490 
3491 /*
3492  * Expands the format string and logs the resulting message to the
3493  * remote DMA
3494  */
3495 void
3496 ndmp_log_dma(ndmp_context_t *nctx, ndmp_log_dma_type_t lt, const char *fmt, ...)
3497 {
3498 	va_list ap;
3499 	char buf[256];
3500 	ndmpd_module_params_t *params;
3501 
3502 	if (nctx == NULL ||
3503 	    (params = (ndmpd_module_params_t *)nctx->nc_params) == NULL)
3504 		return;
3505 
3506 	va_start(ap, fmt);
3507 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
3508 	va_end(ap);
3509 
3510 	MOD_LOGV3(params, (ndmp_log_type)lt, "%s", buf);
3511 }
3512 
3513 
3514 /*
3515  * ndmpd_rs_sar_tar_v3
3516  *
3517  * Main non-DAR restore function. It will try to restore all the entries
3518  * that have been backed up.
3519  *
3520  * Parameters:
3521  *   session (input) - pointer to the session
3522  *   params (input) - pointer to the parameters structure
3523  *   nlp (input) - pointer to the nlp structure
3524  *
3525  * Returns:
3526  *   0: on success
3527  *   -1: on error
3528  */
3529 static int
3530 ndmpd_rs_sar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3531     ndmp_lbr_params_t *nlp)
3532 {
3533 	char jname[TLM_MAX_BACKUP_JOB_NAME];
3534 	char *excl;
3535 	char **sels;
3536 	int flags;
3537 	int err;
3538 	tlm_commands_t *cmds;
3539 	struct rs_name_maker rn;
3540 	ndmp_tar_reader_arg_t arg;
3541 	pthread_t rdtp;
3542 	int result;
3543 	ndmp_context_t nctx;
3544 
3545 	result = err = 0;
3546 	(void) ndmp_new_job_name(jname);
3547 	if (restore_alloc_structs_v3(session, jname) < 0)
3548 		return (-1);
3549 
3550 	sels = setupsels(session, params, nlp, 0);
3551 	if (!sels) {
3552 		free_structs_v3(session, jname);
3553 		return (-1);
3554 	}
3555 	excl = NULL;
3556 	flags = RSFLG_OVR_ALWAYS;
3557 	rn.rn_nlp = nlp;
3558 	rn.rn_fp = mknewname;
3559 
3560 	nlp->nlp_jstat->js_start_ltime = time(NULL);
3561 	nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
3562 
3563 	if (!session->ns_data.dd_abort && !session->ns_data.dd_abort) {
3564 		cmds = &nlp->nlp_cmds;
3565 		cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
3566 		cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
3567 		cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
3568 
3569 		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" started.",
3570 		    (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3571 
3572 		arg.tr_session = session;
3573 		arg.tr_mod_params = params;
3574 		arg.tr_cmds = cmds;
3575 		err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
3576 		    (void *)&arg);
3577 		if (err == 0) {
3578 			tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
3579 		} else {
3580 			NDMP_LOG(LOG_DEBUG, "Launch ndmp_tar_reader: %m");
3581 			free_structs_v3(session, jname);
3582 			return (-1);
3583 		}
3584 
3585 		if (!ndmp_check_utf8magic(cmds->tcs_command)) {
3586 			NDMP_LOG(LOG_DEBUG, "UTF8Magic not found!");
3587 		} else {
3588 			NDMP_LOG(LOG_DEBUG, "UTF8Magic found");
3589 		}
3590 
3591 		/* Plug-in module */
3592 		if (ndmp_pl != NULL &&
3593 		    ndmp_pl->np_pre_restore != NULL) {
3594 			nctx.nc_cmds = cmds;
3595 			nctx.nc_params = params;
3596 			if ((err = ndmp_plugin_pre_restore(&nctx, params,
3597 			    nlp->nlp_nfiles))
3598 			    != 0) {
3599 				NDMP_LOG(LOG_ERR, "Pre-restore plug-in: %m");
3600 				cmds->tcs_command->tc_reader = TLM_STOP;
3601 				ndmp_stop_local_reader(session, cmds);
3602 				ndmp_wait_for_reader(cmds);
3603 				(void) pthread_join(rdtp, NULL);
3604 				ndmp_stop_remote_reader(session);
3605 				goto restore_out;
3606 			}
3607 		}
3608 
3609 		cmds->tcs_command->tc_ref++;
3610 		cmds->tcs_writer_count++;
3611 
3612 		if (tm_tar_ops.tm_getdir != NULL)
3613 			err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
3614 			    nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags, 0,
3615 			    nlp->nlp_backup_path, session->hardlink_q);
3616 
3617 		cmds->tcs_writer_count--;
3618 		cmds->tcs_command->tc_ref--;
3619 		cmds->tcs_command->tc_reader = TLM_STOP;
3620 		nlp->nlp_jstat->js_stop_time = time(NULL);
3621 
3622 		/* Send the list of un-recovered files/dirs to the client.  */
3623 		(void) send_unrecovered_list_v3(params, nlp);
3624 
3625 		ndmp_stop_local_reader(session, cmds);
3626 		ndmp_wait_for_reader(cmds);
3627 		(void) pthread_join(rdtp, NULL);
3628 
3629 		ndmp_stop_remote_reader(session);
3630 
3631 		/* exit as if there was an internal error */
3632 		if (session->ns_eof)
3633 			err = -1;
3634 		if (err == -1)
3635 			result = EIO;
3636 	}
3637 
3638 	(void) send_unrecovered_list_v3(params, nlp); /* nothing restored. */
3639 	if (session->ns_data.dd_abort) {
3640 		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
3641 		    (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3642 		result = EINTR;
3643 		ndmpd_audit_restore(session->ns_connection,
3644 		    nlp->nlp_restore_path,
3645 		    session->ns_data.dd_data_addr.addr_type,
3646 		    session->ns_tape.td_adapter_name, result);
3647 		err = -1;
3648 	} else {
3649 		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
3650 		    (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL",
3651 		    err);
3652 		ndmpd_audit_restore(session->ns_connection,
3653 		    nlp->nlp_restore_path,
3654 		    session->ns_data.dd_data_addr.addr_type,
3655 		    session->ns_tape.td_adapter_name, result);
3656 
3657 restore_out:
3658 		/* Plug-in module */
3659 		if (ndmp_pl != NULL &&
3660 		    ndmp_pl->np_post_restore != NULL &&
3661 		    ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) {
3662 			NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
3663 			err = -1;
3664 		}
3665 	}
3666 
3667 	NDMP_FREE(sels);
3668 	free_structs_v3(session, jname);
3669 
3670 	return (err);
3671 }
3672 
3673 
3674 /*
3675  * ndmp_backup_get_params_v3
3676  *
3677  * Get the backup parameters from the NDMP env variables
3678  * and log them in the system log and as normal messages
3679  * to the DMA.
3680  *
3681  * Parameters:
3682  *   session (input) - pointer to the session
3683  *   params (input) - pointer to the parameters structure
3684  *
3685  * Returns:
3686  *   NDMP_NO_ERR: on success
3687  *   != NDMP_NO_ERR: otherwise
3688  */
3689 ndmp_error
3690 ndmp_backup_get_params_v3(ndmpd_session_t *session,
3691     ndmpd_module_params_t *params)
3692 {
3693 	ndmp_error rv;
3694 	ndmp_lbr_params_t *nlp;
3695 
3696 	if (!session || !params)
3697 		return (NDMP_ILLEGAL_ARGS_ERR);
3698 
3699 	rv = NDMP_NO_ERR;
3700 	nlp = ndmp_get_nlp(session);
3701 	if (!nlp) {
3702 		MOD_LOGV3(params, NDMP_LOG_ERROR,
3703 		    "Internal error: NULL nlp.\n");
3704 		rv = NDMP_ILLEGAL_ARGS_ERR;
3705 	} else {
3706 		if (!(nlp->nlp_backup_path = get_bk_path_v3(params)))
3707 			rv = NDMP_FILE_NOT_FOUND_ERR;
3708 		else if (!is_valid_backup_dir_v3(params, nlp->nlp_backup_path))
3709 			rv = NDMP_ILLEGAL_ARGS_ERR;
3710 	}
3711 
3712 	nlp->nlp_backup_path = get_absolute_path(nlp->nlp_backup_path);
3713 	if (!nlp->nlp_backup_path)
3714 		rv = NDMP_FILE_NOT_FOUND_ERR;
3715 
3716 	if (rv != NDMP_NO_ERR)
3717 		return (rv);
3718 
3719 	if (fs_is_chkpntvol(nlp->nlp_backup_path) ||
3720 	    fs_is_rdonly(nlp->nlp_backup_path) ||
3721 	    !fs_is_chkpnt_enabled(nlp->nlp_backup_path))
3722 		NLP_SET(nlp, NLPF_CHKPNTED_PATH);
3723 	else
3724 		NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
3725 
3726 	/* Should the st_ctime be ignored when backing up? */
3727 	if (ndmp_ignore_ctime) {
3728 		NDMP_LOG(LOG_DEBUG, "ignoring st_ctime");
3729 		NLP_SET(nlp, NLPF_IGNCTIME);
3730 	} else {
3731 		NLP_UNSET(nlp, NLPF_IGNCTIME);
3732 	}
3733 
3734 	if (ndmp_include_lmtime == TRUE) {
3735 		NDMP_LOG(LOG_DEBUG, "including st_lmtime");
3736 		NLP_SET(nlp, NLPF_INCLMTIME);
3737 	} else {
3738 		NLP_UNSET(nlp, NLPF_INCLMTIME);
3739 	}
3740 
3741 	NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
3742 
3743 	get_hist_env_v3(params, nlp);
3744 	get_exc_env_v3(params, nlp);
3745 	get_inc_env_v3(params, nlp);
3746 	get_direct_env_v3(params, nlp);
3747 	rv = get_backup_level_v3(params, nlp);
3748 
3749 	return (rv);
3750 }
3751 
3752 
3753 /*
3754  * ndmpd_tar_backup_starter_v3
3755  *
3756  * Create the checkpoint for the backup and do the backup,
3757  * then remove the backup checkpoint if we created it.
3758  * Save the backup time information based on the backup
3759  * type and stop the data server.
3760  *
3761  * Parameters:
3762  *   params (input) - pointer to the parameters structure
3763  *
3764  * Returns:
3765  *   0: on success
3766  *   != 0: otherwise
3767  */
3768 int
3769 ndmpd_tar_backup_starter_v3(ndmpd_module_params_t *params)
3770 {
3771 	int err;
3772 	ndmpd_session_t *session;
3773 	ndmp_lbr_params_t *nlp;
3774 	char jname[TLM_MAX_BACKUP_JOB_NAME];
3775 	ndmp_bkup_size_arg_t sarg;
3776 	pthread_t tid;
3777 
3778 	session = (ndmpd_session_t *)(params->mp_daemon_cookie);
3779 	*(params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
3780 	ndmp_session_ref(session);
3781 	(void) ndmp_new_job_name(jname);
3782 
3783 	err = 0;
3784 	if (!NLP_ISCHKPNTED(nlp) &&
3785 	    ndmp_start_check_point(nlp->nlp_backup_path, jname) < 0) {
3786 		MOD_LOGV3(params, NDMP_LOG_ERROR,
3787 		    "Creating checkpoint on \"%s\".\n",
3788 		    nlp->nlp_backup_path);
3789 		err = -1;
3790 	}
3791 
3792 	NDMP_LOG(LOG_DEBUG, "err %d, chkpnted %c",
3793 	    err, NDMP_YORN(NLP_ISCHKPNTED(nlp)));
3794 
3795 	if (err == 0) {
3796 		sarg.bs_session = session;
3797 		sarg.bs_jname = jname;
3798 		sarg.bs_path = nlp->nlp_backup_path;
3799 
3800 		/* Get an estimate of the data size */
3801 		if (pthread_create(&tid, NULL, (funct_t)get_backup_size,
3802 		    (void *)&sarg) == 0)
3803 			(void) pthread_detach(tid);
3804 
3805 		err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate, jname);
3806 		if (err != 0) {
3807 			NDMP_LOG(LOG_DEBUG, "err %d", err);
3808 		} else {
3809 			log_bk_params_v3(session, params, nlp);
3810 			err = tar_backup_v3(session, params, nlp, jname);
3811 		}
3812 	}
3813 
3814 	if (!NLP_ISCHKPNTED(nlp))
3815 		(void) ndmp_release_check_point(nlp->nlp_backup_path, jname);
3816 
3817 	NDMP_LOG(LOG_DEBUG, "err %d, update %c",
3818 	    err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
3819 
3820 	if (err == 0)
3821 		save_backup_date_v3(params, nlp);
3822 
3823 	MOD_DONE(params, err);
3824 
3825 	/* nlp_params is allocated in start_backup_v3() */
3826 	NDMP_FREE(nlp->nlp_params);
3827 	NDMP_FREE(nlp->nlp_backup_path);
3828 
3829 	NS_DEC(nbk);
3830 	ndmp_session_unref(session);
3831 	return (err);
3832 
3833 }
3834 
3835 
3836 /*
3837  * ndmpd_tar_backup_abort_v3
3838  *
3839  * Abort the backup operation and stop the reader thread.
3840  *
3841  * Parameters:
3842  *   module_cookie (input) - pointer to the nlp structure
3843  *
3844  * Returns:
3845  *   0: always
3846  */
3847 int
3848 ndmpd_tar_backup_abort_v3(void *module_cookie)
3849 {
3850 	ndmp_lbr_params_t *nlp;
3851 
3852 	nlp = (ndmp_lbr_params_t *)module_cookie;
3853 	if (nlp && nlp->nlp_session) {
3854 		if (nlp->nlp_session->ns_data.dd_data_addr.addr_type ==
3855 		    NDMP_ADDR_TCP &&
3856 		    nlp->nlp_session->ns_data.dd_sock != -1) {
3857 			(void) close(nlp->nlp_session->ns_data.dd_sock);
3858 			nlp->nlp_session->ns_data.dd_sock = -1;
3859 		}
3860 		ndmp_stop_reader_thread(nlp->nlp_session);
3861 	}
3862 
3863 	return (0);
3864 }
3865 
3866 
3867 /*
3868  * ndmp_restore_get_params_v3
3869  *
3870  * Get the parameters specified for recovery such as restore path, type
3871  * of restore (DAR, non-DAR) etc
3872  *
3873  * Parameters:
3874  *   session (input) - pointer to the session
3875  *   params (input) - pointer to the parameters structure
3876  *
3877  * Returns:
3878  *   NDMP_NO_ERR: on success
3879  *   != NDMP_NO_ERR: otherwise
3880  */
3881 ndmp_error
3882 ndmp_restore_get_params_v3(ndmpd_session_t *session,
3883     ndmpd_module_params_t *params)
3884 {
3885 	ndmp_error rv;
3886 	ndmp_lbr_params_t *nlp;
3887 
3888 	if (!(nlp = ndmp_get_nlp(session))) {
3889 		NDMP_LOG(LOG_DEBUG, "nlp is NULL");
3890 		rv = NDMP_ILLEGAL_ARGS_ERR;
3891 	} else if (!(nlp->nlp_backup_path = get_bk_path_v3(params)))
3892 		rv = NDMP_ILLEGAL_ARGS_ERR;
3893 	else if ((nlp->nlp_nfiles = session->ns_data.dd_nlist_len) == 0) {
3894 		NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
3895 		rv = NDMP_ILLEGAL_ARGS_ERR;
3896 	} else if (get_rs_path_v3(params, nlp) != NDMP_NO_ERR) {
3897 		rv = NDMP_ILLEGAL_ARGS_ERR;
3898 	} else if ((rv = fix_nlist_v3(session, params, nlp)) != NDMP_NO_ERR) {
3899 		NDMP_LOG(LOG_DEBUG, "fix_nlist_v3: %d", rv);
3900 	} else {
3901 		rv = NDMP_NO_ERR;
3902 		get_direct_env_v3(params, nlp);
3903 		if (NLP_ISSET(nlp, NLPF_DIRECT)) {
3904 			if (NLP_ISSET(nlp, NLPF_RECURSIVE)) {
3905 				/* Currently we dont support DAR on directory */
3906 				NDMP_LOG(LOG_DEBUG,
3907 				    "Can't have RECURSIVE and DIRECT together");
3908 				rv = NDMP_ILLEGAL_ARGS_ERR;
3909 				return (rv);
3910 			}
3911 
3912 			/*
3913 			 * DAR can be done if all the fh_info's are valid.
3914 			 */
3915 			if (allvalidfh(session, params)) {
3916 				ndmp_sort_nlist_v3(session);
3917 			} else {
3918 				MOD_LOGV3(params, NDMP_LOG_WARNING,
3919 				    "Cannot do direct access recovery. "
3920 				    "Some 'fh_info'es are not valid.\n");
3921 				NLP_UNSET(nlp, NLPF_DIRECT);
3922 			}
3923 		}
3924 
3925 		log_rs_params_v3(session, params, nlp);
3926 	}
3927 
3928 	return (rv);
3929 }
3930 
3931 
3932 /*
3933  * ndmpd_tar_restore_starter_v3
3934  *
3935  * The main restore starter function. It will start a DAR or
3936  * non-DAR recovery based on the parameters. (V3 and V4 only)
3937  *
3938  * Parameters:
3939  *   params (input) - pointer to the parameters structure
3940  *
3941  * Returns:
3942  *   NDMP_NO_ERR: on success
3943  *   != NDMP_NO_ERR: otherwise
3944  */
3945 int
3946 ndmpd_tar_restore_starter_v3(ndmpd_module_params_t *params)
3947 {
3948 	int err;
3949 	ndmpd_session_t *session;
3950 	ndmp_lbr_params_t *nlp;
3951 
3952 
3953 	session = (ndmpd_session_t *)(params->mp_daemon_cookie);
3954 	*(params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
3955 	ndmp_session_ref(session);
3956 
3957 	if (NLP_ISSET(nlp, NLPF_DIRECT))
3958 		err = ndmpd_rs_dar_tar_v3(session, params, nlp);
3959 	else
3960 		err = ndmpd_rs_sar_tar_v3(session, params, nlp);
3961 
3962 	MOD_DONE(params, err);
3963 
3964 	NS_DEC(nrs);
3965 	/* nlp_params is allocated in start_recover() */
3966 	NDMP_FREE(nlp->nlp_params);
3967 	ndmp_session_unref(session);
3968 	return (err);
3969 
3970 }
3971 
3972 
3973 /*
3974  * ndmp_tar_restore_abort_v3
3975  *
3976  * Restore abort function (V3 and V4 only)
3977  *
3978  * Parameters:
3979  *   module_cookie (input) - pointer to nlp
3980  *
3981  * Returns:
3982  *   0
3983  */
3984 int
3985 ndmpd_tar_restore_abort_v3(void *module_cookie)
3986 {
3987 	ndmp_lbr_params_t *nlp;
3988 
3989 	nlp = (ndmp_lbr_params_t *)module_cookie;
3990 	if (nlp != NULL && nlp->nlp_session != NULL) {
3991 		if (nlp->nlp_session->ns_data.dd_mover.addr_type ==
3992 		    NDMP_ADDR_TCP &&
3993 		    nlp->nlp_session->ns_data.dd_sock != -1) {
3994 			(void) close(nlp->nlp_session->ns_data.dd_sock);
3995 			nlp->nlp_session->ns_data.dd_sock = -1;
3996 		}
3997 		nlp_event_nw(nlp->nlp_session);
3998 		ndmp_stop_writer_thread(nlp->nlp_session);
3999 	}
4000 
4001 
4002 	return (0);
4003 
4004 }
4005