xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c (revision a8039bf395ff9572baeefc76b39d2c3355ebd2d5)
1 /*
2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
4  */
5 
6 /*
7  * BSD 3 Clause License
8  *
9  * Copyright (c) 2007, The Storage Networking Industry Association.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 	- Redistributions of source code must retain the above copyright
15  *	  notice, this list of conditions and the following disclaimer.
16  *
17  * 	- Redistributions in binary form must reproduce the above copyright
18  *	  notice, this list of conditions and the following disclaimer in
19  *	  the documentation and/or other materials provided with the
20  *	  distribution.
21  *
22  *	- Neither the name of The Storage Networking Industry Association (SNIA)
23  *	  nor the names of its contributors may be used to endorse or promote
24  *	  products derived from this software without specific prior written
25  *	  permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
41 #include <sys/stat.h>
42 #include <sys/types.h>
43 #include <sys/time.h>
44 #include <ctype.h>
45 #include <sys/socket.h>
46 #include <sys/acl.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <errno.h>
50 #include <stdio.h>
51 #include <string.h>
52 #include <time.h>
53 #include <cstack.h>
54 #include "ndmp.h"
55 #include "ndmpd.h"
56 #include <bitmap.h>
57 #include <traverse.h>
58 
59 
60 /*
61  * Maximum length of the string-representation of u_longlong_t type.
62  */
63 #define	QUAD_DECIMAL_LEN	20
64 
65 
66 /* Is Y=yes or T=true */
67 #define	IS_YORT(c)	(strchr("YT", toupper(c)))
68 
69 /* Is F=file format (vs D=node-dir format) */
70 #define	IS_F(c)		(toupper(c) == 'F')
71 
72 /*
73  * If path is defined.
74  */
75 #define	ISDEFINED(cp)	((cp) && *(cp))
76 #define	SHOULD_LBRBK(bpp)	(!((bpp)->bp_opr & TLM_OP_CHOOSE_ARCHIVE))
77 
78 /*
79  * Component boundary means end of path or on a '/'.  At this
80  * point both paths should be on component boundary.
81  */
82 #define	COMPBNDRY(p)	(!*(p) || (*p) == '/')
83 
84 typedef struct bk_param_v3 {
85 	ndmpd_session_t *bp_session;
86 	ndmp_lbr_params_t *bp_nlp;
87 	tlm_job_stats_t *bp_js;
88 	tlm_cmd_t *bp_lcmd;
89 	tlm_commands_t *bp_cmds;
90 	tlm_acls_t *bp_tlmacl;
91 	int bp_opr;
92 	char *bp_tmp;
93 	char *bp_chkpnm;
94 	char **bp_excls;
95 	char *bp_unchkpnm;
96 } bk_param_v3_t;
97 
98 
99 /*
100  * Multiple destination restore mode
101  */
102 #define	MULTIPLE_DEST_DIRS 128
103 
104 int multiple_dest_restore = 0;
105 
106 /*
107  * Plug-in module ops
108  */
109 ndmp_plugin_t *ndmp_pl;
110 
111 /*
112  * NDMP exclusion list
113  */
114 char **ndmp_excl_list = NULL;
115 
116 /*
117  * split_env
118  *
119  * Splits the string into list of sections separated by the
120  * sep character.
121  *
122  * Parameters:
123  *   envp (input) - the environment variable that should be broken
124  *   sep (input) - the separator character
125  *
126  * Returns:
127  *   Array of character pointers: On success.  The array is allocated
128  *	as well as all its entries.  They all should be freed by the
129  *	caller.
130  *   NULL: on error
131  */
132 static char **
133 split_env(char *envp, char sep)
134 {
135 	char *bp, *cp, *ep;
136 	char *save;
137 	char **cpp;
138 	int n;
139 
140 	if (!envp)
141 		return (NULL);
142 
143 	while (isspace(*envp))
144 		envp++;
145 
146 	if (!*envp)
147 		return (NULL);
148 
149 	bp = save = strdup(envp);
150 	if (!bp)
151 		return (NULL);
152 
153 	/*
154 	 * Since the env variable is not empty, it contains at least one
155 	 * component
156 	 */
157 	n = 1;
158 	while ((cp = strchr(bp, sep))) {
159 		if (cp > save && *(cp-1) != '\\')
160 			n++;
161 
162 		bp = cp + 1;
163 	}
164 
165 	n++; /* for the terminating NULL pointer */
166 	cpp = ndmp_malloc(sizeof (char *) * n);
167 	if (!cpp) {
168 		free(save);
169 		return (NULL);
170 	}
171 
172 	(void) memset(cpp, 0, n * sizeof (char *));
173 	n = 0;
174 	cp = bp = ep = save;
175 	while (*cp)
176 		if (*cp == sep) {
177 			*ep = '\0';
178 			if (strlen(bp) > 0) {
179 				cpp[n] = strdup(bp);
180 				if (!cpp[n++]) {
181 					tlm_release_list(cpp);
182 					cpp = NULL;
183 					break;
184 				}
185 			}
186 			ep = bp = ++cp;
187 		} else if (*cp == '\\') {
188 			++cp;
189 			if (*cp == 'n') {	/* "\n" */
190 				*ep++ = '\n';
191 				cp++;
192 			} else if (*cp == 't') {	/* "\t" */
193 				*ep++ = '\t';
194 				cp++;
195 			} else
196 				*ep++ = *cp++;
197 		} else
198 			*ep++ = *cp++;
199 
200 	*ep = '\0';
201 	if (cpp) {
202 		if (strlen(bp) > 0) {
203 			cpp[n] = strdup(bp);
204 			if (!cpp[n++]) {
205 				tlm_release_list(cpp);
206 				cpp = NULL;
207 			} else
208 				cpp[n] = NULL;
209 		}
210 
211 		if (n == 0 && cpp != NULL) {
212 			tlm_release_list(cpp);
213 			cpp = NULL;
214 		}
215 	}
216 
217 	free(save);
218 	return (cpp);
219 }
220 
221 
222 /*
223  * prl
224  *
225  * Print the array of character pointers passed to it.  This is
226  * used for debugging purpose.
227  *
228  * Parameters:
229  *   lpp (input) - pointer to the array of strings
230  *
231  * Returns:
232  *   void
233  */
234 static void
235 prl(char **lpp)
236 {
237 	if (!lpp) {
238 		NDMP_LOG(LOG_DEBUG, "empty");
239 		return;
240 	}
241 
242 	while (*lpp)
243 		NDMP_LOG(LOG_DEBUG, "\"%s\"", *lpp++);
244 }
245 
246 
247 /*
248  * inlist
249  *
250  * Looks through all the strings of the array to see if the ent
251  * matches any of the strings.  The strings are patterns.
252  *
253  * Parameters:
254  *   lpp (input) - pointer to the array of strings
255  *   ent (input) - the entry to be matched
256  *
257  * Returns:
258  *   TRUE: if there is a match
259  *   FALSE: invalid argument or no match
260  */
261 static boolean_t
262 inlist(char **lpp, char *ent)
263 {
264 	if (!lpp || !ent) {
265 		NDMP_LOG(LOG_DEBUG, "empty list");
266 		return (FALSE);
267 	}
268 
269 	while (*lpp) {
270 		/*
271 		 * Fixing the sync_sort NDMPV3 problem, it sends the inclusion
272 		 * like "./" which we should skip the "./"
273 		 */
274 		char *pattern = *lpp;
275 		if (strncmp(pattern, "./", 2) == 0)
276 			pattern += 2;
277 
278 		NDMP_LOG(LOG_DEBUG, "pattern %s, ent %s", pattern, ent);
279 
280 		if (match(pattern, ent)) {
281 			NDMP_LOG(LOG_DEBUG, "match(%s,%s)", pattern, ent);
282 			return (TRUE);
283 		}
284 		lpp++;
285 	}
286 
287 	NDMP_LOG(LOG_DEBUG, "no match");
288 	return (FALSE);
289 }
290 
291 
292 /*
293  * inexl
294  *
295  * Checks if the entry is in the list.  This is used for exclusion
296  * list.  If the exclusion list is empty, FALSE should be returned
297  * showing that nothing should be excluded by default.
298  *
299  * Parameters:
300  *   lpp (input) - pointer to the array of strings
301  *   ent (input) - the entry to be matched
302  *
303  * Returns:
304  *   TRUE: if there is a match
305  *   FALSE: invalid argument or no match
306  *
307  */
308 static boolean_t
309 inexl(char **lpp, char *ent)
310 {
311 	if (!lpp || !ent)
312 		return (FALSE);
313 
314 	return (inlist(lpp, ent));
315 }
316 
317 
318 /*
319  * ininc
320  *
321  * Checks if the entry is in the list.  This is used for inclusion
322  * list.  If the inclusion list is empty, TRUE should be returned
323  * showing that everything should be included by default.
324  *
325  * Parameters:
326  *   lpp (input) - pointer to the array of strings
327  *   ent (input) - the entry to be matched
328  *
329  * Returns:
330  *   TRUE: if there is a match or the list is empty
331  *   FALSE: no match
332  */
333 static boolean_t
334 ininc(char **lpp, char *ent)
335 {
336 	if (!lpp || !ent || !*ent)
337 		return (TRUE);
338 
339 	return (inlist(lpp, ent));
340 }
341 
342 
343 /*
344  * setupsels
345  *
346  * Set up the selection list for Local B/R functions.  A new array of
347  * "char *" is created and the pointers point to the original paths of
348  * the Nlist.
349  *
350  * Parameters:
351  *   session (input) - pointer to the session
352  *   params (input) - pointer to the parameters structure
353  *   nlp (input) - pointer to the nlp structure
354  *   index(input) - If not zero is the DAR entry position
355  *
356  * Returns:
357  *   list pointer: on success
358  *   NULL: on error
359  */
360 /*ARGSUSED*/
361 char **
362 setupsels(ndmpd_session_t *session, ndmpd_module_params_t *params,
363     ndmp_lbr_params_t *nlp, int index)
364 {
365 	char **lpp, **save;
366 	int i, n;
367 	int len;
368 	int start, end;
369 	mem_ndmp_name_v3_t *ep;
370 
371 	n = session->ns_data.dd_nlist_len;
372 
373 	save = lpp = ndmp_malloc(sizeof (char *) * (n + 1));
374 	if (!lpp) {
375 		MOD_LOGV3(params, NDMP_LOG_ERROR, "Insufficient memory.\n");
376 		return (NULL);
377 	}
378 
379 	if (index) { /* DAR, just one entry */
380 		/*
381 		 * We have to setup a list of strings that will not match any
382 		 * file. One DAR entry will be added in the right position later
383 		 * in this function.
384 		 * When the match is called from tar_getdir the
385 		 * location of the selection that matches the entry is
386 		 * important
387 		 */
388 		for (i = 0; i < n; ++i)
389 			*(lpp+i) = " ";
390 		n = 1;
391 		start = index-1;
392 		end = start+1;
393 		lpp += start; /* Next selection entry will be in lpp[start] */
394 	} else {
395 		start = 0;
396 		end = n;
397 	}
398 
399 	for (i = start; i < end; i++) {
400 		ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
401 		if (!ep)
402 			continue;
403 
404 		/*
405 		 * Check for clients that send original path as "."(like
406 		 * CA products). In this situation opath is something like
407 		 * "/v1/." and we should change it to "/v1/"
408 		 */
409 		len = strlen(ep->nm3_opath);
410 		if (len > 1 && ep->nm3_opath[len-2] == '/' &&
411 		    ep->nm3_opath[len-1] == '.') {
412 			ep->nm3_opath[len-1] = '\0';
413 			NDMP_LOG(LOG_DEBUG,
414 			    "nm3_opath changed from %s. to %s",
415 			    ep->nm3_opath, ep->nm3_opath);
416 		}
417 		*lpp++ = ep->nm3_opath;
418 	}
419 
420 	/* list termination indicator is a null pointer */
421 	*lpp = NULL;
422 
423 	return (save);
424 }
425 
426 
427 /*
428  * mkrsp
429  *
430  * Make Restore Path.
431  * It gets a path, a selection (with which the path has matched) a new
432  * name and makes a new name for the path.
433  * All the components of the path and the selection are skipped as long
434  * as they are the same.  If either of the path or selection are not on
435  * a component boundary, the match was reported falsefully and no new name
436  * is generated(Except the situation in which both path and selection
437  * end with trailing '/' and selection is the prefix of the path).
438  * Otherwise, the remaining of the path is appended to the
439  * new name.  The result is saved in the buffer passed.
440  *
441  * Parameters:
442  *   bp (output) - pointer to the result buffer
443  *   pp (input) - pointer to the path
444  *   sp (input) - pointer to the selection
445  *   np (input) - pointer to the new name
446  *
447  * Returns:
448  *   pointer to the bp: on success
449  *   NULL: otherwise
450  */
451 char *
452 mkrsp(char *bp, char *pp, char *sp, char *np)
453 {
454 	if (!bp || !pp)
455 		return (NULL);
456 
457 
458 	pp += strspn(pp, "/");
459 	if (sp) {
460 		sp += strspn(sp, "/");
461 
462 		/* skip as much as match */
463 		while (*sp && *pp && *sp == *pp) {
464 			sp++;
465 			pp++;
466 		}
467 
468 		if (!COMPBNDRY(pp) || !COMPBNDRY(sp))
469 			/* An exception to the boundary rule */
470 			/* (!(!*sp && (*(pp - 1)) == '/')) */
471 			if (*sp || (*(pp - 1)) != '/')
472 				return (NULL);
473 
474 		/* if pp shorter than sp, it should not be restored */
475 		if (!*pp && *sp) {
476 			sp += strspn(sp, "/");
477 			if (strlen(sp) > 0)
478 				return (NULL);
479 		}
480 	}
481 
482 	if (np)
483 		np += strspn(np, "/");
484 	else
485 		np = "";
486 
487 	if (!tlm_cat_path(bp, np, pp)) {
488 		NDMP_LOG(LOG_ERR, "Restore path too long %s/%s.", np, pp);
489 		return (NULL);
490 	}
491 
492 	return (bp);
493 }
494 
495 
496 /*
497  * mknewname
498  *
499  * This is used as callback for creating the restore path. This function
500  * can handle both single destination and multiple restore paths.
501  *
502  * Make up the restore destination path for a particular file/directory, path,
503  * based on nm3_opath and nm3_dpath.  path should have matched nm3_opath
504  * in some way.
505  */
506 char *
507 mknewname(struct rs_name_maker *rnp, char *buf, int idx, char *path)
508 {
509 	char *rv;
510 	ndmp_lbr_params_t *nlp;
511 	mem_ndmp_name_v3_t *ep;
512 
513 	rv = NULL;
514 	if (!buf) {
515 		NDMP_LOG(LOG_DEBUG, "buf is NULL");
516 	} else if (!path) {
517 		NDMP_LOG(LOG_DEBUG, "path is NULL");
518 	} else if ((nlp = rnp->rn_nlp) == 0) {
519 		NDMP_LOG(LOG_DEBUG, "rnp->rn_nlp is NULL");
520 	} else if (!nlp->nlp_params) {
521 		NDMP_LOG(LOG_DEBUG, "nlp->nlp_params is NULL");
522 	} else
523 		if (!ndmp_full_restore_path) {
524 			if (idx < 0 || idx >= (int)nlp->nlp_nfiles) {
525 				NDMP_LOG(LOG_DEBUG,
526 				    "Invalid idx %d range (0, %d)",
527 				    idx, nlp->nlp_nfiles);
528 			} else if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(
529 			    nlp->nlp_params, idx))) {
530 				NDMP_LOG(LOG_DEBUG,
531 				    "nlist entry %d is NULL", idx);
532 			} else {
533 				rv = mkrsp(buf, path, ep->nm3_opath,
534 				    ep->nm3_dpath);
535 
536 				NDMP_LOG(LOG_DEBUG,
537 				    "idx %d org \"%s\" dst \"%s\"",
538 				    idx, ep->nm3_opath, ep->nm3_dpath);
539 				if (rv) {
540 					NDMP_LOG(LOG_DEBUG,
541 					    "path \"%s\": \"%s\"", path, rv);
542 				} else {
543 					NDMP_LOG(LOG_DEBUG,
544 					    "path \"%s\": NULL", path);
545 				}
546 			}
547 		} else {
548 			if (!tlm_cat_path(buf, nlp->nlp_restore_path, path)) {
549 				NDMP_LOG(LOG_ERR, "Path too long %s/%s.",
550 				    nlp->nlp_restore_path, path);
551 				rv = NULL;
552 			} else {
553 				rv = buf;
554 				NDMP_LOG(LOG_DEBUG,
555 				    "path \"%s\": \"%s\"", path, rv);
556 			}
557 		}
558 
559 	return (rv);
560 }
561 
562 
563 /*
564  * chopslash
565  *
566  * Remove the slash from the end of the given path
567  */
568 static void
569 chopslash(char *cp)
570 {
571 	int ln;
572 
573 	if (!cp || !*cp)
574 		return;
575 
576 	ln = strlen(cp);
577 	cp += ln - 1; /* end of the string */
578 	while (ln > 0 && *cp == '/') {
579 		*cp-- = '\0';
580 		ln--;
581 	}
582 }
583 
584 
585 /*
586  * joinpath
587  *
588  * Join two given paths
589  */
590 static char *
591 joinpath(char *bp, char *pp, char *np)
592 {
593 	if (pp && *pp) {
594 		if (np && *np)
595 			(void) tlm_cat_path(bp, pp, np);
596 		else
597 			(void) strlcpy(bp, pp, TLM_MAX_PATH_NAME);
598 	} else {
599 		if (np && *np)
600 			(void) strlcpy(bp, np, TLM_MAX_PATH_NAME);
601 		else
602 			bp = NULL;
603 	}
604 
605 	return (bp);
606 }
607 
608 
609 /*
610  * voliswr
611  *
612  * Is the volume writable?
613  */
614 static int
615 voliswr(char *path)
616 {
617 	int rv;
618 
619 	if (!path)
620 		return (0);
621 
622 	rv = !fs_is_rdonly(path) && !fs_is_chkpntvol(path);
623 	NDMP_LOG(LOG_DEBUG, "%d path \"%s\"", rv, path);
624 	return (rv);
625 
626 }
627 
628 
629 /*
630  * is_valid_backup_dir_v3
631  *
632  * Checks the validity of the backup path.  Backup path should
633  * have the following characteristics to be valid:
634  *	1) It should be an absolute path.
635  *	2) It should be a directory.
636  *	3) It should not be checkpoint root directory
637  *	4) If the file system is read-only, the backup path
638  *	    should be a checkpointed path.  Checkpoint cannot
639  *	    be created on a read-only file system.
640  *
641  * Parameters:
642  *   params (input) - pointer to the parameters structure.
643  *   bkpath (input) - the backup path
644  *
645  * Returns:
646  *   TRUE: if everything's OK
647  *   FALSE: otherwise.
648  */
649 static boolean_t
650 is_valid_backup_dir_v3(ndmpd_module_params_t *params, char *bkpath)
651 {
652 	char *msg;
653 	struct stat64 st;
654 
655 	if (*bkpath != '/') {
656 		MOD_LOGV3(params, NDMP_LOG_ERROR,
657 		    "Relative backup path not allowed \"%s\".\n", bkpath);
658 		return (FALSE);
659 	}
660 	if (stat64(bkpath, &st) < 0) {
661 		msg = strerror(errno);
662 		MOD_LOGV3(params, NDMP_LOG_ERROR, "\"%s\" %s.\n",
663 		    bkpath, msg);
664 		return (FALSE);
665 	}
666 	if (!S_ISDIR(st.st_mode)) {
667 		/* only directories can be specified as the backup path */
668 		MOD_LOGV3(params, NDMP_LOG_ERROR,
669 		    "\"%s\" is not a directory.\n", bkpath);
670 		return (FALSE);
671 	}
672 	if (fs_is_rdonly(bkpath) && !fs_is_chkpntvol(bkpath) &&
673 	    fs_is_chkpnt_enabled(bkpath)) {
674 		/* it is not a chkpnted path */
675 		MOD_LOGV3(params, NDMP_LOG_ERROR,
676 		    "\"%s\" is not a checkpointed path.\n", bkpath);
677 		return (FALSE);
678 	}
679 
680 	return (TRUE);
681 }
682 
683 
684 /*
685  * log_date_token_v3
686  *
687  * Log the token sequence number and also the date of the
688  * last backup for token-based backup in the system log
689  * and also send them as normal log to the client.
690  *
691  * Parameters:
692  *   params (input) - pointer to the parameters structure
693  *   nlp (input) - pointer to the nlp structure
694  *
695  * Returns:
696  *   void
697  */
698 static void
699 log_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
700 {
701 	MOD_LOGV3(params, NDMP_LOG_NORMAL, "Token sequence counter: %d.\n",
702 	    nlp->nlp_tokseq);
703 
704 	MOD_LOGV3(params, NDMP_LOG_NORMAL, "Date of the last backup: %s.\n",
705 	    cctime(&nlp->nlp_tokdate));
706 
707 	if (nlp->nlp_dmpnm) {
708 		MOD_LOGV3(params, NDMP_LOG_NORMAL,
709 		    "Backup date log file name: \"%s\".\n", nlp->nlp_dmpnm);
710 	}
711 }
712 
713 
714 /*
715  * log_lbr_bk_v3
716  *
717  * Log the backup level and data of the backup for LBR-type
718  * backup in the system log and also send them as normal log
719  * to the client.
720  *
721  * Parameters:
722  *   params (input) - pointer to the parameters structure
723  *   nlp (input) - pointer to the nlp structure
724  *
725  * Returns:
726  *   void
727  */
728 static void
729 log_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
730 {
731 	MOD_LOGV3(params, NDMP_LOG_NORMAL,
732 	    "Date of this level '%c': %s.\n", nlp->nlp_clevel,
733 	    cctime(&nlp->nlp_cdate));
734 
735 	if (nlp->nlp_dmpnm) {
736 		MOD_LOGV3(params, NDMP_LOG_NORMAL,
737 		    "Backup date log file name: \"%s\".\n", nlp->nlp_dmpnm);
738 	}
739 }
740 
741 
742 /*
743  * log_level_v3
744  *
745  * Log the backup level and date of the last and the current
746  * backup for level-type backup in the system log and also
747  * send them as normal log to the client.
748  *
749  * Parameters:
750  *   params (input) - pointer to the parameters structure
751  *   nlp (input) - pointer to the nlp structure
752  *
753  * Returns:
754  *   void
755  */
756 static void
757 log_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
758 {
759 	MOD_LOGV3(params, NDMP_LOG_NORMAL,
760 	    "Date of the last level '%u': %s.\n", nlp->nlp_llevel,
761 	    cctime(&nlp->nlp_ldate));
762 
763 	MOD_LOGV3(params, NDMP_LOG_NORMAL,
764 	    "Date of this level '%u': %s.\n", nlp->nlp_clevel,
765 	    cctime(&nlp->nlp_cdate));
766 
767 	MOD_LOGV3(params, NDMP_LOG_NORMAL, "Update: %s.\n",
768 	    NDMP_TORF(NLP_ISSET(nlp, NLPF_UPDATE)));
769 }
770 
771 
772 /*
773  * log_bk_params_v3
774  *
775  * Dispatcher function which calls the appropriate function
776  * for logging the backup date and level in the system log
777  * and also send them as normal log message to the client.
778  *
779  * Parameters:
780  *   session (input) - pointer to the session
781  *   params (input) - pointer to the parameters structure
782  *   nlp (input) - pointer to the nlp structure
783  *
784  * Returns:
785  *   void
786  */
787 static void
788 log_bk_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
789     ndmp_lbr_params_t *nlp)
790 {
791 	MOD_LOGV3(params, NDMP_LOG_NORMAL, "Backing up \"%s\".\n",
792 	    nlp->nlp_backup_path);
793 
794 	if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_LOCAL)
795 		MOD_LOGV3(params, NDMP_LOG_NORMAL,
796 		    "Tape record size: %d.\n",
797 		    session->ns_mover.md_record_size);
798 
799 	MOD_LOGV3(params, NDMP_LOG_NORMAL, "File history: %c.\n",
800 	    NDMP_YORN(NLP_ISSET(nlp, NLPF_FH)));
801 
802 	if (NLP_ISSET(nlp, NLPF_TOKENBK))
803 		log_date_token_v3(params, nlp);
804 	else if (NLP_ISSET(nlp, NLPF_LBRBK))
805 		log_lbr_bk_v3(params, nlp);
806 	else if (NLP_ISSET(nlp, NLPF_LEVELBK))
807 		log_level_v3(params, nlp);
808 	else {
809 		MOD_LOGV3(params, NDMP_LOG_ERROR,
810 		    "Internal error: backup level not defined for \"%s\".\n",
811 		    nlp->nlp_backup_path);
812 	}
813 }
814 
815 
816 /*
817  * get_update_env_v3
818  *
819  * Is the UPDATE environment variable specified?  If it is
820  * the corresponding flag is set in the flags field of the
821  * nlp structure, otherwise the flag is cleared.
822  *
823  * Parameters:
824  *   params (input) - pointer to the parameters structure
825  *   nlp (input) - pointer to the nlp structure
826  *
827  * Returns:
828  *   void
829  */
830 static void
831 get_update_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
832 {
833 	char *envp;
834 
835 	envp = MOD_GETENV(params, "UPDATE");
836 	if (!envp) {
837 		NLP_SET(nlp, NLPF_UPDATE);
838 		NDMP_LOG(LOG_DEBUG,
839 		    "env(UPDATE) not defined, default to TRUE");
840 	} else {
841 		NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp);
842 		if (IS_YORT(*envp))
843 			NLP_SET(nlp, NLPF_UPDATE);
844 		else
845 			NLP_UNSET(nlp, NLPF_UPDATE);
846 	}
847 }
848 
849 
850 /*
851  * get_hist_env_v3
852  *
853  * Is backup history requested?  If it is, the corresponding
854  * flag is set in the flags field of the nlp structure, otherwise
855  * the flag is cleared.
856  *
857  * Parameters:
858  *   params (input) - pointer to the parameters structure
859  *   nlp (input) - pointer to the nlp structure
860  *
861  * Returns:
862  *   void
863  */
864 static void
865 get_hist_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
866 {
867 	char *envp;
868 
869 	envp = MOD_GETENV(params, "HIST");
870 	if (!envp) {
871 		NDMP_LOG(LOG_DEBUG, "env(HIST) not defined");
872 		NLP_UNSET(nlp, NLPF_FH);
873 	} else {
874 		NDMP_LOG(LOG_DEBUG, "env(HIST): \"%s\"", envp);
875 		if (IS_YORT(*envp) || IS_F(*envp))
876 			NLP_SET(nlp, NLPF_FH);
877 		else
878 			NLP_UNSET(nlp, NLPF_FH);
879 
880 		/* Force file format if specified */
881 		if (IS_F(*envp)) {
882 			params->mp_file_history_path_func =
883 			    ndmpd_api_file_history_file_v3;
884 			params->mp_file_history_dir_func = 0;
885 			params->mp_file_history_node_func = 0;
886 		}
887 	}
888 }
889 
890 
891 /*
892  * get_exc_env_v3
893  *
894  * Gets the EXCLUDE environment variable and breaks it
895  * into strings.  The separator of the EXCLUDE environment
896  * variable is the ',' character.
897  *
898  * Parameters:
899  *   params (input) - pointer to the parameters structure
900  *   nlp (input) - pointer to the nlp structure
901  *
902  * Returns:
903  *   void
904  */
905 static void
906 get_exc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
907 {
908 	char *envp;
909 
910 	envp = MOD_GETENV(params, "EXCLUDE");
911 	if (!envp) {
912 		NDMP_LOG(LOG_DEBUG, "env(EXCLUDE) not defined");
913 		nlp->nlp_exl = NULL;
914 	} else {
915 		NDMP_LOG(LOG_DEBUG, "env(EXCLUDE): \"%s\"", envp);
916 		nlp->nlp_exl = split_env(envp, ',');
917 		prl(nlp->nlp_exl);
918 	}
919 }
920 
921 
922 /*
923  * get_inc_env_v3
924  *
925  * Gets the FILES environment variable that shows which files
926  * should be backed up, and breaks it into strings.  The
927  * separator of the FILES environment variable is the space
928  * character.
929  *
930  * Parameters:
931  *   params (input) - pointer to the parameters structure
932  *   nlp (input) - pointer to the nlp structure
933  *
934  * Returns:
935  *   void
936  */
937 static void
938 get_inc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
939 {
940 	char *envp;
941 
942 	envp = MOD_GETENV(params, "FILES");
943 	if (!envp) {
944 		NDMP_LOG(LOG_DEBUG, "env(FILES) not defined");
945 		nlp->nlp_inc = NULL;
946 	} else {
947 		NDMP_LOG(LOG_DEBUG, "env(FILES): \"%s\"", envp);
948 		nlp->nlp_inc = split_env(envp, ' ');
949 		prl(nlp->nlp_inc);
950 	}
951 }
952 
953 
954 /*
955  * get_direct_env_v3
956  *
957  * Gets the DIRECT environment variable that shows if the fh_info should
958  * be sent to the client or not.
959  *
960  * Parameters:
961  *   params (input) - pointer to the parameters structure
962  *   nlp (input) - pointer to the nlp structure
963  *
964  * Returns:
965  *   void
966  */
967 static void
968 get_direct_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
969 {
970 	char *envp;
971 
972 	/*
973 	 * We should send the fh_info to the DMA, unless it is specified
974 	 * in the request that we should not send fh_info.
975 	 * At the moment we do not support DAR on directories, so if the user
976 	 * needs to restore a directory they should disable the DAR.
977 	 */
978 	if (params->mp_operation == NDMP_DATA_OP_RECOVER && !ndmp_dar_support) {
979 		NDMP_LOG(LOG_DEBUG, "Direct Access Restore Disabled");
980 		NLP_UNSET(nlp, NLPF_DIRECT);
981 		MOD_LOGV3(params, NDMP_LOG_NORMAL,
982 		    "DAR is disabled. Running Restore without DAR");
983 		return;
984 	}
985 
986 	/*
987 	 * Regardless of whether DIRECT is defined at backup time we send
988 	 * back the fh_info, for some clients do not use get_backup_attrs.
989 	 * If operation is restore we have to unset the DIRECT, for
990 	 * some clients do not set the MOVER window.
991 	 */
992 	if (params->mp_operation == NDMP_DATA_OP_BACKUP) {
993 		NDMP_LOG(LOG_DEBUG, "backup default env(DIRECT): YES");
994 		NLP_SET(nlp, NLPF_DIRECT);
995 	} else {
996 
997 		envp = MOD_GETENV(params, "DIRECT");
998 		if (!envp) {
999 			NDMP_LOG(LOG_DEBUG, "env(DIRECT) not defined");
1000 			NLP_UNSET(nlp, NLPF_DIRECT);
1001 		} else {
1002 			NDMP_LOG(LOG_DEBUG, "env(DIRECT): \"%s\"", envp);
1003 			if (IS_YORT(*envp)) {
1004 				NLP_SET(nlp, NLPF_DIRECT);
1005 				NDMP_LOG(LOG_DEBUG,
1006 				    "Direct Access Restore Enabled");
1007 			} else {
1008 				NLP_UNSET(nlp, NLPF_DIRECT);
1009 				NDMP_LOG(LOG_DEBUG,
1010 				    "Direct Access Restore Disabled");
1011 			}
1012 		}
1013 	}
1014 
1015 	if (NLP_ISSET(nlp, NLPF_DIRECT)) {
1016 		if (params->mp_operation == NDMP_DATA_OP_BACKUP)
1017 			MOD_LOGV3(params, NDMP_LOG_NORMAL,
1018 			    "Direct Access Restore information is supported");
1019 		else
1020 			MOD_LOGV3(params, NDMP_LOG_NORMAL,
1021 			    "Running Restore with Direct Access Restore");
1022 	} else {
1023 		if (params->mp_operation == NDMP_DATA_OP_BACKUP)
1024 			MOD_LOGV3(params, NDMP_LOG_NORMAL,
1025 			    "Direct Access Restore is not supported");
1026 		else
1027 			MOD_LOGV3(params, NDMP_LOG_NORMAL,
1028 			    "Running Restore without Direct Access Restore");
1029 	}
1030 }
1031 
1032 
1033 /*
1034  * get_date_token_v3
1035  *
1036  * Parse the token passed as the argument.  Evaluate it and
1037  * issue any warning or error if needed.  Save the date and
1038  * token sequence in the nlp structure fields.  The sequence
1039  * number in the token should be less than hard-limit.  If
1040  * it's between soft and hard limit, a warning is issued.
1041  * There is a configurable limit which should be less than
1042  * the soft-limit saved in ndmp_max_tok_seq variable.
1043  *
1044  * The NLPF_TOKENBK flag is set in the nlp flags field to
1045  * show that the backup type is token-based.
1046  *
1047  * Parameters:
1048  *   params (input) - pointer to the parameters structure
1049  *   nlp (input) - pointer to the nlp structure
1050  *   basedate (input) - the value of the BASE_DATE environment
1051  *	variable.
1052  *
1053  * Returns:
1054  *   NDMP_NO_ERR: on success
1055  *   != NDMP_NO_ERR: Otherwise
1056  *
1057  */
1058 static ndmp_error
1059 get_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp,
1060     char *basedate)
1061 {
1062 	char *endp;
1063 	uint_t seq;
1064 	ndmp_error rv;
1065 	time_t tstamp;
1066 	u_longlong_t tok;
1067 
1068 	if (!params || !nlp || !basedate || !*basedate)
1069 		return (NDMP_ILLEGAL_ARGS_ERR);
1070 
1071 	if (MOD_GETENV(params, "LEVEL")) {
1072 		MOD_LOGV3(params, NDMP_LOG_WARNING,
1073 		    "Both BASE_DATE and LEVEL environment variables "
1074 		    "defined.\n");
1075 		MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
1076 		    "BASE_DATE is being used for this backup.\n");
1077 	}
1078 
1079 	tok = strtoll(basedate, &endp, 10);
1080 	if (endp == basedate) {
1081 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1082 		    "Invalid BASE_DATE environment variable: \"%s\".\n",
1083 		    basedate);
1084 		return (NDMP_ILLEGAL_ARGS_ERR);
1085 	}
1086 
1087 	tstamp = tok & 0xffffffff;
1088 	seq = (tok >> 32) & 0xffffffff;
1089 	NDMP_LOG(LOG_DEBUG, "basedate \"%s\" %lld seq %u tstamp %u",
1090 	    basedate, tok, seq, tstamp);
1091 
1092 	if ((int)seq > ndmp_get_max_tok_seq()) {
1093 		rv = NDMP_ILLEGAL_ARGS_ERR;
1094 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1095 		    "The sequence counter of the token exceeds the "
1096 		    "maximum permitted value.\n");
1097 		MOD_LOGCONTV3(params, NDMP_LOG_ERROR,
1098 		    "Token sequence: %u, maxiumum value: %u.\n",
1099 		    seq, ndmp_get_max_tok_seq());
1100 	} else if (seq >= NDMP_TOKSEQ_HLIMIT) {
1101 		rv = NDMP_ILLEGAL_ARGS_ERR;
1102 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1103 		    "The sequence counter the of token exceeds the "
1104 		    "hard-limit.\n");
1105 		MOD_LOGCONTV3(params, NDMP_LOG_ERROR,
1106 		    "Token sequence: %u, hard-limit: %u.\n",
1107 		    seq, NDMP_TOKSEQ_HLIMIT);
1108 	} else {
1109 		rv = NDMP_NO_ERR;
1110 		/*
1111 		 * Issue a warning if the seq is equal to the maximum
1112 		 * permitted seq number or equal to the soft-limit.
1113 		 */
1114 		if (seq == NDMP_TOKSEQ_SLIMIT) {
1115 			MOD_LOGV3(params, NDMP_LOG_WARNING,
1116 			    "The sequence counter of the token has reached "
1117 			    "the soft-limit.\n");
1118 			MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
1119 			    "Token sequence: %u, soft-limit: %u.\n",
1120 			    seq, NDMP_TOKSEQ_SLIMIT);
1121 		} else if ((int)seq == ndmp_get_max_tok_seq()) {
1122 			MOD_LOGV3(params, NDMP_LOG_WARNING,
1123 			    "The sequence counter of the token has reached "
1124 			    "the maximum permitted value.\n");
1125 			MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
1126 			    "Token sequence: %u, maxiumum value: %u.\n",
1127 			    seq, ndmp_get_max_tok_seq());
1128 		}
1129 
1130 		/*
1131 		 * The current seq is equal to the seq field of the
1132 		 * token.  It will be increased after successful backup
1133 		 * before setting the DUMP_DATE environment variable.
1134 		 */
1135 		nlp->nlp_dmpnm = MOD_GETENV(params, "DMP_NAME");
1136 		NLP_SET(nlp, NLPF_TOKENBK);
1137 		NLP_UNSET(nlp, NLPF_LEVELBK);
1138 		NLP_UNSET(nlp, NLPF_LBRBK);
1139 		nlp->nlp_tokseq = seq;
1140 		nlp->nlp_tokdate = tstamp;
1141 		/*
1142 		 * The value of nlp_cdate will be set to the checkpoint
1143 		 * creation time after it is created.
1144 		 */
1145 	}
1146 
1147 	return (rv);
1148 }
1149 
1150 
1151 /*
1152  * get_lbr_bk_v3
1153  *
1154  * Sets the level fields of the nlp structures for
1155  * LBR-type backup.  The NLPF_LBRBK flag of the
1156  * nlp flags is also set to show the backup type.
1157  *
1158  * Parameters:
1159  *   params (input) - pointer to the parameters structure
1160  *   nlp (input) - pointer to the nlp structure
1161  *   type (input) - the backup level: 'F', 'A', 'I', 'D' or
1162  *	their lower-case values.
1163  *
1164  * Returns:
1165  *   NDMP_NO_ERR: on success
1166  *   != NDMP_NO_ERR: Otherwise
1167  */
1168 static ndmp_error
1169 get_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, char *type)
1170 {
1171 	if (!params || !nlp || !type || !*type)
1172 		return (NDMP_ILLEGAL_ARGS_ERR);
1173 
1174 	NLP_SET(nlp, NLPF_LBRBK);
1175 	NLP_UNSET(nlp, NLPF_TOKENBK);
1176 	NLP_UNSET(nlp, NLPF_LEVELBK);
1177 	nlp->nlp_dmpnm = MOD_GETENV(params, "DMP_NAME");
1178 	nlp->nlp_llevel = toupper(*type);
1179 	nlp->nlp_ldate = (time_t)0;
1180 	nlp->nlp_clevel = nlp->nlp_llevel;
1181 	(void) time(&nlp->nlp_cdate);
1182 
1183 	return (NDMP_NO_ERR);
1184 }
1185 
1186 
1187 /*
1188  * get_backup_level_v3
1189  *
1190  * Gets the backup level from the environment variables.  If
1191  * BASE_DATE is specified, it will be used, otherwise LEVEL
1192  * will be used.  If neither is specified, LEVEL = '0' is
1193  * assumed.
1194  *
1195  * Parameters:
1196  *   params (input) - pointer to the parameters structure
1197  *   nlp (input) - pointer to the nlp structure
1198  *
1199  * Returns:
1200  *   NDMP_NO_ERR: on success
1201  *   != NDMP_NO_ERR: Otherwise
1202  */
1203 static ndmp_error
1204 get_backup_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1205 {
1206 	char *envp;
1207 	ndmp_error rv;
1208 
1209 	/*
1210 	 * If the BASE_DATE env variable is specified use it, otherwise
1211 	 * look to see if LEVEL is specified.  If LEVEL is not
1212 	 * specified either, backup level '0' must be made. Level backup
1213 	 * does not clear the archive bit.
1214 	 *
1215 	 * If LEVEL environment varaible is specified, values for
1216 	 * 'F', 'D', 'I' and 'A' (for 'Full', 'Differential',
1217 	 * 'Incremental', and 'Archive' is checked first.  Then
1218 	 * level '0' to '9' will be checked.
1219 	 *
1220 	 * LEVEL environment variable can hold only one character.
1221 	 * If its length is longer than 1, an error is returned.
1222 	 */
1223 	envp = MOD_GETENV(params, "BASE_DATE");
1224 	if (envp)
1225 		return (get_date_token_v3(params, nlp, envp));
1226 
1227 
1228 	envp = MOD_GETENV(params, "LEVEL");
1229 	if (!envp) {
1230 		NDMP_LOG(LOG_DEBUG, "env(LEVEL) not defined, default to 0");
1231 		NLP_SET(nlp, NLPF_LEVELBK);
1232 		NLP_UNSET(nlp, NLPF_LBRBK);
1233 		NLP_UNSET(nlp, NLPF_TOKENBK);
1234 		nlp->nlp_llevel = 0;
1235 		nlp->nlp_ldate = 0;
1236 		nlp->nlp_clevel = 0;
1237 		/*
1238 		 * The value of nlp_cdate will be set to the checkpoint
1239 		 * creation time after it is created.
1240 		 */
1241 		return (NDMP_NO_ERR);
1242 	}
1243 
1244 	if (*(envp+1) != '\0') {
1245 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1246 		    "Invalid backup level \"%s\".\n", envp);
1247 		return (NDMP_ILLEGAL_ARGS_ERR);
1248 	}
1249 
1250 	if (IS_LBR_BKTYPE(*envp))
1251 		return (get_lbr_bk_v3(params, nlp, envp));
1252 
1253 	if (!isdigit(*envp)) {
1254 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1255 		    "Invalid backup level \"%s\".\n", envp);
1256 		return (NDMP_ILLEGAL_ARGS_ERR);
1257 	}
1258 
1259 	NLP_SET(nlp, NLPF_LEVELBK);
1260 	NLP_UNSET(nlp, NLPF_LBRBK);
1261 	NLP_UNSET(nlp, NLPF_TOKENBK);
1262 	nlp->nlp_llevel = *envp - '0';
1263 	nlp->nlp_ldate = 0;
1264 	nlp->nlp_clevel = nlp->nlp_llevel;
1265 	/*
1266 	 * The value of nlp_cdate will be set to the checkpoint
1267 	 * creation time after it is created.
1268 	 */
1269 	if (ndmpd_get_dumptime(nlp->nlp_backup_path, &nlp->nlp_llevel,
1270 	    &nlp->nlp_ldate) < 0) {
1271 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1272 		    "Getting dumpdates for %s level '%c'.\n",
1273 		    nlp->nlp_backup_path, *envp);
1274 		return (NDMP_NO_MEM_ERR);
1275 	} else {
1276 		get_update_env_v3(params, nlp);
1277 		rv = NDMP_NO_ERR;
1278 	}
1279 
1280 	return (rv);
1281 }
1282 
1283 
1284 /*
1285  * save_date_token_v3
1286  *
1287  * Make the value of DUMP_DATE env variable and append the values
1288  * of the current backup in the file specified with the DMP_NAME
1289  * env variable if any file is specified.  The file will be
1290  * relative name in the backup directory path.
1291  *
1292  * Parameters:
1293  *   params (input) - pointer to the parameters structure
1294  *   nlp (input) - pointer to the nlp structure
1295  *
1296  * Returns:
1297  *   void
1298  */
1299 static void
1300 save_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1301 {
1302 	char val[QUAD_DECIMAL_LEN];
1303 	u_longlong_t tok;
1304 
1305 	if (!params || !nlp)
1306 		return;
1307 
1308 	nlp->nlp_tokseq++;
1309 	tok = ((u_longlong_t)nlp->nlp_tokseq << 32) | nlp->nlp_cdate;
1310 	(void) snprintf(val, sizeof (val), "%llu", tok);
1311 
1312 	NDMP_LOG(LOG_DEBUG, "tok: %lld %s", tok, val);
1313 
1314 	if (MOD_SETENV(params, "DUMP_DATE", val) != 0) {
1315 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1316 		    "Could not set DUMP_DATE to %s", val);
1317 	} else if (!nlp->nlp_dmpnm) {
1318 		NDMP_LOG(LOG_DEBUG, "No log file defined");
1319 	} else if (ndmpd_append_dumptime(nlp->nlp_dmpnm, nlp->nlp_backup_path,
1320 	    nlp->nlp_tokseq, nlp->nlp_tokdate) < 0) {
1321 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1322 		    "Saving backup date for \"%s\" in \"%s\".\n",
1323 		    nlp->nlp_backup_path, nlp->nlp_dmpnm);
1324 	}
1325 }
1326 
1327 
1328 /*
1329  * save_lbr_bk_v3
1330  *
1331  * Append the backup type and date in the DMP_NAME file for
1332  * LBR-type backup if any file is specified.
1333  *
1334  * Parameters:
1335  *   params (input) - pointer to the parameters structure
1336  *   nlp (input) - pointer to the nlp structure
1337  *
1338  * Returns:
1339  *   void
1340  */
1341 static void
1342 save_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1343 {
1344 	if (!params || !nlp)
1345 		return;
1346 
1347 	if (!nlp->nlp_dmpnm) {
1348 		NDMP_LOG(LOG_DEBUG, "No log file defined");
1349 	} else if (ndmpd_append_dumptime(nlp->nlp_dmpnm, nlp->nlp_backup_path,
1350 	    nlp->nlp_clevel, nlp->nlp_cdate) < 0) {
1351 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1352 		    "Saving backup date for \"%s\" in \"%s\".\n",
1353 		    nlp->nlp_backup_path, nlp->nlp_dmpnm);
1354 	}
1355 }
1356 
1357 
1358 /*
1359  * save_level_v3
1360  *
1361  * Save the date and level of the current backup in the dumpdates
1362  * file.
1363  *
1364  * Parameters:
1365  *   params (input) - pointer to the parameters structure
1366  *   nlp (input) - pointer to the nlp structure
1367  *
1368  * Returns:
1369  *   void
1370  */
1371 static void
1372 save_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1373 {
1374 	if (!params || !nlp)
1375 		return;
1376 
1377 	if (!NLP_SHOULD_UPDATE(nlp)) {
1378 		NDMP_LOG(LOG_DEBUG, "update not requested");
1379 	} else if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel,
1380 	    nlp->nlp_cdate) < 0) {
1381 		MOD_LOGV3(params, NDMP_LOG_ERROR, "Logging backup date.\n");
1382 	}
1383 }
1384 
1385 
1386 /*
1387  * save_backup_date_v3
1388  *
1389  * A dispatcher function to call the corresponding save function
1390  * based on the backup type.
1391  *
1392  * Parameters:
1393  *   params (input) - pointer to the parameters structure
1394  *   nlp (input) - pointer to the nlp structure
1395  *
1396  * Returns:
1397  *   void
1398  */
1399 static void
1400 save_backup_date_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1401 {
1402 	if (!params || !nlp)
1403 		return;
1404 
1405 	if (NLP_ISSET(nlp, NLPF_TOKENBK))
1406 		save_date_token_v3(params, nlp);
1407 	else if (NLP_ISSET(nlp, NLPF_LBRBK))
1408 		save_lbr_bk_v3(params, nlp);
1409 	else if (NLP_ISSET(nlp, NLPF_LEVELBK))
1410 		save_level_v3(params, nlp);
1411 	else {
1412 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1413 		    "Internal error: lost backup level type for \"%s\".\n",
1414 		    nlp->nlp_backup_path);
1415 	}
1416 }
1417 
1418 
1419 /*
1420  * backup_alloc_structs_v3
1421  *
1422  * Create the structures for V3 backup.  This includes:
1423  *	Job stats
1424  *	Reader writer IPC
1425  *	File history callback structure
1426  *
1427  * Parameters:
1428  *   session (input) - pointer to the session
1429  *   jname (input) - name assigned to the current backup for
1430  *	job stats strucure
1431  *
1432  * Returns:
1433  *   0: on success
1434  *   -1: otherwise
1435  */
1436 static int
1437 backup_alloc_structs_v3(ndmpd_session_t *session, char *jname)
1438 {
1439 	int n;
1440 	long xfer_size;
1441 	ndmp_lbr_params_t *nlp;
1442 	tlm_commands_t *cmds;
1443 
1444 	nlp = ndmp_get_nlp(session);
1445 	if (!nlp) {
1446 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1447 		return (-1);
1448 	}
1449 
1450 	nlp->nlp_jstat = tlm_new_job_stats(jname);
1451 	if (!nlp->nlp_jstat) {
1452 		NDMP_LOG(LOG_DEBUG, "Creating job stats");
1453 		return (-1);
1454 	}
1455 
1456 	cmds = &nlp->nlp_cmds;
1457 	(void) memset(cmds, 0, sizeof (*cmds));
1458 
1459 	xfer_size = ndmp_buffer_get_size(session);
1460 	if (xfer_size < 512*KILOBYTE) {
1461 		/*
1462 		 * Read multiple of mover_record_size near to 512K.  This
1463 		 * will prevent the data being copied in the mover buffer
1464 		 * when we write the data.
1465 		 */
1466 		n = 512 * KILOBYTE / xfer_size;
1467 		if (n <= 0)
1468 			n = 1;
1469 		xfer_size *= n;
1470 		NDMP_LOG(LOG_DEBUG, "Adjusted read size: %d",
1471 		    xfer_size);
1472 	}
1473 
1474 	cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, xfer_size);
1475 	if (!cmds->tcs_command) {
1476 		tlm_un_ref_job_stats(jname);
1477 		return (-1);
1478 	}
1479 
1480 	nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
1481 	    ndmpd_fhpath_v3_cb, ndmpd_fhdir_v3_cb, ndmpd_fhnode_v3_cb);
1482 	if (!nlp->nlp_logcallbacks) {
1483 		tlm_release_reader_writer_ipc(cmds->tcs_command);
1484 		tlm_un_ref_job_stats(jname);
1485 		return (-1);
1486 	}
1487 	nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
1488 	nlp->nlp_restored = NULL;
1489 
1490 	return (0);
1491 }
1492 
1493 
1494 /*
1495  * restore_alloc_structs_v3
1496  *
1497  * Create the structures for V3 Restore.  This includes:
1498  *	Job stats
1499  *	Reader writer IPC
1500  *	File recovery callback structure
1501  *
1502  * Parameters:
1503  *   session (input) - pointer to the session
1504  *   jname (input) - name assigned to the current backup for
1505  *	job stats strucure
1506  *
1507  * Returns:
1508  *   0: on success
1509  *   -1: otherwise
1510  */
1511 int
1512 restore_alloc_structs_v3(ndmpd_session_t *session, char *jname)
1513 {
1514 	long xfer_size;
1515 	ndmp_lbr_params_t *nlp;
1516 	tlm_commands_t *cmds;
1517 
1518 	nlp = ndmp_get_nlp(session);
1519 	if (!nlp) {
1520 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1521 		return (-1);
1522 	}
1523 
1524 	/* this is used in ndmpd_path_restored_v3() */
1525 	nlp->nlp_lastidx = -1;
1526 
1527 	nlp->nlp_jstat = tlm_new_job_stats(jname);
1528 	if (!nlp->nlp_jstat) {
1529 		NDMP_LOG(LOG_DEBUG, "Creating job stats");
1530 		return (-1);
1531 	}
1532 
1533 	cmds = &nlp->nlp_cmds;
1534 	(void) memset(cmds, 0, sizeof (*cmds));
1535 
1536 	xfer_size = ndmp_buffer_get_size(session);
1537 	cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
1538 	if (!cmds->tcs_command) {
1539 		tlm_un_ref_job_stats(jname);
1540 		return (-1);
1541 	}
1542 
1543 	nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
1544 	    ndmpd_path_restored_v3, NULL, NULL);
1545 	if (!nlp->nlp_logcallbacks) {
1546 		tlm_release_reader_writer_ipc(cmds->tcs_command);
1547 		tlm_un_ref_job_stats(jname);
1548 		return (-1);
1549 	}
1550 	nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
1551 
1552 	nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0);
1553 	if (nlp->nlp_rsbm < 0) {
1554 		NDMP_LOG(LOG_ERR, "Out of memory.");
1555 		lbrlog_callbacks_done(nlp->nlp_logcallbacks);
1556 		tlm_release_reader_writer_ipc(cmds->tcs_command);
1557 		tlm_un_ref_job_stats(jname);
1558 		return (-1);
1559 	}
1560 
1561 	return (0);
1562 }
1563 
1564 
1565 /*
1566  * free_structs_v3
1567  *
1568  * Release the resources allocated by backup_alloc_structs_v3
1569  * function.
1570  *
1571  * Parameters:
1572  *   session (input) - pointer to the session
1573  *   jname (input) - name assigned to the current backup for
1574  *	job stats strucure
1575  *
1576  * Returns:
1577  *   void
1578  */
1579 /*ARGSUSED*/
1580 static void
1581 free_structs_v3(ndmpd_session_t *session, char *jname)
1582 {
1583 	ndmp_lbr_params_t *nlp;
1584 	tlm_commands_t *cmds;
1585 
1586 	nlp = ndmp_get_nlp(session);
1587 	if (!nlp) {
1588 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1589 		return;
1590 	}
1591 	cmds = &nlp->nlp_cmds;
1592 	if (!cmds) {
1593 		NDMP_LOG(LOG_DEBUG, "cmds == NULL");
1594 		return;
1595 	}
1596 
1597 	if (nlp->nlp_logcallbacks) {
1598 		lbrlog_callbacks_done(nlp->nlp_logcallbacks);
1599 		nlp->nlp_logcallbacks = NULL;
1600 	} else
1601 		NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL");
1602 
1603 	if (cmds->tcs_command) {
1604 		if (cmds->tcs_command->tc_buffers != NULL)
1605 			tlm_release_reader_writer_ipc(cmds->tcs_command);
1606 		else
1607 			NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL");
1608 		cmds->tcs_command = NULL;
1609 	} else
1610 		NDMP_LOG(LOG_DEBUG, "COMMAND == NULL");
1611 
1612 	if (nlp->nlp_bkmap >= 0) {
1613 		(void) dbm_free(nlp->nlp_bkmap);
1614 		nlp->nlp_bkmap = -1;
1615 	}
1616 
1617 	if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) {
1618 		if (nlp->nlp_rsbm < 0) {
1619 			NDMP_LOG(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm);
1620 		} else {
1621 			(void) bm_free(nlp->nlp_rsbm);
1622 			nlp->nlp_rsbm = -1;
1623 		}
1624 	}
1625 }
1626 
1627 
1628 /*
1629  * backup_dirv3
1630  *
1631  * Backup a directory and update the bytes processed field of the
1632  * data server.
1633  *
1634  * Parameters:
1635  *   bpp (input) - pointer to the backup parameters structure
1636  *   pnp (input) - pointer to the path node
1637  *   enp (input) - pointer to the entry node
1638  *
1639  * Returns:
1640  *   0: on success
1641  *   != 0: otherwise
1642  */
1643 static int
1644 backup_dirv3(bk_param_v3_t *bpp, fst_node_t *pnp,
1645     fst_node_t *enp)
1646 {
1647 	longlong_t apos, bpos;
1648 	acl_t *aclp = NULL;
1649 	char *acltp;
1650 	struct stat64 st;
1651 	char fullpath[TLM_MAX_PATH_NAME];
1652 	char *p;
1653 
1654 	if (!bpp || !pnp || !enp) {
1655 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1656 		return (-1);
1657 	}
1658 
1659 	NDMP_LOG(LOG_DEBUG, "d(%s)", bpp->bp_tmp);
1660 
1661 	if (lstat64(bpp->bp_tmp, &st) != 0)
1662 		return (0);
1663 
1664 	if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) {
1665 		NDMP_LOG(LOG_DEBUG, "acl_get error errno=%d", errno);
1666 		return (-1);
1667 	}
1668 	if (aclp && (acltp = acl_totext(aclp,
1669 	    ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
1670 		(void) strlcpy(bpp->bp_tlmacl->acl_info.attr_info,
1671 		    acltp, TLM_MAX_ACL_TXT);
1672 		acl_free(aclp);
1673 		free(acltp);
1674 	} else {
1675 		*bpp->bp_tlmacl->acl_info.attr_info = '\0';
1676 	}
1677 
1678 	bpos = tlm_get_data_offset(bpp->bp_lcmd);
1679 
1680 	p = bpp->bp_tmp + strlen(bpp->bp_chkpnm);
1681 	if (*p == '/')
1682 		(void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s%s",
1683 		    bpp->bp_unchkpnm, p);
1684 	else
1685 		(void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s",
1686 		    bpp->bp_unchkpnm, p);
1687 
1688 	if (tm_tar_ops.tm_putdir != NULL)
1689 		(void) (tm_tar_ops.tm_putdir)(fullpath, bpp->bp_tlmacl,
1690 		    bpp->bp_lcmd, bpp->bp_js);
1691 
1692 	apos = tlm_get_data_offset(bpp->bp_lcmd);
1693 	bpp->bp_session->ns_data.dd_module.dm_stats.ms_bytes_processed +=
1694 	    apos - bpos;
1695 
1696 	return (0);
1697 }
1698 
1699 
1700 /*
1701  * backup_filev3
1702  *
1703  * Backup a file and update the bytes processed field of the
1704  * data server.
1705  *
1706  * Parameters:
1707  *   bpp (input) - pointer to the backup parameters structure
1708  *   pnp (input) - pointer to the path node
1709  *   enp (input) - pointer to the entry node
1710  *
1711  * Returns:
1712  *   0: on success
1713  *   != 0: otherwise
1714  */
1715 static int
1716 backup_filev3(bk_param_v3_t *bpp, fst_node_t *pnp,
1717     fst_node_t *enp)
1718 {
1719 	char *ent;
1720 	longlong_t rv;
1721 	longlong_t apos, bpos;
1722 	acl_t *aclp = NULL;
1723 	char *acltp;
1724 	struct stat64 st;
1725 	char fullpath[TLM_MAX_PATH_NAME];
1726 	char *p;
1727 
1728 	if (!bpp || !pnp || !enp) {
1729 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1730 		return (-1);
1731 	}
1732 
1733 	NDMP_LOG(LOG_DEBUG, "f(%s)", bpp->bp_tmp);
1734 
1735 	if (lstat64(bpp->bp_tmp, &st) != 0)
1736 		return (0);
1737 
1738 	if (!S_ISLNK(bpp->bp_tlmacl->acl_attr.st_mode)) {
1739 		if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) {
1740 			NDMP_LOG(LOG_DEBUG, "acl_get error");
1741 			return (-1);
1742 		}
1743 
1744 		if (aclp &&
1745 		    (acltp = acl_totext(aclp,
1746 		    ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
1747 			(void) strlcpy(bpp->bp_tlmacl->acl_info.attr_info,
1748 			    acltp, TLM_MAX_ACL_TXT);
1749 			acl_free(aclp);
1750 			free(acltp);
1751 		} else {
1752 			*bpp->bp_tlmacl->acl_info.attr_info = '\0';
1753 		}
1754 	}
1755 
1756 	bpos = tlm_get_data_offset(bpp->bp_lcmd);
1757 	ent = enp->tn_path ? enp->tn_path : "";
1758 
1759 	p = pnp->tn_path + strlen(bpp->bp_chkpnm);
1760 	if (*p == '/')
1761 		(void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s%s",
1762 		    bpp->bp_unchkpnm, p);
1763 	else
1764 		(void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s",
1765 		    bpp->bp_unchkpnm, p);
1766 
1767 	if (tm_tar_ops.tm_putfile != NULL)
1768 		rv = (tm_tar_ops.tm_putfile)(fullpath, ent, pnp->tn_path,
1769 		    bpp->bp_tlmacl, bpp->bp_cmds, bpp->bp_lcmd, bpp->bp_js,
1770 		    bpp->bp_session->hardlink_q);
1771 
1772 	apos = tlm_get_data_offset(bpp->bp_lcmd);
1773 	bpp->bp_session->ns_data.dd_module.dm_stats.ms_bytes_processed +=
1774 	    apos - bpos;
1775 
1776 	return (rv < 0 ? rv : 0);
1777 }
1778 
1779 
1780 /*
1781  * check_bk_args
1782  *
1783  * Check the argument of the bpp.  This is shared function between
1784  * timebk_v3 and lbrbk_v3 functions.  The checks include:
1785  *	- The bpp itself.
1786  *	- If the session pointer of the bpp is valid.
1787  *	- If the session connection to the DMA is closed.
1788  *	- If the nlp pointer of the bpp is valid.
1789  *	- If the backup is aborted.
1790  *
1791  * Parameters:
1792  *   bpp (input) - pointer to the backup parameters structure
1793  *
1794  * Returns:
1795  *   0: if everything's OK
1796  *   != 0: otherwise
1797  */
1798 static int
1799 check_bk_args(bk_param_v3_t *bpp)
1800 {
1801 	int rv;
1802 
1803 	if (!bpp) {
1804 		rv = -1;
1805 		NDMP_LOG(LOG_DEBUG, "Lost bpp");
1806 	} else if (!bpp->bp_session) {
1807 		rv = -1;
1808 		NDMP_LOG(LOG_DEBUG, "Session is NULL");
1809 	} else if (bpp->bp_session->ns_eof) {
1810 		rv = -1;
1811 		NDMP_LOG(LOG_INFO,
1812 		    "Connection client is closed for backup \"%s\"",
1813 		    bpp->bp_nlp->nlp_backup_path);
1814 	} else if (!bpp->bp_nlp) {
1815 		NDMP_LOG(LOG_DEBUG, "Lost nlp");
1816 		return (-1);
1817 	} else if (bpp->bp_session->ns_data.dd_abort) {
1818 		rv = -1;
1819 		NDMP_LOG(LOG_INFO, "Backup aborted \"%s\"",
1820 		    bpp->bp_nlp->nlp_backup_path);
1821 	} else
1822 		rv = 0;
1823 
1824 	return (rv);
1825 }
1826 
1827 
1828 /*
1829  * shouldskip
1830  *
1831  * Determines if the current entry should be skipped or it
1832  * should be backed up.
1833  *
1834  * Parameters:
1835  *   bpp (input) - pointer to the backup parameters structure
1836  *   pnp (input) - pointer to the path node
1837  *   enp (input) - pointer to the entry node
1838  *   errp (output) - pointer to the error value that should be
1839  *	returned by the caller
1840  *
1841  * Returns:
1842  *   TRUE: if the entry should not be backed up
1843  *   FALSE: otherwise
1844  */
1845 static boolean_t
1846 shouldskip(bk_param_v3_t *bpp, fst_node_t *pnp,
1847     fst_node_t *enp, int *errp)
1848 {
1849 	char *ent;
1850 	boolean_t rv;
1851 	struct stat64 *estp;
1852 
1853 	if (!bpp || !pnp || !enp || !errp) {
1854 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1855 		return (TRUE);
1856 	}
1857 
1858 	if (!enp->tn_path) {
1859 		ent = "";
1860 		estp = pnp->tn_st;
1861 	} else {
1862 		ent = enp->tn_path;
1863 		estp = enp->tn_st;
1864 	}
1865 
1866 	/*
1867 	 * When excluding or skipping entries, FST_SKIP should be
1868 	 * returned, otherwise, 0 should be returned to
1869 	 * get other entries in the directory of this entry.
1870 	 */
1871 	if (!dbm_getone(bpp->bp_nlp->nlp_bkmap, (u_longlong_t)estp->st_ino)) {
1872 		rv = TRUE;
1873 		*errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;
1874 		NDMP_LOG(LOG_DEBUG, "Skipping %d %s/%s",
1875 		    *errp, pnp->tn_path, ent);
1876 	} else if (tlm_is_excluded(pnp->tn_path, ent, bpp->bp_excls)) {
1877 		rv = TRUE;
1878 		*errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;
1879 		NDMP_LOG(LOG_DEBUG, "excl %d \"%s/%s\"",
1880 		    *errp, pnp->tn_path, ent);
1881 	} else if (inexl(bpp->bp_nlp->nlp_exl, ent)) {
1882 		rv = TRUE;
1883 		*errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;
1884 		NDMP_LOG(LOG_DEBUG, "out %d \"%s/%s\"",
1885 		    *errp, pnp->tn_path, ent);
1886 	} else if (!S_ISDIR(estp->st_mode) &&
1887 	    !ininc(bpp->bp_nlp->nlp_inc, ent)) {
1888 		rv = TRUE;
1889 		*errp = 0;
1890 		NDMP_LOG(LOG_DEBUG, "!in \"%s/%s\"", pnp->tn_path, ent);
1891 	} else
1892 		rv = FALSE;
1893 
1894 	return (rv);
1895 }
1896 
1897 
1898 /*
1899  * ischngd
1900  *
1901  * Check if the object specified should be backed up or not.
1902  * If stp belongs to a directory and if it is marked in the
1903  * bitmap vector, it shows that either the directory itself is
1904  * modified or there is something below it that will be backed
1905  * up.
1906  *
1907  * By setting ndmp_force_bk_dirs global variable to a non-zero
1908  * value, directories are backed up anyways.
1909  *
1910  * Backing up the directories unconditionally helps
1911  * restoring the metadata of directories as well, when one
1912  * of the objects below them are being restored.
1913  *
1914  * For non-directory objects, if the modification or change
1915  * time of the object is after the date specified by the
1916  * bk_selector_t, the the object must be backed up.
1917  */
1918 static boolean_t
1919 ischngd(struct stat64 *stp, time_t t, ndmp_lbr_params_t *nlp)
1920 {
1921 	boolean_t rv;
1922 
1923 	if (!stp) {
1924 		rv = FALSE;
1925 		NDMP_LOG(LOG_DEBUG, "stp is NULL");
1926 	} else if (!nlp) {
1927 		rv = FALSE;
1928 		NDMP_LOG(LOG_DEBUG, "nlp is NULL");
1929 	} else if (t == 0) {
1930 		/*
1931 		 * if we are doing base backup then we do not need to
1932 		 * check the time, for we should backup everything.
1933 		 */
1934 		rv = TRUE;
1935 		NDMP_LOG(LOG_DEBUG, "Base Backup");
1936 	} else if (S_ISDIR(stp->st_mode) && ndmp_force_bk_dirs) {
1937 		rv = TRUE;
1938 		NDMP_LOG(LOG_DEBUG, "d(%lu)", (uint_t)stp->st_ino);
1939 	} else if (S_ISDIR(stp->st_mode) &&
1940 	    dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino) &&
1941 	    ((NLP_ISDUMP(nlp) && ndmp_dump_path_node) ||
1942 	    (NLP_ISTAR(nlp) && ndmp_tar_path_node))) {
1943 		/*
1944 		 * If the object is a directory and it leads to a modified
1945 		 * object (that should be backed up) and for that type of
1946 		 * backup the path nodes should be backed up, then return
1947 		 * TRUE.
1948 		 *
1949 		 * This is required by some DMAs like Backup Express, which
1950 		 * needs to receive ADD_NODE (for dump) or ADD_PATH (for tar)
1951 		 * for the intermediate directories of a modified object.
1952 		 * Other DMAs, like net_backup and net_worker, do not have such
1953 		 * requirement.  This requirement makes sense for dump format
1954 		 * but for 'tar' format, it does not.  In provision to the
1955 		 * NDMP-v4 spec, for 'tar' format the intermediate directories
1956 		 * need not to be reported.
1957 		 */
1958 		rv = TRUE;
1959 		NDMP_LOG(LOG_DEBUG, "p(%lu)", (u_longlong_t)stp->st_ino);
1960 	} else if (stp->st_mtime > t) {
1961 		rv = TRUE;
1962 		NDMP_LOG(LOG_DEBUG, "m(%lu): %lu > %lu",
1963 		    (uint_t)stp->st_ino, (uint_t)stp->st_mtime, (uint_t)t);
1964 	} else if (stp->st_ctime > t) {
1965 		if (NLP_IGNCTIME(nlp)) {
1966 			rv = FALSE;
1967 			NDMP_LOG(LOG_DEBUG, "ign c(%lu): %lu > %lu",
1968 			    (uint_t)stp->st_ino, (uint_t)stp->st_ctime,
1969 			    (uint_t)t);
1970 		} else {
1971 			rv = TRUE;
1972 			NDMP_LOG(LOG_DEBUG, "c(%lu): %lu > %lu",
1973 			    (uint_t)stp->st_ino, (uint_t)stp->st_ctime,
1974 			    (uint_t)t);
1975 		}
1976 	} else {
1977 		rv = FALSE;
1978 		NDMP_LOG(LOG_DEBUG, "mc(%lu): (%lu,%lu) < %lu",
1979 		    (uint_t)stp->st_ino, (uint_t)stp->st_mtime,
1980 		    (uint_t)stp->st_ctime, (uint_t)t);
1981 	}
1982 
1983 	return (rv);
1984 }
1985 
1986 
1987 /*
1988  * iscreated
1989  *
1990  * This function is used to check last mtime (currently inside the ACL
1991  * structure) instead of ctime for checking if the file is to be backed up
1992  * or not. See option "inc.lmtime" for more details
1993  */
1994 /*ARGSUSED*/
1995 int iscreated(ndmp_lbr_params_t *nlp, char *name, tlm_acls_t *tacl,
1996     time_t t)
1997 {
1998 	int ret;
1999 	acl_t *aclp = NULL;
2000 	char *acltp;
2001 
2002 	NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
2003 	if (NLP_INCLMTIME(nlp) == FALSE)
2004 		return (0);
2005 
2006 	ret = acl_get(name, ACL_NO_TRIVIAL, &aclp);
2007 	if (ret != 0) {
2008 		NDMP_LOG(LOG_DEBUG,
2009 		    "Error getting the acl information: err %d", ret);
2010 		return (0);
2011 	}
2012 	if (aclp && (acltp = acl_totext(aclp,
2013 	    ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
2014 		(void) strlcpy(tacl->acl_info.attr_info, acltp,
2015 		    TLM_MAX_ACL_TXT);
2016 		acl_free(aclp);
2017 		free(acltp);
2018 	}
2019 
2020 	/* Need to add support for last mtime */
2021 
2022 	return (0);
2023 }
2024 
2025 /*
2026  * size_cb
2027  *
2028  * The callback function for calculating the size of
2029  * the backup path. This is used to get an estimate
2030  * of the progress of backup during NDMP backup
2031  */
2032 static int
2033 size_cb(void *arg, fst_node_t *pnp, fst_node_t *enp)
2034 {
2035 	struct stat64 *stp;
2036 
2037 	stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2038 	*((u_longlong_t *)arg) += stp->st_size;
2039 
2040 	return (0);
2041 }
2042 
2043 /*
2044  * timebk_v3
2045  *
2046  * The callback function for backing up objects based on
2047  * their time stamp.  This is shared between token-based
2048  * and level-based backup, which look at the time stamps
2049  * of the objects to determine if they should be backed
2050  * up.
2051  *
2052  * Parameters:
2053  *   arg (input) - pointer to the backup parameters structure
2054  *   pnp (input) - pointer to the path node
2055  *   enp (input) - pointer to the entry node
2056  *
2057  * Returns:
2058  *   0: if backup should continue
2059  *   -1: if the backup should be stopped
2060  *   FST_SKIP: if backing up the current directory is enough
2061  */
2062 static int
2063 timebk_v3(void *arg, fst_node_t *pnp, fst_node_t *enp)
2064 {
2065 	char *ent;
2066 	int rv;
2067 	time_t t;
2068 	bk_param_v3_t *bpp;
2069 	struct stat64 *stp;
2070 	fs_fhandle_t *fhp;
2071 
2072 	bpp = (bk_param_v3_t *)arg;
2073 
2074 	rv = check_bk_args(bpp);
2075 	if (rv != 0)
2076 		return (rv);
2077 
2078 	stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2079 	if (shouldskip(bpp, pnp, enp, &rv))
2080 		return (rv);
2081 
2082 	if (enp->tn_path) {
2083 		ent = enp->tn_path;
2084 		stp = enp->tn_st;
2085 		fhp = enp->tn_fh;
2086 	} else {
2087 		ent = "";
2088 		stp = pnp->tn_st;
2089 		fhp = pnp->tn_fh;
2090 	}
2091 
2092 
2093 	if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) {
2094 		NDMP_LOG(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent);
2095 		return (FST_SKIP);
2096 	}
2097 	if (NLP_ISSET(bpp->bp_nlp, NLPF_TOKENBK))
2098 		t = bpp->bp_nlp->nlp_tokdate;
2099 	else if (NLP_ISSET(bpp->bp_nlp, NLPF_LEVELBK)) {
2100 		t = bpp->bp_nlp->nlp_ldate;
2101 	} else {
2102 		NDMP_LOG(LOG_DEBUG, "Unknown backup type on \"%s/%s\"",
2103 		    pnp->tn_path, ent);
2104 		return (-1);
2105 	}
2106 
2107 	if (S_ISDIR(stp->st_mode)) {
2108 		bpp->bp_tlmacl->acl_dir_fh = *fhp;
2109 		(void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks,
2110 		    bpp->bp_tmp, stp);
2111 
2112 		if (ischngd(stp, t, bpp->bp_nlp)) {
2113 			(void) memcpy(&bpp->bp_tlmacl->acl_attr, stp,
2114 			    sizeof (struct stat64));
2115 			rv = backup_dirv3(bpp, pnp, enp);
2116 		}
2117 	} else {
2118 		if (ischngd(stp, t, bpp->bp_nlp) ||
2119 		    iscreated(bpp->bp_nlp, bpp->bp_tmp, bpp->bp_tlmacl, t)) {
2120 			rv = 0;
2121 			(void) memcpy(&bpp->bp_tlmacl->acl_attr, stp,
2122 			    sizeof (struct stat64));
2123 			bpp->bp_tlmacl->acl_fil_fh = *fhp;
2124 			(void) backup_filev3(bpp, pnp, enp);
2125 		}
2126 	}
2127 
2128 	return (rv);
2129 }
2130 
2131 
2132 /*
2133  * lbrbk_v3
2134  *
2135  * The callback function for backing up objects based on
2136  * their archive directory bit.  This is used in LBR-type
2137  * backup.  In which the objects are backed up if their
2138  * archive bit is set.
2139  *
2140  * Parameters:
2141  *   arg (input) - pointer to the backup parameters structure
2142  *   pnp (input) - pointer to the path node
2143  *   enp (input) - pointer to the entry node
2144  *
2145  * Returns:
2146  *   0: if backup should continue
2147  *   -1: if the backup should be stopped
2148  *   FST_SKIP: if backing up the current directory is enough
2149  */
2150 static int
2151 lbrbk_v3(void *arg, fst_node_t *pnp, fst_node_t *enp)
2152 {
2153 	char *ent;
2154 	int rv;
2155 	bk_param_v3_t *bpp;
2156 	struct stat64 *stp;
2157 	fs_fhandle_t *fhp;
2158 
2159 	bpp = (bk_param_v3_t *)arg;
2160 	rv = check_bk_args(bpp);
2161 	if (rv != 0)
2162 		return (rv);
2163 
2164 	stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2165 	if (shouldskip(bpp, pnp, enp, &rv))
2166 		return (rv);
2167 
2168 	if (enp->tn_path) {
2169 		ent = enp->tn_path;
2170 		stp = enp->tn_st;
2171 		fhp = enp->tn_fh;
2172 	} else {
2173 		ent = "";
2174 		stp = pnp->tn_st;
2175 		fhp = pnp->tn_fh;
2176 	}
2177 
2178 	if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) {
2179 		NDMP_LOG(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent);
2180 		return (FST_SKIP);
2181 	}
2182 	if (!NLP_ISSET(bpp->bp_nlp, NLPF_LBRBK)) {
2183 		NDMP_LOG(LOG_DEBUG, "!NLPF_LBRBK");
2184 		return (-1);
2185 	}
2186 
2187 	if (S_ISDIR(stp->st_mode)) {
2188 		bpp->bp_tlmacl->acl_dir_fh = *fhp;
2189 		(void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks,
2190 		    bpp->bp_tmp, stp);
2191 
2192 		if (SHOULD_LBRBK(bpp)) {
2193 			bpp->bp_tlmacl->acl_attr = *stp;
2194 			rv = backup_dirv3(bpp, pnp, enp);
2195 		}
2196 	} else if (SHOULD_LBRBK(bpp)) {
2197 		rv = 0;
2198 		bpp->bp_tlmacl->acl_attr = *stp;
2199 		bpp->bp_tlmacl->acl_fil_fh = *fhp;
2200 		(void) backup_filev3(bpp, pnp, enp);
2201 	}
2202 
2203 	return (rv);
2204 }
2205 
2206 
2207 /*
2208  * backup_reader_v3
2209  *
2210  * The reader thread for the backup.  It sets up the callback
2211  * parameters and traverses the backup hierarchy in level-order
2212  * way.
2213  *
2214  * Parameters:
2215  *   jname (input) - name assigned to the current backup for
2216  *	job stats strucure
2217  *   nlp (input) - pointer to the nlp structure
2218  *   cmds (input) - pointer to the tlm_commands_t structure
2219  *
2220  * Returns:
2221  *   0: on success
2222  *   != 0: otherwise
2223  */
2224 static int
2225 backup_reader_v3(backup_reader_arg_t *argp)
2226 {
2227 	int rv;
2228 	tlm_cmd_t *lcmd;
2229 	tlm_acls_t tlm_acls;
2230 	longlong_t bpos, n;
2231 	bk_param_v3_t bp;
2232 	fs_traverse_t ft;
2233 	char *jname;
2234 	ndmp_lbr_params_t *nlp;
2235 	tlm_commands_t *cmds;
2236 
2237 	if (!argp)
2238 		return (-1);
2239 
2240 	jname = argp->br_jname;
2241 	nlp = argp->br_nlp;
2242 	cmds = argp->br_cmds;
2243 
2244 	rv = 0;
2245 	lcmd = cmds->tcs_command;
2246 	lcmd->tc_ref++;
2247 	cmds->tcs_reader_count++;
2248 
2249 	(void) memset(&tlm_acls, 0, sizeof (tlm_acls));
2250 
2251 	/* NDMP parameters */
2252 	bp.bp_session = nlp->nlp_session;
2253 	bp.bp_nlp = nlp;
2254 
2255 	/* LBR-related parameters  */
2256 	bp.bp_js = tlm_ref_job_stats(jname);
2257 	bp.bp_cmds = cmds;
2258 	bp.bp_lcmd = lcmd;
2259 	bp.bp_tlmacl = &tlm_acls;
2260 	bp.bp_opr = 0;
2261 
2262 	/* release the parent thread, after referencing the job stats */
2263 	(void) pthread_barrier_wait(&argp->br_barrier);
2264 
2265 	bp.bp_tmp = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
2266 	if (!bp.bp_tmp)
2267 		return (-1);
2268 
2269 	/*
2270 	 * Make the checkpointed paths for traversing the
2271 	 * backup hierarchy, if we make the checkpoint.
2272 	 */
2273 	bp.bp_unchkpnm = nlp->nlp_backup_path;
2274 	if (!NLP_ISCHKPNTED(nlp)) {
2275 		tlm_acls.acl_checkpointed = TRUE;
2276 		bp.bp_chkpnm = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
2277 		if (!bp.bp_chkpnm) {
2278 			NDMP_FREE(bp.bp_tmp);
2279 			return (-1);
2280 		}
2281 		(void) tlm_build_snapshot_name(nlp->nlp_backup_path,
2282 		    bp.bp_chkpnm, nlp->nlp_jstat->js_job_name);
2283 	} else {
2284 		tlm_acls.acl_checkpointed = FALSE;
2285 		bp.bp_chkpnm = nlp->nlp_backup_path;
2286 	}
2287 	bp.bp_excls = ndmpd_make_exc_list();
2288 
2289 	/* set traversing arguments */
2290 	ft.ft_path = nlp->nlp_backup_path;
2291 	ft.ft_lpath = bp.bp_chkpnm;
2292 
2293 	NDMP_LOG(LOG_DEBUG, "path %s lpath %s", ft.ft_path, ft.ft_lpath);
2294 	if (NLP_ISSET(nlp, NLPF_TOKENBK) || NLP_ISSET(nlp, NLPF_LEVELBK)) {
2295 		ft.ft_callbk = timebk_v3;
2296 		tlm_acls.acl_clear_archive = FALSE;
2297 	} else if (NLP_ISSET(nlp, NLPF_LBRBK)) {
2298 		ft.ft_callbk = lbrbk_v3;
2299 		tlm_acls.acl_clear_archive = FALSE;
2300 
2301 		NDMP_LOG(LOG_DEBUG, "bp_opr %x clr_arc %c",
2302 		    bp.bp_opr, NDMP_YORN(tlm_acls.acl_clear_archive));
2303 	} else {
2304 		rv = -1;
2305 		MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR,
2306 		    "Unknow backup type.\n");
2307 	}
2308 	ft.ft_arg = &bp;
2309 	ft.ft_logfp = (ft_log_t)ndmp_log;
2310 	ft.ft_flags = FST_VERBOSE | FST_STOP_ONERR;
2311 
2312 	/* take into account the header written to the stream so far */
2313 	n = tlm_get_data_offset(lcmd);
2314 	nlp->nlp_session->ns_data.dd_module.dm_stats.ms_bytes_processed = n;
2315 
2316 	if (rv == 0) {
2317 		/* start traversing the hierarchy and actual backup */
2318 		rv = traverse_level(&ft);
2319 		if (rv == 0) {
2320 			/* write the trailer and update the bytes processed */
2321 			bpos = tlm_get_data_offset(lcmd);
2322 			(void) write_tar_eof(lcmd);
2323 			n = tlm_get_data_offset(lcmd) - bpos;
2324 			nlp->nlp_session->
2325 			    ns_data.dd_module.dm_stats.ms_bytes_processed += n;
2326 		} else {
2327 			MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR,
2328 			    "Filesystem traverse error.\n");
2329 			ndmpd_data_error(nlp->nlp_session,
2330 			    NDMP_DATA_HALT_INTERNAL_ERROR);
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_lbr_params_t *nlp;
3666 
3667 	if (!session || !params)
3668 		return (NDMP_ILLEGAL_ARGS_ERR);
3669 
3670 	nlp = ndmp_get_nlp(session);
3671 	if (!nlp) {
3672 		MOD_LOGV3(params, NDMP_LOG_ERROR,
3673 		    "Internal error: NULL nlp.\n");
3674 		return (NDMP_ILLEGAL_ARGS_ERR);
3675 	} else {
3676 		if (!(nlp->nlp_backup_path = get_backup_path_v3(params)) ||
3677 		    !is_valid_backup_dir_v3(params, nlp->nlp_backup_path))
3678 		return (NDMP_ILLEGAL_ARGS_ERR);
3679 	}
3680 
3681 	nlp->nlp_backup_path = get_absolute_path(nlp->nlp_backup_path);
3682 	if (!nlp->nlp_backup_path)
3683 		return (NDMP_ILLEGAL_ARGS_ERR);
3684 
3685 	if (fs_is_chkpntvol(nlp->nlp_backup_path) ||
3686 	    fs_is_rdonly(nlp->nlp_backup_path) ||
3687 	    !fs_is_chkpnt_enabled(nlp->nlp_backup_path))
3688 		NLP_SET(nlp, NLPF_CHKPNTED_PATH);
3689 	else
3690 		NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
3691 
3692 	/* Should the st_ctime be ignored when backing up? */
3693 	if (ndmp_ignore_ctime) {
3694 		NDMP_LOG(LOG_DEBUG, "ignoring st_ctime");
3695 		NLP_SET(nlp, NLPF_IGNCTIME);
3696 	} else {
3697 		NLP_UNSET(nlp, NLPF_IGNCTIME);
3698 	}
3699 
3700 	if (ndmp_include_lmtime == TRUE) {
3701 		NDMP_LOG(LOG_DEBUG, "including st_lmtime");
3702 		NLP_SET(nlp, NLPF_INCLMTIME);
3703 	} else {
3704 		NLP_UNSET(nlp, NLPF_INCLMTIME);
3705 	}
3706 
3707 	NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
3708 
3709 	get_hist_env_v3(params, nlp);
3710 	get_exc_env_v3(params, nlp);
3711 	get_inc_env_v3(params, nlp);
3712 	get_direct_env_v3(params, nlp);
3713 	return (get_backup_level_v3(params, nlp));
3714 }
3715 
3716 
3717 /*
3718  * ndmpd_tar_backup_starter_v3
3719  *
3720  * Create the checkpoint for the backup and do the backup,
3721  * then remove the backup checkpoint if we created it.
3722  * Save the backup time information based on the backup
3723  * type and stop the data server.
3724  *
3725  * Parameters:
3726  *   params (input) - pointer to the parameters structure
3727  *
3728  * Returns:
3729  *   0: on success
3730  *   != 0: otherwise
3731  */
3732 int
3733 ndmpd_tar_backup_starter_v3(void *arg)
3734 {
3735 	ndmpd_module_params_t *params = arg;
3736 	int err;
3737 	ndmpd_session_t *session;
3738 	ndmp_lbr_params_t *nlp;
3739 	char jname[TLM_MAX_BACKUP_JOB_NAME];
3740 	ndmp_bkup_size_arg_t sarg;
3741 	pthread_t tid;
3742 
3743 	session = (ndmpd_session_t *)(params->mp_daemon_cookie);
3744 	*(params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
3745 	ndmp_session_ref(session);
3746 	(void) ndmp_new_job_name(jname);
3747 
3748 	err = 0;
3749 	if (!NLP_ISCHKPNTED(nlp) &&
3750 	    ndmp_create_snapshot(nlp->nlp_backup_path, jname) < 0) {
3751 		MOD_LOGV3(params, NDMP_LOG_ERROR,
3752 		    "Creating checkpoint on \"%s\".\n",
3753 		    nlp->nlp_backup_path);
3754 		err = -1;
3755 	}
3756 
3757 	NDMP_LOG(LOG_DEBUG, "err %d, chkpnted %c",
3758 	    err, NDMP_YORN(NLP_ISCHKPNTED(nlp)));
3759 
3760 	if (err == 0) {
3761 		sarg.bs_session = session;
3762 		sarg.bs_jname = jname;
3763 		sarg.bs_path = nlp->nlp_backup_path;
3764 
3765 		/* Get an estimate of the data size */
3766 		if (pthread_create(&tid, NULL, (funct_t)get_backup_size,
3767 		    (void *)&sarg) == 0)
3768 			(void) pthread_detach(tid);
3769 
3770 		err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate, jname);
3771 		if (err != 0) {
3772 			NDMP_LOG(LOG_DEBUG, "err %d", err);
3773 		} else {
3774 			log_bk_params_v3(session, params, nlp);
3775 			err = tar_backup_v3(session, params, nlp, jname);
3776 		}
3777 	}
3778 
3779 	if (!NLP_ISCHKPNTED(nlp))
3780 		(void) ndmp_remove_snapshot(nlp->nlp_backup_path, jname);
3781 
3782 	NDMP_LOG(LOG_DEBUG, "err %d, update %c",
3783 	    err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
3784 
3785 	if (err == 0)
3786 		save_backup_date_v3(params, nlp);
3787 
3788 	MOD_DONE(params, err);
3789 
3790 	/* nlp_params is allocated in start_backup_v3() */
3791 	NDMP_FREE(nlp->nlp_params);
3792 	NDMP_FREE(nlp->nlp_backup_path);
3793 
3794 	NS_DEC(nbk);
3795 	ndmp_session_unref(session);
3796 	return (err);
3797 
3798 }
3799 
3800 
3801 /*
3802  * ndmpd_tar_backup_abort_v3
3803  *
3804  * Abort the backup operation and stop the reader thread.
3805  *
3806  * Parameters:
3807  *   module_cookie (input) - pointer to the nlp structure
3808  *
3809  * Returns:
3810  *   0: always
3811  */
3812 int
3813 ndmpd_tar_backup_abort_v3(void *module_cookie)
3814 {
3815 	ndmp_lbr_params_t *nlp;
3816 
3817 	nlp = (ndmp_lbr_params_t *)module_cookie;
3818 	if (nlp && nlp->nlp_session) {
3819 		if (nlp->nlp_session->ns_data.dd_data_addr.addr_type ==
3820 		    NDMP_ADDR_TCP &&
3821 		    nlp->nlp_session->ns_data.dd_sock != -1) {
3822 			(void) close(nlp->nlp_session->ns_data.dd_sock);
3823 			nlp->nlp_session->ns_data.dd_sock = -1;
3824 		}
3825 		ndmp_stop_reader_thread(nlp->nlp_session);
3826 	}
3827 
3828 	return (0);
3829 }
3830 
3831 
3832 /*
3833  * ndmp_restore_get_params_v3
3834  *
3835  * Get the parameters specified for recovery such as restore path, type
3836  * of restore (DAR, non-DAR) etc
3837  *
3838  * Parameters:
3839  *   session (input) - pointer to the session
3840  *   params (input) - pointer to the parameters structure
3841  *
3842  * Returns:
3843  *   NDMP_NO_ERR: on success
3844  *   != NDMP_NO_ERR: otherwise
3845  */
3846 ndmp_error
3847 ndmp_restore_get_params_v3(ndmpd_session_t *session,
3848     ndmpd_module_params_t *params)
3849 {
3850 	ndmp_error rv;
3851 	ndmp_lbr_params_t *nlp;
3852 
3853 	if (!(nlp = ndmp_get_nlp(session))) {
3854 		NDMP_LOG(LOG_DEBUG, "nlp is NULL");
3855 		rv = NDMP_ILLEGAL_ARGS_ERR;
3856 	} else if (!(nlp->nlp_backup_path = get_backup_path_v3(params)))
3857 		rv = NDMP_ILLEGAL_ARGS_ERR;
3858 	else if ((nlp->nlp_nfiles = session->ns_data.dd_nlist_len) == 0) {
3859 		NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
3860 		rv = NDMP_ILLEGAL_ARGS_ERR;
3861 	} else if (get_rs_path_v3(params, nlp) != NDMP_NO_ERR) {
3862 		rv = NDMP_ILLEGAL_ARGS_ERR;
3863 	} else if ((rv = fix_nlist_v3(session, params, nlp)) != NDMP_NO_ERR) {
3864 		NDMP_LOG(LOG_DEBUG, "fix_nlist_v3: %d", rv);
3865 	} else {
3866 		rv = NDMP_NO_ERR;
3867 		get_direct_env_v3(params, nlp);
3868 		if (NLP_ISSET(nlp, NLPF_DIRECT)) {
3869 			if (NLP_ISSET(nlp, NLPF_RECURSIVE)) {
3870 				/* Currently we dont support DAR on directory */
3871 				NDMP_LOG(LOG_DEBUG,
3872 				    "Can't have RECURSIVE and DIRECT together");
3873 				rv = NDMP_ILLEGAL_ARGS_ERR;
3874 				return (rv);
3875 			}
3876 
3877 			/*
3878 			 * DAR can be done if all the fh_info's are valid.
3879 			 */
3880 			if (allvalidfh(session, params)) {
3881 				ndmp_sort_nlist_v3(session);
3882 			} else {
3883 				MOD_LOGV3(params, NDMP_LOG_WARNING,
3884 				    "Cannot do direct access recovery. "
3885 				    "Some 'fh_info'es are not valid.\n");
3886 				NLP_UNSET(nlp, NLPF_DIRECT);
3887 			}
3888 		}
3889 
3890 		log_rs_params_v3(session, params, nlp);
3891 	}
3892 
3893 	return (rv);
3894 }
3895 
3896 
3897 /*
3898  * ndmpd_tar_restore_starter_v3
3899  *
3900  * The main restore starter function. It will start a DAR or
3901  * non-DAR recovery based on the parameters. (V3 and V4 only)
3902  *
3903  * Parameters:
3904  *   params (input) - pointer to the parameters structure
3905  *
3906  * Returns:
3907  *   NDMP_NO_ERR: on success
3908  *   != NDMP_NO_ERR: otherwise
3909  */
3910 int
3911 ndmpd_tar_restore_starter_v3(void *arg)
3912 {
3913 	ndmpd_module_params_t *params = arg;
3914 	int err;
3915 	ndmpd_session_t *session;
3916 	ndmp_lbr_params_t *nlp;
3917 
3918 
3919 	session = (ndmpd_session_t *)(params->mp_daemon_cookie);
3920 	*(params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
3921 	ndmp_session_ref(session);
3922 
3923 	if (NLP_ISSET(nlp, NLPF_DIRECT))
3924 		err = ndmpd_rs_dar_tar_v3(session, params, nlp);
3925 	else
3926 		err = ndmpd_rs_sar_tar_v3(session, params, nlp);
3927 
3928 	MOD_DONE(params, err);
3929 
3930 	NS_DEC(nrs);
3931 	/* nlp_params is allocated in start_recover() */
3932 	NDMP_FREE(nlp->nlp_params);
3933 	ndmp_session_unref(session);
3934 	return (err);
3935 
3936 }
3937 
3938 
3939 /*
3940  * ndmp_tar_restore_abort_v3
3941  *
3942  * Restore abort function (V3 and V4 only)
3943  *
3944  * Parameters:
3945  *   module_cookie (input) - pointer to nlp
3946  *
3947  * Returns:
3948  *   0
3949  */
3950 int
3951 ndmpd_tar_restore_abort_v3(void *module_cookie)
3952 {
3953 	ndmp_lbr_params_t *nlp;
3954 
3955 	nlp = (ndmp_lbr_params_t *)module_cookie;
3956 	if (nlp != NULL && nlp->nlp_session != NULL) {
3957 		if (nlp->nlp_session->ns_data.dd_mover.addr_type ==
3958 		    NDMP_ADDR_TCP &&
3959 		    nlp->nlp_session->ns_data.dd_sock != -1) {
3960 			(void) close(nlp->nlp_session->ns_data.dd_sock);
3961 			nlp->nlp_session->ns_data.dd_sock = -1;
3962 		}
3963 		nlp_event_nw(nlp->nlp_session);
3964 		ndmp_stop_writer_thread(nlp->nlp_session);
3965 	}
3966 
3967 
3968 	return (0);
3969 
3970 }
3971