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/socket.h>
45#include <errno.h>
46#include <stdio.h>
47#include <string.h>
48#include <unistd.h>
49#include <time.h>
50#include <cstack.h>
51#include <dirent.h>
52#include <traverse.h>
53#include "bitmap.h"
54#include "ndmpd.h"
55#include "tlm_buffers.h"
56
57
58typedef struct ndmp_run_args {
59	char *nr_chkp_nm;
60	char *nr_unchkp_nm;
61	char **nr_excls;
62} ndmp_run_args_t;
63
64
65/*
66 * backup_create_structs
67 *
68 * Allocate the structures before performing backup
69 *
70 * Parameters:
71 *   sesison (input) - session handle
72 *   jname (input) - backup job name
73 *
74 * Returns:
75 *   0: on success
76 *  -1: otherwise
77 */
78static int
79backup_create_structs(ndmpd_session_t *session, char *jname)
80{
81	int n;
82	long xfer_size;
83	ndmp_lbr_params_t *nlp;
84	tlm_commands_t *cmds;
85
86	if ((nlp = ndmp_get_nlp(session)) == NULL) {
87		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
88		return (-1);
89	}
90
91	if ((nlp->nlp_jstat = tlm_new_job_stats(jname)) == NULL) {
92		NDMP_LOG(LOG_DEBUG, "Creating job stats");
93		return (-1);
94	}
95
96	cmds = &nlp->nlp_cmds;
97	(void) memset(cmds, 0, sizeof (*cmds));
98
99	xfer_size = ndmp_buffer_get_size(session);
100	if (xfer_size < 512*KILOBYTE) {
101		/*
102		 * Read multiple of mover_record_size near to 512K.  This
103		 * will prevent the data being copied in the mover buffer
104		 * when we write the data.
105		 */
106		if ((n = (512 * KILOBYTE/xfer_size)) <= 0)
107			n = 1;
108		xfer_size *= n;
109		NDMP_LOG(LOG_DEBUG, "Adjusted read size: %d", xfer_size);
110	}
111
112	cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, xfer_size);
113	if (cmds->tcs_command == NULL) {
114		NDMP_LOG(LOG_DEBUG, "Error creating ipc buffers");
115		tlm_un_ref_job_stats(jname);
116		return (-1);
117	}
118
119	nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
120	    ndmpd_file_history_path,
121	    ndmpd_file_history_dir,
122	    ndmpd_file_history_node);
123	if (nlp->nlp_logcallbacks == NULL) {
124		tlm_release_reader_writer_ipc(cmds->tcs_command);
125		tlm_un_ref_job_stats(jname);
126		return (-1);
127	}
128	nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
129
130	return (0);
131}
132
133
134/*
135 * restore_create_structs
136 *
137 * Allocate structures for performing a restore
138 *
139 * Parameters:
140 *   sesison (input) - session handle
141 *   jname (input) - backup job name
142 *
143 * Returns:
144 *   0: on success
145 *  -1: otherwise
146 */
147static int
148restore_create_structs(ndmpd_session_t *session, char *jname)
149{
150	int i;
151	long xfer_size;
152	ndmp_lbr_params_t *nlp;
153	tlm_commands_t *cmds;
154
155	if ((nlp = ndmp_get_nlp(session)) == NULL) {
156		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
157		return (-1);
158	}
159	if ((nlp->nlp_jstat = tlm_new_job_stats(jname)) == NULL) {
160		NDMP_LOG(LOG_DEBUG, "Creating job stats");
161		return (-1);
162	}
163
164	cmds = &nlp->nlp_cmds;
165	(void) memset(cmds, 0, sizeof (*cmds));
166
167	xfer_size = ndmp_buffer_get_size(session);
168	cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
169	if (cmds->tcs_command == NULL) {
170		NDMP_LOG(LOG_DEBUG, "Error creating ipc buffers");
171		tlm_un_ref_job_stats(jname);
172		return (-1);
173	}
174
175	nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
176	    ndmpd_path_restored, NULL, NULL);
177	if (nlp->nlp_logcallbacks == NULL) {
178		tlm_release_reader_writer_ipc(cmds->tcs_command);
179		tlm_un_ref_job_stats(jname);
180		return (-1);
181	}
182	nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
183
184	nlp->nlp_restored = ndmp_malloc(sizeof (boolean_t) * nlp->nlp_nfiles);
185	if (nlp->nlp_restored == NULL) {
186		lbrlog_callbacks_done(nlp->nlp_logcallbacks);
187		tlm_release_reader_writer_ipc(cmds->tcs_command);
188		tlm_un_ref_job_stats(jname);
189		return (-1);
190	}
191	for (i = 0; i < (int)nlp->nlp_nfiles; i++)
192		nlp->nlp_restored[i] = FALSE;
193
194	return (0);
195}
196
197
198/*
199 * send_unrecovered_list
200 *
201 * Creates a list of restored files
202 *
203 * Parameters:
204 *   params (input) - NDMP parameters
205 *   nlp (input) - NDMP/LBR parameters
206 *
207 * Returns:
208 *   0: on success
209 *  -1: otherwise
210 */
211static int
212send_unrecovered_list(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
213{
214	int i, rv;
215	ndmp_name *ent;
216
217	if (params == NULL) {
218		NDMP_LOG(LOG_DEBUG, "params == NULL");
219		return (-1);
220	}
221	if (nlp == NULL) {
222		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
223		return (-1);
224	}
225
226	rv = 0;
227	for (i = 0; i < (int)nlp->nlp_nfiles; i++) {
228		NDMP_LOG(LOG_DEBUG, "nlp->nlp_restored[%d]: %s", i,
229		    nlp->nlp_restored[i] ? "TRUE" : "FALSE");
230
231		if (!nlp->nlp_restored[i]) {
232			ent = (ndmp_name *)MOD_GETNAME(params, i);
233			if (ent == NULL) {
234				NDMP_LOG(LOG_DEBUG, "ent == NULL");
235				rv = -1;
236				break;
237			}
238			if (ent->name == NULL) {
239				NDMP_LOG(LOG_DEBUG, "ent->name == NULL");
240				rv = -1;
241				break;
242			}
243
244			NDMP_LOG(LOG_DEBUG, "ent.name: \"%s\"", ent->name);
245
246			rv = MOD_FILERECOVERD(params, ent->name, ENOENT);
247			if (rv < 0)
248				break;
249		}
250	}
251
252	return (rv);
253}
254
255
256/*
257 * backup_release_structs
258 *
259 * Deallocated the NDMP/LBR specific parameters
260 *
261 * Parameters:
262 *   session (input) - session handle
263 *
264 * Returns:
265 *   void
266 */
267/*ARGSUSED*/
268static void
269backup_release_structs(ndmpd_session_t *session)
270{
271	ndmp_lbr_params_t *nlp;
272	tlm_commands_t *cmds;
273
274	if ((nlp = ndmp_get_nlp(session)) == NULL) {
275		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
276		return;
277	}
278	cmds = &nlp->nlp_cmds;
279	if (cmds == NULL) {
280		NDMP_LOG(LOG_DEBUG, "cmds == NULL");
281		return;
282	}
283
284	if (nlp->nlp_logcallbacks != NULL) {
285		lbrlog_callbacks_done(nlp->nlp_logcallbacks);
286		nlp->nlp_logcallbacks = NULL;
287	} else {
288		NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL");
289	}
290
291	if (cmds->tcs_command != NULL) {
292		if (cmds->tcs_command->tc_buffers != NULL)
293			tlm_release_reader_writer_ipc(cmds->tcs_command);
294		else
295			NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL");
296		cmds->tcs_command = NULL;
297	} else {
298		NDMP_LOG(LOG_DEBUG, "COMMAND == NULL");
299	}
300
301	if (nlp->nlp_bkmap >= 0) {
302		(void) dbm_free(nlp->nlp_bkmap);
303		nlp->nlp_bkmap = -1;
304	}
305
306	if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER &&
307	    nlp->nlp_restored != NULL) {
308		free(nlp->nlp_restored);
309		nlp->nlp_restored = NULL;
310	} else {
311		NDMP_LOG(LOG_DEBUG, "nlp_restored == NULL");
312	}
313}
314
315/*
316 * ndmp_write_utf8magic
317 *
318 * Write a magic pattern to the tar header. This is used
319 * as a crest to indicate that tape belongs to us.
320 */
321int
322ndmp_write_utf8magic(tlm_cmd_t *cmd)
323{
324	char *cp;
325	long actual_size;
326
327	if (cmd->tc_buffers == NULL) {
328		NDMP_LOG(LOG_DEBUG, "cmd->tc_buffers == NULL");
329		return (-1);
330	}
331
332	cp = tlm_get_write_buffer(RECORDSIZE, &actual_size,
333	    cmd->tc_buffers, TRUE);
334	if (actual_size < RECORDSIZE) {
335		NDMP_LOG(LOG_DEBUG, "Couldn't get enough buffer");
336		return (-1);
337	}
338
339	(void) strlcpy(cp, NDMPUTF8MAGIC, RECORDSIZE);
340	return (0);
341}
342
343
344/*
345 * timecmp
346 *
347 * This callback function is used during backup.  It checks
348 * if the object specified by the 'attr' should be backed
349 * up or not.
350 *
351 * Directories are backed up anyways for dump format.
352 * If this function is called, then the directory is
353 * marked in the bitmap vector, it shows that either the
354 * directory itself is modified or there is something below
355 * it that will be backed up.
356 *
357 * Directories for tar format are backed up if and only if
358 * they are modified.
359 *
360 * By setting ndmp_force_bk_dirs global variable to a non-zero
361 * value, directories are backed up anyways.
362 *
363 * Backing up the directories unconditionally, helps
364 * restoring the metadata of directories as well, when one
365 * of the objects below them are being restored.
366 *
367 * For non-directory objects, if the modification or change
368 * time of the object is after the date specified by the
369 * bk_selector_t, the the object must be backed up.
370 *
371 */
372static boolean_t
373timecmp(bk_selector_t *bksp,
374		struct stat64 *attr)
375{
376	ndmp_lbr_params_t *nlp;
377
378	nlp = (ndmp_lbr_params_t *)bksp->bs_cookie;
379	if (S_ISDIR(attr->st_mode) && ndmp_force_bk_dirs) {
380		NDMP_LOG(LOG_DEBUG, "d(%lu)",
381		    (uint_t)attr->st_ino);
382		return (TRUE);
383	}
384	if (S_ISDIR(attr->st_mode) &&
385	    dbm_getone(nlp->nlp_bkmap, (u_longlong_t)attr->st_ino) &&
386	    ((NLP_ISDUMP(nlp) && ndmp_dump_path_node) ||
387	    (NLP_ISTAR(nlp) && ndmp_tar_path_node))) {
388		/*
389		 * If the object is a directory and it leads to a modified
390		 * object (that should be backed up) and for that type of
391		 * backup the path nodes should be backed up, then return
392		 * TRUE.
393		 *
394		 * This is required by some DMAs like Backup Express, which
395		 * needs to receive ADD_NODE (for dump) or ADD_PATH (for tar)
396		 * for the intermediate directories of a modified object.
397		 * Other DMAs, like net_backup and net_worker, do not have such
398		 * requirement.  This requirement makes sense for dump format
399		 * but for 'tar' format, it does not.  In provision to the
400		 * NDMP-v4 spec, for 'tar' format the intermediate directories
401		 * need not to be reported.
402		 */
403		NDMP_LOG(LOG_DEBUG, "p(%lu)", (u_longlong_t)attr->st_ino);
404		return (TRUE);
405	}
406	if (attr->st_mtime > bksp->bs_ldate) {
407		NDMP_LOG(LOG_DEBUG, "m(%lu): %lu > %lu",
408		    (uint_t)attr->st_ino, (uint_t)attr->st_mtime,
409		    (uint_t)bksp->bs_ldate);
410		return (TRUE);
411	}
412	if (attr->st_ctime > bksp->bs_ldate) {
413		if (NLP_IGNCTIME(nlp)) {
414			NDMP_LOG(LOG_DEBUG, "ign c(%lu): %lu > %lu",
415			    (uint_t)attr->st_ino, (uint_t)attr->st_ctime,
416			    (uint_t)bksp->bs_ldate);
417			return (FALSE);
418		}
419		NDMP_LOG(LOG_DEBUG, "c(%lu): %lu > %lu",
420		    (uint_t)attr->st_ino, (uint_t)attr->st_ctime,
421		    (uint_t)bksp->bs_ldate);
422		return (TRUE);
423	}
424	NDMP_LOG(LOG_DEBUG, "mc(%lu): (%lu,%lu) < %lu",
425	    (uint_t)attr->st_ino, (uint_t)attr->st_mtime,
426	    (uint_t)attr->st_ctime, (uint_t)bksp->bs_ldate);
427	return (FALSE);
428}
429
430
431/*
432 * get_acl_info
433 *
434 * load up all the access and attribute info
435 */
436static int
437get_acl_info(char *name, tlm_acls_t *tlm_acls)
438{
439	int erc;
440	acl_t *aclp = NULL;
441	char *acltp;
442
443	erc = lstat64(name, &tlm_acls->acl_attr);
444	if (erc != 0) {
445		NDMP_LOG(LOG_ERR, "Could not find file %s.", name);
446		erc = TLM_NO_SOURCE_FILE;
447		return (erc);
448	}
449	erc = acl_get(name, ACL_NO_TRIVIAL, &aclp);
450	if (erc != 0) {
451		NDMP_LOG(LOG_DEBUG,
452		    "Could not read ACL for file [%s]", name);
453		erc = TLM_NO_SOURCE_FILE;
454		return (erc);
455	}
456	if (aclp && (acltp = acl_totext(aclp,
457	    ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
458		(void) strlcpy(tlm_acls->acl_info.attr_info, acltp,
459		    TLM_MAX_ACL_TXT);
460		acl_free(aclp);
461		free(acltp);
462	}
463	return (erc);
464}
465/*
466 * get_dir_acl_info
467 *
468 * load up all ACL and attr info about a directory
469 */
470static int
471get_dir_acl_info(char *dir, tlm_acls_t *tlm_acls, tlm_job_stats_t *js)
472{
473	int	erc;
474	char	*checkpointed_dir;
475	char	root_dir[TLM_VOLNAME_MAX_LENGTH];
476	char	*spot;
477	char	*fil;
478	acl_t	*aclp = NULL;
479	char 	*acltp;
480
481	checkpointed_dir = ndmp_malloc(TLM_MAX_PATH_NAME);
482	if (checkpointed_dir == NULL)
483		return (-1);
484
485	if (tlm_acls->acl_checkpointed)
486		fil = tlm_build_snapshot_name(dir, checkpointed_dir,
487		    js->js_job_name);
488	else
489		fil = dir;
490	erc = lstat64(fil, &tlm_acls->acl_attr);
491	if (erc != 0) {
492		NDMP_LOG(LOG_ERR, "Could not find directory %s.", dir);
493		free(checkpointed_dir);
494		return (-1);
495	}
496
497	spot = strchr(&fil[1], '/');
498	if (spot == NULL) {
499		(void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH);
500	} else {
501		*spot = 0;
502		(void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH);
503		*spot = '/';
504	}
505	if (strcmp(root_dir, tlm_acls->acl_root_dir) != 0) {
506		struct stat64 attr;
507
508		erc = lstat64(root_dir, &attr);
509		if (erc != 0) {
510			NDMP_LOG(LOG_ERR, "Cannot find root directory %s.",
511			    root_dir);
512			free(checkpointed_dir);
513			return (-1);
514		}
515		(void) strlcpy(tlm_acls->acl_root_dir, root_dir,
516		    TLM_VOLNAME_MAX_LENGTH);
517	}
518	erc = acl_get(fil, ACL_NO_TRIVIAL, &aclp);
519	if (erc != 0) {
520		NDMP_LOG(LOG_DEBUG,
521		    "Could not read metadata for directory [%s]", dir);
522		free(checkpointed_dir);
523		return (-1);
524	}
525	if (aclp && (acltp = acl_totext(aclp,
526	    ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
527		(void) strlcpy(tlm_acls->acl_info.attr_info, acltp,
528		    TLM_MAX_ACL_TXT);
529		acl_free(aclp);
530		free(acltp);
531	}
532
533	free(checkpointed_dir);
534	return (0);
535}
536
537/*
538 * backup_dir
539 *
540 * Create a TAR entry record for a directory
541 */
542static int
543backup_dir(char *dir, tlm_acls_t *tlm_acls,
544    tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats,
545    bk_selector_t *bksp)
546{
547	int erc;
548
549	NDMP_LOG(LOG_DEBUG, "\"%s\"", dir);
550
551	erc = get_dir_acl_info(dir, tlm_acls, job_stats);
552	if (erc != 0) {
553		NDMP_LOG(LOG_DEBUG,
554		    "Could not read directory info for %s", dir);
555		job_stats->js_errors++;
556	} else {
557		/*
558		 * See if the directory must be backed up.
559		 */
560		if (bksp && !(*bksp->bs_fn)(bksp, &tlm_acls->acl_attr)) {
561			NDMP_LOG(LOG_DEBUG, "[%s] dir skipped", dir);
562			return (erc);
563		}
564
565		if (tm_tar_ops.tm_putdir != NULL)
566			(void) (tm_tar_ops.tm_putdir)(dir, tlm_acls,
567			    local_commands, job_stats);
568	}
569
570	return (erc);
571}
572
573
574/*
575 * backup_file
576 *
577 * Create a TAR record entry for a file
578 */
579static longlong_t
580backup_file(char *dir, char *name, tlm_acls_t *tlm_acls,
581    tlm_commands_t *commands, tlm_cmd_t *local_commands,
582    tlm_job_stats_t *job_stats, bk_selector_t *bksp)
583{
584
585	int erc;
586	char buf[TLM_MAX_PATH_NAME];
587	longlong_t rv;
588
589	NDMP_LOG(LOG_DEBUG, "\"%s/%s\"", dir, name);
590
591	(void) strlcpy(buf, dir, sizeof (buf));
592	(void) strlcat(buf, "/", sizeof (buf));
593	(void) strlcat(buf, name, sizeof (buf));
594
595	/*
596	 * get_acl_info extracts file handle, attributes and ACLs of the file.
597	 * This is not efficient when the attributes and file handle of
598	 * the file is already known.
599	 */
600	erc = get_acl_info(buf, tlm_acls);
601	if (erc != TLM_NO_ERRORS) {
602		NDMP_LOG(LOG_ERR, "Could not open file %s/%s.", dir, name);
603		return (-ENOENT);
604	}
605
606	/* Should the file be backed up? */
607	if (!bksp) {
608		NDMP_LOG(LOG_DEBUG,
609		    "[%s/%s] has no selection criteria", dir, name);
610
611	} else if (!((*bksp->bs_fn)(bksp, &tlm_acls->acl_attr))) {
612		NDMP_LOG(LOG_DEBUG, "[%s/%s] file skipped", dir, name);
613		return (0);
614	}
615
616	/* Only the regular files and symbolic links can be backed up. */
617	if (!S_ISLNK(tlm_acls->acl_attr.st_mode) &&
618	    !S_ISREG(tlm_acls->acl_attr.st_mode)) {
619		NDMP_LOG(LOG_DEBUG,
620		    "Warning: skip backing up [%s][%s]", dir, name);
621		return (-EINVAL);
622	}
623
624
625	if (tm_tar_ops.tm_putfile != NULL)
626		rv = (tm_tar_ops.tm_putfile)(dir, name, tlm_acls, commands,
627		    local_commands, job_stats);
628
629	return (rv);
630}
631
632
633
634/*
635 * backup_work
636 *
637 * Start the NDMP backup (V2 only).
638 */
639int
640backup_work(char *bk_path, tlm_job_stats_t *job_stats,
641    ndmp_run_args_t *np, tlm_commands_t *commands,
642    ndmp_lbr_params_t *nlp)
643{
644	struct full_dir_info dir_info; /* the blob to push/pop with cstack_t */
645	struct full_dir_info *t_dir_info, *p_dir_info;
646	struct stat64 ret_attr; /* attributes of current file name */
647	fs_fhandle_t ret_fh;
648	char *first_name; /* where the first name is located */
649	char *dname;
650	int erc;
651	int retval;
652	cstack_t *stk;
653	unsigned long fileid;
654	tlm_acls_t tlm_acls;
655	int dname_size;
656	longlong_t fsize;
657	bk_selector_t bks;
658	tlm_cmd_t *local_commands;
659	long 	dpos;
660
661	NDMP_LOG(LOG_DEBUG, "nr_chkpnted %d nr_ldate: %u bk_path: \"%s\"",
662	    NLP_ISCHKPNTED(nlp), nlp->nlp_ldate, bk_path);
663
664	/* Get every name in this directory */
665	dname = ndmp_malloc(TLM_MAX_PATH_NAME);
666	if (dname == NULL)
667		return (-ENOMEM);
668
669	local_commands = commands->tcs_command;
670	retval = 0;
671	(void) memset(&bks, 0, sizeof (bks));
672	bks.bs_cookie = (void *)nlp;
673	bks.bs_level = nlp->nlp_clevel;
674	bks.bs_ldate = nlp->nlp_ldate;
675	bks.bs_fn = timecmp;
676
677	/*
678	 * should we skip the whole thing?
679	 */
680	if (tlm_is_excluded("", bk_path, np->nr_excls)) {
681		NDMP_LOG(LOG_DEBUG, "%s excluded", bk_path);
682		free(dname);
683		return (0);
684	}
685
686	/*
687	 * Search for the top-level file-directory
688	 */
689	if (NLP_ISCHKPNTED(nlp)) {
690		first_name = np->nr_chkp_nm;
691		(void) strlcpy(first_name, bk_path, TLM_MAX_PATH_NAME);
692	} else {
693		first_name = tlm_build_snapshot_name(bk_path, np->nr_chkp_nm,
694		    nlp->nlp_jstat->js_job_name);
695	}
696
697	(void) memset(&ret_fh, 0, sizeof (ret_fh));
698	erc = fs_getstat(first_name, &ret_fh, &ret_attr);
699	if (erc != 0) {
700		NDMP_LOG(LOG_ERR, "Path %s not found.", first_name);
701		free(dname);
702		return (-EINVAL);
703	}
704
705	if ((stk = cstack_new()) == NULL) {
706		free(dname);
707		NDMP_LOG(LOG_DEBUG, "cstack_new failed");
708		return (-ENOMEM);
709	}
710	(void) strlcpy(dir_info.fd_dir_name, first_name, TLM_MAX_PATH_NAME);
711	(void) memcpy(&dir_info.fd_dir_fh, &ret_fh, sizeof (fs_fhandle_t));
712	p_dir_info = dup_dir_info(&dir_info);
713
714	/*
715	 * Push the first name onto the stack so that we can pop it back
716	 * off as part of the normal cycle
717	 */
718	if (cstack_push(stk, p_dir_info, 0)) {
719		free(dname);
720		free(p_dir_info);
721		cstack_delete(stk);
722		NDMP_LOG(LOG_DEBUG, "cstack_push failed");
723		return (-ENOMEM);
724	}
725
726	(void) memset(&tlm_acls, 0, sizeof (tlm_acls));
727	/*
728	 * Did NDMP create a checkpoint?
729	 */
730	if (NLP_ISCHKPNTED(nlp) || fs_is_rdonly(bk_path)) {
731		tlm_acls.acl_checkpointed = FALSE;
732	} else {
733		/* Use the checkpoint created by NDMP */
734		tlm_acls.acl_checkpointed = TRUE;
735	}
736
737	/*
738	 * This is level-backup.  It never resets the archive bit.
739	 */
740	tlm_acls.acl_clear_archive = FALSE;
741
742	NDMP_LOG(LOG_DEBUG, "acls.chkpnt: %c acls.clear_arcbit: %c",
743	    NDMP_YORN(tlm_acls.acl_checkpointed),
744	    NDMP_YORN(tlm_acls.acl_clear_archive));
745
746	while (commands->tcs_reader == TLM_BACKUP_RUN &&
747	    local_commands->tc_reader == TLM_BACKUP_RUN &&
748	    cstack_pop(stk, (void **)&p_dir_info, 0) == 0) {
749
750		if (NLP_ISCHKPNTED(nlp))
751			(void) strlcpy(np->nr_unchkp_nm,
752			    p_dir_info->fd_dir_name, TLM_MAX_PATH_NAME);
753		else
754			(void) tlm_remove_checkpoint(p_dir_info->fd_dir_name,
755			    np->nr_unchkp_nm);
756
757		(void) backup_dir(np->nr_unchkp_nm, &tlm_acls, local_commands,
758		    job_stats, &bks);
759
760
761		while (commands->tcs_reader == TLM_BACKUP_RUN &&
762		    local_commands->tc_reader == TLM_BACKUP_RUN) {
763
764			dname_size = TLM_MAX_PATH_NAME - 1;
765
766			NDMP_LOG(LOG_DEBUG,
767			    "dir_name: %s", p_dir_info->fd_dir_name);
768
769			(void) memset(&ret_fh, 0, sizeof (ret_fh));
770			erc = fs_readdir(&p_dir_info->fd_dir_fh,
771			    p_dir_info->fd_dir_name, &dpos,
772			    dname, &dname_size, &ret_fh, &ret_attr);
773			if (erc == 0) {
774				fileid = ret_fh.fh_fid;
775			} else {
776				NDMP_LOG(LOG_DEBUG,
777				    "Filesystem readdir in [%s]",
778				    p_dir_info->fd_dir_name);
779				retval = -ENOENT;
780				break;
781			}
782
783			/* an empty name size marks the end of the list */
784			if (dname_size == 0)
785				break;
786			dname[dname_size] = '\0';
787
788			NDMP_LOG(LOG_DEBUG, "dname: \"%s\"", dname);
789
790			/*
791			 * If name refers to a directory, push its file
792			 *   handle onto the stack  (skip "." and "..").
793			 */
794			if (rootfs_dot_or_dotdot(dname)) {
795				fileid = 0;
796				continue;
797			}
798
799			/*
800			 * Skip the:
801			 * non-dir entries which should not be backed up
802			 * Or
803			 * dir-type entries which have have nothing under
804			 * their hierarchy to be backed up.
805			 */
806			if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)fileid)) {
807				NDMP_LOG(LOG_DEBUG, "Skipping %s/%s",
808				    p_dir_info->fd_dir_name, dname);
809				fileid = 0;
810				continue;
811			}
812
813			if (tlm_is_excluded(np->nr_unchkp_nm, dname,
814			    np->nr_excls)) {
815				fileid = 0;
816				continue;
817			}
818			if (S_ISDIR(ret_attr.st_mode)) {
819				/*
820				 * only directories get pushed onto this stack,
821				 * so we do not have to test for regular files.
822				 */
823				t_dir_info = tlm_new_dir_info(&ret_fh,
824				    p_dir_info->fd_dir_name, dname);
825				if (t_dir_info == NULL) {
826					NDMP_LOG(LOG_DEBUG,
827					    "While backing up [%s][%s]",
828					    p_dir_info->fd_dir_name, dname);
829				} else if (cstack_push(stk, t_dir_info,
830				    0) != 0) {
831					NDMP_LOG(LOG_DEBUG,
832					    "No enough memory stack_push");
833					retval = -ENOMEM;
834					break;
835				}
836			} else if (S_ISREG(ret_attr.st_mode) ||
837			    S_ISLNK(ret_attr.st_mode)) {
838
839				fsize = backup_file(np->nr_unchkp_nm, dname,
840				    &tlm_acls, commands, local_commands,
841				    job_stats, &bks);
842
843				if (fsize >= 0) {
844					job_stats->js_files_so_far++;
845					job_stats->js_bytes_total += fsize;
846				} else
847					job_stats->js_errors++;
848				fileid = 0;
849			}
850		}
851		fileid = 0;
852		free(p_dir_info);
853		if (retval != 0)
854			break;
855	}
856
857	free(dname);
858
859	while (cstack_pop(stk, (void **)&p_dir_info, 0) == 0) {
860		free(p_dir_info);
861	}
862
863	cstack_delete(stk);
864	return (retval);
865}
866
867
868/*
869 * free_paths
870 *
871 * Free the path names
872 */
873static void
874free_paths(ndmp_run_args_t *np)
875{
876	free(np->nr_chkp_nm);
877	free(np->nr_unchkp_nm);
878	free(np->nr_excls);
879}
880
881
882/*
883 * malloc_paths
884 *
885 * Allocate the path names (direct and checkpointed paths)
886 */
887static boolean_t
888malloc_paths(ndmp_run_args_t *np)
889{
890	boolean_t rv;
891
892	rv = TRUE;
893	np->nr_chkp_nm = ndmp_malloc(TLM_MAX_PATH_NAME);
894	np->nr_unchkp_nm = ndmp_malloc(TLM_MAX_PATH_NAME);
895	if (!np->nr_chkp_nm || !np->nr_unchkp_nm) {
896		free_paths(np);
897		rv = FALSE;
898	} else if ((np->nr_excls = ndmpd_make_exc_list()) == NULL) {
899		free_paths(np);
900		rv = FALSE;
901	}
902	return (rv);
903}
904
905
906/*
907 * ndmp_backup_reader
908 *
909 * Backup reader thread which uses backup_work to read and TAR
910 * the files/dirs to be backed up (V2 only)
911 */
912static int
913ndmp_backup_reader(tlm_commands_t *commands, ndmp_lbr_params_t *nlp,
914    char *job_name)
915{
916	int retval;
917	ndmp_run_args_t np;
918	tlm_job_stats_t *job_stats;
919	tlm_cmd_t *local_commands;
920
921	NDMP_LOG(LOG_DEBUG, "bk_path: \"%s\"", nlp->nlp_backup_path);
922
923	local_commands = commands->tcs_command;
924	(void) memset(&np, 0, sizeof (np));
925	if (!malloc_paths(&np))
926		return (-1);
927	local_commands->tc_ref++;
928	commands->tcs_reader_count++;
929
930	job_stats = tlm_ref_job_stats(job_name);
931
932	retval = backup_work(nlp->nlp_backup_path, job_stats, &np,
933	    commands, nlp);
934	write_tar_eof(local_commands);
935
936	commands->tcs_reader_count--;
937	local_commands->tc_writer = TLM_STOP;
938	tlm_release_reader_writer_ipc(local_commands);
939	tlm_un_ref_job_stats(job_name);
940
941	free_paths(&np);
942	return (retval);
943
944}
945
946
947/*
948 * ndmp_tar_writer
949 *
950 * The backup writer thread that writes the TAR records to the
951 * tape media (V2 only)
952 */
953int
954ndmp_tar_writer(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
955    tlm_commands_t *cmds)
956{
957	int bidx, nw;
958	int err;
959	tlm_buffer_t *buf;
960	tlm_buffers_t *bufs;
961	tlm_cmd_t *lcmd;	/* Local command */
962
963	err = 0;
964	if (session == NULL) {
965		NDMP_LOG(LOG_DEBUG, "session == NULL");
966		err = -1;
967	} else if (mod_params == NULL) {
968		NDMP_LOG(LOG_DEBUG, "mod_params == NULL");
969		err = -1;
970	} else if (cmds == NULL) {
971		NDMP_LOG(LOG_DEBUG, "cmds == NULL");
972		err = -1;
973	}
974
975	if (err != 0)
976		return (err);
977
978	lcmd = cmds->tcs_command;
979	bufs = lcmd->tc_buffers;
980
981	lcmd->tc_ref++;
982	cmds->tcs_writer_count++;
983
984	nw = 0;
985	buf = tlm_buffer_out_buf(bufs, &bidx);
986	while (cmds->tcs_writer != (int)TLM_ABORT &&
987	    lcmd->tc_writer != (int)TLM_ABORT) {
988		if (buf->tb_full) {
989			NDMP_LOG(LOG_DEBUG, "w%d", bidx);
990
991			if (MOD_WRITE(mod_params, buf->tb_buffer_data,
992			    buf->tb_buffer_size) != 0) {
993				NDMP_LOG(LOG_DEBUG,
994				    "Writing buffer %d, pos: %lld",
995				    bidx, session->ns_mover.md_position);
996				err = -1;
997				break;
998			}
999
1000			tlm_buffer_mark_empty(buf);
1001			(void) tlm_buffer_advance_out_idx(bufs);
1002			buf = tlm_buffer_out_buf(bufs, &bidx);
1003			tlm_buffer_release_out_buf(bufs);
1004			nw++;
1005		} else {
1006			if (lcmd->tc_writer != TLM_BACKUP_RUN) {
1007				/* No more data is comming; time to exit. */
1008				NDMP_LOG(LOG_DEBUG,
1009				    "tc_writer!=TLM_BACKUP_RUN; time to exit");
1010				break;
1011			} else {
1012				NDMP_LOG(LOG_DEBUG, "W%d", bidx);
1013				tlm_buffer_in_buf_timed_wait(bufs, 100);
1014			}
1015		}
1016	}
1017
1018	NDMP_LOG(LOG_DEBUG, "nw: %d", nw);
1019	if (cmds->tcs_writer != (int)TLM_ABORT) {
1020		NDMP_LOG(LOG_DEBUG, "tcs_writer != TLM_ABORT");
1021	} else {
1022		NDMP_LOG(LOG_DEBUG, "tcs_writer == TLM_ABORT");
1023	}
1024
1025	if (lcmd->tc_writer != (int)TLM_ABORT) {
1026		NDMP_LOG(LOG_DEBUG, "tc_writer != TLM_ABORT");
1027	} else {
1028		NDMP_LOG(LOG_DEBUG, "tc_writer == TLM_ABORT");
1029	}
1030	cmds->tcs_writer_count--;
1031	lcmd->tc_reader = TLM_STOP;
1032	lcmd->tc_ref--;
1033
1034	return (err);
1035}
1036
1037
1038/*
1039 * read_one_buf
1040 *
1041 * Read one buffer from the tape
1042 */
1043static int
1044read_one_buf(ndmpd_module_params_t *mod_params, tlm_buffers_t *bufs,
1045    tlm_buffer_t *buf)
1046{
1047	int rv;
1048
1049	if ((rv = MOD_READ(mod_params, buf->tb_buffer_data,
1050	    bufs->tbs_data_transfer_size)) == 0) {
1051		buf->tb_eof = buf->tb_eot = FALSE;
1052		buf->tb_errno = 0;
1053		buf->tb_buffer_size = bufs->tbs_data_transfer_size;
1054		buf->tb_buffer_spot = 0;
1055		buf->tb_full = TRUE;
1056		(void) tlm_buffer_advance_in_idx(bufs);
1057	}
1058
1059	return (rv);
1060}
1061
1062
1063/*
1064 * ndmp_tar_reader
1065 *
1066 * NDMP Tar reader thread. This threads keep reading the tar
1067 * file from the tape and wakes up the consumer thread to extract
1068 * it on the disk
1069 */
1070int
1071ndmp_tar_reader(ndmp_tar_reader_arg_t *argp)
1072{
1073	int bidx;
1074	int err;
1075	tlm_buffer_t *buf;
1076	tlm_buffers_t *bufs;
1077	tlm_cmd_t *lcmd;	/* Local command */
1078	ndmpd_session_t *session;
1079	ndmpd_module_params_t *mod_params;
1080	tlm_commands_t *cmds;
1081
1082	if (!argp)
1083		return (-1);
1084
1085	session = argp->tr_session;
1086	mod_params = argp->tr_mod_params;
1087	cmds = argp->tr_cmds;
1088
1089	err = 0;
1090	if (session == NULL) {
1091		NDMP_LOG(LOG_DEBUG, "session == NULL");
1092		err = -1;
1093	} else if (cmds == NULL) {
1094		NDMP_LOG(LOG_DEBUG, "cmds == NULL");
1095		err = -1;
1096	}
1097
1098	if (err != 0) {
1099		tlm_cmd_signal(cmds->tcs_command, TLM_TAR_READER);
1100		return (err);
1101	}
1102
1103	lcmd = cmds->tcs_command;
1104	bufs = lcmd->tc_buffers;
1105
1106	lcmd->tc_ref++;
1107	cmds->tcs_reader_count++;
1108
1109	/*
1110	 * Synchronize with our parent thread.
1111	 */
1112	tlm_cmd_signal(cmds->tcs_command, TLM_TAR_READER);
1113
1114	buf = tlm_buffer_in_buf(bufs, &bidx);
1115	while (cmds->tcs_reader == TLM_RESTORE_RUN &&
1116	    lcmd->tc_reader == TLM_RESTORE_RUN) {
1117
1118		if (buf->tb_full) {
1119			NDMP_LOG(LOG_DEBUG, "R%d", bidx);
1120			/*
1121			 * The buffer is still full, wait for the consumer
1122			 * thread to use it.
1123			 */
1124			tlm_buffer_out_buf_timed_wait(bufs, 100);
1125			buf = tlm_buffer_in_buf(bufs, NULL);
1126		} else {
1127			NDMP_LOG(LOG_DEBUG, "r%d", bidx);
1128
1129			err = read_one_buf(mod_params, bufs, buf);
1130			if (err < 0) {
1131				NDMP_LOG(LOG_DEBUG,
1132				    "Reading buffer %d, pos: %lld",
1133				    bidx, session->ns_mover.md_position);
1134
1135				/* Force the writer to stop. */
1136				buf->tb_eot = buf->tb_eof = TRUE;
1137				break;
1138			} else if (err == 1) {
1139				NDMP_LOG(LOG_DEBUG,
1140				    "operation aborted or session terminated");
1141				err = 0;
1142				break;
1143			}
1144
1145			buf = tlm_buffer_in_buf(bufs, &bidx);
1146			tlm_buffer_release_in_buf(bufs);
1147		}
1148	}
1149
1150	/*
1151	 * If the consumer is waiting for us, wake it up so that it detects
1152	 * we're quiting.
1153	 */
1154	lcmd->tc_writer = TLM_STOP;
1155	tlm_buffer_release_in_buf(bufs);
1156	(void) usleep(1000);
1157
1158	/*
1159	 * Clean up.
1160	 */
1161	cmds->tcs_reader_count--;
1162	lcmd->tc_ref--;
1163	return (err);
1164}
1165
1166
1167/*
1168 * ndmpd_tar_backup
1169 *
1170 * Check must have been done that backup work directory exists, before
1171 * calling this function.
1172 */
1173static int
1174ndmpd_tar_backup(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
1175    ndmp_lbr_params_t *nlp)
1176{
1177	char jname[TLM_MAX_BACKUP_JOB_NAME];
1178	int err;
1179	tlm_commands_t *cmds;
1180
1181	if (mod_params->mp_operation != NDMP_DATA_OP_BACKUP) {
1182		NDMP_LOG(LOG_DEBUG,
1183		    "mod_params->mp_operation != NDMP_DATA_OP_BACKUP");
1184		err = -1;
1185	} else {
1186		if (ndmpd_mark_inodes_v2(session, nlp) != 0)
1187			err = -1;
1188		else if (ndmp_get_bk_dir_ino(nlp))
1189			err = -1;
1190		else
1191			err = 0;
1192	}
1193
1194	if (err != 0)
1195		return (err);
1196
1197	(void) ndmp_new_job_name(jname);
1198	if (backup_create_structs(session, jname) < 0)
1199		return (-1);
1200
1201	nlp->nlp_jstat->js_start_ltime = time(NULL);
1202	nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
1203	nlp->nlp_jstat->js_chkpnt_time = nlp->nlp_cdate;
1204
1205	if (!session->ns_data.dd_abort) {
1206
1207		cmds = &nlp->nlp_cmds;
1208		cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
1209		cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
1210		cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
1211
1212		if (ndmp_write_utf8magic(cmds->tcs_command) < 0) {
1213			backup_release_structs(session);
1214			return (-1);
1215		}
1216
1217		NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" started.",
1218		    nlp->nlp_backup_path);
1219
1220		err = ndmp_backup_reader(cmds, nlp, jname);
1221		if (err != 0) {
1222			backup_release_structs(session);
1223			NDMP_LOG(LOG_DEBUG, "Launch ndmp_backup_reader: %s",
1224			    strerror(err));
1225			return (-1);
1226		}
1227
1228		/* Act as the writer thread. */
1229		err = ndmp_tar_writer(session, mod_params, cmds);
1230
1231		nlp->nlp_jstat->js_stop_time = time(NULL);
1232
1233		NDMP_LOG(LOG_DEBUG,
1234		    "Runtime [%s] %llu bytes (%llu): %d seconds",
1235		    nlp->nlp_backup_path, session->ns_mover.md_data_written,
1236		    session->ns_mover.md_data_written,
1237		    nlp->nlp_jstat->js_stop_time -
1238		    nlp->nlp_jstat->js_start_ltime);
1239		MOD_LOG(mod_params,
1240		    "Runtime [%s] %llu bytes (%llu): %d seconds",
1241		    nlp->nlp_backup_path, session->ns_mover.md_data_written,
1242		    session->ns_mover.md_data_written,
1243		    nlp->nlp_jstat->js_stop_time -
1244		    nlp->nlp_jstat->js_start_ltime);
1245
1246		if (session->ns_data.dd_abort)
1247			err = -1;
1248
1249		NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" finished. (%d)",
1250		    nlp->nlp_backup_path, err);
1251	} else {
1252		nlp->nlp_jstat->js_stop_time = time(NULL);
1253		NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
1254		    nlp->nlp_backup_path);
1255		err = 0;
1256	}
1257
1258	backup_release_structs(session);
1259	return (err);
1260}
1261
1262
1263/*
1264 * ndmpd_tar_restore
1265 *
1266 * Restore function that launches TAR reader thread to read from the
1267 * tape and writes the extracted files/dirs to the filesystem
1268 */
1269static int
1270ndmpd_tar_restore(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
1271    ndmp_lbr_params_t *nlp)
1272{
1273	char jname[TLM_MAX_BACKUP_JOB_NAME];
1274	char *rspath;
1275	int err;
1276	tlm_commands_t *cmds;
1277	ndmp_tar_reader_arg_t arg;
1278	tlm_backup_restore_arg_t tlm_arg;
1279	ndmp_name *ent;
1280	pthread_t rdtp, wrtp;
1281	int i;
1282
1283	if (mod_params->mp_operation != NDMP_DATA_OP_RECOVER) {
1284		NDMP_LOG(LOG_DEBUG,
1285		    "mod_params->mp_operation != NDMP_DATA_OP_RECOVER");
1286		return (-1);
1287	}
1288
1289	if (nlp->nlp_restore_path[0] != '\0')
1290		rspath = nlp->nlp_restore_path;
1291	else if (nlp->nlp_restore_bk_path[0] != '\0')
1292		rspath = nlp->nlp_restore_bk_path;
1293	else
1294		rspath = "";
1295
1296	(void) ndmp_new_job_name(jname);
1297	if (restore_create_structs(session, jname) < 0)
1298		return (-1);
1299
1300	nlp->nlp_jstat->js_start_ltime = time(NULL);
1301	nlp->nlp_jstat->js_start_time = time(NULL);
1302
1303	if (!session->ns_data.dd_abort) {
1304		cmds = &nlp->nlp_cmds;
1305		cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
1306		cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
1307		cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
1308
1309		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" started.", rspath);
1310		NDMP_LOG(LOG_DEBUG, "Restoring from %s tape(s).",
1311		    ndmp_data_get_mover_mode(session));
1312
1313		arg.tr_session = session;
1314		arg.tr_mod_params = mod_params;
1315		arg.tr_cmds = cmds;
1316
1317		err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
1318		    (void *)&arg);
1319		if (err == 0) {
1320			tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
1321		} else {
1322			NDMP_LOG(LOG_DEBUG, "Launch ndmp_tar_reader: %m");
1323			return (-1);
1324		}
1325
1326		if (!ndmp_check_utf8magic(cmds->tcs_command)) {
1327			NDMP_LOG(LOG_DEBUG, "UTF8Magic not found!");
1328		} else {
1329			NDMP_LOG(LOG_DEBUG, "UTF8Magic found");
1330		}
1331
1332		(void) memset(&tlm_arg, 0, sizeof (tlm_backup_restore_arg_t));
1333		(void) pthread_barrier_init(&tlm_arg.ba_barrier, 0, 2);
1334
1335		/*
1336		 * Set up restore parameters
1337		 */
1338		tlm_arg.ba_commands = cmds;
1339		tlm_arg.ba_cmd = cmds->tcs_command;
1340		tlm_arg.ba_job = nlp->nlp_jstat->js_job_name;
1341		tlm_arg.ba_dir = nlp->nlp_restore_path;
1342		for (i = 0; i < nlp->nlp_nfiles; i++) {
1343			ent = (ndmp_name *)MOD_GETNAME(mod_params, i);
1344			tlm_arg.ba_sels[i] = ent->name;
1345		}
1346
1347
1348		if (tm_tar_ops.tm_getfile != NULL) {
1349			err = pthread_create(&wrtp, NULL,
1350			    (funct_t)tm_tar_ops.tm_getfile, (void *)&tlm_arg);
1351		} else {
1352			(void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1353			NDMP_LOG(LOG_DEBUG,
1354			    "Thread create tm_getfile: ops NULL");
1355			return (-1);
1356		}
1357		if (err == 0) {
1358			(void) pthread_barrier_wait(&tlm_arg.ba_barrier);
1359		} else {
1360			(void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1361			NDMP_LOG(LOG_DEBUG, "thread create tm_getfile: %m");
1362			return (-1);
1363		}
1364
1365		(void) pthread_join(rdtp, NULL);
1366		(void) pthread_join(wrtp, NULL);
1367		(void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1368
1369		nlp->nlp_jstat->js_stop_time = time(NULL);
1370
1371		/* Send the list of un-recovered files/dirs to the client.  */
1372		(void) send_unrecovered_list(mod_params, nlp);
1373
1374		ndmp_stop_local_reader(session, cmds);
1375		ndmp_wait_for_reader(cmds);
1376		ndmp_stop_remote_reader(session);
1377		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
1378		    rspath, err);
1379	} else {
1380		nlp->nlp_jstat->js_stop_time = time(NULL);
1381
1382		/* nothing restored. */
1383		(void) send_unrecovered_list(mod_params, nlp);
1384		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
1385		    rspath);
1386		err = -1;
1387	}
1388
1389	NDMP_FREE(nlp->nlp_restore_path);
1390	backup_release_structs(session);
1391
1392	return (err);
1393}
1394
1395
1396/*
1397 * prefixdir
1398 *
1399 * Extract the path for a given full path entry
1400 */
1401static char *
1402prefixdir(char *dir, char *suffix)
1403{
1404	static char tmp[TLM_MAX_PATH_NAME];
1405	char *tend, *send; /* tmp and suffix end */
1406
1407	if (dir == NULL || suffix == NULL)
1408		return (NULL);
1409
1410	if (*suffix == '\0')
1411		return (dir);
1412
1413	if (*dir == '\0')
1414		return (NULL);
1415
1416	(void) strlcpy(tmp, dir, TLM_MAX_PATH_NAME);
1417	tend = &tmp[strlen(tmp)];
1418	send = &suffix[strlen(suffix)];
1419
1420	/*
1421	 * Move backward as far as the last part of the dir and
1422	 * the suffix match.
1423	 */
1424	while (tend >= tmp && send >= suffix)
1425		if (*tend == *send)
1426			tend--, send--;
1427		else
1428			break;
1429
1430	*++tend = '\0';
1431	return (tmp);
1432}
1433
1434
1435/*
1436 * get_nfiles
1437 *
1438 * Get the count of files to be restored
1439 */
1440static int
1441get_nfiles(ndmpd_session_t *session, ndmpd_module_params_t *params)
1442{
1443	if (session->ns_data.dd_nlist_len == 0) {
1444		MOD_LOG(params, "Error: nothing specified to be restored.\n");
1445		return (-1);
1446	}
1447
1448	return (session->ns_data.dd_nlist_len);
1449}
1450
1451
1452/*
1453 * get_restore_dest
1454 *
1455 * Get the full pathname of where the entries should be restored to.
1456 */
1457static char *
1458get_restore_dest(ndmpd_module_params_t *params)
1459{
1460	ndmp_name *ent;
1461	char *cp;
1462
1463	/*
1464	 * Destination of restore:
1465	 * NetBackup of Veritas(C) sends the entries like this:
1466	 *
1467	 *	ent[i].name: is the relative pathname of what is selected in
1468	 *	  the GUI.
1469	 *	ent[i].dest: is the full pathname of where the dir/file must
1470	 *	  be restored to.
1471	 *	ent[i].ssi: 0
1472	 *	ent[i].fh_info: 0
1473	 *
1474	 */
1475	ent = (ndmp_name *)MOD_GETNAME(params, 0);
1476	cp = prefixdir(ent->dest, ent->name);
1477	if (cp == NULL) {
1478		MOD_LOG(params, "Error: empty restore path.\n");
1479		return (NULL);
1480	}
1481
1482	return (cp);
1483}
1484
1485
1486/*
1487 * correct_ents
1488 *
1489 * Correct the entries in the restore list by appending the appropriate
1490 * path to them
1491 */
1492static int
1493correct_ents(ndmpd_module_params_t *params, int n, char *bkpath)
1494{
1495	char *cp, *pathname;
1496	int i, len, rv;
1497	ndmp_name *ent;
1498
1499	if ((pathname = ndmp_malloc(TLM_MAX_PATH_NAME)) == NULL) {
1500		MOD_LOG(params, "Error: insufficient memory.\n");
1501		return (-1);
1502	}
1503
1504	rv = 0;
1505	/* Append the backup path to all the "ent[].name"s. */
1506	for (i = 0; i < n; i++) {
1507		ent = (ndmp_name *)MOD_GETNAME(params, i);
1508
1509		NDMP_LOG(LOG_DEBUG,
1510		    "Old: ent[%d].name: \"%s\"", i, ent->name);
1511		NDMP_LOG(LOG_DEBUG,
1512		    "Old: ent[%d].dest: \"%s\"", i, ent->dest);
1513
1514		/* remove trailing slash */
1515		len = strlen(ent->name);
1516		if (ent->name[len - 1] == '/')
1517			ent->name[len - 1] = '\0';
1518
1519		if (!tlm_cat_path(pathname, bkpath, ent->name)) {
1520			MOD_LOG(params, "Error: path too long.\n");
1521			rv = -1;
1522			break;
1523		}
1524
1525		/* Make a copy of the new string and save it in ent->name. */
1526		cp = strdup(pathname);
1527		if (cp == NULL) {
1528			MOD_LOG(params, "Error: insufficient memory.\n");
1529			rv = -1;
1530			break;
1531		}
1532		free(ent->name);
1533		ent->name = cp;
1534
1535		NDMP_LOG(LOG_DEBUG,
1536		    "New: ent[%d].name: \"%s\"", i, ent->name);
1537	}
1538
1539	free(pathname);
1540	return (rv);
1541}
1542
1543
1544/*
1545 * check_restore_paths
1546 *
1547 * Go through the restore list and check the validity of the
1548 * restore path.
1549 */
1550static int
1551check_restore_paths(ndmpd_module_params_t *params, int n, char *rspath)
1552{
1553	int i, rv;
1554	ndmp_name *ent;
1555
1556	rv = 0;
1557	if (rspath != NULL && *rspath != '\0') {
1558		NDMP_LOG(LOG_DEBUG, "rspath: \"%s\"", rspath);
1559		if (!fs_volexist(rspath)) {
1560			MOD_LOG(params,
1561			    "Error: Invalid volume name for restore.");
1562			rv = -1;
1563		}
1564	} else {
1565		for (i = 0; i < n; i++) {
1566			ent = (ndmp_name *)MOD_GETNAME(params, i);
1567			NDMP_LOG(LOG_DEBUG,
1568			    "ent[%d].name: \"%s\"", i, ent->name);
1569
1570			if (!fs_volexist(ent->name)) {
1571				MOD_LOG(params,
1572				    "Error: Invalid volume name for restore.",
1573				    ent->name);
1574				rv = -1;
1575				break;
1576			}
1577		}
1578	}
1579
1580	return (rv);
1581}
1582
1583
1584/*
1585 * check_backup_dir_validity
1586 *
1587 * Check if the backup directory is valid. Make sure it exists and
1588 * is writable. Check for snapshot and readonly cases.
1589 */
1590static int
1591check_backup_dir_validity(ndmpd_module_params_t *params, char *bkpath)
1592{
1593	char *msg;
1594	int rv;
1595	struct stat64 st;
1596
1597	rv = NDMP_NO_ERR;
1598	if (stat64(bkpath, &st) < 0) {
1599		msg = strerror(errno);
1600		MOD_LOG(params, "Error: stat(%s): %s.\n", bkpath, msg);
1601		rv = NDMP_ILLEGAL_ARGS_ERR;
1602	} else if (!S_ISDIR(st.st_mode)) {
1603		MOD_LOG(params, "Error: %s is not a directory.\n", bkpath);
1604		rv = NDMP_ILLEGAL_ARGS_ERR;
1605	} else if (fs_is_rdonly(bkpath) && !fs_is_chkpntvol(bkpath) &&
1606	    fs_is_chkpnt_enabled(bkpath)) {
1607		MOD_LOG(params, "Error: %s is not a checkpointed path.\n",
1608		    bkpath);
1609		rv = NDMP_BAD_FILE_ERR;
1610	}
1611
1612	return (rv);
1613}
1614
1615
1616/*
1617 * ndmp_backup_extract_params
1618 *
1619 * Go through the backup parameters and check the validity
1620 * for each one. Then set the NLP flags according to the parameters.
1621 */
1622int
1623ndmp_backup_extract_params(ndmpd_session_t *session,
1624    ndmpd_module_params_t *params)
1625{
1626	char *cp;
1627	int rv;
1628	ndmp_lbr_params_t *nlp;
1629
1630	/* Extract directory to be backed up from env variables */
1631	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1632		MOD_LOG(params, "Error: Internal error: nlp == NULL.\n");
1633		return (NDMP_ILLEGAL_ARGS_ERR);
1634	}
1635	if ((nlp->nlp_backup_path = get_backup_path_v2(params)) == NULL)
1636		return (NDMP_FILE_NOT_FOUND_ERR);
1637
1638	if ((rv = check_backup_dir_validity(params,
1639	    nlp->nlp_backup_path)) != NDMP_NO_ERR)
1640		return (rv);
1641
1642	/* Should the st_ctime be ignored when backing up? */
1643	if (ndmp_ignore_ctime) {
1644		NDMP_LOG(LOG_DEBUG, "ignoring st_ctime");
1645		NLP_SET(nlp, NLPF_IGNCTIME);
1646	} else
1647		NLP_UNSET(nlp, NLPF_IGNCTIME);
1648
1649	/* Should the st_lmtime be ignored when backing up? */
1650	if (ndmp_include_lmtime) {
1651		NDMP_LOG(LOG_DEBUG, "including st_lmtime");
1652		NLP_SET(nlp, NLPF_INCLMTIME);
1653	} else
1654		NLP_UNSET(nlp, NLPF_INCLMTIME);
1655
1656	NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
1657
1658	/* Is backup history requested? */
1659	cp = MOD_GETENV(params, "HIST");
1660	if (cp == NULL) {
1661		NDMP_LOG(LOG_DEBUG, "env(HIST) not specified");
1662		NLP_UNSET(nlp, NLPF_FH);
1663	} else {
1664		NDMP_LOG(LOG_DEBUG, "env(HIST): \"%s\"", cp);
1665
1666		if (strchr("t_ty_y", *cp))
1667			NLP_SET(nlp, NLPF_FH);
1668		else
1669			NLP_UNSET(nlp, NLPF_FH);
1670	}
1671
1672	nlp->nlp_clevel = 0;
1673	/* Is it an incremental backup? */
1674	cp = MOD_GETENV(params, "LEVEL");
1675	if (cp == NULL) {
1676		NDMP_LOG(LOG_DEBUG,
1677		    "env(LEVEL) not specified, default to 0");
1678	} else if (*cp < '0' || *cp > '9' || *(cp+1) != '\0') {
1679		NDMP_LOG(LOG_DEBUG, "Invalid backup level '%s'", cp);
1680		return (NDMP_ILLEGAL_ARGS_ERR);
1681	} else
1682		nlp->nlp_clevel = *cp - '0';
1683
1684	/* Extract last backup time from the dumpdates file */
1685	nlp->nlp_llevel = nlp->nlp_clevel;
1686	nlp->nlp_ldate = 0;
1687	if (ndmpd_get_dumptime(nlp->nlp_backup_path, &nlp->nlp_llevel,
1688	    &nlp->nlp_ldate) < 0) {
1689		MOD_LOG(params, "Error: getting dumpdate for %s level %d\n",
1690		    nlp->nlp_backup_path, nlp->nlp_clevel);
1691		return (NDMP_NO_MEM_ERR);
1692	}
1693
1694	NDMP_LOG(LOG_DEBUG,
1695	    "Date of this level %d on \"%s\": %s",
1696	    nlp->nlp_clevel, nlp->nlp_backup_path, cctime(&nlp->nlp_cdate));
1697	NDMP_LOG(LOG_DEBUG,
1698	    "Date of last level %d on \"%s\": %s",
1699	    nlp->nlp_llevel, nlp->nlp_backup_path, cctime(&nlp->nlp_ldate));
1700
1701	/* Should the dumpdate file be updated? */
1702	cp = MOD_GETENV(params, "UPDATE");
1703	if (cp == NULL) {
1704		NDMP_LOG(LOG_DEBUG,
1705		    "env(UPDATE) not specified, default to TRUE");
1706		NLP_SET(nlp, NLPF_UPDATE);
1707	} else {
1708		NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", cp);
1709		if (strchr("t_ty_y", *cp) != NULL)
1710			NLP_SET(nlp, NLPF_UPDATE);
1711		else
1712			NLP_UNSET(nlp, NLPF_UPDATE);
1713	}
1714
1715	return (NDMP_NO_ERR);
1716}
1717
1718
1719
1720/*
1721 * log_bk_params_v2
1722 *
1723 * Dump the value of the parameters in the log file for debugging.
1724 */
1725void
1726log_bk_params_v2(ndmpd_session_t *session, ndmpd_module_params_t *params,
1727    ndmp_lbr_params_t *nlp)
1728{
1729	MOD_LOG(params, "Date of this level %d on \"%s\": %s\n",
1730	    nlp->nlp_clevel, nlp->nlp_backup_path, cctime(&nlp->nlp_cdate));
1731	MOD_LOG(params, "Date of last level %d on \"%s\": %s\n",
1732	    nlp->nlp_llevel, nlp->nlp_backup_path, cctime(&nlp->nlp_ldate));
1733
1734	MOD_LOG(params, "Backing up: \"%s\".\n", nlp->nlp_backup_path);
1735	MOD_LOG(params, "Record size: %d\n", session->ns_mover.md_record_size);
1736	MOD_LOG(params, "File history: %c.\n",
1737	    NDMP_YORN(NLP_ISSET(nlp, NLPF_FH)));
1738	MOD_LOG(params, "Update: %s\n",
1739	    NLP_ISSET(nlp, NLPF_UPDATE) ? "TRUE" : "FALSE");
1740
1741}
1742
1743
1744/*
1745 * same_path
1746 *
1747 * Find out if the paths are the same regardless of the ending slash
1748 *
1749 * Examples :
1750 *   /a/b/c == /a/b/c
1751 *   /a/b/c/ == /a/b/c
1752 *   /a/b/c == /a/b/c/
1753 */
1754static boolean_t
1755same_path(char *s, char *t)
1756{
1757	boolean_t rv;
1758	int slen, tlen;
1759
1760	rv = FALSE;
1761	slen = strlen(s);
1762	tlen = strlen(t);
1763	if (slen == tlen && strcmp(s, t) == 0) {
1764		rv = TRUE;
1765	} else {
1766		if (slen == tlen - 1) {
1767			if (strncmp(s, t, slen) == 0 && t[tlen - 1] == '/')
1768				rv = TRUE;
1769		} else if (tlen == slen -1) {
1770			if (strncmp(s, t, tlen) == 0 && s[slen - 1] == '/')
1771				rv = TRUE;
1772		}
1773	}
1774
1775	NDMP_LOG(LOG_DEBUG, "rv: %d", rv);
1776	return (rv);
1777}
1778
1779
1780/*
1781 * ndmp_restore_extract_params
1782 *
1783 * Go through the restore parameters and check them and extract them
1784 * by setting NLP flags and other values.
1785 *
1786 * Parameters:
1787 *
1788 * Returns:
1789 *   0: on success
1790 *  -1: otherwise
1791 */
1792int
1793ndmp_restore_extract_params(ndmpd_session_t *session,
1794    ndmpd_module_params_t *params)
1795{
1796	char *bkpath, *rspath;
1797	ndmp_lbr_params_t *nlp;
1798
1799	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1800		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1801		return (-1);
1802	}
1803
1804	/* Extract directory from where the backup was made. */
1805	if ((bkpath = get_backup_path_v2(params)) == NULL)
1806		return (NDMP_ILLEGAL_ARGS_ERR);
1807
1808	nlp->nlp_restore_bk_path = bkpath;
1809
1810	/* The number of the selections. */
1811	if ((nlp->nlp_nfiles = get_nfiles(session, params)) == 0)
1812		return (NDMP_ILLEGAL_ARGS_ERR);
1813
1814	NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
1815
1816	if ((rspath = get_restore_dest(params)) == NULL)
1817		return (NDMP_ILLEGAL_ARGS_ERR);
1818
1819	if (fs_is_rdonly(rspath)) {
1820		MOD_LOG(params,
1821		    "Error: Can't restore to a read-only volume: \"%s\"\n",
1822		    rspath);
1823		return (NDMP_ILLEGAL_ARGS_ERR);
1824	}
1825	if (fs_is_chkpntvol(rspath)) {
1826		MOD_LOG(params,
1827		    "Error: Can't restore to a checkpoint: \"%s\"\n", rspath);
1828		return (NDMP_ILLEGAL_ARGS_ERR);
1829	}
1830
1831	if (same_path(bkpath, rspath))
1832		rspath = "";
1833
1834	if ((nlp->nlp_restore_path = strdup(rspath)) == NULL)
1835		return (NDMP_NO_MEM_ERR);
1836
1837	bkpath = trim_name(bkpath);
1838	if (correct_ents(params, nlp->nlp_nfiles, bkpath) < 0) {
1839		free(nlp->nlp_restore_path);
1840		return (NDMP_ILLEGAL_ARGS_ERR);
1841	}
1842
1843	if (check_restore_paths(params, nlp->nlp_nfiles, rspath) < 0) {
1844		free(nlp->nlp_restore_path);
1845		return (NDMP_ILLEGAL_ARGS_ERR);
1846	}
1847
1848	MOD_LOG(params, "Restoring %d files.\n", nlp->nlp_nfiles);
1849	MOD_LOG(params, "Restoring to: \"%s\".\n", nlp->nlp_restore_path);
1850	MOD_LOG(params, "Record size: %d\n", session->ns_mover.md_record_size);
1851
1852	return (NDMP_NO_ERR);
1853}
1854
1855/*
1856 * ndmpd_tar_backup_starter (V2 only)
1857 *
1858 * The main backup starter function. It creates a snapshot if necessary
1859 * and calls ndmp_tar_backup to perform the actual backup. It does the cleanup
1860 * and release the snapshot at the end.
1861 */
1862int
1863ndmpd_tar_backup_starter(void *arg)
1864{
1865	ndmpd_module_params_t *mod_params = arg;
1866	int err;
1867	ndmpd_session_t *session;
1868	ndmp_lbr_params_t *nlp;
1869
1870	session = (ndmpd_session_t *)(mod_params->mp_daemon_cookie);
1871	*(mod_params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
1872	ndmp_session_ref(session);
1873
1874	err = 0;
1875	if (fs_is_chkpntvol(nlp->nlp_backup_path) ||
1876	    fs_is_rdonly(nlp->nlp_backup_path) ||
1877	    !fs_is_chkpnt_enabled(nlp->nlp_backup_path))
1878		NLP_SET(nlp, NLPF_CHKPNTED_PATH);
1879	else {
1880		NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
1881		if (ndmp_create_snapshot(nlp->nlp_backup_path,
1882		    nlp->nlp_jstat->js_job_name) < 0) {
1883			MOD_LOG(mod_params,
1884			    "Error: creating checkpoint on %s\n",
1885			    nlp->nlp_backup_path);
1886			/* -1 causes halt reason to become internal error. */
1887			err = -1;
1888		}
1889	}
1890
1891	NDMP_LOG(LOG_DEBUG, "NLPF_CHKPNTED_PATH: %c",
1892	    NDMP_YORN(NLP_ISCHKPNTED(nlp)));
1893	NDMP_LOG(LOG_DEBUG, "err: %d, update %c",
1894	    err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
1895
1896	if (err == 0) {
1897		err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate,
1898		    nlp->nlp_jstat->js_job_name);
1899		if (err != 0) {
1900			NDMP_LOG(LOG_DEBUG, "err %d", err);
1901		} else {
1902			log_bk_params_v2(session, mod_params, nlp);
1903			err = ndmpd_tar_backup(session, mod_params, nlp);
1904		}
1905	}
1906
1907	if (nlp->nlp_bkmap >= 0) {
1908		(void) dbm_free(nlp->nlp_bkmap);
1909		nlp->nlp_bkmap = -1;
1910	}
1911
1912	if (!NLP_ISCHKPNTED(nlp))
1913		(void) ndmp_remove_snapshot(nlp->nlp_backup_path,
1914		    nlp->nlp_jstat->js_job_name);
1915
1916	NDMP_LOG(LOG_DEBUG, "err %d, update %c",
1917	    err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
1918
1919	if (err == 0 && NLP_SHOULD_UPDATE(nlp)) {
1920		if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel,
1921		    nlp->nlp_cdate) < 0) {
1922			err = EPERM;
1923			MOD_LOG(mod_params,
1924			    "Error: updating the dumpdates file on %s\n",
1925			    nlp->nlp_backup_path);
1926		}
1927	}
1928
1929	MOD_DONE(mod_params, err);
1930
1931	/* nlp_params is allocated in start_backup() */
1932	NDMP_FREE(nlp->nlp_params);
1933
1934	NS_DEC(nbk);
1935	ndmp_session_unref(session);
1936	return (err);
1937}
1938
1939
1940/*
1941 * ndmpd_tar_backup_abort
1942 *
1943 * Abort the running backup by stopping the reader thread (V2 only)
1944 */
1945int
1946ndmpd_tar_backup_abort(void *module_cookie)
1947{
1948	ndmp_lbr_params_t *nlp;
1949
1950	nlp = (ndmp_lbr_params_t *)module_cookie;
1951	if (nlp != NULL && nlp->nlp_session != NULL) {
1952		if (nlp->nlp_session->ns_data.dd_mover.addr_type ==
1953		    NDMP_ADDR_TCP && nlp->nlp_session->ns_data.dd_sock != -1) {
1954			(void) close(nlp->nlp_session->ns_data.dd_sock);
1955			nlp->nlp_session->ns_data.dd_sock = -1;
1956		}
1957		ndmp_stop_reader_thread(nlp->nlp_session);
1958	}
1959
1960	return (0);
1961}
1962
1963/*
1964 * ndmpd_tar_restore_starter
1965 *
1966 * Starts the restore by running ndmpd_tar_restore function (V2 only)
1967 */
1968
1969int
1970ndmpd_tar_restore_starter(void *arg)
1971{
1972	ndmpd_module_params_t *mod_params = arg;
1973	int err;
1974	ndmpd_session_t *session;
1975	ndmp_lbr_params_t *nlp;
1976
1977	session = (ndmpd_session_t *)(mod_params->mp_daemon_cookie);
1978	*(mod_params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
1979	ndmp_session_ref(session);
1980
1981	err = ndmpd_tar_restore(session, mod_params, nlp);
1982	MOD_DONE(mod_params, err);
1983
1984	/* nlp_params is allocated in start_recover() */
1985	NDMP_FREE(nlp->nlp_params);
1986
1987	NS_DEC(nrs);
1988	ndmp_session_unref(session);
1989	return (err);
1990}
1991
1992
1993/*
1994 * ndmpd_tar_restore_abort
1995 *
1996 * Aborts the restore operation by stopping the writer thread (V2 only)
1997 */
1998int
1999ndmpd_tar_restore_abort(void *module_cookie)
2000{
2001	ndmp_lbr_params_t *nlp;
2002
2003	nlp = (ndmp_lbr_params_t *)module_cookie;
2004	if (nlp != NULL && nlp->nlp_session != NULL) {
2005		(void) mutex_lock(&nlp->nlp_mtx);
2006		if (nlp->nlp_session->ns_data.dd_mover.addr_type ==
2007		    NDMP_ADDR_TCP && nlp->nlp_session->ns_data.dd_sock != -1) {
2008			(void) close(nlp->nlp_session->ns_data.dd_sock);
2009			nlp->nlp_session->ns_data.dd_sock = -1;
2010		}
2011		(void) cond_broadcast(&nlp->nlp_cv);
2012		(void) mutex_unlock(&nlp->nlp_mtx);
2013		ndmp_stop_writer_thread(nlp->nlp_session);
2014	}
2015
2016	return (0);
2017}
2018