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