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>
46 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
62 * Maximum length of the string-representation of u_longlong_t type.
64 #define QUAD_DECIMAL_LEN 20
67 /* Is Y=yes or T=true */
68 #define IS_YORT(c) (strchr("YT", toupper(c)))
70 /* Is F=file format (vs D=node-dir format) */
71 #define IS_F(c) (toupper(c) == 'F')
76 #define ISDEFINED(cp) ((cp) && *(cp))
77 #define SHOULD_LBRBK(bpp) (!((bpp)->bp_opr & TLM_OP_CHOOSE_ARCHIVE))
80 * Component boundary means end of path or on a '/'. At this
81 * point both paths should be on component boundary.
83 #define COMPBNDRY(p) (!*(p) || (*p) == '/')
85 typedef struct bk_param_v3
{
86 ndmpd_session_t
*bp_session
;
87 ndmp_lbr_params_t
*bp_nlp
;
88 tlm_job_stats_t
*bp_js
;
90 tlm_commands_t
*bp_cmds
;
91 tlm_acls_t
*bp_tlmacl
;
101 * Multiple destination restore mode
103 #define MULTIPLE_DEST_DIRS 128
105 int multiple_dest_restore
= 0;
110 ndmp_plugin_t
*ndmp_pl
;
113 * NDMP exclusion list
115 char **ndmp_excl_list
= NULL
;
120 * Splits the string into list of sections separated by the
124 * envp (input) - the environment variable that should be broken
125 * sep (input) - the separator character
128 * Array of character pointers: On success. The array is allocated
129 * as well as all its entries. They all should be freed by the
134 split_env(char *envp
, char sep
)
144 while (isspace(*envp
))
150 bp
= save
= strdup(envp
);
155 * Since the env variable is not empty, it contains at least one
159 while ((cp
= strchr(bp
, sep
))) {
160 if (cp
> save
&& *(cp
-1) != '\\')
166 n
++; /* for the terminating NULL pointer */
167 cpp
= ndmp_malloc(sizeof (char *) * n
);
173 (void) memset(cpp
, 0, n
* sizeof (char *));
179 if (strlen(bp
) > 0) {
182 tlm_release_list(cpp
);
188 } else if (*cp
== '\\') {
190 if (*cp
== 'n') { /* "\n" */
193 } else if (*cp
== 't') { /* "\t" */
203 if (strlen(bp
) > 0) {
206 tlm_release_list(cpp
);
212 if (n
== 0 && cpp
!= NULL
) {
213 tlm_release_list(cpp
);
226 * Print the array of character pointers passed to it. This is
227 * used for debugging purpose.
230 * lpp (input) - pointer to the array of strings
239 NDMP_LOG(LOG_DEBUG
, "empty");
244 NDMP_LOG(LOG_DEBUG
, "\"%s\"", *lpp
++);
251 * Looks through all the strings of the array to see if the ent
252 * matches any of the strings. The strings are patterns.
255 * lpp (input) - pointer to the array of strings
256 * ent (input) - the entry to be matched
259 * TRUE: if there is a match
260 * FALSE: invalid argument or no match
263 inlist(char **lpp
, char *ent
)
266 NDMP_LOG(LOG_DEBUG
, "empty list");
272 * Fixing the sync_sort NDMPV3 problem, it sends the inclusion
273 * like "./" which we should skip the "./"
275 char *pattern
= *lpp
;
276 if (strncmp(pattern
, "./", 2) == 0)
279 NDMP_LOG(LOG_DEBUG
, "pattern %s, ent %s", pattern
, ent
);
281 if (match(pattern
, ent
)) {
282 NDMP_LOG(LOG_DEBUG
, "match(%s,%s)", pattern
, ent
);
288 NDMP_LOG(LOG_DEBUG
, "no match");
296 * Checks if the entry is in the list. This is used for exclusion
297 * list. If the exclusion list is empty, FALSE should be returned
298 * showing that nothing should be excluded by default.
301 * lpp (input) - pointer to the array of strings
302 * ent (input) - the entry to be matched
305 * TRUE: if there is a match
306 * FALSE: invalid argument or no match
310 inexl(char **lpp
, char *ent
)
315 return (inlist(lpp
, ent
));
322 * Checks if the entry is in the list. This is used for inclusion
323 * list. If the inclusion list is empty, TRUE should be returned
324 * showing that everything should be included by default.
327 * lpp (input) - pointer to the array of strings
328 * ent (input) - the entry to be matched
331 * TRUE: if there is a match or the list is empty
335 ininc(char **lpp
, char *ent
)
337 if (!lpp
|| !ent
|| !*ent
)
340 return (inlist(lpp
, ent
));
347 * Set up the selection list for Local B/R functions. A new array of
348 * "char *" is created and the pointers point to the original paths of
352 * session (input) - pointer to the session
353 * params (input) - pointer to the parameters structure
354 * nlp (input) - pointer to the nlp structure
355 * index(input) - If not zero is the DAR entry position
358 * list pointer: on success
363 setupsels(ndmpd_session_t
*session
, ndmpd_module_params_t
*params
,
364 ndmp_lbr_params_t
*nlp
, int index
)
370 mem_ndmp_name_v3_t
*ep
;
372 n
= session
->ns_data
.dd_nlist_len
;
374 save
= lpp
= ndmp_malloc(sizeof (char *) * (n
+ 1));
376 MOD_LOGV3(params
, NDMP_LOG_ERROR
, "Insufficient memory.\n");
380 if (index
) { /* DAR, just one entry */
382 * We have to setup a list of strings that will not match any
383 * file. One DAR entry will be added in the right position later
385 * When the match is called from tar_getdir the
386 * location of the selection that matches the entry is
389 for (i
= 0; i
< n
; ++i
)
394 lpp
+= start
; /* Next selection entry will be in lpp[start] */
400 for (i
= start
; i
< end
; i
++) {
401 ep
= (mem_ndmp_name_v3_t
*)MOD_GETNAME(params
, i
);
406 * Check for clients that send original path as "."(like
407 * CA products). In this situation opath is something like
408 * "/v1/." and we should change it to "/v1/"
410 len
= strlen(ep
->nm3_opath
);
411 if (len
> 1 && ep
->nm3_opath
[len
-2] == '/' &&
412 ep
->nm3_opath
[len
-1] == '.') {
413 ep
->nm3_opath
[len
-1] = '\0';
415 "nm3_opath changed from %s. to %s",
416 ep
->nm3_opath
, ep
->nm3_opath
);
418 *lpp
++ = ep
->nm3_opath
;
421 /* list termination indicator is a null pointer */
432 * It gets a path, a selection (with which the path has matched) a new
433 * name and makes a new name for the path.
434 * All the components of the path and the selection are skipped as long
435 * as they are the same. If either of the path or selection are not on
436 * a component boundary, the match was reported falsefully and no new name
437 * is generated(Except the situation in which both path and selection
438 * end with trailing '/' and selection is the prefix of the path).
439 * Otherwise, the remaining of the path is appended to the
440 * new name. The result is saved in the buffer passed.
443 * bp (output) - pointer to the result buffer
444 * pp (input) - pointer to the path
445 * sp (input) - pointer to the selection
446 * np (input) - pointer to the new name
449 * pointer to the bp: on success
453 mkrsp(char *bp
, char *pp
, char *sp
, char *np
)
459 pp
+= strspn(pp
, "/");
461 sp
+= strspn(sp
, "/");
463 /* skip as much as match */
464 while (*sp
&& *pp
&& *sp
== *pp
) {
469 if (!COMPBNDRY(pp
) || !COMPBNDRY(sp
))
470 /* An exception to the boundary rule */
471 /* (!(!*sp && (*(pp - 1)) == '/')) */
472 if (*sp
|| (*(pp
- 1)) != '/')
475 /* if pp shorter than sp, it should not be restored */
477 sp
+= strspn(sp
, "/");
484 np
+= strspn(np
, "/");
488 if (!tlm_cat_path(bp
, np
, pp
)) {
489 NDMP_LOG(LOG_ERR
, "Restore path too long %s/%s.", np
, pp
);
500 * This is used as callback for creating the restore path. This function
501 * can handle both single destination and multiple restore paths.
503 * Make up the restore destination path for a particular file/directory, path,
504 * based on nm3_opath and nm3_dpath. path should have matched nm3_opath
508 mknewname(struct rs_name_maker
*rnp
, char *buf
, int idx
, char *path
)
511 ndmp_lbr_params_t
*nlp
;
512 mem_ndmp_name_v3_t
*ep
;
516 NDMP_LOG(LOG_DEBUG
, "buf is NULL");
518 NDMP_LOG(LOG_DEBUG
, "path is NULL");
519 } else if ((nlp
= rnp
->rn_nlp
) == 0) {
520 NDMP_LOG(LOG_DEBUG
, "rnp->rn_nlp is NULL");
521 } else if (!nlp
->nlp_params
) {
522 NDMP_LOG(LOG_DEBUG
, "nlp->nlp_params is NULL");
524 if (!ndmp_full_restore_path
) {
525 if (idx
< 0 || idx
>= (int)nlp
->nlp_nfiles
) {
527 "Invalid idx %d range (0, %d)",
528 idx
, nlp
->nlp_nfiles
);
529 } else if (!(ep
= (mem_ndmp_name_v3_t
*)MOD_GETNAME(
530 nlp
->nlp_params
, idx
))) {
532 "nlist entry %d is NULL", idx
);
534 rv
= mkrsp(buf
, path
, ep
->nm3_opath
,
538 "idx %d org \"%s\" dst \"%s\"",
539 idx
, ep
->nm3_opath
, ep
->nm3_dpath
);
542 "path \"%s\": \"%s\"", path
, rv
);
545 "path \"%s\": NULL", path
);
549 if (!tlm_cat_path(buf
, nlp
->nlp_restore_path
, path
)) {
550 NDMP_LOG(LOG_ERR
, "Path too long %s/%s.",
551 nlp
->nlp_restore_path
, path
);
556 "path \"%s\": \"%s\"", path
, rv
);
567 * Remove the slash from the end of the given path
578 cp
+= ln
- 1; /* end of the string */
579 while (ln
> 0 && *cp
== '/') {
589 * Join two given paths
592 joinpath(char *bp
, char *pp
, char *np
)
596 (void) tlm_cat_path(bp
, pp
, np
);
598 (void) strlcpy(bp
, pp
, TLM_MAX_PATH_NAME
);
601 (void) strlcpy(bp
, np
, TLM_MAX_PATH_NAME
);
613 * Is the volume writable?
623 rv
= !fs_is_rdonly(path
) && !fs_is_chkpntvol(path
);
624 NDMP_LOG(LOG_DEBUG
, "%d path \"%s\"", rv
, path
);
631 * is_valid_backup_dir_v3
633 * Checks the validity of the backup path. Backup path should
634 * have the following characteristics to be valid:
635 * 1) It should be an absolute path.
636 * 2) It should be a directory.
637 * 3) It should not be checkpoint root directory
638 * 4) If the file system is read-only, the backup path
639 * should be a checkpointed path. Checkpoint cannot
640 * be created on a read-only file system.
643 * params (input) - pointer to the parameters structure.
644 * bkpath (input) - the backup path
647 * TRUE: if everything's OK
651 is_valid_backup_dir_v3(ndmpd_module_params_t
*params
, char *bkpath
)
656 if (*bkpath
!= '/') {
657 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
658 "Relative backup path not allowed \"%s\".\n", bkpath
);
661 if (stat64(bkpath
, &st
) < 0) {
662 msg
= strerror(errno
);
663 MOD_LOGV3(params
, NDMP_LOG_ERROR
, "\"%s\" %s.\n",
667 if (!S_ISDIR(st
.st_mode
)) {
668 /* only directories can be specified as the backup path */
669 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
670 "\"%s\" is not a directory.\n", bkpath
);
673 if (fs_is_rdonly(bkpath
) && !fs_is_chkpntvol(bkpath
) &&
674 fs_is_chkpnt_enabled(bkpath
)) {
675 /* it is not a chkpnted path */
676 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
677 "\"%s\" is not a checkpointed path.\n", bkpath
);
688 * Log the token sequence number and also the date of the
689 * last backup for token-based backup in the system log
690 * and also send them as normal log to the client.
693 * params (input) - pointer to the parameters structure
694 * nlp (input) - pointer to the nlp structure
700 log_date_token_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
702 MOD_LOGV3(params
, NDMP_LOG_NORMAL
, "Token sequence counter: %d.\n",
705 MOD_LOGV3(params
, NDMP_LOG_NORMAL
, "Date of the last backup: %s.\n",
706 cctime(&nlp
->nlp_tokdate
));
708 if (nlp
->nlp_dmpnm
) {
709 MOD_LOGV3(params
, NDMP_LOG_NORMAL
,
710 "Backup date log file name: \"%s\".\n", nlp
->nlp_dmpnm
);
718 * Log the backup level and data of the backup for LBR-type
719 * backup in the system log and also send them as normal log
723 * params (input) - pointer to the parameters structure
724 * nlp (input) - pointer to the nlp structure
730 log_lbr_bk_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
732 MOD_LOGV3(params
, NDMP_LOG_NORMAL
,
733 "Date of this level '%c': %s.\n", nlp
->nlp_clevel
,
734 cctime(&nlp
->nlp_cdate
));
736 if (nlp
->nlp_dmpnm
) {
737 MOD_LOGV3(params
, NDMP_LOG_NORMAL
,
738 "Backup date log file name: \"%s\".\n", nlp
->nlp_dmpnm
);
746 * Log the backup level and date of the last and the current
747 * backup for level-type backup in the system log and also
748 * send them as normal log to the client.
751 * params (input) - pointer to the parameters structure
752 * nlp (input) - pointer to the nlp structure
758 log_level_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
760 MOD_LOGV3(params
, NDMP_LOG_NORMAL
,
761 "Date of the last level '%u': %s.\n", nlp
->nlp_llevel
,
762 cctime(&nlp
->nlp_ldate
));
764 MOD_LOGV3(params
, NDMP_LOG_NORMAL
,
765 "Date of this level '%u': %s.\n", nlp
->nlp_clevel
,
766 cctime(&nlp
->nlp_cdate
));
768 MOD_LOGV3(params
, NDMP_LOG_NORMAL
, "Update: %s.\n",
769 NDMP_TORF(NLP_ISSET(nlp
, NLPF_UPDATE
)));
776 * Dispatcher function which calls the appropriate function
777 * for logging the backup date and level in the system log
778 * and also send them as normal log message to the client.
781 * session (input) - pointer to the session
782 * params (input) - pointer to the parameters structure
783 * nlp (input) - pointer to the nlp structure
789 log_bk_params_v3(ndmpd_session_t
*session
, ndmpd_module_params_t
*params
,
790 ndmp_lbr_params_t
*nlp
)
792 MOD_LOGV3(params
, NDMP_LOG_NORMAL
, "Backing up \"%s\".\n",
793 nlp
->nlp_backup_path
);
795 if (session
->ns_mover
.md_data_addr
.addr_type
== NDMP_ADDR_LOCAL
)
796 MOD_LOGV3(params
, NDMP_LOG_NORMAL
,
797 "Tape record size: %d.\n",
798 session
->ns_mover
.md_record_size
);
800 MOD_LOGV3(params
, NDMP_LOG_NORMAL
, "File history: %c.\n",
801 NDMP_YORN(NLP_ISSET(nlp
, NLPF_FH
)));
803 if (NLP_ISSET(nlp
, NLPF_TOKENBK
))
804 log_date_token_v3(params
, nlp
);
805 else if (NLP_ISSET(nlp
, NLPF_LBRBK
))
806 log_lbr_bk_v3(params
, nlp
);
807 else if (NLP_ISSET(nlp
, NLPF_LEVELBK
))
808 log_level_v3(params
, nlp
);
810 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
811 "Internal error: backup level not defined for \"%s\".\n",
812 nlp
->nlp_backup_path
);
820 * Is the UPDATE environment variable specified? If it is
821 * the corresponding flag is set in the flags field of the
822 * nlp structure, otherwise the flag is cleared.
825 * params (input) - pointer to the parameters structure
826 * nlp (input) - pointer to the nlp structure
832 get_update_env_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
836 envp
= MOD_GETENV(params
, "UPDATE");
838 NLP_SET(nlp
, NLPF_UPDATE
);
840 "env(UPDATE) not defined, default to TRUE");
842 NDMP_LOG(LOG_DEBUG
, "env(UPDATE): \"%s\"", envp
);
844 NLP_SET(nlp
, NLPF_UPDATE
);
846 NLP_UNSET(nlp
, NLPF_UPDATE
);
854 * Is backup history requested? If it is, the corresponding
855 * flag is set in the flags field of the nlp structure, otherwise
856 * the flag is cleared.
859 * params (input) - pointer to the parameters structure
860 * nlp (input) - pointer to the nlp structure
866 get_hist_env_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
870 envp
= MOD_GETENV(params
, "HIST");
872 NDMP_LOG(LOG_DEBUG
, "env(HIST) not defined");
873 NLP_UNSET(nlp
, NLPF_FH
);
875 NDMP_LOG(LOG_DEBUG
, "env(HIST): \"%s\"", envp
);
876 if (IS_YORT(*envp
) || IS_F(*envp
))
877 NLP_SET(nlp
, NLPF_FH
);
879 NLP_UNSET(nlp
, NLPF_FH
);
881 /* Force file format if specified */
883 params
->mp_file_history_path_func
=
884 ndmpd_api_file_history_file_v3
;
885 params
->mp_file_history_dir_func
= 0;
886 params
->mp_file_history_node_func
= 0;
895 * Gets the EXCLUDE environment variable and breaks it
896 * into strings. The separator of the EXCLUDE environment
897 * variable is the ',' character.
900 * params (input) - pointer to the parameters structure
901 * nlp (input) - pointer to the nlp structure
907 get_exc_env_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
911 envp
= MOD_GETENV(params
, "EXCLUDE");
913 NDMP_LOG(LOG_DEBUG
, "env(EXCLUDE) not defined");
916 NDMP_LOG(LOG_DEBUG
, "env(EXCLUDE): \"%s\"", envp
);
917 nlp
->nlp_exl
= split_env(envp
, ',');
926 * Gets the FILES environment variable that shows which files
927 * should be backed up, and breaks it into strings. The
928 * separator of the FILES environment variable is the space
932 * params (input) - pointer to the parameters structure
933 * nlp (input) - pointer to the nlp structure
939 get_inc_env_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
943 envp
= MOD_GETENV(params
, "FILES");
945 NDMP_LOG(LOG_DEBUG
, "env(FILES) not defined");
948 NDMP_LOG(LOG_DEBUG
, "env(FILES): \"%s\"", envp
);
949 nlp
->nlp_inc
= split_env(envp
, ' ');
958 * Gets the DIRECT environment variable that shows if the fh_info should
959 * be sent to the client or not.
962 * params (input) - pointer to the parameters structure
963 * nlp (input) - pointer to the nlp structure
969 get_direct_env_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
974 * We should send the fh_info to the DMA, unless it is specified
975 * in the request that we should not send fh_info.
976 * At the moment we do not support DAR on directories, so if the user
977 * needs to restore a directory they should disable the DAR.
979 if (params
->mp_operation
== NDMP_DATA_OP_RECOVER
&& !ndmp_dar_support
) {
980 NDMP_LOG(LOG_DEBUG
, "Direct Access Restore Disabled");
981 NLP_UNSET(nlp
, NLPF_DIRECT
);
982 MOD_LOGV3(params
, NDMP_LOG_NORMAL
,
983 "DAR is disabled. Running Restore without DAR");
988 * Regardless of whether DIRECT is defined at backup time we send
989 * back the fh_info, for some clients do not use get_backup_attrs.
990 * If operation is restore we have to unset the DIRECT, for
991 * some clients do not set the MOVER window.
993 if (params
->mp_operation
== NDMP_DATA_OP_BACKUP
) {
994 NDMP_LOG(LOG_DEBUG
, "backup default env(DIRECT): YES");
995 NLP_SET(nlp
, NLPF_DIRECT
);
998 envp
= MOD_GETENV(params
, "DIRECT");
1000 NDMP_LOG(LOG_DEBUG
, "env(DIRECT) not defined");
1001 NLP_UNSET(nlp
, NLPF_DIRECT
);
1003 NDMP_LOG(LOG_DEBUG
, "env(DIRECT): \"%s\"", envp
);
1004 if (IS_YORT(*envp
)) {
1005 NLP_SET(nlp
, NLPF_DIRECT
);
1007 "Direct Access Restore Enabled");
1009 NLP_UNSET(nlp
, NLPF_DIRECT
);
1011 "Direct Access Restore Disabled");
1016 if (NLP_ISSET(nlp
, NLPF_DIRECT
)) {
1017 if (params
->mp_operation
== NDMP_DATA_OP_BACKUP
)
1018 MOD_LOGV3(params
, NDMP_LOG_NORMAL
,
1019 "Direct Access Restore information is supported");
1021 MOD_LOGV3(params
, NDMP_LOG_NORMAL
,
1022 "Running Restore with Direct Access Restore");
1024 if (params
->mp_operation
== NDMP_DATA_OP_BACKUP
)
1025 MOD_LOGV3(params
, NDMP_LOG_NORMAL
,
1026 "Direct Access Restore is not supported");
1028 MOD_LOGV3(params
, NDMP_LOG_NORMAL
,
1029 "Running Restore without Direct Access Restore");
1037 * Parse the token passed as the argument. Evaluate it and
1038 * issue any warning or error if needed. Save the date and
1039 * token sequence in the nlp structure fields. The sequence
1040 * number in the token should be less than hard-limit. If
1041 * it's between soft and hard limit, a warning is issued.
1042 * There is a configurable limit which should be less than
1043 * the soft-limit saved in ndmp_max_tok_seq variable.
1045 * The NLPF_TOKENBK flag is set in the nlp flags field to
1046 * show that the backup type is token-based.
1049 * params (input) - pointer to the parameters structure
1050 * nlp (input) - pointer to the nlp structure
1051 * basedate (input) - the value of the BASE_DATE environment
1055 * NDMP_NO_ERR: on success
1056 * != NDMP_NO_ERR: Otherwise
1060 get_date_token_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
,
1069 if (!params
|| !nlp
|| !basedate
|| !*basedate
)
1070 return (NDMP_ILLEGAL_ARGS_ERR
);
1072 if (MOD_GETENV(params
, "LEVEL")) {
1073 MOD_LOGV3(params
, NDMP_LOG_WARNING
,
1074 "Both BASE_DATE and LEVEL environment variables "
1076 MOD_LOGCONTV3(params
, NDMP_LOG_WARNING
,
1077 "BASE_DATE is being used for this backup.\n");
1080 tok
= strtoll(basedate
, &endp
, 10);
1081 if (endp
== basedate
) {
1082 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
1083 "Invalid BASE_DATE environment variable: \"%s\".\n",
1085 return (NDMP_ILLEGAL_ARGS_ERR
);
1088 tstamp
= tok
& 0xffffffff;
1089 seq
= (tok
>> 32) & 0xffffffff;
1090 NDMP_LOG(LOG_DEBUG
, "basedate \"%s\" %lld seq %u tstamp %u",
1091 basedate
, tok
, seq
, tstamp
);
1093 if ((int)seq
> ndmp_get_max_tok_seq()) {
1094 rv
= NDMP_ILLEGAL_ARGS_ERR
;
1095 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
1096 "The sequence counter of the token exceeds the "
1097 "maximum permitted value.\n");
1098 MOD_LOGCONTV3(params
, NDMP_LOG_ERROR
,
1099 "Token sequence: %u, maxiumum value: %u.\n",
1100 seq
, ndmp_get_max_tok_seq());
1101 } else if (seq
>= NDMP_TOKSEQ_HLIMIT
) {
1102 rv
= NDMP_ILLEGAL_ARGS_ERR
;
1103 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
1104 "The sequence counter the of token exceeds the "
1106 MOD_LOGCONTV3(params
, NDMP_LOG_ERROR
,
1107 "Token sequence: %u, hard-limit: %u.\n",
1108 seq
, NDMP_TOKSEQ_HLIMIT
);
1112 * Issue a warning if the seq is equal to the maximum
1113 * permitted seq number or equal to the soft-limit.
1115 if (seq
== NDMP_TOKSEQ_SLIMIT
) {
1116 MOD_LOGV3(params
, NDMP_LOG_WARNING
,
1117 "The sequence counter of the token has reached "
1118 "the soft-limit.\n");
1119 MOD_LOGCONTV3(params
, NDMP_LOG_WARNING
,
1120 "Token sequence: %u, soft-limit: %u.\n",
1121 seq
, NDMP_TOKSEQ_SLIMIT
);
1122 } else if ((int)seq
== ndmp_get_max_tok_seq()) {
1123 MOD_LOGV3(params
, NDMP_LOG_WARNING
,
1124 "The sequence counter of the token has reached "
1125 "the maximum permitted value.\n");
1126 MOD_LOGCONTV3(params
, NDMP_LOG_WARNING
,
1127 "Token sequence: %u, maxiumum value: %u.\n",
1128 seq
, ndmp_get_max_tok_seq());
1132 * The current seq is equal to the seq field of the
1133 * token. It will be increased after successful backup
1134 * before setting the DUMP_DATE environment variable.
1136 nlp
->nlp_dmpnm
= MOD_GETENV(params
, "DMP_NAME");
1137 NLP_SET(nlp
, NLPF_TOKENBK
);
1138 NLP_UNSET(nlp
, NLPF_LEVELBK
);
1139 NLP_UNSET(nlp
, NLPF_LBRBK
);
1140 nlp
->nlp_tokseq
= seq
;
1141 nlp
->nlp_tokdate
= tstamp
;
1143 * The value of nlp_cdate will be set to the checkpoint
1144 * creation time after it is created.
1155 * Sets the level fields of the nlp structures for
1156 * LBR-type backup. The NLPF_LBRBK flag of the
1157 * nlp flags is also set to show the backup type.
1160 * params (input) - pointer to the parameters structure
1161 * nlp (input) - pointer to the nlp structure
1162 * type (input) - the backup level: 'F', 'A', 'I', 'D' or
1163 * their lower-case values.
1166 * NDMP_NO_ERR: on success
1167 * != NDMP_NO_ERR: Otherwise
1170 get_lbr_bk_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
, char *type
)
1172 if (!params
|| !nlp
|| !type
|| !*type
)
1173 return (NDMP_ILLEGAL_ARGS_ERR
);
1175 NLP_SET(nlp
, NLPF_LBRBK
);
1176 NLP_UNSET(nlp
, NLPF_TOKENBK
);
1177 NLP_UNSET(nlp
, NLPF_LEVELBK
);
1178 nlp
->nlp_dmpnm
= MOD_GETENV(params
, "DMP_NAME");
1179 nlp
->nlp_llevel
= toupper(*type
);
1180 nlp
->nlp_ldate
= (time_t)0;
1181 nlp
->nlp_clevel
= nlp
->nlp_llevel
;
1182 (void) time(&nlp
->nlp_cdate
);
1184 return (NDMP_NO_ERR
);
1189 * get_backup_level_v3
1191 * Gets the backup level from the environment variables. If
1192 * BASE_DATE is specified, it will be used, otherwise LEVEL
1193 * will be used. If neither is specified, LEVEL = '0' is
1197 * params (input) - pointer to the parameters structure
1198 * nlp (input) - pointer to the nlp structure
1201 * NDMP_NO_ERR: on success
1202 * != NDMP_NO_ERR: Otherwise
1205 get_backup_level_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
1211 * If the BASE_DATE env variable is specified use it, otherwise
1212 * look to see if LEVEL is specified. If LEVEL is not
1213 * specified either, backup level '0' must be made. Level backup
1214 * does not clear the archive bit.
1216 * If LEVEL environment varaible is specified, values for
1217 * 'F', 'D', 'I' and 'A' (for 'Full', 'Differential',
1218 * 'Incremental', and 'Archive' is checked first. Then
1219 * level '0' to '9' will be checked.
1221 * LEVEL environment variable can hold only one character.
1222 * If its length is longer than 1, an error is returned.
1224 envp
= MOD_GETENV(params
, "BASE_DATE");
1226 return (get_date_token_v3(params
, nlp
, envp
));
1229 envp
= MOD_GETENV(params
, "LEVEL");
1231 NDMP_LOG(LOG_DEBUG
, "env(LEVEL) not defined, default to 0");
1232 NLP_SET(nlp
, NLPF_LEVELBK
);
1233 NLP_UNSET(nlp
, NLPF_LBRBK
);
1234 NLP_UNSET(nlp
, NLPF_TOKENBK
);
1235 nlp
->nlp_llevel
= 0;
1237 nlp
->nlp_clevel
= 0;
1239 * The value of nlp_cdate will be set to the checkpoint
1240 * creation time after it is created.
1242 return (NDMP_NO_ERR
);
1245 if (*(envp
+1) != '\0') {
1246 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
1247 "Invalid backup level \"%s\".\n", envp
);
1248 return (NDMP_ILLEGAL_ARGS_ERR
);
1251 if (IS_LBR_BKTYPE(*envp
))
1252 return (get_lbr_bk_v3(params
, nlp
, envp
));
1254 if (!isdigit(*envp
)) {
1255 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
1256 "Invalid backup level \"%s\".\n", envp
);
1257 return (NDMP_ILLEGAL_ARGS_ERR
);
1260 NLP_SET(nlp
, NLPF_LEVELBK
);
1261 NLP_UNSET(nlp
, NLPF_LBRBK
);
1262 NLP_UNSET(nlp
, NLPF_TOKENBK
);
1263 nlp
->nlp_llevel
= *envp
- '0';
1265 nlp
->nlp_clevel
= nlp
->nlp_llevel
;
1267 * The value of nlp_cdate will be set to the checkpoint
1268 * creation time after it is created.
1270 if (ndmpd_get_dumptime(nlp
->nlp_backup_path
, &nlp
->nlp_llevel
,
1271 &nlp
->nlp_ldate
) < 0) {
1272 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
1273 "Getting dumpdates for %s level '%c'.\n",
1274 nlp
->nlp_backup_path
, *envp
);
1275 return (NDMP_NO_MEM_ERR
);
1277 get_update_env_v3(params
, nlp
);
1286 * save_date_token_v3
1288 * Make the value of DUMP_DATE env variable and append the values
1289 * of the current backup in the file specified with the DMP_NAME
1290 * env variable if any file is specified. The file will be
1291 * relative name in the backup directory path.
1294 * params (input) - pointer to the parameters structure
1295 * nlp (input) - pointer to the nlp structure
1301 save_date_token_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
1303 char val
[QUAD_DECIMAL_LEN
];
1306 if (!params
|| !nlp
)
1310 tok
= ((u_longlong_t
)nlp
->nlp_tokseq
<< 32) | nlp
->nlp_cdate
;
1311 (void) snprintf(val
, sizeof (val
), "%llu", tok
);
1313 NDMP_LOG(LOG_DEBUG
, "tok: %lld %s", tok
, val
);
1315 if (MOD_SETENV(params
, "DUMP_DATE", val
) != 0) {
1316 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
1317 "Could not set DUMP_DATE to %s", val
);
1318 } else if (!nlp
->nlp_dmpnm
) {
1319 NDMP_LOG(LOG_DEBUG
, "No log file defined");
1320 } else if (ndmpd_append_dumptime(nlp
->nlp_dmpnm
, nlp
->nlp_backup_path
,
1321 nlp
->nlp_tokseq
, nlp
->nlp_tokdate
) < 0) {
1322 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
1323 "Saving backup date for \"%s\" in \"%s\".\n",
1324 nlp
->nlp_backup_path
, nlp
->nlp_dmpnm
);
1332 * Append the backup type and date in the DMP_NAME file for
1333 * LBR-type backup if any file is specified.
1336 * params (input) - pointer to the parameters structure
1337 * nlp (input) - pointer to the nlp structure
1343 save_lbr_bk_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
1345 if (!params
|| !nlp
)
1348 if (!nlp
->nlp_dmpnm
) {
1349 NDMP_LOG(LOG_DEBUG
, "No log file defined");
1350 } else if (ndmpd_append_dumptime(nlp
->nlp_dmpnm
, nlp
->nlp_backup_path
,
1351 nlp
->nlp_clevel
, nlp
->nlp_cdate
) < 0) {
1352 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
1353 "Saving backup date for \"%s\" in \"%s\".\n",
1354 nlp
->nlp_backup_path
, nlp
->nlp_dmpnm
);
1362 * Save the date and level of the current backup in the dumpdates
1366 * params (input) - pointer to the parameters structure
1367 * nlp (input) - pointer to the nlp structure
1373 save_level_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
1375 if (!params
|| !nlp
)
1378 if (!NLP_SHOULD_UPDATE(nlp
)) {
1379 NDMP_LOG(LOG_DEBUG
, "update not requested");
1380 } else if (ndmpd_put_dumptime(nlp
->nlp_backup_path
, nlp
->nlp_clevel
,
1381 nlp
->nlp_cdate
) < 0) {
1382 MOD_LOGV3(params
, NDMP_LOG_ERROR
, "Logging backup date.\n");
1388 * save_backup_date_v3
1390 * A dispatcher function to call the corresponding save function
1391 * based on the backup type.
1394 * params (input) - pointer to the parameters structure
1395 * nlp (input) - pointer to the nlp structure
1401 save_backup_date_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
1403 if (!params
|| !nlp
)
1406 if (NLP_ISSET(nlp
, NLPF_TOKENBK
))
1407 save_date_token_v3(params
, nlp
);
1408 else if (NLP_ISSET(nlp
, NLPF_LBRBK
))
1409 save_lbr_bk_v3(params
, nlp
);
1410 else if (NLP_ISSET(nlp
, NLPF_LEVELBK
))
1411 save_level_v3(params
, nlp
);
1413 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
1414 "Internal error: lost backup level type for \"%s\".\n",
1415 nlp
->nlp_backup_path
);
1421 * backup_alloc_structs_v3
1423 * Create the structures for V3 backup. This includes:
1426 * File history callback structure
1429 * session (input) - pointer to the session
1430 * jname (input) - name assigned to the current backup for
1431 * job stats strucure
1438 backup_alloc_structs_v3(ndmpd_session_t
*session
, char *jname
)
1442 ndmp_lbr_params_t
*nlp
;
1443 tlm_commands_t
*cmds
;
1445 nlp
= ndmp_get_nlp(session
);
1447 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
1451 nlp
->nlp_jstat
= tlm_new_job_stats(jname
);
1452 if (!nlp
->nlp_jstat
) {
1453 NDMP_LOG(LOG_DEBUG
, "Creating job stats");
1457 cmds
= &nlp
->nlp_cmds
;
1458 (void) memset(cmds
, 0, sizeof (*cmds
));
1460 xfer_size
= ndmp_buffer_get_size(session
);
1461 if (xfer_size
< 512*KILOBYTE
) {
1463 * Read multiple of mover_record_size near to 512K. This
1464 * will prevent the data being copied in the mover buffer
1465 * when we write the data.
1467 n
= 512 * KILOBYTE
/ xfer_size
;
1471 NDMP_LOG(LOG_DEBUG
, "Adjusted read size: %d",
1475 cmds
->tcs_command
= tlm_create_reader_writer_ipc(TRUE
, xfer_size
);
1476 if (!cmds
->tcs_command
) {
1477 tlm_un_ref_job_stats(jname
);
1481 nlp
->nlp_logcallbacks
= lbrlog_callbacks_init(session
,
1482 ndmpd_fhpath_v3_cb
, ndmpd_fhdir_v3_cb
, ndmpd_fhnode_v3_cb
);
1483 if (!nlp
->nlp_logcallbacks
) {
1484 tlm_release_reader_writer_ipc(cmds
->tcs_command
);
1485 tlm_un_ref_job_stats(jname
);
1488 nlp
->nlp_jstat
->js_callbacks
= (void *)(nlp
->nlp_logcallbacks
);
1489 nlp
->nlp_restored
= NULL
;
1496 * restore_alloc_structs_v3
1498 * Create the structures for V3 Restore. This includes:
1501 * File recovery callback structure
1504 * session (input) - pointer to the session
1505 * jname (input) - name assigned to the current backup for
1506 * job stats strucure
1513 restore_alloc_structs_v3(ndmpd_session_t
*session
, char *jname
)
1516 ndmp_lbr_params_t
*nlp
;
1517 tlm_commands_t
*cmds
;
1519 nlp
= ndmp_get_nlp(session
);
1521 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
1525 /* this is used in ndmpd_path_restored_v3() */
1526 nlp
->nlp_lastidx
= -1;
1528 nlp
->nlp_jstat
= tlm_new_job_stats(jname
);
1529 if (!nlp
->nlp_jstat
) {
1530 NDMP_LOG(LOG_DEBUG
, "Creating job stats");
1534 cmds
= &nlp
->nlp_cmds
;
1535 (void) memset(cmds
, 0, sizeof (*cmds
));
1537 xfer_size
= ndmp_buffer_get_size(session
);
1538 cmds
->tcs_command
= tlm_create_reader_writer_ipc(FALSE
, xfer_size
);
1539 if (!cmds
->tcs_command
) {
1540 tlm_un_ref_job_stats(jname
);
1544 nlp
->nlp_logcallbacks
= lbrlog_callbacks_init(session
,
1545 ndmpd_path_restored_v3
, NULL
, NULL
);
1546 if (!nlp
->nlp_logcallbacks
) {
1547 tlm_release_reader_writer_ipc(cmds
->tcs_command
);
1548 tlm_un_ref_job_stats(jname
);
1551 nlp
->nlp_jstat
->js_callbacks
= (void *)(nlp
->nlp_logcallbacks
);
1553 nlp
->nlp_rsbm
= bm_alloc(nlp
->nlp_nfiles
, 0);
1554 if (nlp
->nlp_rsbm
< 0) {
1555 NDMP_LOG(LOG_ERR
, "Out of memory.");
1556 lbrlog_callbacks_done(nlp
->nlp_logcallbacks
);
1557 tlm_release_reader_writer_ipc(cmds
->tcs_command
);
1558 tlm_un_ref_job_stats(jname
);
1569 * Release the resources allocated by backup_alloc_structs_v3
1573 * session (input) - pointer to the session
1574 * jname (input) - name assigned to the current backup for
1575 * job stats strucure
1582 free_structs_v3(ndmpd_session_t
*session
, char *jname
)
1584 ndmp_lbr_params_t
*nlp
;
1585 tlm_commands_t
*cmds
;
1587 nlp
= ndmp_get_nlp(session
);
1589 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
1592 cmds
= &nlp
->nlp_cmds
;
1594 NDMP_LOG(LOG_DEBUG
, "cmds == NULL");
1598 if (nlp
->nlp_logcallbacks
) {
1599 lbrlog_callbacks_done(nlp
->nlp_logcallbacks
);
1600 nlp
->nlp_logcallbacks
= NULL
;
1602 NDMP_LOG(LOG_DEBUG
, "FH CALLBACKS == NULL");
1604 if (cmds
->tcs_command
) {
1605 if (cmds
->tcs_command
->tc_buffers
!= NULL
)
1606 tlm_release_reader_writer_ipc(cmds
->tcs_command
);
1608 NDMP_LOG(LOG_DEBUG
, "BUFFERS == NULL");
1609 cmds
->tcs_command
= NULL
;
1611 NDMP_LOG(LOG_DEBUG
, "COMMAND == NULL");
1613 if (nlp
->nlp_bkmap
>= 0) {
1614 (void) dbm_free(nlp
->nlp_bkmap
);
1615 nlp
->nlp_bkmap
= -1;
1618 if (session
->ns_data
.dd_operation
== NDMP_DATA_OP_RECOVER
) {
1619 if (nlp
->nlp_rsbm
< 0) {
1620 NDMP_LOG(LOG_DEBUG
, "nlp_rsbm < 0 %d", nlp
->nlp_rsbm
);
1622 (void) bm_free(nlp
->nlp_rsbm
);
1632 * Backup a directory and update the bytes processed field of the
1636 * bpp (input) - pointer to the backup parameters structure
1637 * pnp (input) - pointer to the path node
1638 * enp (input) - pointer to the entry node
1645 backup_dirv3(bk_param_v3_t
*bpp
, fst_node_t
*pnp
,
1648 longlong_t apos
, bpos
;
1652 char fullpath
[TLM_MAX_PATH_NAME
];
1655 if (!bpp
|| !pnp
|| !enp
) {
1656 NDMP_LOG(LOG_DEBUG
, "Invalid argument");
1660 NDMP_LOG(LOG_DEBUG
, "d(%s)", bpp
->bp_tmp
);
1662 if (lstat64(bpp
->bp_tmp
, &st
) != 0)
1665 if (acl_get(bpp
->bp_tmp
, ACL_NO_TRIVIAL
, &aclp
) != 0) {
1666 NDMP_LOG(LOG_DEBUG
, "acl_get error errno=%d", errno
);
1669 if (aclp
&& (acltp
= acl_totext(aclp
,
1670 ACL_APPEND_ID
| ACL_SID_FMT
| ACL_COMPACT_FMT
)) != NULL
) {
1671 (void) strlcpy(bpp
->bp_tlmacl
->acl_info
.attr_info
,
1672 acltp
, TLM_MAX_ACL_TXT
);
1676 *bpp
->bp_tlmacl
->acl_info
.attr_info
= '\0';
1679 bpos
= tlm_get_data_offset(bpp
->bp_lcmd
);
1681 p
= bpp
->bp_tmp
+ strlen(bpp
->bp_chkpnm
);
1683 (void) snprintf(fullpath
, TLM_MAX_PATH_NAME
, "%s%s",
1684 bpp
->bp_unchkpnm
, p
);
1686 (void) snprintf(fullpath
, TLM_MAX_PATH_NAME
, "%s/%s",
1687 bpp
->bp_unchkpnm
, p
);
1689 if (tm_tar_ops
.tm_putdir
!= NULL
)
1690 (void) (tm_tar_ops
.tm_putdir
)(fullpath
, bpp
->bp_tlmacl
,
1691 bpp
->bp_lcmd
, bpp
->bp_js
);
1693 apos
= tlm_get_data_offset(bpp
->bp_lcmd
);
1694 bpp
->bp_session
->ns_data
.dd_module
.dm_stats
.ms_bytes_processed
+=
1704 * Backup a file and update the bytes processed field of the
1708 * bpp (input) - pointer to the backup parameters structure
1709 * pnp (input) - pointer to the path node
1710 * enp (input) - pointer to the entry node
1717 backup_filev3(bk_param_v3_t
*bpp
, fst_node_t
*pnp
,
1722 longlong_t apos
, bpos
;
1726 char fullpath
[TLM_MAX_PATH_NAME
];
1729 if (!bpp
|| !pnp
|| !enp
) {
1730 NDMP_LOG(LOG_DEBUG
, "Invalid argument");
1734 NDMP_LOG(LOG_DEBUG
, "f(%s)", bpp
->bp_tmp
);
1736 if (lstat64(bpp
->bp_tmp
, &st
) != 0)
1739 if (!S_ISLNK(bpp
->bp_tlmacl
->acl_attr
.st_mode
)) {
1740 if (acl_get(bpp
->bp_tmp
, ACL_NO_TRIVIAL
, &aclp
) != 0) {
1741 NDMP_LOG(LOG_DEBUG
, "acl_get error");
1746 (acltp
= acl_totext(aclp
,
1747 ACL_APPEND_ID
| ACL_SID_FMT
| ACL_COMPACT_FMT
)) != NULL
) {
1748 (void) strlcpy(bpp
->bp_tlmacl
->acl_info
.attr_info
,
1749 acltp
, TLM_MAX_ACL_TXT
);
1753 *bpp
->bp_tlmacl
->acl_info
.attr_info
= '\0';
1757 bpos
= tlm_get_data_offset(bpp
->bp_lcmd
);
1758 ent
= enp
->tn_path
? enp
->tn_path
: "";
1760 p
= pnp
->tn_path
+ strlen(bpp
->bp_chkpnm
);
1762 (void) snprintf(fullpath
, TLM_MAX_PATH_NAME
, "%s%s",
1763 bpp
->bp_unchkpnm
, p
);
1765 (void) snprintf(fullpath
, TLM_MAX_PATH_NAME
, "%s/%s",
1766 bpp
->bp_unchkpnm
, p
);
1768 if (tm_tar_ops
.tm_putfile
!= NULL
)
1769 rv
= (tm_tar_ops
.tm_putfile
)(fullpath
, ent
, pnp
->tn_path
,
1770 bpp
->bp_tlmacl
, bpp
->bp_cmds
, bpp
->bp_lcmd
, bpp
->bp_js
,
1771 bpp
->bp_session
->hardlink_q
);
1773 apos
= tlm_get_data_offset(bpp
->bp_lcmd
);
1774 bpp
->bp_session
->ns_data
.dd_module
.dm_stats
.ms_bytes_processed
+=
1777 return (rv
< 0 ? rv
: 0);
1784 * Check the argument of the bpp. This is shared function between
1785 * timebk_v3 and lbrbk_v3 functions. The checks include:
1787 * - If the session pointer of the bpp is valid.
1788 * - If the session connection to the DMA is closed.
1789 * - If the nlp pointer of the bpp is valid.
1790 * - If the backup is aborted.
1793 * bpp (input) - pointer to the backup parameters structure
1796 * 0: if everything's OK
1800 check_bk_args(bk_param_v3_t
*bpp
)
1806 NDMP_LOG(LOG_DEBUG
, "Lost bpp");
1807 } else if (!bpp
->bp_session
) {
1809 NDMP_LOG(LOG_DEBUG
, "Session is NULL");
1810 } else if (bpp
->bp_session
->ns_eof
) {
1813 "Connection client is closed for backup \"%s\"",
1814 bpp
->bp_nlp
->nlp_backup_path
);
1815 } else if (!bpp
->bp_nlp
) {
1816 NDMP_LOG(LOG_DEBUG
, "Lost nlp");
1818 } else if (bpp
->bp_session
->ns_data
.dd_abort
) {
1820 NDMP_LOG(LOG_INFO
, "Backup aborted \"%s\"",
1821 bpp
->bp_nlp
->nlp_backup_path
);
1832 * Determines if the current entry should be skipped or it
1833 * should be backed up.
1836 * bpp (input) - pointer to the backup parameters structure
1837 * pnp (input) - pointer to the path node
1838 * enp (input) - pointer to the entry node
1839 * errp (output) - pointer to the error value that should be
1840 * returned by the caller
1843 * TRUE: if the entry should not be backed up
1847 shouldskip(bk_param_v3_t
*bpp
, fst_node_t
*pnp
,
1848 fst_node_t
*enp
, int *errp
)
1852 struct stat64
*estp
;
1854 if (!bpp
|| !pnp
|| !enp
|| !errp
) {
1855 NDMP_LOG(LOG_DEBUG
, "Invalid argument");
1859 if (!enp
->tn_path
) {
1868 * When excluding or skipping entries, FST_SKIP should be
1869 * returned, otherwise, 0 should be returned to
1870 * get other entries in the directory of this entry.
1872 if (!dbm_getone(bpp
->bp_nlp
->nlp_bkmap
, (u_longlong_t
)estp
->st_ino
)) {
1874 *errp
= S_ISDIR(estp
->st_mode
) ? FST_SKIP
: 0;
1875 NDMP_LOG(LOG_DEBUG
, "Skipping %d %s/%s",
1876 *errp
, pnp
->tn_path
, ent
);
1877 } else if (tlm_is_excluded(pnp
->tn_path
, ent
, bpp
->bp_excls
)) {
1879 *errp
= S_ISDIR(estp
->st_mode
) ? FST_SKIP
: 0;
1880 NDMP_LOG(LOG_DEBUG
, "excl %d \"%s/%s\"",
1881 *errp
, pnp
->tn_path
, ent
);
1882 } else if (inexl(bpp
->bp_nlp
->nlp_exl
, ent
)) {
1884 *errp
= S_ISDIR(estp
->st_mode
) ? FST_SKIP
: 0;
1885 NDMP_LOG(LOG_DEBUG
, "out %d \"%s/%s\"",
1886 *errp
, pnp
->tn_path
, ent
);
1887 } else if (!S_ISDIR(estp
->st_mode
) &&
1888 !ininc(bpp
->bp_nlp
->nlp_inc
, ent
)) {
1891 NDMP_LOG(LOG_DEBUG
, "!in \"%s/%s\"", pnp
->tn_path
, ent
);
1902 * Check if the object specified should be backed up or not.
1903 * If stp belongs to a directory and if it is marked in the
1904 * bitmap vector, it shows that either the directory itself is
1905 * modified or there is something below it that will be backed
1908 * By setting ndmp_force_bk_dirs global variable to a non-zero
1909 * value, directories are backed up anyways.
1911 * Backing up the directories unconditionally helps
1912 * restoring the metadata of directories as well, when one
1913 * of the objects below them are being restored.
1915 * For non-directory objects, if the modification or change
1916 * time of the object is after the date specified by the
1917 * bk_selector_t, the the object must be backed up.
1920 ischngd(struct stat64
*stp
, time_t t
, ndmp_lbr_params_t
*nlp
)
1926 NDMP_LOG(LOG_DEBUG
, "stp is NULL");
1929 NDMP_LOG(LOG_DEBUG
, "nlp is NULL");
1930 } else if (t
== 0) {
1932 * if we are doing base backup then we do not need to
1933 * check the time, for we should backup everything.
1936 NDMP_LOG(LOG_DEBUG
, "Base Backup");
1937 } else if (S_ISDIR(stp
->st_mode
) && ndmp_force_bk_dirs
) {
1939 NDMP_LOG(LOG_DEBUG
, "d(%lu)", (uint_t
)stp
->st_ino
);
1940 } else if (S_ISDIR(stp
->st_mode
) &&
1941 dbm_getone(nlp
->nlp_bkmap
, (u_longlong_t
)stp
->st_ino
) &&
1942 ((NLP_ISDUMP(nlp
) && ndmp_dump_path_node
) ||
1943 (NLP_ISTAR(nlp
) && ndmp_tar_path_node
))) {
1945 * If the object is a directory and it leads to a modified
1946 * object (that should be backed up) and for that type of
1947 * backup the path nodes should be backed up, then return
1950 * This is required by some DMAs like Backup Express, which
1951 * needs to receive ADD_NODE (for dump) or ADD_PATH (for tar)
1952 * for the intermediate directories of a modified object.
1953 * Other DMAs, like net_backup and net_worker, do not have such
1954 * requirement. This requirement makes sense for dump format
1955 * but for 'tar' format, it does not. In provision to the
1956 * NDMP-v4 spec, for 'tar' format the intermediate directories
1957 * need not to be reported.
1960 NDMP_LOG(LOG_DEBUG
, "p(%lu)", (u_longlong_t
)stp
->st_ino
);
1961 } else if (stp
->st_mtime
> t
) {
1963 NDMP_LOG(LOG_DEBUG
, "m(%lu): %lu > %lu",
1964 (uint_t
)stp
->st_ino
, (uint_t
)stp
->st_mtime
, (uint_t
)t
);
1965 } else if (stp
->st_ctime
> t
) {
1966 if (NLP_IGNCTIME(nlp
)) {
1968 NDMP_LOG(LOG_DEBUG
, "ign c(%lu): %lu > %lu",
1969 (uint_t
)stp
->st_ino
, (uint_t
)stp
->st_ctime
,
1973 NDMP_LOG(LOG_DEBUG
, "c(%lu): %lu > %lu",
1974 (uint_t
)stp
->st_ino
, (uint_t
)stp
->st_ctime
,
1979 NDMP_LOG(LOG_DEBUG
, "mc(%lu): (%lu,%lu) < %lu",
1980 (uint_t
)stp
->st_ino
, (uint_t
)stp
->st_mtime
,
1981 (uint_t
)stp
->st_ctime
, (uint_t
)t
);
1991 * This function is used to check last mtime (currently inside the ACL
1992 * structure) instead of ctime for checking if the file is to be backed up
1993 * or not. See option "inc.lmtime" for more details
1996 int iscreated(ndmp_lbr_params_t
*nlp
, char *name
, tlm_acls_t
*tacl
,
2003 NDMP_LOG(LOG_DEBUG
, "flags %x", nlp
->nlp_flags
);
2004 if (NLP_INCLMTIME(nlp
) == FALSE
)
2007 ret
= acl_get(name
, ACL_NO_TRIVIAL
, &aclp
);
2010 "Error getting the acl information: err %d", ret
);
2013 if (aclp
&& (acltp
= acl_totext(aclp
,
2014 ACL_APPEND_ID
| ACL_SID_FMT
| ACL_COMPACT_FMT
)) != NULL
) {
2015 (void) strlcpy(tacl
->acl_info
.attr_info
, acltp
,
2021 /* Need to add support for last mtime */
2029 * The callback function for calculating the size of
2030 * the backup path. This is used to get an estimate
2031 * of the progress of backup during NDMP backup
2034 size_cb(void *arg
, fst_node_t
*pnp
, fst_node_t
*enp
)
2038 stp
= enp
->tn_path
? enp
->tn_st
: pnp
->tn_st
;
2039 *((u_longlong_t
*)arg
) += stp
->st_size
;
2047 * The callback function for backing up objects based on
2048 * their time stamp. This is shared between token-based
2049 * and level-based backup, which look at the time stamps
2050 * of the objects to determine if they should be backed
2054 * arg (input) - pointer to the backup parameters structure
2055 * pnp (input) - pointer to the path node
2056 * enp (input) - pointer to the entry node
2059 * 0: if backup should continue
2060 * -1: if the backup should be stopped
2061 * FST_SKIP: if backing up the current directory is enough
2064 timebk_v3(void *arg
, fst_node_t
*pnp
, fst_node_t
*enp
)
2073 bpp
= (bk_param_v3_t
*)arg
;
2075 rv
= check_bk_args(bpp
);
2079 stp
= enp
->tn_path
? enp
->tn_st
: pnp
->tn_st
;
2080 if (shouldskip(bpp
, pnp
, enp
, &rv
))
2094 if (!tlm_cat_path(bpp
->bp_tmp
, pnp
->tn_path
, ent
)) {
2095 NDMP_LOG(LOG_ERR
, "Path too long %s/%s.", pnp
->tn_path
, ent
);
2098 if (NLP_ISSET(bpp
->bp_nlp
, NLPF_TOKENBK
))
2099 t
= bpp
->bp_nlp
->nlp_tokdate
;
2100 else if (NLP_ISSET(bpp
->bp_nlp
, NLPF_LEVELBK
)) {
2101 t
= bpp
->bp_nlp
->nlp_ldate
;
2103 NDMP_LOG(LOG_DEBUG
, "Unknown backup type on \"%s/%s\"",
2108 if (S_ISDIR(stp
->st_mode
)) {
2109 bpp
->bp_tlmacl
->acl_dir_fh
= *fhp
;
2110 (void) ndmpd_fhdir_v3_cb(bpp
->bp_nlp
->nlp_logcallbacks
,
2113 if (ischngd(stp
, t
, bpp
->bp_nlp
)) {
2114 (void) memcpy(&bpp
->bp_tlmacl
->acl_attr
, stp
,
2115 sizeof (struct stat64
));
2116 rv
= backup_dirv3(bpp
, pnp
, enp
);
2119 if (ischngd(stp
, t
, bpp
->bp_nlp
) ||
2120 iscreated(bpp
->bp_nlp
, bpp
->bp_tmp
, bpp
->bp_tlmacl
, t
)) {
2122 (void) memcpy(&bpp
->bp_tlmacl
->acl_attr
, stp
,
2123 sizeof (struct stat64
));
2124 bpp
->bp_tlmacl
->acl_fil_fh
= *fhp
;
2125 (void) backup_filev3(bpp
, pnp
, enp
);
2136 * The callback function for backing up objects based on
2137 * their archive directory bit. This is used in LBR-type
2138 * backup. In which the objects are backed up if their
2139 * archive bit is set.
2142 * arg (input) - pointer to the backup parameters structure
2143 * pnp (input) - pointer to the path node
2144 * enp (input) - pointer to the entry node
2147 * 0: if backup should continue
2148 * -1: if the backup should be stopped
2149 * FST_SKIP: if backing up the current directory is enough
2152 lbrbk_v3(void *arg
, fst_node_t
*pnp
, fst_node_t
*enp
)
2160 bpp
= (bk_param_v3_t
*)arg
;
2161 rv
= check_bk_args(bpp
);
2165 stp
= enp
->tn_path
? enp
->tn_st
: pnp
->tn_st
;
2166 if (shouldskip(bpp
, pnp
, enp
, &rv
))
2179 if (!tlm_cat_path(bpp
->bp_tmp
, pnp
->tn_path
, ent
)) {
2180 NDMP_LOG(LOG_ERR
, "Path too long %s/%s.", pnp
->tn_path
, ent
);
2183 if (!NLP_ISSET(bpp
->bp_nlp
, NLPF_LBRBK
)) {
2184 NDMP_LOG(LOG_DEBUG
, "!NLPF_LBRBK");
2188 if (S_ISDIR(stp
->st_mode
)) {
2189 bpp
->bp_tlmacl
->acl_dir_fh
= *fhp
;
2190 (void) ndmpd_fhdir_v3_cb(bpp
->bp_nlp
->nlp_logcallbacks
,
2193 if (SHOULD_LBRBK(bpp
)) {
2194 bpp
->bp_tlmacl
->acl_attr
= *stp
;
2195 rv
= backup_dirv3(bpp
, pnp
, enp
);
2197 } else if (SHOULD_LBRBK(bpp
)) {
2199 bpp
->bp_tlmacl
->acl_attr
= *stp
;
2200 bpp
->bp_tlmacl
->acl_fil_fh
= *fhp
;
2201 (void) backup_filev3(bpp
, pnp
, enp
);
2211 * The reader thread for the backup. It sets up the callback
2212 * parameters and traverses the backup hierarchy in level-order
2216 * jname (input) - name assigned to the current backup for
2217 * job stats strucure
2218 * nlp (input) - pointer to the nlp structure
2219 * cmds (input) - pointer to the tlm_commands_t structure
2226 backup_reader_v3(backup_reader_arg_t
*argp
)
2230 tlm_acls_t tlm_acls
;
2235 ndmp_lbr_params_t
*nlp
;
2236 tlm_commands_t
*cmds
;
2241 jname
= argp
->br_jname
;
2243 cmds
= argp
->br_cmds
;
2246 lcmd
= cmds
->tcs_command
;
2248 cmds
->tcs_reader_count
++;
2250 (void) memset(&tlm_acls
, 0, sizeof (tlm_acls
));
2252 /* NDMP parameters */
2253 bp
.bp_session
= nlp
->nlp_session
;
2256 /* LBR-related parameters */
2257 bp
.bp_js
= tlm_ref_job_stats(jname
);
2260 bp
.bp_tlmacl
= &tlm_acls
;
2263 /* release the parent thread, after referencing the job stats */
2264 (void) pthread_barrier_wait(&argp
->br_barrier
);
2266 bp
.bp_tmp
= ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME
);
2271 * Make the checkpointed paths for traversing the
2272 * backup hierarchy, if we make the checkpoint.
2274 bp
.bp_unchkpnm
= nlp
->nlp_backup_path
;
2275 if (!NLP_ISCHKPNTED(nlp
)) {
2276 tlm_acls
.acl_checkpointed
= TRUE
;
2277 bp
.bp_chkpnm
= ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME
);
2278 if (!bp
.bp_chkpnm
) {
2279 NDMP_FREE(bp
.bp_tmp
);
2282 (void) tlm_build_snapshot_name(nlp
->nlp_backup_path
,
2283 bp
.bp_chkpnm
, nlp
->nlp_jstat
->js_job_name
);
2285 tlm_acls
.acl_checkpointed
= FALSE
;
2286 bp
.bp_chkpnm
= nlp
->nlp_backup_path
;
2288 bp
.bp_excls
= ndmpd_make_exc_list();
2290 /* set traversing arguments */
2291 ft
.ft_path
= nlp
->nlp_backup_path
;
2292 ft
.ft_lpath
= bp
.bp_chkpnm
;
2294 NDMP_LOG(LOG_DEBUG
, "path %s lpath %s", ft
.ft_path
, ft
.ft_lpath
);
2295 if (NLP_ISSET(nlp
, NLPF_TOKENBK
) || NLP_ISSET(nlp
, NLPF_LEVELBK
)) {
2296 ft
.ft_callbk
= timebk_v3
;
2297 tlm_acls
.acl_clear_archive
= FALSE
;
2298 } else if (NLP_ISSET(nlp
, NLPF_LBRBK
)) {
2299 ft
.ft_callbk
= lbrbk_v3
;
2300 tlm_acls
.acl_clear_archive
= FALSE
;
2302 NDMP_LOG(LOG_DEBUG
, "bp_opr %x clr_arc %c",
2303 bp
.bp_opr
, NDMP_YORN(tlm_acls
.acl_clear_archive
));
2306 MOD_LOGV3(nlp
->nlp_params
, NDMP_LOG_ERROR
,
2307 "Unknow backup type.\n");
2310 ft
.ft_logfp
= (ft_log_t
)ndmp_log
;
2311 ft
.ft_flags
= FST_VERBOSE
| FST_STOP_ONERR
;
2313 /* take into account the header written to the stream so far */
2314 n
= tlm_get_data_offset(lcmd
);
2315 nlp
->nlp_session
->ns_data
.dd_module
.dm_stats
.ms_bytes_processed
= n
;
2318 /* start traversing the hierarchy and actual backup */
2319 rv
= traverse_level(&ft
);
2321 /* write the trailer and update the bytes processed */
2322 bpos
= tlm_get_data_offset(lcmd
);
2323 (void) write_tar_eof(lcmd
);
2324 n
= tlm_get_data_offset(lcmd
) - bpos
;
2326 ns_data
.dd_module
.dm_stats
.ms_bytes_processed
+= n
;
2328 MOD_LOGV3(nlp
->nlp_params
, NDMP_LOG_ERROR
,
2329 "Filesystem traverse error.\n");
2330 ndmpd_data_error(nlp
->nlp_session
,
2331 NDMP_DATA_HALT_INTERNAL_ERROR
);
2335 if (!NLP_ISCHKPNTED(nlp
))
2336 NDMP_FREE(bp
.bp_chkpnm
);
2337 NDMP_FREE(bp
.bp_tmp
);
2338 NDMP_FREE(bp
.bp_excls
);
2340 cmds
->tcs_reader_count
--;
2341 lcmd
->tc_writer
= TLM_STOP
;
2342 tlm_release_reader_writer_ipc(lcmd
);
2343 tlm_un_ref_job_stats(jname
);
2352 * Traverse the backup hierarchy if needed and make the bitmap.
2353 * Then launch reader and writer threads to do the actual backup.
2356 * session (input) - pointer to the session
2357 * params (input) - pointer to the parameters structure
2358 * nlp (input) - pointer to the nlp structure
2359 * jname (input) - job name
2366 tar_backup_v3(ndmpd_session_t
*session
, ndmpd_module_params_t
*params
,
2367 ndmp_lbr_params_t
*nlp
, char *jname
)
2369 tlm_commands_t
*cmds
;
2370 backup_reader_arg_t arg
;
2374 ndmp_context_t nctx
;
2377 if (ndmp_get_bk_dir_ino(nlp
))
2382 /* exit as if there was an internal error */
2383 if (session
->ns_eof
)
2386 if (!session
->ns_data
.dd_abort
) {
2387 if (backup_alloc_structs_v3(session
, jname
) < 0) {
2388 nlp
->nlp_bkmap
= -1;
2392 if (ndmpd_mark_inodes_v3(session
, nlp
) != 0) {
2393 if (nlp
->nlp_bkmap
!= -1) {
2394 (void) dbm_free(nlp
->nlp_bkmap
);
2395 nlp
->nlp_bkmap
= -1;
2397 free_structs_v3(session
, jname
);
2401 nlp
->nlp_jstat
->js_start_ltime
= time(NULL
);
2402 nlp
->nlp_jstat
->js_start_time
= nlp
->nlp_jstat
->js_start_ltime
;
2403 nlp
->nlp_jstat
->js_chkpnt_time
= nlp
->nlp_cdate
;
2405 cmds
= &nlp
->nlp_cmds
;
2406 cmds
->tcs_reader
= cmds
->tcs_writer
= TLM_BACKUP_RUN
;
2407 cmds
->tcs_command
->tc_reader
= TLM_BACKUP_RUN
;
2408 cmds
->tcs_command
->tc_writer
= TLM_BACKUP_RUN
;
2410 if (ndmp_write_utf8magic(cmds
->tcs_command
) < 0) {
2411 free_structs_v3(session
, jname
);
2416 "Backing up \"%s\" started.", nlp
->nlp_backup_path
);
2418 /* Plug-in module */
2419 if (ndmp_pl
!= NULL
&&
2420 ndmp_pl
->np_pre_backup
!= NULL
) {
2421 (void) memset(&nctx
, 0, sizeof (ndmp_context_t
));
2422 nctx
.nc_plversion
= ndmp_pl
->np_plversion
;
2423 nctx
.nc_plname
= ndmpd_get_prop(NDMP_PLUGIN_PATH
);
2424 nctx
.nc_cmds
= cmds
;
2425 nctx
.nc_params
= params
;
2426 nctx
.nc_ddata
= (void *) session
;
2427 if ((err
= ndmp_pl
->np_pre_backup(ndmp_pl
, &nctx
,
2428 nlp
->nlp_backup_path
)) != 0) {
2429 NDMP_LOG(LOG_ERR
, "Pre-backup plug-in: %m");
2434 (void) memset(&arg
, 0, sizeof (backup_reader_arg_t
));
2435 arg
.br_jname
= jname
;
2439 (void) pthread_barrier_init(&arg
.br_barrier
, 0, 2);
2441 err
= pthread_create(&rdtp
, NULL
, (funct_t
)backup_reader_v3
,
2444 (void) pthread_barrier_wait(&arg
.br_barrier
);
2445 (void) pthread_barrier_destroy(&arg
.br_barrier
);
2447 (void) pthread_barrier_destroy(&arg
.br_barrier
);
2448 free_structs_v3(session
, jname
);
2449 NDMP_LOG(LOG_DEBUG
, "Launch backup_reader_v3: %m");
2453 if ((err
= ndmp_tar_writer(session
, params
, cmds
)) != 0)
2456 nlp
->nlp_jstat
->js_stop_time
= time(NULL
);
2458 (void) snprintf(info
, sizeof (info
),
2459 "Runtime [%s] %llu bytes (%llu): %d seconds\n",
2460 nlp
->nlp_backup_path
,
2461 session
->ns_data
.dd_module
.dm_stats
.ms_bytes_processed
,
2462 session
->ns_data
.dd_module
.dm_stats
.ms_bytes_processed
,
2463 nlp
->nlp_jstat
->js_stop_time
-
2464 nlp
->nlp_jstat
->js_start_ltime
);
2465 MOD_LOGV3(params
, NDMP_LOG_NORMAL
, info
);
2467 ndmp_wait_for_reader(cmds
);
2468 (void) pthread_join(rdtp
, NULL
);
2470 /* exit as if there was an internal error */
2471 if (session
->ns_eof
) {
2475 if (!session
->ns_data
.dd_abort
) {
2476 ndmpd_audit_backup(session
->ns_connection
,
2477 nlp
->nlp_backup_path
,
2478 session
->ns_data
.dd_data_addr
.addr_type
,
2479 session
->ns_tape
.td_adapter_name
, result
);
2480 NDMP_LOG(LOG_DEBUG
, "Backing up \"%s\" Finished.",
2481 nlp
->nlp_backup_path
);
2485 if (session
->ns_data
.dd_abort
) {
2486 ndmpd_audit_backup(session
->ns_connection
,
2487 nlp
->nlp_backup_path
,
2488 session
->ns_data
.dd_data_addr
.addr_type
,
2489 session
->ns_tape
.td_adapter_name
, EINTR
);
2491 "Backing up \"%s\" aborted.", nlp
->nlp_backup_path
);
2496 /* Plug-in module */
2497 if (ndmp_pl
!= NULL
&&
2498 ndmp_pl
->np_post_backup
!= NULL
&&
2499 ndmp_pl
->np_post_backup(ndmp_pl
, &nctx
, err
) == -1) {
2500 NDMP_LOG(LOG_DEBUG
, "Post-backup plug-in: %m");
2505 free_structs_v3(session
, jname
);
2512 * Find the estimate of backup size. This is used to get an estimate
2513 * of the progress of backup during NDMP backup.
2516 get_backup_size(ndmp_bkup_size_arg_t
*sarg
)
2519 u_longlong_t bk_size
;
2520 char spath
[PATH_MAX
];
2524 if (fs_is_chkpntvol(sarg
->bs_path
)) {
2525 ft
.ft_path
= sarg
->bs_path
;
2527 (void) tlm_build_snapshot_name(sarg
->bs_path
,
2528 spath
, sarg
->bs_jname
);
2532 ft
.ft_lpath
= ft
.ft_path
;
2533 ft
.ft_callbk
= size_cb
;
2534 ft
.ft_arg
= &bk_size
;
2535 ft
.ft_logfp
= (ft_log_t
)ndmp_log
;
2536 ft
.ft_flags
= FST_VERBOSE
;
2538 if ((rv
= traverse_level(&ft
)) != 0) {
2539 NDMP_LOG(LOG_DEBUG
, "bksize err=%d", rv
);
2542 NDMP_LOG(LOG_DEBUG
, "bksize %lld, %lldKB, %lldMB\n",
2543 bk_size
, bk_size
/ 1024, bk_size
/(1024 * 1024));
2545 sarg
->bs_session
->ns_data
.dd_data_size
= bk_size
;
2551 * Find the restore path
2554 get_rs_path_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
2558 mem_ndmp_name_v3_t
*ep
;
2560 char *nm_dpath_list
[MULTIPLE_DEST_DIRS
];
2561 static char mdest_buf
[256];
2564 *nm_dpath_list
= "";
2565 for (i
= 0, nm_cnt
= 0; i
< (int)nlp
->nlp_nfiles
; i
++) {
2566 ep
= (mem_ndmp_name_v3_t
*)MOD_GETNAME(params
, i
);
2568 NDMP_LOG(LOG_DEBUG
, "Can't get Nlist[%d]", i
);
2569 return (NDMP_ILLEGAL_ARGS_ERR
);
2571 if (strcmp(nm_dpath_list
[nm_cnt
], ep
->nm3_dpath
) != 0 &&
2572 nm_cnt
< MULTIPLE_DEST_DIRS
- 1)
2573 nm_dpath_list
[++nm_cnt
] = ep
->nm3_dpath
;
2576 multiple_dest_restore
= (nm_cnt
> 1);
2577 nlp
->nlp_restore_path
= mdest_buf
;
2579 for (i
= 1; i
< nm_cnt
+ 1; i
++) {
2580 if (ISDEFINED(nm_dpath_list
[i
]))
2581 dp
= nm_dpath_list
[i
];
2583 /* the default destination path is backup directory */
2584 dp
= nlp
->nlp_backup_path
;
2586 /* check the destination directory exists and is writable */
2587 if (!fs_volexist(dp
)) {
2588 rv
= NDMP_ILLEGAL_ARGS_ERR
;
2589 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
2590 "Invalid destination path volume \"%s\".\n", dp
);
2591 } else if (!voliswr(dp
)) {
2592 rv
= NDMP_ILLEGAL_ARGS_ERR
;
2593 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
2594 "The destination path volume"
2595 " is not writable \"%s\".\n", dp
);
2598 (void) strlcat(nlp
->nlp_restore_path
, dp
,
2599 sizeof (mdest_buf
));
2600 NDMP_LOG(LOG_DEBUG
, "rspath: \"%s\"", dp
);
2604 * Exit if there is an error or it is not a multiple
2605 * destination restore mode
2607 if (rv
!= NDMP_NO_ERR
|| !multiple_dest_restore
)
2611 (void) strlcat(nlp
->nlp_restore_path
, ", ",
2612 sizeof (mdest_buf
));
2622 * Check if the recovery list is valid and fix it if there are some
2623 * unspecified entries in it. It checks for original, destination
2624 * and new path for all NDMP names provided inside the list.
2626 * V3: dpath is the destination directory. If newnm is not NULL, the
2627 * destination path is dpath/newnm. Otherwise the destination path is
2628 * dpath/opath_last_node, where opath_last_node is the last node in opath.
2630 * V4: If newnm is not NULL, dpath is the destination directory, and
2631 * dpath/newnm is the destination path. If newnm is NULL, dpath is
2632 * the destination path (opath is not involved in forming destination path).
2635 fix_nlist_v3(ndmpd_session_t
*session
, ndmpd_module_params_t
*params
,
2636 ndmp_lbr_params_t
*nlp
)
2638 char *cp
, *buf
, *bp
;
2643 mem_ndmp_name_v3_t
*ep
;
2649 buf
= ndmp_malloc(TLM_MAX_PATH_NAME
);
2651 MOD_LOGV3(params
, NDMP_LOG_ERROR
, "Insufficient memory.\n");
2652 return (NDMP_NO_MEM_ERR
);
2655 bvexists
= fs_volexist(nlp
->nlp_backup_path
);
2656 iswrbk
= voliswr(nlp
->nlp_backup_path
);
2659 n
= session
->ns_data
.dd_nlist_len
;
2660 for (i
= 0; i
< n
; i
++) {
2661 ep
= (mem_ndmp_name_v3_t
*)MOD_GETNAME(params
, i
);
2665 /* chop off the trailing slashes */
2666 chopslash(ep
->nm3_opath
);
2668 chopslash(ep
->nm3_dpath
);
2669 chopslash(ep
->nm3_newnm
);
2671 /* existing and non-empty destination path */
2672 if (ISDEFINED(ep
->nm3_dpath
)) {
2674 existsvol
= fs_volexist(dp
);
2675 isrwdst
= voliswr(dp
);
2677 /* the default destination path is backup directory */
2678 dp
= nlp
->nlp_backup_path
;
2679 existsvol
= bvexists
;
2683 /* check the destination directory exists and is writable */
2685 rv
= NDMP_ILLEGAL_ARGS_ERR
;
2686 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
2687 "Invalid destination path volume "
2692 rv
= NDMP_ILLEGAL_ARGS_ERR
;
2693 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
2694 "The destination path volume is not "
2695 "writable \"%s\".\n", dp
);
2700 * If new name is not specified, the default new name is
2701 * the last component of the original path, if any
2704 if (ISDEFINED(ep
->nm3_newnm
)) {
2710 * Find the last component of nm3_opath.
2711 * nm3_opath has no trailing '/'.
2713 p
= strrchr(ep
->nm3_opath
, '/');
2714 nm
= p
? p
+ 1 : ep
->nm3_opath
;
2717 * In DDAR the last component could
2718 * be repeated in nm3_dpath
2720 q
= strrchr(ep
->nm3_dpath
, '/');
2721 q
= q
? q
+ 1 : ep
->nm3_dpath
;
2722 if (strcmp(nm
, q
) == 0)
2727 bp
= joinpath(buf
, dp
, nm
);
2730 * Note: What should be done with this entry?
2731 * We leave it untouched for now, hence no path in
2732 * the backup image matches with this entry and will
2733 * be reported as not found.
2735 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
2736 "Destination path too long(%s/%s)", dp
, nm
);
2741 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
2742 "Insufficient memory.\n");
2743 rv
= NDMP_NO_MEM_ERR
;
2746 free(ep
->nm3_dpath
);
2748 NDMP_FREE(ep
->nm3_newnm
);
2750 bp
= joinpath(buf
, nlp
->nlp_backup_path
, ep
->nm3_opath
);
2753 * Note: The same problem of above with long path.
2755 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
2756 "Path too long(%s/%s)",
2757 nlp
->nlp_backup_path
, ep
->nm3_opath
);
2762 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
2763 "Insufficient memory.\n");
2764 rv
= NDMP_NO_MEM_ERR
;
2767 NDMP_FREE(ep
->nm3_opath
);
2770 NDMP_LOG(LOG_DEBUG
, "orig[%d]: \"%s\"", i
, ep
->nm3_opath
);
2771 if (ep
->nm3_dpath
) {
2773 "dest[%d]: \"%s\"", i
, ep
->nm3_dpath
);
2775 NDMP_LOG(LOG_DEBUG
, "dest[%d]: \"%s\"", i
, "NULL");
2788 * Run a sanity check on the file history info. The file history
2789 * info is the offset of the record starting the entry on the tape
2790 * and is used in DAR (direct access restore mode).
2793 allvalidfh(ndmpd_session_t
*session
, ndmpd_module_params_t
*params
)
2797 mem_ndmp_name_v3_t
*ep
;
2800 n
= session
->ns_data
.dd_nlist_len
;
2801 for (i
= 0; i
< n
; i
++) {
2802 ep
= (mem_ndmp_name_v3_t
*)MOD_GETNAME(params
, i
);
2806 * The fh_info's sent from the client are multiples
2807 * of RECORDSIZE which is 512 bytes.
2809 * All our fh_info's are at the RECORDSIZE boundary. If there
2810 * is any fh_info that is less than RECORDSIZE (this covers 0
2811 * and -1 values too), then the result is that DAR cannot be
2814 if (ep
->nm3_fh_info
< RECORDSIZE
||
2815 ep
->nm3_fh_info
% RECORDSIZE
!= 0) {
2828 * Log a copy of all values of the restore parameters
2831 log_rs_params_v3(ndmpd_session_t
*session
, ndmpd_module_params_t
*params
,
2832 ndmp_lbr_params_t
*nlp
)
2834 MOD_LOGV3(params
, NDMP_LOG_NORMAL
, "Restoring to \"%s\".\n",
2835 (nlp
->nlp_restore_path
) ? nlp
->nlp_restore_path
: "NULL");
2837 if (session
->ns_data
.dd_data_addr
.addr_type
== NDMP_ADDR_LOCAL
) {
2838 MOD_LOGV3(params
, NDMP_LOG_NORMAL
, "Tape server: local.\n");
2839 MOD_LOGV3(params
, NDMP_LOG_NORMAL
,
2840 "Tape record size: %d.\n",
2841 session
->ns_mover
.md_record_size
);
2842 } else if (session
->ns_data
.dd_data_addr
.addr_type
== NDMP_ADDR_TCP
)
2843 MOD_LOGV3(params
, NDMP_LOG_NORMAL
,
2844 "Tape server: remote at %s:%d.\n",
2845 inet_ntoa(IN_ADDR(session
->ns_data
.dd_data_addr
.tcp_ip_v3
)),
2846 session
->ns_data
.dd_data_addr
.tcp_port_v3
);
2848 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
2849 "Unknown tape server address type.\n");
2851 if (NLP_ISSET(nlp
, NLPF_DIRECT
))
2852 MOD_LOGV3(params
, NDMP_LOG_NORMAL
,
2853 "Direct Access Restore.\n");
2858 * send_unrecovered_list_v3
2860 * Create the list of files that were in restore list but
2861 * not recovered due to some errors.
2864 send_unrecovered_list_v3(ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
)
2870 NDMP_LOG(LOG_DEBUG
, "params == NULL");
2874 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
2878 if (nlp
->nlp_lastidx
!= -1) {
2879 if (!bm_getone(nlp
->nlp_rsbm
, (u_longlong_t
)nlp
->nlp_lastidx
))
2883 (void) ndmp_send_recovery_stat_v3(params
, nlp
,
2884 nlp
->nlp_lastidx
, err
);
2885 nlp
->nlp_lastidx
= -1;
2889 for (i
= 0; i
< (int)nlp
->nlp_nfiles
; i
++) {
2890 if (!bm_getone(nlp
->nlp_rsbm
, (u_longlong_t
)i
)) {
2891 rv
= ndmp_send_recovery_stat_v3(params
, nlp
, i
, ENOENT
);
2903 * restore_dar_alloc_structs_v3
2905 * Allocates the necessary structures for running DAR restore.
2906 * It just creates the reader writer IPC.
2907 * This function is called for each entry in the restore entry list.
2910 * session (input) - pointer to the session
2911 * jname (input) - Job name
2918 restore_dar_alloc_structs_v3(ndmpd_session_t
*session
, char *jname
)
2921 ndmp_lbr_params_t
*nlp
;
2922 tlm_commands_t
*cmds
;
2924 nlp
= ndmp_get_nlp(session
);
2926 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
2930 cmds
= &nlp
->nlp_cmds
;
2931 (void) memset(cmds
, 0, sizeof (*cmds
));
2933 xfer_size
= ndmp_buffer_get_size(session
);
2934 cmds
->tcs_command
= tlm_create_reader_writer_ipc(FALSE
, xfer_size
);
2935 if (!cmds
->tcs_command
) {
2936 tlm_un_ref_job_stats(jname
);
2945 * free_dar_structs_v3
2947 * To free the structures were created by restore_dar_alloc_structs_v3.
2948 * This funnction is called for each entry in restore entry list.
2951 * session (input) - pointer to the session
2952 * jname (input) - job name
2959 free_dar_structs_v3(ndmpd_session_t
*session
, char *jname
)
2961 ndmp_lbr_params_t
*nlp
;
2962 tlm_commands_t
*cmds
;
2964 nlp
= ndmp_get_nlp(session
);
2966 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
2969 cmds
= &nlp
->nlp_cmds
;
2971 NDMP_LOG(LOG_DEBUG
, "cmds == NULL");
2975 if (cmds
->tcs_command
) {
2976 if (cmds
->tcs_command
->tc_buffers
!= NULL
)
2977 tlm_release_reader_writer_ipc(cmds
->tcs_command
);
2979 NDMP_LOG(LOG_DEBUG
, "BUFFERS == NULL");
2980 cmds
->tcs_command
= NULL
;
2982 NDMP_LOG(LOG_DEBUG
, "COMMAND == NULL");
2987 * ndmp_dar_tar_init_v3
2989 * Constructor for the DAR restore. Creates job name, allocates structures
2990 * needed for keeping the statistics, and reports the start of restore action.
2991 * It is called once for each DAR restore request.
2994 * session (input) - pointer to the session
2995 * nlp (input) - pointer to the nlp structure
2998 * char pointer: on success
3001 static char *ndmpd_dar_tar_init_v3(ndmpd_session_t
*session
,
3002 ndmp_lbr_params_t
*nlp
)
3006 jname
= ndmp_malloc(TLM_MAX_BACKUP_JOB_NAME
);
3011 (void) ndmp_new_job_name(jname
);
3015 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
3019 nlp
->nlp_jstat
= tlm_new_job_stats(jname
);
3020 if (!nlp
->nlp_jstat
) {
3022 NDMP_LOG(LOG_DEBUG
, "Creating job stats");
3026 nlp
->nlp_jstat
->js_start_ltime
= time(NULL
);
3027 nlp
->nlp_jstat
->js_start_time
= nlp
->nlp_jstat
->js_start_ltime
;
3029 nlp
->nlp_logcallbacks
= lbrlog_callbacks_init(session
,
3030 ndmpd_path_restored_v3
, NULL
, NULL
);
3031 if (!nlp
->nlp_logcallbacks
) {
3032 tlm_un_ref_job_stats(jname
);
3036 nlp
->nlp_jstat
->js_callbacks
= (void *)(nlp
->nlp_logcallbacks
);
3038 nlp
->nlp_rsbm
= bm_alloc(nlp
->nlp_nfiles
, 0);
3039 if (nlp
->nlp_rsbm
< 0) {
3040 NDMP_LOG(LOG_ERR
, "Out of memory.");
3041 lbrlog_callbacks_done(nlp
->nlp_logcallbacks
);
3042 tlm_un_ref_job_stats(jname
);
3047 /* this is used in ndmpd_path_restored_v3() */
3048 nlp
->nlp_lastidx
= -1;
3050 NDMP_LOG(LOG_DEBUG
, "Restoring from %s tape(s).",
3051 ndmp_data_get_mover_mode(session
));
3057 * ndmpd_dar_tar_end_v3
3059 * Deconstructor for the DAR restore. This function is called once per
3060 * DAR request. It deallocates memories allocated by ndmpd_dar_tar_init_v3.
3063 * session (input) - pointer to the session
3064 * params (input) - pointer to the parameters structure
3065 * nlp (input) - pointer to the nlp structure
3066 * jname(input) - job name
3072 static int ndmpd_dar_tar_end_v3(ndmpd_session_t
*session
,
3073 ndmpd_module_params_t
*params
, ndmp_lbr_params_t
*nlp
, char *jname
)
3078 NDMP_LOG(LOG_DEBUG
, "lastidx %d", nlp
->nlp_lastidx
);
3080 /* nothing restored. */
3081 (void) send_unrecovered_list_v3(params
, nlp
);
3083 if (nlp
->nlp_jstat
) {
3084 nlp
->nlp_bytes_total
=
3085 (u_longlong_t
)nlp
->nlp_jstat
->js_bytes_total
;
3086 tlm_un_ref_job_stats(jname
);
3087 nlp
->nlp_jstat
= NULL
;
3089 NDMP_LOG(LOG_DEBUG
, "JSTAT == NULL");
3092 if (nlp
->nlp_logcallbacks
) {
3093 lbrlog_callbacks_done(nlp
->nlp_logcallbacks
);
3094 nlp
->nlp_logcallbacks
= NULL
;
3096 NDMP_LOG(LOG_DEBUG
, "FH CALLBACKS == NULL");
3099 if (session
->ns_data
.dd_abort
) {
3100 NDMP_LOG(LOG_DEBUG
, "Restoring to \"%s\" aborted.",
3101 (nlp
->nlp_restore_path
) ? nlp
->nlp_restore_path
: "NULL");
3104 NDMP_LOG(LOG_DEBUG
, "Restoring to \"%s\" finished. (%d)",
3105 (nlp
->nlp_restore_path
) ? nlp
->nlp_restore_path
:
3109 if (session
->ns_data
.dd_operation
== NDMP_DATA_OP_RECOVER
) {
3110 if (nlp
->nlp_rsbm
< 0) {
3111 NDMP_LOG(LOG_DEBUG
, "nlp_rsbm < 0 %d", nlp
->nlp_rsbm
);
3113 (void) bm_free(nlp
->nlp_rsbm
);
3127 * This function is called for each entry in DAR entry list. The window
3128 * is already located and we should be in the right position to read
3129 * the data from the tape.
3130 * For each entry we setup selection list; so that, if the file name from
3131 * tape is not as the name client asked for, error be returned.
3134 * session (input) - pointer to the session
3135 * params (input) - pointer to the parameters structure
3136 * nlp (input) - pointer to the nlp structure
3137 * jname (input) - job name
3138 * dar_index(input) - Index of this entry in the restore list
3145 ndmpd_dar_tar_v3(ndmpd_session_t
*session
, ndmpd_module_params_t
*params
,
3146 ndmp_lbr_params_t
*nlp
, char *jname
, int dar_index
)
3152 tlm_commands_t
*cmds
;
3153 struct rs_name_maker rn
;
3154 int data_addr_type
= session
->ns_data
.dd_data_addr
.addr_type
;
3155 ndmp_tar_reader_arg_t arg
;
3157 ndmp_context_t nctx
;
3158 mem_ndmp_name_v3_t
*ep
;
3163 * We have to allocate and deallocate buffers every time we
3164 * run the restore, for we need to flush the buffers.
3166 if (restore_dar_alloc_structs_v3(session
, jname
) < 0)
3169 sels
= setupsels(session
, params
, nlp
, dar_index
);
3171 free_dar_structs_v3(session
, jname
);
3175 flags
= RSFLG_OVR_ALWAYS
;
3177 rn
.rn_fp
= mknewname
;
3179 if (!session
->ns_data
.dd_abort
) {
3180 cmds
= &nlp
->nlp_cmds
;
3181 cmds
->tcs_reader
= cmds
->tcs_writer
= TLM_RESTORE_RUN
;
3182 cmds
->tcs_command
->tc_reader
= TLM_RESTORE_RUN
;
3183 cmds
->tcs_command
->tc_writer
= TLM_RESTORE_RUN
;
3185 arg
.tr_session
= session
;
3186 arg
.tr_mod_params
= params
;
3189 err
= pthread_create(&rdtp
, NULL
, (funct_t
)ndmp_tar_reader
,
3192 tlm_cmd_wait(cmds
->tcs_command
, TLM_TAR_READER
);
3194 NDMP_LOG(LOG_DEBUG
, "launch ndmp_tar_reader: %m");
3198 cmds
->tcs_command
->tc_ref
++;
3199 cmds
->tcs_writer_count
++;
3201 /* Plug-in module */
3202 if (ndmp_pl
!= NULL
&&
3203 ndmp_pl
->np_pre_restore
!= NULL
) {
3204 (void) memset(&nctx
, 0, sizeof (ndmp_context_t
));
3205 nctx
.nc_cmds
= cmds
;
3206 nctx
.nc_params
= params
;
3207 nctx
.nc_ddata
= (void *) session
;
3208 ep
= (mem_ndmp_name_v3_t
*)MOD_GETNAME(params
,
3211 if ((err
= ndmp_pl
->np_pre_restore(ndmp_pl
, &nctx
,
3212 ep
->nm3_opath
, ep
->nm3_dpath
))
3214 NDMP_LOG(LOG_ERR
, "Pre-restore plug-in: %m");
3215 ndmp_stop_local_reader(session
, cmds
);
3216 ndmp_wait_for_reader(cmds
);
3217 (void) pthread_join(rdtp
, NULL
);
3218 ndmp_stop_remote_reader(session
);
3223 if (tm_tar_ops
.tm_getdir
!= NULL
) {
3226 err
= (tm_tar_ops
.tm_getdir
)(cmds
, cmds
->tcs_command
,
3227 nlp
->nlp_jstat
, &rn
, 1, 1, sels
, &excl
, flags
,
3228 dar_index
, nlp
->nlp_backup_path
,
3229 session
->hardlink_q
);
3231 * If the fatal error from tm_getdir looks like an
3232 * errno code, we send the error description to DMA.
3234 if (err
> 0 && strerror_r(err
, errbuf
,
3235 sizeof (errbuf
)) == 0) {
3236 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
3237 "Fatal error during the restore: %s\n",
3242 cmds
->tcs_writer_count
--;
3243 cmds
->tcs_command
->tc_ref
--;
3244 NDMP_LOG(LOG_DEBUG
, "stop local reader.");
3245 ndmp_stop_local_reader(session
, cmds
);
3247 ndmp_wait_for_reader(cmds
);
3248 (void) pthread_join(rdtp
, NULL
);
3251 * If this is the last DAR entry and it is a three-way
3252 * restore then we should close the connection.
3254 if ((data_addr_type
== NDMP_ADDR_TCP
) &&
3255 (dar_index
== (int)session
->ns_data
.dd_nlist_len
)) {
3256 NDMP_LOG(LOG_DEBUG
, "stop remote reader.");
3257 ndmp_stop_remote_reader(session
);
3260 /* exit as if there was an internal error */
3261 if (session
->ns_eof
)
3264 /* Plug-in module */
3265 if (ndmp_pl
!= NULL
&&
3266 ndmp_pl
->np_post_restore
!= NULL
&&
3267 ndmp_pl
->np_post_restore(ndmp_pl
, &nctx
, err
) == -1) {
3268 NDMP_LOG(LOG_DEBUG
, "Post-restore plug-in: %m");
3275 free_dar_structs_v3(session
, jname
);
3281 * ndmpd_dar_locate_windwos_v3
3283 * Locating the right window in which the requested file is backed up.
3284 * We should go through windows to find the exact location, for the
3285 * file can be located in for example 10th window after the current window.
3288 * session (input) - pointer to the session
3289 * params (input) - pointer to the parameters structure
3290 * fh_info (input) - index from the beginning of the backup stream
3291 * len (input) - Length of the mover window
3298 ndmpd_dar_locate_window_v3(ndmpd_session_t
*session
,
3299 ndmpd_module_params_t
*params
, u_longlong_t fh_info
, u_longlong_t len
)
3305 ret
= (*params
->mp_seek_func
)(session
, fh_info
, len
);
3307 NDMP_LOG(LOG_DEBUG
, "ret %d", ret
);
3308 if (ret
== 0) /* Seek was done successfully */
3311 NDMP_LOG(LOG_DEBUG
, "Seek error");
3316 * DMA moved to a new window.
3317 * If we are reading the remainig of the file from
3318 * new window, seek is handled by ndmpd_local_read_v3.
3319 * Here we should continue the seek inside the new
3328 * ndmpd_rs_dar_tar_v3
3330 * Main DAR function. It calls the constructor, then for each entry it
3331 * calls the locate_window_v3 to find the exact position of the file. Then
3332 * it restores the file.
3333 * When all restore requests are done it calls the deconstructor to clean
3337 * session (input) - pointer to the session
3338 * params (input) - pointer to the parameters structure
3339 * nlp (input) - pointer to the nlp structure
3346 ndmpd_rs_dar_tar_v3(ndmpd_session_t
*session
, ndmpd_module_params_t
*params
,
3347 ndmp_lbr_params_t
*nlp
)
3349 mem_ndmp_name_v3_t
*ep
;
3352 int n
= session
->ns_data
.dd_nlist_len
;
3356 jname
= ndmpd_dar_tar_init_v3(session
, nlp
);
3362 * We set the length = sizeof (tlm_tar_hdr_t)
3363 * This is important for three-way DAR restore, for we should
3364 * read the header first (If we ask for more data then we have
3365 * to read and discard the remaining data in the socket)
3367 len
= tlm_tarhdr_size();
3369 for (i
= 0; i
< n
; ++i
) {
3370 ep
= (mem_ndmp_name_v3_t
*)MOD_GETNAME(params
, i
);
3372 NDMP_LOG(LOG_DEBUG
, "ep NULL, i %d", i
);
3376 "restoring opath %s, dpath %s, fh_info %lld",
3377 ep
->nm3_opath
? ep
->nm3_opath
: "NULL",
3378 ep
->nm3_dpath
? ep
->nm3_dpath
: "NULL",
3382 * We should seek till finding the window in which file
3385 ret
= ndmpd_dar_locate_window_v3(session
, params
,
3386 ep
->nm3_fh_info
, len
);
3388 if (ret
< 0) /* If seek fails, restore should be aborted */
3391 * We are inside the target window.
3392 * for each restore we will use one entry as selection list
3394 if ((ret
= ndmpd_dar_tar_v3(session
, params
, nlp
, jname
, i
+1))
3397 ndmpd_audit_restore(session
->ns_connection
,
3398 ep
->nm3_opath
? ep
->nm3_opath
: "NULL",
3399 session
->ns_data
.dd_data_addr
.addr_type
,
3400 session
->ns_tape
.td_adapter_name
, result
);
3403 NDMP_LOG(LOG_DEBUG
, "End of restore list");
3405 (void) ndmpd_dar_tar_end_v3(session
, params
, nlp
, jname
);
3411 * ndmp_plugin_pre_restore
3413 * Wrapper for pre-restore callback with multiple path
3416 ndmp_plugin_pre_restore(ndmp_context_t
*ctxp
, ndmpd_module_params_t
*params
,
3419 mem_ndmp_name_v3_t
*ep
;
3423 for (i
= 0; i
< ncount
; i
++) {
3424 if (!(ep
= (mem_ndmp_name_v3_t
*)MOD_GETNAME(params
, i
)))
3426 if ((err
= ndmp_pl
->np_pre_restore(ndmp_pl
, ctxp
,
3427 ep
->nm3_opath
, ep
->nm3_dpath
)) != 0)
3437 * Get resolved path name which does not involve ".", ".." or extra
3438 * "/" or symbolic links.
3442 * /backup/path/ -> /backup/path
3443 * /backup/path/. -> /backup/path
3444 * /backup/path/../path/ -> /backup/path
3445 * /link-to-backup-path -> /backup/path
3448 * Pointer to the new path (allocated)
3449 * NULL if the path doesnt exist
3452 get_absolute_path(const char *bkpath
)
3457 if (!(pbuf
= ndmp_malloc(TLM_MAX_PATH_NAME
)))
3460 if ((rv
= realpath(bkpath
, pbuf
)) == NULL
) {
3461 NDMP_LOG(LOG_DEBUG
, "Invalid path [%s] err=%d",
3468 * Expands the format string and logs the resulting message to the
3472 ndmp_log_dma(ndmp_context_t
*nctx
, ndmp_log_dma_type_t lt
, const char *fmt
, ...)
3476 ndmpd_module_params_t
*params
;
3479 (params
= (ndmpd_module_params_t
*)nctx
->nc_params
) == NULL
)
3483 (void) vsnprintf(buf
, sizeof (buf
), fmt
, ap
);
3486 MOD_LOGV3(params
, (ndmp_log_type
)lt
, "%s", buf
);
3491 * ndmpd_rs_sar_tar_v3
3493 * Main non-DAR restore function. It will try to restore all the entries
3494 * that have been backed up.
3497 * session (input) - pointer to the session
3498 * params (input) - pointer to the parameters structure
3499 * nlp (input) - pointer to the nlp structure
3506 ndmpd_rs_sar_tar_v3(ndmpd_session_t
*session
, ndmpd_module_params_t
*params
,
3507 ndmp_lbr_params_t
*nlp
)
3509 char jname
[TLM_MAX_BACKUP_JOB_NAME
];
3514 tlm_commands_t
*cmds
;
3515 struct rs_name_maker rn
;
3516 ndmp_tar_reader_arg_t arg
;
3519 ndmp_context_t nctx
;
3522 (void) ndmp_new_job_name(jname
);
3523 if (restore_alloc_structs_v3(session
, jname
) < 0)
3526 sels
= setupsels(session
, params
, nlp
, 0);
3528 free_structs_v3(session
, jname
);
3532 flags
= RSFLG_OVR_ALWAYS
;
3534 rn
.rn_fp
= mknewname
;
3536 nlp
->nlp_jstat
->js_start_ltime
= time(NULL
);
3537 nlp
->nlp_jstat
->js_start_time
= nlp
->nlp_jstat
->js_start_ltime
;
3539 if (!session
->ns_data
.dd_abort
&& !session
->ns_data
.dd_abort
) {
3540 cmds
= &nlp
->nlp_cmds
;
3541 cmds
->tcs_reader
= cmds
->tcs_writer
= TLM_RESTORE_RUN
;
3542 cmds
->tcs_command
->tc_reader
= TLM_RESTORE_RUN
;
3543 cmds
->tcs_command
->tc_writer
= TLM_RESTORE_RUN
;
3545 NDMP_LOG(LOG_DEBUG
, "Restoring to \"%s\" started.",
3546 (nlp
->nlp_restore_path
) ? nlp
->nlp_restore_path
: "NULL");
3548 arg
.tr_session
= session
;
3549 arg
.tr_mod_params
= params
;
3551 err
= pthread_create(&rdtp
, NULL
, (funct_t
)ndmp_tar_reader
,
3554 tlm_cmd_wait(cmds
->tcs_command
, TLM_TAR_READER
);
3556 NDMP_LOG(LOG_DEBUG
, "Launch ndmp_tar_reader: %m");
3557 free_structs_v3(session
, jname
);
3561 if (!ndmp_check_utf8magic(cmds
->tcs_command
)) {
3562 NDMP_LOG(LOG_DEBUG
, "UTF8Magic not found!");
3564 NDMP_LOG(LOG_DEBUG
, "UTF8Magic found");
3567 /* Plug-in module */
3568 if (ndmp_pl
!= NULL
&&
3569 ndmp_pl
->np_pre_restore
!= NULL
) {
3570 (void) memset(&nctx
, 0, sizeof (ndmp_context_t
));
3571 nctx
.nc_cmds
= cmds
;
3572 nctx
.nc_params
= params
;
3573 nctx
.nc_ddata
= (void *) session
;
3574 if ((err
= ndmp_plugin_pre_restore(&nctx
, params
,
3577 NDMP_LOG(LOG_ERR
, "Pre-restore plug-in: %m");
3578 ndmp_stop_local_reader(session
, cmds
);
3579 ndmp_wait_for_reader(cmds
);
3580 (void) pthread_join(rdtp
, NULL
);
3581 ndmp_stop_remote_reader(session
);
3586 cmds
->tcs_command
->tc_ref
++;
3587 cmds
->tcs_writer_count
++;
3589 if (tm_tar_ops
.tm_getdir
!= NULL
) {
3592 err
= (tm_tar_ops
.tm_getdir
)(cmds
, cmds
->tcs_command
,
3593 nlp
->nlp_jstat
, &rn
, 1, 1, sels
, &excl
, flags
, 0,
3594 nlp
->nlp_backup_path
, session
->hardlink_q
);
3596 * If the fatal error from tm_getdir looks like an
3597 * errno code, we send the error description to DMA.
3599 if (err
> 0 && strerror_r(err
, errbuf
,
3600 sizeof (errbuf
)) == 0) {
3601 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
3602 "Fatal error during the restore: %s\n",
3607 cmds
->tcs_writer_count
--;
3608 cmds
->tcs_command
->tc_ref
--;
3609 nlp
->nlp_jstat
->js_stop_time
= time(NULL
);
3611 /* Send the list of un-recovered files/dirs to the client. */
3612 (void) send_unrecovered_list_v3(params
, nlp
);
3614 ndmp_stop_local_reader(session
, cmds
);
3615 ndmp_wait_for_reader(cmds
);
3616 (void) pthread_join(rdtp
, NULL
);
3618 ndmp_stop_remote_reader(session
);
3620 /* exit as if there was an internal error */
3621 if (session
->ns_eof
)
3627 (void) send_unrecovered_list_v3(params
, nlp
); /* nothing restored. */
3628 if (session
->ns_data
.dd_abort
) {
3629 NDMP_LOG(LOG_DEBUG
, "Restoring to \"%s\" aborted.",
3630 (nlp
->nlp_restore_path
) ? nlp
->nlp_restore_path
: "NULL");
3632 ndmpd_audit_restore(session
->ns_connection
,
3633 nlp
->nlp_restore_path
,
3634 session
->ns_data
.dd_data_addr
.addr_type
,
3635 session
->ns_tape
.td_adapter_name
, result
);
3638 NDMP_LOG(LOG_DEBUG
, "Restoring to \"%s\" finished. (%d)",
3639 (nlp
->nlp_restore_path
) ? nlp
->nlp_restore_path
: "NULL",
3641 ndmpd_audit_restore(session
->ns_connection
,
3642 nlp
->nlp_restore_path
,
3643 session
->ns_data
.dd_data_addr
.addr_type
,
3644 session
->ns_tape
.td_adapter_name
, result
);
3647 /* Plug-in module */
3648 if (ndmp_pl
!= NULL
&&
3649 ndmp_pl
->np_post_restore
!= NULL
&&
3650 ndmp_pl
->np_post_restore(ndmp_pl
, &nctx
, err
) == -1) {
3651 NDMP_LOG(LOG_DEBUG
, "Post-restore plug-in: %m");
3657 free_structs_v3(session
, jname
);
3664 * ndmp_backup_get_params_v3
3666 * Get the backup parameters from the NDMP env variables
3667 * and log them in the system log and as normal messages
3671 * session (input) - pointer to the session
3672 * params (input) - pointer to the parameters structure
3675 * NDMP_NO_ERR: on success
3676 * != NDMP_NO_ERR: otherwise
3679 ndmp_backup_get_params_v3(ndmpd_session_t
*session
,
3680 ndmpd_module_params_t
*params
)
3682 ndmp_lbr_params_t
*nlp
;
3684 if (!session
|| !params
)
3685 return (NDMP_ILLEGAL_ARGS_ERR
);
3687 nlp
= ndmp_get_nlp(session
);
3689 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
3690 "Internal error: NULL nlp.\n");
3691 return (NDMP_ILLEGAL_ARGS_ERR
);
3693 if (!(nlp
->nlp_backup_path
= get_backup_path_v3(params
)) ||
3694 !is_valid_backup_dir_v3(params
, nlp
->nlp_backup_path
))
3695 return (NDMP_ILLEGAL_ARGS_ERR
);
3698 nlp
->nlp_backup_path
= get_absolute_path(nlp
->nlp_backup_path
);
3699 if (!nlp
->nlp_backup_path
)
3700 return (NDMP_ILLEGAL_ARGS_ERR
);
3702 if (fs_is_chkpntvol(nlp
->nlp_backup_path
) ||
3703 fs_is_rdonly(nlp
->nlp_backup_path
) ||
3704 !fs_is_chkpnt_enabled(nlp
->nlp_backup_path
))
3705 NLP_SET(nlp
, NLPF_CHKPNTED_PATH
);
3707 NLP_UNSET(nlp
, NLPF_CHKPNTED_PATH
);
3709 /* Should the st_ctime be ignored when backing up? */
3710 if (ndmp_ignore_ctime
) {
3711 NDMP_LOG(LOG_DEBUG
, "ignoring st_ctime");
3712 NLP_SET(nlp
, NLPF_IGNCTIME
);
3714 NLP_UNSET(nlp
, NLPF_IGNCTIME
);
3717 if (ndmp_include_lmtime
== TRUE
) {
3718 NDMP_LOG(LOG_DEBUG
, "including st_lmtime");
3719 NLP_SET(nlp
, NLPF_INCLMTIME
);
3721 NLP_UNSET(nlp
, NLPF_INCLMTIME
);
3724 NDMP_LOG(LOG_DEBUG
, "flags %x", nlp
->nlp_flags
);
3726 get_hist_env_v3(params
, nlp
);
3727 get_exc_env_v3(params
, nlp
);
3728 get_inc_env_v3(params
, nlp
);
3729 get_direct_env_v3(params
, nlp
);
3730 return (get_backup_level_v3(params
, nlp
));
3735 * ndmpd_tar_backup_starter_v3
3737 * Create the checkpoint for the backup and do the backup,
3738 * then remove the backup checkpoint if we created it.
3739 * Save the backup time information based on the backup
3740 * type and stop the data server.
3743 * params (input) - pointer to the parameters structure
3750 ndmpd_tar_backup_starter_v3(void *arg
)
3752 ndmpd_module_params_t
*params
= arg
;
3754 ndmpd_session_t
*session
;
3755 ndmp_lbr_params_t
*nlp
;
3756 char jname
[TLM_MAX_BACKUP_JOB_NAME
];
3757 ndmp_bkup_size_arg_t sarg
;
3760 session
= (ndmpd_session_t
*)(params
->mp_daemon_cookie
);
3761 *(params
->mp_module_cookie
) = nlp
= ndmp_get_nlp(session
);
3762 ndmp_session_ref(session
);
3763 (void) ndmp_new_job_name(jname
);
3766 if (!NLP_ISCHKPNTED(nlp
) &&
3767 ndmp_create_snapshot(nlp
->nlp_backup_path
, jname
) < 0) {
3768 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
3769 "Creating checkpoint on \"%s\".\n",
3770 nlp
->nlp_backup_path
);
3774 NDMP_LOG(LOG_DEBUG
, "err %d, chkpnted %c",
3775 err
, NDMP_YORN(NLP_ISCHKPNTED(nlp
)));
3778 sarg
.bs_session
= session
;
3779 sarg
.bs_jname
= jname
;
3780 sarg
.bs_path
= nlp
->nlp_backup_path
;
3782 /* Get an estimate of the data size */
3783 if (pthread_create(&tid
, NULL
, (funct_t
)get_backup_size
,
3784 (void *)&sarg
) == 0)
3785 (void) pthread_detach(tid
);
3787 err
= ndmp_get_cur_bk_time(nlp
, &nlp
->nlp_cdate
, jname
);
3789 NDMP_LOG(LOG_DEBUG
, "err %d", err
);
3791 log_bk_params_v3(session
, params
, nlp
);
3792 err
= tar_backup_v3(session
, params
, nlp
, jname
);
3796 if (!NLP_ISCHKPNTED(nlp
))
3797 (void) ndmp_remove_snapshot(nlp
->nlp_backup_path
, jname
);
3799 NDMP_LOG(LOG_DEBUG
, "err %d, update %c",
3800 err
, NDMP_YORN(NLP_SHOULD_UPDATE(nlp
)));
3803 save_backup_date_v3(params
, nlp
);
3805 MOD_DONE(params
, err
);
3807 /* nlp_params is allocated in start_backup_v3() */
3808 NDMP_FREE(nlp
->nlp_params
);
3809 NDMP_FREE(nlp
->nlp_backup_path
);
3812 ndmp_session_unref(session
);
3819 * ndmpd_tar_backup_abort_v3
3821 * Abort the backup operation and stop the reader thread.
3824 * module_cookie (input) - pointer to the nlp structure
3830 ndmpd_tar_backup_abort_v3(void *module_cookie
)
3832 ndmp_lbr_params_t
*nlp
;
3834 nlp
= (ndmp_lbr_params_t
*)module_cookie
;
3835 if (nlp
&& nlp
->nlp_session
) {
3836 if (nlp
->nlp_session
->ns_data
.dd_data_addr
.addr_type
==
3838 nlp
->nlp_session
->ns_data
.dd_sock
!= -1) {
3839 (void) close(nlp
->nlp_session
->ns_data
.dd_sock
);
3840 nlp
->nlp_session
->ns_data
.dd_sock
= -1;
3842 ndmp_stop_reader_thread(nlp
->nlp_session
);
3850 * ndmp_restore_get_params_v3
3852 * Get the parameters specified for recovery such as restore path, type
3853 * of restore (DAR, non-DAR) etc
3856 * session (input) - pointer to the session
3857 * params (input) - pointer to the parameters structure
3860 * NDMP_NO_ERR: on success
3861 * != NDMP_NO_ERR: otherwise
3864 ndmp_restore_get_params_v3(ndmpd_session_t
*session
,
3865 ndmpd_module_params_t
*params
)
3868 ndmp_lbr_params_t
*nlp
;
3870 if (!(nlp
= ndmp_get_nlp(session
))) {
3871 NDMP_LOG(LOG_DEBUG
, "nlp is NULL");
3872 rv
= NDMP_ILLEGAL_ARGS_ERR
;
3873 } else if (!(nlp
->nlp_backup_path
= get_backup_path_v3(params
)))
3874 rv
= NDMP_ILLEGAL_ARGS_ERR
;
3875 else if ((nlp
->nlp_nfiles
= session
->ns_data
.dd_nlist_len
) == 0) {
3876 NDMP_LOG(LOG_DEBUG
, "nfiles: %d", nlp
->nlp_nfiles
);
3877 rv
= NDMP_ILLEGAL_ARGS_ERR
;
3878 } else if (get_rs_path_v3(params
, nlp
) != NDMP_NO_ERR
) {
3879 rv
= NDMP_ILLEGAL_ARGS_ERR
;
3880 } else if ((rv
= fix_nlist_v3(session
, params
, nlp
)) != NDMP_NO_ERR
) {
3881 NDMP_LOG(LOG_DEBUG
, "fix_nlist_v3: %d", rv
);
3884 get_direct_env_v3(params
, nlp
);
3885 if (NLP_ISSET(nlp
, NLPF_DIRECT
)) {
3886 if (NLP_ISSET(nlp
, NLPF_RECURSIVE
)) {
3887 /* Currently we dont support DAR on directory */
3889 "Can't have RECURSIVE and DIRECT together");
3890 rv
= NDMP_ILLEGAL_ARGS_ERR
;
3895 * DAR can be done if all the fh_info's are valid.
3897 if (allvalidfh(session
, params
)) {
3898 ndmp_sort_nlist_v3(session
);
3900 MOD_LOGV3(params
, NDMP_LOG_WARNING
,
3901 "Cannot do direct access recovery. "
3902 "Some 'fh_info'es are not valid.\n");
3903 NLP_UNSET(nlp
, NLPF_DIRECT
);
3907 log_rs_params_v3(session
, params
, nlp
);
3915 * ndmpd_tar_restore_starter_v3
3917 * The main restore starter function. It will start a DAR or
3918 * non-DAR recovery based on the parameters. (V3 and V4 only)
3921 * params (input) - pointer to the parameters structure
3924 * NDMP_NO_ERR: on success
3925 * != NDMP_NO_ERR: otherwise
3928 ndmpd_tar_restore_starter_v3(void *arg
)
3930 ndmpd_module_params_t
*params
= arg
;
3932 ndmpd_session_t
*session
;
3933 ndmp_lbr_params_t
*nlp
;
3936 session
= (ndmpd_session_t
*)(params
->mp_daemon_cookie
);
3937 *(params
->mp_module_cookie
) = nlp
= ndmp_get_nlp(session
);
3938 ndmp_session_ref(session
);
3940 if (NLP_ISSET(nlp
, NLPF_DIRECT
))
3941 err
= ndmpd_rs_dar_tar_v3(session
, params
, nlp
);
3943 err
= ndmpd_rs_sar_tar_v3(session
, params
, nlp
);
3945 MOD_DONE(params
, err
);
3948 /* nlp_params is allocated in start_recover() */
3949 NDMP_FREE(nlp
->nlp_params
);
3950 ndmp_session_unref(session
);
3956 * ndmp_tar_restore_abort_v3
3958 * Restore abort function (V3 and V4 only)
3961 * module_cookie (input) - pointer to nlp
3967 ndmpd_tar_restore_abort_v3(void *module_cookie
)
3969 ndmp_lbr_params_t
*nlp
;
3971 nlp
= (ndmp_lbr_params_t
*)module_cookie
;
3972 if (nlp
!= NULL
&& nlp
->nlp_session
!= NULL
) {
3973 if (nlp
->nlp_session
->ns_data
.dd_mover
.addr_type
==
3975 nlp
->nlp_session
->ns_data
.dd_sock
!= -1) {
3976 (void) close(nlp
->nlp_session
->ns_data
.dd_sock
);
3977 nlp
->nlp_session
->ns_data
.dd_sock
= -1;
3979 ndmp_stop_writer_thread(nlp
->nlp_session
);