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