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