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