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