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