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