2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
8 * Copyright (c) 2007, The Storage Networking Industry Association.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
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
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
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.
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. */
43 #include <sys/types.h>
44 #include <sys/socket.h>
55 #include "tlm_buffers.h"
58 typedef struct ndmp_run_args
{
66 * backup_create_structs
68 * Allocate the structures before performing backup
71 * sesison (input) - session handle
72 * jname (input) - backup job name
79 backup_create_structs(ndmpd_session_t
*session
, char *jname
)
83 ndmp_lbr_params_t
*nlp
;
86 if ((nlp
= ndmp_get_nlp(session
)) == NULL
) {
87 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
91 if ((nlp
->nlp_jstat
= tlm_new_job_stats(jname
)) == NULL
) {
92 NDMP_LOG(LOG_DEBUG
, "Creating job stats");
96 cmds
= &nlp
->nlp_cmds
;
97 (void) memset(cmds
, 0, sizeof (*cmds
));
99 xfer_size
= ndmp_buffer_get_size(session
);
100 if (xfer_size
< 512*KILOBYTE
) {
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.
106 if ((n
= (512 * KILOBYTE
/xfer_size
)) <= 0)
109 NDMP_LOG(LOG_DEBUG
, "Adjusted read size: %d", xfer_size
);
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
);
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
);
128 nlp
->nlp_jstat
->js_callbacks
= (void *)(nlp
->nlp_logcallbacks
);
135 * restore_create_structs
137 * Allocate structures for performing a restore
140 * sesison (input) - session handle
141 * jname (input) - backup job name
148 restore_create_structs(ndmpd_session_t
*session
, char *jname
)
152 ndmp_lbr_params_t
*nlp
;
153 tlm_commands_t
*cmds
;
155 if ((nlp
= ndmp_get_nlp(session
)) == NULL
) {
156 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
159 if ((nlp
->nlp_jstat
= tlm_new_job_stats(jname
)) == NULL
) {
160 NDMP_LOG(LOG_DEBUG
, "Creating job stats");
164 cmds
= &nlp
->nlp_cmds
;
165 (void) memset(cmds
, 0, sizeof (*cmds
));
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
);
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
);
182 nlp
->nlp_jstat
->js_callbacks
= (void *)(nlp
->nlp_logcallbacks
);
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
);
191 for (i
= 0; i
< (int)nlp
->nlp_nfiles
; i
++)
192 nlp
->nlp_restored
[i
] = FALSE
;
199 * send_unrecovered_list
201 * Creates a list of restored files
204 * params (input) - NDMP parameters
205 * nlp (input) - NDMP/LBR parameters
212 send_unrecovered_list(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
217 if (params
== NULL
) {
218 NDMP_LOG(LOG_DEBUG
, "params == NULL");
222 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
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");
231 if (!nlp
->nlp_restored
[i
]) {
232 ent
= (ndmp_name
*)MOD_GETNAME(params
, i
);
234 NDMP_LOG(LOG_DEBUG
, "ent == NULL");
238 if (ent
->name
== NULL
) {
239 NDMP_LOG(LOG_DEBUG
, "ent->name == NULL");
244 NDMP_LOG(LOG_DEBUG
, "ent.name: \"%s\"", ent
->name
);
246 rv
= MOD_FILERECOVERD(params
, ent
->name
, ENOENT
);
257 * backup_release_structs
259 * Deallocated the NDMP/LBR specific parameters
262 * session (input) - session handle
269 backup_release_structs(ndmpd_session_t
*session
)
271 ndmp_lbr_params_t
*nlp
;
272 tlm_commands_t
*cmds
;
274 if ((nlp
= ndmp_get_nlp(session
)) == NULL
) {
275 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
278 cmds
= &nlp
->nlp_cmds
;
280 NDMP_LOG(LOG_DEBUG
, "cmds == NULL");
284 if (nlp
->nlp_logcallbacks
!= NULL
) {
285 lbrlog_callbacks_done(nlp
->nlp_logcallbacks
);
286 nlp
->nlp_logcallbacks
= NULL
;
288 NDMP_LOG(LOG_DEBUG
, "FH CALLBACKS == NULL");
291 if (cmds
->tcs_command
!= NULL
) {
292 if (cmds
->tcs_command
->tc_buffers
!= NULL
)
293 tlm_release_reader_writer_ipc(cmds
->tcs_command
);
295 NDMP_LOG(LOG_DEBUG
, "BUFFERS == NULL");
296 cmds
->tcs_command
= NULL
;
298 NDMP_LOG(LOG_DEBUG
, "COMMAND == NULL");
301 if (nlp
->nlp_bkmap
>= 0) {
302 (void) dbm_free(nlp
->nlp_bkmap
);
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
;
311 NDMP_LOG(LOG_DEBUG
, "nlp_restored == NULL");
316 * ndmp_write_utf8magic
318 * Write a magic pattern to the tar header. This is used
319 * as a crest to indicate that tape belongs to us.
322 ndmp_write_utf8magic(tlm_cmd_t
*cmd
)
327 if (cmd
->tc_buffers
== NULL
) {
328 NDMP_LOG(LOG_DEBUG
, "cmd->tc_buffers == NULL");
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");
339 (void) strlcpy(cp
, NDMPUTF8MAGIC
, RECORDSIZE
);
347 * This callback function is used during backup. It checks
348 * if the object specified by the 'attr' should be backed
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.
357 * Directories for tar format are backed up if and only if
360 * By setting ndmp_force_bk_dirs global variable to a non-zero
361 * value, directories are backed up anyways.
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.
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.
373 timecmp(bk_selector_t
*bksp
,
376 ndmp_lbr_params_t
*nlp
;
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
);
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
))) {
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
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.
403 NDMP_LOG(LOG_DEBUG
, "p(%lu)", (u_longlong_t
)attr
->st_ino
);
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
);
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
);
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
);
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
);
434 * load up all the access and attribute info
437 get_acl_info(char *name
, tlm_acls_t
*tlm_acls
)
443 erc
= lstat64(name
, &tlm_acls
->acl_attr
);
445 NDMP_LOG(LOG_ERR
, "Could not find file %s.", name
);
446 erc
= TLM_NO_SOURCE_FILE
;
449 erc
= acl_get(name
, ACL_NO_TRIVIAL
, &aclp
);
452 "Could not read ACL for file [%s]", name
);
453 erc
= TLM_NO_SOURCE_FILE
;
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
,
468 * load up all ACL and attr info about a directory
471 get_dir_acl_info(char *dir
, tlm_acls_t
*tlm_acls
, tlm_job_stats_t
*js
)
474 char *checkpointed_dir
;
475 char root_dir
[TLM_VOLNAME_MAX_LENGTH
];
481 checkpointed_dir
= ndmp_malloc(TLM_MAX_PATH_NAME
);
482 if (checkpointed_dir
== NULL
)
485 if (tlm_acls
->acl_checkpointed
)
486 fil
= tlm_build_snapshot_name(dir
, checkpointed_dir
,
490 erc
= lstat64(fil
, &tlm_acls
->acl_attr
);
492 NDMP_LOG(LOG_ERR
, "Could not find directory %s.", dir
);
493 free(checkpointed_dir
);
497 spot
= strchr(&fil
[1], '/');
499 (void) strlcpy(root_dir
, fil
, TLM_VOLNAME_MAX_LENGTH
);
502 (void) strlcpy(root_dir
, fil
, TLM_VOLNAME_MAX_LENGTH
);
505 if (strcmp(root_dir
, tlm_acls
->acl_root_dir
) != 0) {
508 erc
= lstat64(root_dir
, &attr
);
510 NDMP_LOG(LOG_ERR
, "Cannot find root directory %s.",
512 free(checkpointed_dir
);
515 (void) strlcpy(tlm_acls
->acl_root_dir
, root_dir
,
516 TLM_VOLNAME_MAX_LENGTH
);
518 erc
= acl_get(fil
, ACL_NO_TRIVIAL
, &aclp
);
521 "Could not read metadata for directory [%s]", dir
);
522 free(checkpointed_dir
);
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
,
533 free(checkpointed_dir
);
540 * Create a TAR entry record for a directory
543 backup_dir(char *dir
, tlm_acls_t
*tlm_acls
,
544 tlm_cmd_t
*local_commands
, tlm_job_stats_t
*job_stats
,
549 NDMP_LOG(LOG_DEBUG
, "\"%s\"", dir
);
551 erc
= get_dir_acl_info(dir
, tlm_acls
, job_stats
);
554 "Could not read directory info for %s", dir
);
555 job_stats
->js_errors
++;
558 * See if the directory must be backed up.
560 if (bksp
&& !(*bksp
->bs_fn
)(bksp
, &tlm_acls
->acl_attr
)) {
561 NDMP_LOG(LOG_DEBUG
, "[%s] dir skipped", dir
);
565 if (tm_tar_ops
.tm_putdir
!= NULL
)
566 (void) (tm_tar_ops
.tm_putdir
)(dir
, tlm_acls
,
567 local_commands
, job_stats
);
577 * Create a TAR record entry for a file
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
)
586 char buf
[TLM_MAX_PATH_NAME
];
589 NDMP_LOG(LOG_DEBUG
, "\"%s/%s\"", dir
, name
);
591 (void) strlcpy(buf
, dir
, sizeof (buf
));
592 (void) strlcat(buf
, "/", sizeof (buf
));
593 (void) strlcat(buf
, name
, sizeof (buf
));
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.
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
);
606 /* Should the file be backed up? */
609 "[%s/%s] has no selection criteria", dir
, name
);
611 } else if (!((*bksp
->bs_fn
)(bksp
, &tlm_acls
->acl_attr
))) {
612 NDMP_LOG(LOG_DEBUG
, "[%s/%s] file skipped", dir
, name
);
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
)) {
620 "Warning: skip backing up [%s][%s]", dir
, name
);
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
);
637 * Start the NDMP backup (V2 only).
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
)
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 */
648 char *first_name
; /* where the first name is located */
653 unsigned long fileid
;
658 tlm_cmd_t
*local_commands
;
661 NDMP_LOG(LOG_DEBUG
, "nr_chkpnted %d nr_ldate: %u bk_path: \"%s\"",
662 NLP_ISCHKPNTED(nlp
), nlp
->nlp_ldate
, bk_path
);
664 /* Get every name in this directory */
665 dname
= ndmp_malloc(TLM_MAX_PATH_NAME
);
669 local_commands
= commands
->tcs_command
;
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
;
678 * should we skip the whole thing?
680 if (tlm_is_excluded("", bk_path
, np
->nr_excls
)) {
681 NDMP_LOG(LOG_DEBUG
, "%s excluded", bk_path
);
687 * Search for the top-level file-directory
689 if (NLP_ISCHKPNTED(nlp
)) {
690 first_name
= np
->nr_chkp_nm
;
691 (void) strlcpy(first_name
, bk_path
, TLM_MAX_PATH_NAME
);
693 first_name
= tlm_build_snapshot_name(bk_path
, np
->nr_chkp_nm
,
694 nlp
->nlp_jstat
->js_job_name
);
697 (void) memset(&ret_fh
, 0, sizeof (ret_fh
));
698 erc
= fs_getstat(first_name
, &ret_fh
, &ret_attr
);
700 NDMP_LOG(LOG_ERR
, "Path %s not found.", first_name
);
705 if ((stk
= cstack_new()) == NULL
) {
707 NDMP_LOG(LOG_DEBUG
, "cstack_new failed");
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
);
715 * Push the first name onto the stack so that we can pop it back
716 * off as part of the normal cycle
718 if (cstack_push(stk
, p_dir_info
, 0)) {
722 NDMP_LOG(LOG_DEBUG
, "cstack_push failed");
726 (void) memset(&tlm_acls
, 0, sizeof (tlm_acls
));
728 * Did NDMP create a checkpoint?
730 if (NLP_ISCHKPNTED(nlp
) || fs_is_rdonly(bk_path
)) {
731 tlm_acls
.acl_checkpointed
= FALSE
;
733 /* Use the checkpoint created by NDMP */
734 tlm_acls
.acl_checkpointed
= TRUE
;
738 * This is level-backup. It never resets the archive bit.
740 tlm_acls
.acl_clear_archive
= FALSE
;
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
));
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) {
750 if (NLP_ISCHKPNTED(nlp
))
751 (void) strlcpy(np
->nr_unchkp_nm
,
752 p_dir_info
->fd_dir_name
, TLM_MAX_PATH_NAME
);
754 (void) tlm_remove_checkpoint(p_dir_info
->fd_dir_name
,
757 (void) backup_dir(np
->nr_unchkp_nm
, &tlm_acls
, local_commands
,
761 while (commands
->tcs_reader
== TLM_BACKUP_RUN
&&
762 local_commands
->tc_reader
== TLM_BACKUP_RUN
) {
764 dname_size
= TLM_MAX_PATH_NAME
- 1;
767 "dir_name: %s", p_dir_info
->fd_dir_name
);
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
);
774 fileid
= ret_fh
.fh_fid
;
777 "Filesystem readdir in [%s]",
778 p_dir_info
->fd_dir_name
);
783 /* an empty name size marks the end of the list */
786 dname
[dname_size
] = '\0';
788 NDMP_LOG(LOG_DEBUG
, "dname: \"%s\"", dname
);
791 * If name refers to a directory, push its file
792 * handle onto the stack (skip "." and "..").
794 if (rootfs_dot_or_dotdot(dname
)) {
801 * non-dir entries which should not be backed up
803 * dir-type entries which have have nothing under
804 * their hierarchy to be backed up.
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
);
813 if (tlm_is_excluded(np
->nr_unchkp_nm
, dname
,
818 if (S_ISDIR(ret_attr
.st_mode
)) {
820 * only directories get pushed onto this stack,
821 * so we do not have to test for regular files.
823 t_dir_info
= tlm_new_dir_info(&ret_fh
,
824 p_dir_info
->fd_dir_name
, dname
);
825 if (t_dir_info
== NULL
) {
827 "While backing up [%s][%s]",
828 p_dir_info
->fd_dir_name
, dname
);
829 } else if (cstack_push(stk
, t_dir_info
,
832 "No enough memory stack_push");
836 } else if (S_ISREG(ret_attr
.st_mode
) ||
837 S_ISLNK(ret_attr
.st_mode
)) {
839 fsize
= backup_file(np
->nr_unchkp_nm
, dname
,
840 &tlm_acls
, commands
, local_commands
,
844 job_stats
->js_files_so_far
++;
845 job_stats
->js_bytes_total
+= fsize
;
847 job_stats
->js_errors
++;
859 while (cstack_pop(stk
, (void **)&p_dir_info
, 0) == 0) {
871 * Free the path names
874 free_paths(ndmp_run_args_t
*np
)
876 free(np
->nr_chkp_nm
);
877 free(np
->nr_unchkp_nm
);
885 * Allocate the path names (direct and checkpointed paths)
888 malloc_paths(ndmp_run_args_t
*np
)
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
) {
898 } else if ((np
->nr_excls
= ndmpd_make_exc_list()) == NULL
) {
909 * Backup reader thread which uses backup_work to read and TAR
910 * the files/dirs to be backed up (V2 only)
913 ndmp_backup_reader(tlm_commands_t
*commands
, ndmp_lbr_params_t
*nlp
,
918 tlm_job_stats_t
*job_stats
;
919 tlm_cmd_t
*local_commands
;
921 NDMP_LOG(LOG_DEBUG
, "bk_path: \"%s\"", nlp
->nlp_backup_path
);
923 local_commands
= commands
->tcs_command
;
924 (void) memset(&np
, 0, sizeof (np
));
925 if (!malloc_paths(&np
))
927 local_commands
->tc_ref
++;
928 commands
->tcs_reader_count
++;
930 job_stats
= tlm_ref_job_stats(job_name
);
932 retval
= backup_work(nlp
->nlp_backup_path
, job_stats
, &np
,
934 write_tar_eof(local_commands
);
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
);
950 * The backup writer thread that writes the TAR records to the
951 * tape media (V2 only)
954 ndmp_tar_writer(ndmpd_session_t
*session
, ndmpd_module_params_t
*mod_params
,
955 tlm_commands_t
*cmds
)
961 tlm_cmd_t
*lcmd
; /* Local command */
964 if (session
== NULL
) {
965 NDMP_LOG(LOG_DEBUG
, "session == NULL");
967 } else if (mod_params
== NULL
) {
968 NDMP_LOG(LOG_DEBUG
, "mod_params == NULL");
970 } else if (cmds
== NULL
) {
971 NDMP_LOG(LOG_DEBUG
, "cmds == NULL");
978 lcmd
= cmds
->tcs_command
;
979 bufs
= lcmd
->tc_buffers
;
982 cmds
->tcs_writer_count
++;
985 buf
= tlm_buffer_out_buf(bufs
, &bidx
);
986 while (cmds
->tcs_writer
!= (int)TLM_ABORT
&&
987 lcmd
->tc_writer
!= (int)TLM_ABORT
) {
989 NDMP_LOG(LOG_DEBUG
, "w%d", bidx
);
991 if (MOD_WRITE(mod_params
, buf
->tb_buffer_data
,
992 buf
->tb_buffer_size
) != 0) {
994 "Writing buffer %d, pos: %lld",
995 bidx
, session
->ns_mover
.md_position
);
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
);
1006 if (lcmd
->tc_writer
!= TLM_BACKUP_RUN
) {
1007 /* No more data is comming; time to exit. */
1009 "tc_writer!=TLM_BACKUP_RUN; time to exit");
1012 NDMP_LOG(LOG_DEBUG
, "W%d", bidx
);
1013 tlm_buffer_in_buf_timed_wait(bufs
, 100);
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");
1022 NDMP_LOG(LOG_DEBUG
, "tcs_writer == TLM_ABORT");
1025 if (lcmd
->tc_writer
!= (int)TLM_ABORT
) {
1026 NDMP_LOG(LOG_DEBUG
, "tc_writer != TLM_ABORT");
1028 NDMP_LOG(LOG_DEBUG
, "tc_writer == TLM_ABORT");
1030 cmds
->tcs_writer_count
--;
1031 lcmd
->tc_reader
= TLM_STOP
;
1041 * Read one buffer from the tape
1044 read_one_buf(ndmpd_module_params_t
*mod_params
, tlm_buffers_t
*bufs
,
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
;
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
);
1066 * NDMP Tar reader thread. This threads keep reading the tar
1067 * file from the tape and wakes up the consumer thread to extract
1071 ndmp_tar_reader(ndmp_tar_reader_arg_t
*argp
)
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
;
1085 session
= argp
->tr_session
;
1086 mod_params
= argp
->tr_mod_params
;
1087 cmds
= argp
->tr_cmds
;
1090 if (session
== NULL
) {
1091 NDMP_LOG(LOG_DEBUG
, "session == NULL");
1093 } else if (cmds
== NULL
) {
1094 NDMP_LOG(LOG_DEBUG
, "cmds == NULL");
1099 tlm_cmd_signal(cmds
->tcs_command
, TLM_TAR_READER
);
1103 lcmd
= cmds
->tcs_command
;
1104 bufs
= lcmd
->tc_buffers
;
1107 cmds
->tcs_reader_count
++;
1110 * Synchronize with our parent thread.
1112 tlm_cmd_signal(cmds
->tcs_command
, TLM_TAR_READER
);
1114 buf
= tlm_buffer_in_buf(bufs
, &bidx
);
1115 while (cmds
->tcs_reader
== TLM_RESTORE_RUN
&&
1116 lcmd
->tc_reader
== TLM_RESTORE_RUN
) {
1119 NDMP_LOG(LOG_DEBUG
, "R%d", bidx
);
1121 * The buffer is still full, wait for the consumer
1124 tlm_buffer_out_buf_timed_wait(bufs
, 100);
1125 buf
= tlm_buffer_in_buf(bufs
, NULL
);
1127 NDMP_LOG(LOG_DEBUG
, "r%d", bidx
);
1129 err
= read_one_buf(mod_params
, bufs
, buf
);
1132 "Reading buffer %d, pos: %lld",
1133 bidx
, session
->ns_mover
.md_position
);
1135 /* Force the writer to stop. */
1136 buf
->tb_eot
= buf
->tb_eof
= TRUE
;
1138 } else if (err
== 1) {
1140 "operation aborted or session terminated");
1145 buf
= tlm_buffer_in_buf(bufs
, &bidx
);
1146 tlm_buffer_release_in_buf(bufs
);
1151 * If the consumer is waiting for us, wake it up so that it detects
1154 lcmd
->tc_writer
= TLM_STOP
;
1155 tlm_buffer_release_in_buf(bufs
);
1156 (void) usleep(1000);
1161 cmds
->tcs_reader_count
--;
1170 * Check must have been done that backup work directory exists, before
1171 * calling this function.
1174 ndmpd_tar_backup(ndmpd_session_t
*session
, ndmpd_module_params_t
*mod_params
,
1175 ndmp_lbr_params_t
*nlp
)
1177 char jname
[TLM_MAX_BACKUP_JOB_NAME
];
1179 tlm_commands_t
*cmds
;
1181 if (mod_params
->mp_operation
!= NDMP_DATA_OP_BACKUP
) {
1183 "mod_params->mp_operation != NDMP_DATA_OP_BACKUP");
1186 if (ndmpd_mark_inodes_v2(session
, nlp
) != 0)
1188 else if (ndmp_get_bk_dir_ino(nlp
))
1197 (void) ndmp_new_job_name(jname
);
1198 if (backup_create_structs(session
, jname
) < 0)
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
;
1205 if (!session
->ns_data
.dd_abort
) {
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
;
1212 if (ndmp_write_utf8magic(cmds
->tcs_command
) < 0) {
1213 backup_release_structs(session
);
1217 NDMP_LOG(LOG_DEBUG
, "Backing up \"%s\" started.",
1218 nlp
->nlp_backup_path
);
1220 err
= ndmp_backup_reader(cmds
, nlp
, jname
);
1222 backup_release_structs(session
);
1223 NDMP_LOG(LOG_DEBUG
, "Launch ndmp_backup_reader: %s",
1228 /* Act as the writer thread. */
1229 err
= ndmp_tar_writer(session
, mod_params
, cmds
);
1231 nlp
->nlp_jstat
->js_stop_time
= time(NULL
);
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
);
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
);
1246 if (session
->ns_data
.dd_abort
)
1249 NDMP_LOG(LOG_DEBUG
, "Backing up \"%s\" finished. (%d)",
1250 nlp
->nlp_backup_path
, err
);
1252 nlp
->nlp_jstat
->js_stop_time
= time(NULL
);
1253 NDMP_LOG(LOG_DEBUG
, "Backing up \"%s\" aborted.",
1254 nlp
->nlp_backup_path
);
1258 backup_release_structs(session
);
1266 * Restore function that launches TAR reader thread to read from the
1267 * tape and writes the extracted files/dirs to the filesystem
1270 ndmpd_tar_restore(ndmpd_session_t
*session
, ndmpd_module_params_t
*mod_params
,
1271 ndmp_lbr_params_t
*nlp
)
1273 char jname
[TLM_MAX_BACKUP_JOB_NAME
];
1276 tlm_commands_t
*cmds
;
1277 ndmp_tar_reader_arg_t arg
;
1278 tlm_backup_restore_arg_t tlm_arg
;
1280 pthread_t rdtp
, wrtp
;
1283 if (mod_params
->mp_operation
!= NDMP_DATA_OP_RECOVER
) {
1285 "mod_params->mp_operation != NDMP_DATA_OP_RECOVER");
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
;
1296 (void) ndmp_new_job_name(jname
);
1297 if (restore_create_structs(session
, jname
) < 0)
1300 nlp
->nlp_jstat
->js_start_ltime
= time(NULL
);
1301 nlp
->nlp_jstat
->js_start_time
= time(NULL
);
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
;
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
));
1313 arg
.tr_session
= session
;
1314 arg
.tr_mod_params
= mod_params
;
1317 err
= pthread_create(&rdtp
, NULL
, (funct_t
)ndmp_tar_reader
,
1320 tlm_cmd_wait(cmds
->tcs_command
, TLM_TAR_READER
);
1322 NDMP_LOG(LOG_DEBUG
, "Launch ndmp_tar_reader: %m");
1326 if (!ndmp_check_utf8magic(cmds
->tcs_command
)) {
1327 NDMP_LOG(LOG_DEBUG
, "UTF8Magic not found!");
1329 NDMP_LOG(LOG_DEBUG
, "UTF8Magic found");
1332 (void) memset(&tlm_arg
, 0, sizeof (tlm_backup_restore_arg_t
));
1333 (void) pthread_barrier_init(&tlm_arg
.ba_barrier
, 0, 2);
1336 * Set up restore parameters
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
;
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
);
1352 (void) pthread_barrier_destroy(&tlm_arg
.ba_barrier
);
1354 "Thread create tm_getfile: ops NULL");
1358 (void) pthread_barrier_wait(&tlm_arg
.ba_barrier
);
1360 (void) pthread_barrier_destroy(&tlm_arg
.ba_barrier
);
1361 NDMP_LOG(LOG_DEBUG
, "thread create tm_getfile: %m");
1365 (void) pthread_join(rdtp
, NULL
);
1366 (void) pthread_join(wrtp
, NULL
);
1367 (void) pthread_barrier_destroy(&tlm_arg
.ba_barrier
);
1369 nlp
->nlp_jstat
->js_stop_time
= time(NULL
);
1371 /* Send the list of un-recovered files/dirs to the client. */
1372 (void) send_unrecovered_list(mod_params
, nlp
);
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)",
1380 nlp
->nlp_jstat
->js_stop_time
= time(NULL
);
1382 /* nothing restored. */
1383 (void) send_unrecovered_list(mod_params
, nlp
);
1384 NDMP_LOG(LOG_DEBUG
, "Restoring to \"%s\" aborted.",
1389 NDMP_FREE(nlp
->nlp_restore_path
);
1390 backup_release_structs(session
);
1399 * Extract the path for a given full path entry
1402 prefixdir(char *dir
, char *suffix
)
1404 static char tmp
[TLM_MAX_PATH_NAME
];
1405 char *tend
, *send
; /* tmp and suffix end */
1407 if (dir
== NULL
|| suffix
== NULL
)
1410 if (*suffix
== '\0')
1416 (void) strlcpy(tmp
, dir
, TLM_MAX_PATH_NAME
);
1417 tend
= &tmp
[strlen(tmp
)];
1418 send
= &suffix
[strlen(suffix
)];
1421 * Move backward as far as the last part of the dir and
1424 while (tend
>= tmp
&& send
>= suffix
)
1438 * Get the count of files to be restored
1441 get_nfiles(ndmpd_session_t
*session
, ndmpd_module_params_t
*params
)
1443 if (session
->ns_data
.dd_nlist_len
== 0) {
1444 MOD_LOG(params
, "Error: nothing specified to be restored.\n");
1448 return (session
->ns_data
.dd_nlist_len
);
1455 * Get the full pathname of where the entries should be restored to.
1458 get_restore_dest(ndmpd_module_params_t
*params
)
1464 * Destination of restore:
1465 * NetBackup of Veritas(C) sends the entries like this:
1467 * ent[i].name: is the relative pathname of what is selected in
1469 * ent[i].dest: is the full pathname of where the dir/file must
1475 ent
= (ndmp_name
*)MOD_GETNAME(params
, 0);
1476 cp
= prefixdir(ent
->dest
, ent
->name
);
1478 MOD_LOG(params
, "Error: empty restore path.\n");
1489 * Correct the entries in the restore list by appending the appropriate
1493 correct_ents(ndmpd_module_params_t
*params
, int n
, char *bkpath
)
1495 char *cp
, *pathname
;
1499 if ((pathname
= ndmp_malloc(TLM_MAX_PATH_NAME
)) == NULL
) {
1500 MOD_LOG(params
, "Error: insufficient memory.\n");
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
);
1510 "Old: ent[%d].name: \"%s\"", i
, ent
->name
);
1512 "Old: ent[%d].dest: \"%s\"", i
, ent
->dest
);
1514 /* remove trailing slash */
1515 len
= strlen(ent
->name
);
1516 if (ent
->name
[len
- 1] == '/')
1517 ent
->name
[len
- 1] = '\0';
1519 if (!tlm_cat_path(pathname
, bkpath
, ent
->name
)) {
1520 MOD_LOG(params
, "Error: path too long.\n");
1525 /* Make a copy of the new string and save it in ent->name. */
1526 cp
= strdup(pathname
);
1528 MOD_LOG(params
, "Error: insufficient memory.\n");
1536 "New: ent[%d].name: \"%s\"", i
, ent
->name
);
1545 * check_restore_paths
1547 * Go through the restore list and check the validity of the
1551 check_restore_paths(ndmpd_module_params_t
*params
, int n
, char *rspath
)
1557 if (rspath
!= NULL
&& *rspath
!= '\0') {
1558 NDMP_LOG(LOG_DEBUG
, "rspath: \"%s\"", rspath
);
1559 if (!fs_volexist(rspath
)) {
1561 "Error: Invalid volume name for restore.");
1565 for (i
= 0; i
< n
; i
++) {
1566 ent
= (ndmp_name
*)MOD_GETNAME(params
, i
);
1568 "ent[%d].name: \"%s\"", i
, ent
->name
);
1570 if (!fs_volexist(ent
->name
)) {
1572 "Error: Invalid volume name for restore.",
1585 * check_backup_dir_validity
1587 * Check if the backup directory is valid. Make sure it exists and
1588 * is writable. Check for snapshot and readonly cases.
1591 check_backup_dir_validity(ndmpd_module_params_t
*params
, char *bkpath
)
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",
1609 rv
= NDMP_BAD_FILE_ERR
;
1617 * ndmp_backup_extract_params
1619 * Go through the backup parameters and check the validity
1620 * for each one. Then set the NLP flags according to the parameters.
1623 ndmp_backup_extract_params(ndmpd_session_t
*session
,
1624 ndmpd_module_params_t
*params
)
1628 ndmp_lbr_params_t
*nlp
;
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
);
1635 if ((nlp
->nlp_backup_path
= get_backup_path_v2(params
)) == NULL
)
1636 return (NDMP_FILE_NOT_FOUND_ERR
);
1638 if ((rv
= check_backup_dir_validity(params
,
1639 nlp
->nlp_backup_path
)) != NDMP_NO_ERR
)
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
);
1647 NLP_UNSET(nlp
, NLPF_IGNCTIME
);
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
);
1654 NLP_UNSET(nlp
, NLPF_INCLMTIME
);
1656 NDMP_LOG(LOG_DEBUG
, "flags %x", nlp
->nlp_flags
);
1658 /* Is backup history requested? */
1659 cp
= MOD_GETENV(params
, "HIST");
1661 NDMP_LOG(LOG_DEBUG
, "env(HIST) not specified");
1662 NLP_UNSET(nlp
, NLPF_FH
);
1664 NDMP_LOG(LOG_DEBUG
, "env(HIST): \"%s\"", cp
);
1666 if (strchr("t_ty_y", *cp
))
1667 NLP_SET(nlp
, NLPF_FH
);
1669 NLP_UNSET(nlp
, NLPF_FH
);
1672 nlp
->nlp_clevel
= 0;
1673 /* Is it an incremental backup? */
1674 cp
= MOD_GETENV(params
, "LEVEL");
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
);
1682 nlp
->nlp_clevel
= *cp
- '0';
1684 /* Extract last backup time from the dumpdates file */
1685 nlp
->nlp_llevel
= nlp
->nlp_clevel
;
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
);
1695 "Date of this level %d on \"%s\": %s",
1696 nlp
->nlp_clevel
, nlp
->nlp_backup_path
, cctime(&nlp
->nlp_cdate
));
1698 "Date of last level %d on \"%s\": %s",
1699 nlp
->nlp_llevel
, nlp
->nlp_backup_path
, cctime(&nlp
->nlp_ldate
));
1701 /* Should the dumpdate file be updated? */
1702 cp
= MOD_GETENV(params
, "UPDATE");
1705 "env(UPDATE) not specified, default to TRUE");
1706 NLP_SET(nlp
, NLPF_UPDATE
);
1708 NDMP_LOG(LOG_DEBUG
, "env(UPDATE): \"%s\"", cp
);
1709 if (strchr("t_ty_y", *cp
) != NULL
)
1710 NLP_SET(nlp
, NLPF_UPDATE
);
1712 NLP_UNSET(nlp
, NLPF_UPDATE
);
1715 return (NDMP_NO_ERR
);
1723 * Dump the value of the parameters in the log file for debugging.
1726 log_bk_params_v2(ndmpd_session_t
*session
, ndmpd_module_params_t
*params
,
1727 ndmp_lbr_params_t
*nlp
)
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
));
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");
1747 * Find out if the paths are the same regardless of the ending slash
1755 same_path(char *s
, char *t
)
1763 if (slen
== tlen
&& strcmp(s
, t
) == 0) {
1766 if (slen
== tlen
- 1) {
1767 if (strncmp(s
, t
, slen
) == 0 && t
[tlen
- 1] == '/')
1769 } else if (tlen
== slen
-1) {
1770 if (strncmp(s
, t
, tlen
) == 0 && s
[slen
- 1] == '/')
1775 NDMP_LOG(LOG_DEBUG
, "rv: %d", rv
);
1781 * ndmp_restore_extract_params
1783 * Go through the restore parameters and check them and extract them
1784 * by setting NLP flags and other values.
1793 ndmp_restore_extract_params(ndmpd_session_t
*session
,
1794 ndmpd_module_params_t
*params
)
1796 char *bkpath
, *rspath
;
1797 ndmp_lbr_params_t
*nlp
;
1799 if ((nlp
= ndmp_get_nlp(session
)) == NULL
) {
1800 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
1804 /* Extract directory from where the backup was made. */
1805 if ((bkpath
= get_backup_path_v2(params
)) == NULL
)
1806 return (NDMP_ILLEGAL_ARGS_ERR
);
1808 nlp
->nlp_restore_bk_path
= bkpath
;
1810 /* The number of the selections. */
1811 if ((nlp
->nlp_nfiles
= get_nfiles(session
, params
)) == 0)
1812 return (NDMP_ILLEGAL_ARGS_ERR
);
1814 NDMP_LOG(LOG_DEBUG
, "nfiles: %d", nlp
->nlp_nfiles
);
1816 if ((rspath
= get_restore_dest(params
)) == NULL
)
1817 return (NDMP_ILLEGAL_ARGS_ERR
);
1819 if (fs_is_rdonly(rspath
)) {
1821 "Error: Can't restore to a read-only volume: \"%s\"\n",
1823 return (NDMP_ILLEGAL_ARGS_ERR
);
1825 if (fs_is_chkpntvol(rspath
)) {
1827 "Error: Can't restore to a checkpoint: \"%s\"\n", rspath
);
1828 return (NDMP_ILLEGAL_ARGS_ERR
);
1831 if (same_path(bkpath
, rspath
))
1834 if ((nlp
->nlp_restore_path
= strdup(rspath
)) == NULL
)
1835 return (NDMP_NO_MEM_ERR
);
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
);
1843 if (check_restore_paths(params
, nlp
->nlp_nfiles
, rspath
) < 0) {
1844 free(nlp
->nlp_restore_path
);
1845 return (NDMP_ILLEGAL_ARGS_ERR
);
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
);
1852 return (NDMP_NO_ERR
);
1856 * ndmpd_tar_backup_starter (V2 only)
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.
1863 ndmpd_tar_backup_starter(void *arg
)
1865 ndmpd_module_params_t
*mod_params
= arg
;
1867 ndmpd_session_t
*session
;
1868 ndmp_lbr_params_t
*nlp
;
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
);
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
);
1880 NLP_UNSET(nlp
, NLPF_CHKPNTED_PATH
);
1881 if (ndmp_create_snapshot(nlp
->nlp_backup_path
,
1882 nlp
->nlp_jstat
->js_job_name
) < 0) {
1884 "Error: creating checkpoint on %s\n",
1885 nlp
->nlp_backup_path
);
1886 /* -1 causes halt reason to become internal error. */
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
)));
1897 err
= ndmp_get_cur_bk_time(nlp
, &nlp
->nlp_cdate
,
1898 nlp
->nlp_jstat
->js_job_name
);
1900 NDMP_LOG(LOG_DEBUG
, "err %d", err
);
1902 log_bk_params_v2(session
, mod_params
, nlp
);
1903 err
= ndmpd_tar_backup(session
, mod_params
, nlp
);
1907 if (nlp
->nlp_bkmap
>= 0) {
1908 (void) dbm_free(nlp
->nlp_bkmap
);
1909 nlp
->nlp_bkmap
= -1;
1912 if (!NLP_ISCHKPNTED(nlp
))
1913 (void) ndmp_remove_snapshot(nlp
->nlp_backup_path
,
1914 nlp
->nlp_jstat
->js_job_name
);
1916 NDMP_LOG(LOG_DEBUG
, "err %d, update %c",
1917 err
, NDMP_YORN(NLP_SHOULD_UPDATE(nlp
)));
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) {
1924 "Error: updating the dumpdates file on %s\n",
1925 nlp
->nlp_backup_path
);
1929 MOD_DONE(mod_params
, err
);
1931 /* nlp_params is allocated in start_backup() */
1932 NDMP_FREE(nlp
->nlp_params
);
1935 ndmp_session_unref(session
);
1941 * ndmpd_tar_backup_abort
1943 * Abort the running backup by stopping the reader thread (V2 only)
1946 ndmpd_tar_backup_abort(void *module_cookie
)
1948 ndmp_lbr_params_t
*nlp
;
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;
1957 ndmp_stop_reader_thread(nlp
->nlp_session
);
1964 * ndmpd_tar_restore_starter
1966 * Starts the restore by running ndmpd_tar_restore function (V2 only)
1970 ndmpd_tar_restore_starter(void *arg
)
1972 ndmpd_module_params_t
*mod_params
= arg
;
1974 ndmpd_session_t
*session
;
1975 ndmp_lbr_params_t
*nlp
;
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
);
1981 err
= ndmpd_tar_restore(session
, mod_params
, nlp
);
1982 MOD_DONE(mod_params
, err
);
1984 /* nlp_params is allocated in start_recover() */
1985 NDMP_FREE(nlp
->nlp_params
);
1988 ndmp_session_unref(session
);
1994 * ndmpd_tar_restore_abort
1996 * Aborts the restore operation by stopping the writer thread (V2 only)
1999 ndmpd_tar_restore_abort(void *module_cookie
)
2001 ndmp_lbr_params_t
*nlp
;
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;
2011 (void) cond_broadcast(&nlp
->nlp_cv
);
2012 (void) mutex_unlock(&nlp
->nlp_mtx
);
2013 ndmp_stop_writer_thread(nlp
->nlp_session
);