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