xref: /titanic_41/usr/src/cmd/ndmpd/ndmp/ndmpd_tar.c (revision f700969ab27181023551541cb5293e922f1587eb)
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 
58 typedef 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  */
78 static int
79 backup_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  */
147 static int
148 restore_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  */
211 static int
212 send_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*/
268 static void
269 backup_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  */
321 int
322 ndmp_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  */
372 static boolean_t
373 timecmp(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  */
436 static int
437 get_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  */
470 static int
471 get_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  */
542 static int
543 backup_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  */
579 static longlong_t
580 backup_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  */
639 int
640 backup_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  */
873 static void
874 free_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  */
887 static boolean_t
888 malloc_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  */
912 static int
913 ndmp_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  */
953 int
954 ndmp_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  */
1043 static int
1044 read_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  */
1070 int
1071 ndmp_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  */
1173 static int
1174 ndmpd_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  */
1269 static int
1270 ndmpd_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  */
1401 static char *
1402 prefixdir(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  */
1440 static int
1441 get_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  */
1457 static char *
1458 get_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  */
1492 static int
1493 correct_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  */
1550 static int
1551 check_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  */
1590 static int
1591 check_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  */
1622 int
1623 ndmp_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  */
1725 void
1726 log_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  */
1754 static boolean_t
1755 same_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  */
1792 int
1793 ndmp_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  */
1862 int
1863 ndmpd_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  */
1945 int
1946 ndmpd_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 
1969 int
1970 ndmpd_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  */
1998 int
1999 ndmpd_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