20 *
21 * - Neither the name of The Storage Networking Industry Association (SNIA)
22 * nor the names of its contributors may be used to endorse or promote
23 * products derived from this software without specific prior written
24 * permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40 /* Copyright 2014 Nexenta Systems, Inc. All rights reserved. */
41
42 #include <sys/stat.h>
43 #include <sys/types.h>
44 #include <sys/time.h>
45 #include <ctype.h>
46 #include <sys/socket.h>
47 #include <sys/acl.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #include <errno.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <time.h>
54 #include <cstack.h>
55 #include "ndmp.h"
56 #include "ndmpd.h"
57 #include <bitmap.h>
58 #include <traverse.h>
59
60
61 /*
62 * Maximum length of the string-representation of u_longlong_t type.
63 */
64 #define QUAD_DECIMAL_LEN 20
97 } bk_param_v3_t;
98
99
100 /*
101 * Multiple destination restore mode
102 */
103 #define MULTIPLE_DEST_DIRS 128
104
105 int multiple_dest_restore = 0;
106
107 /*
108 * Plug-in module ops
109 */
110 ndmp_plugin_t *ndmp_pl;
111
112 /*
113 * NDMP exclusion list
114 */
115 char **ndmp_excl_list = NULL;
116
117 /*
118 * split_env
119 *
120 * Splits the string into list of sections separated by the
121 * sep character.
122 *
123 * Parameters:
124 * envp (input) - the environment variable that should be broken
125 * sep (input) - the separator character
126 *
127 * Returns:
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
130 * caller.
131 * NULL: on error
132 */
133 static char **
134 split_env(char *envp, char sep)
135 {
136 char *bp, *cp, *ep;
219 return (cpp);
220 }
221
222
223 /*
224 * prl
225 *
226 * Print the array of character pointers passed to it. This is
227 * used for debugging purpose.
228 *
229 * Parameters:
230 * lpp (input) - pointer to the array of strings
231 *
232 * Returns:
233 * void
234 */
235 static void
236 prl(char **lpp)
237 {
238 if (!lpp) {
239 NDMP_LOG(LOG_DEBUG, "empty");
240 return;
241 }
242
243 while (*lpp)
244 NDMP_LOG(LOG_DEBUG, "\"%s\"", *lpp++);
245 }
246
247
248 /*
249 * inlist
250 *
251 * Looks through all the strings of the array to see if the ent
252 * matches any of the strings. The strings are patterns.
253 *
254 * Parameters:
255 * lpp (input) - pointer to the array of strings
256 * ent (input) - the entry to be matched
257 *
258 * Returns:
259 * TRUE: if there is a match
260 * FALSE: invalid argument or no match
261 */
262 static boolean_t
263 inlist(char **lpp, char *ent)
264 {
265 if (!lpp || !ent) {
266 NDMP_LOG(LOG_DEBUG, "empty list");
267 return (FALSE);
268 }
269
270 while (*lpp) {
271 /*
272 * Fixing the sync_sort NDMPV3 problem, it sends the inclusion
273 * like "./" which we should skip the "./"
274 */
275 char *pattern = *lpp;
276 if (strncmp(pattern, "./", 2) == 0)
277 pattern += 2;
278
279 NDMP_LOG(LOG_DEBUG, "pattern %s, ent %s", pattern, ent);
280
281 if (match(pattern, ent)) {
282 NDMP_LOG(LOG_DEBUG, "match(%s,%s)", pattern, ent);
283 return (TRUE);
284 }
285 lpp++;
286 }
287
288 NDMP_LOG(LOG_DEBUG, "no match");
289 return (FALSE);
290 }
291
292
293 /*
294 * inexl
295 *
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.
299 *
300 * Parameters:
301 * lpp (input) - pointer to the array of strings
302 * ent (input) - the entry to be matched
303 *
304 * Returns:
305 * TRUE: if there is a match
306 * FALSE: invalid argument or no match
307 *
308 */
394 lpp += start; /* Next selection entry will be in lpp[start] */
395 } else {
396 start = 0;
397 end = n;
398 }
399
400 for (i = start; i < end; i++) {
401 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
402 if (!ep)
403 continue;
404
405 /*
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/"
409 */
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';
414 NDMP_LOG(LOG_DEBUG,
415 "nm3_opath changed from %s. to %s",
416 ep->nm3_opath, ep->nm3_opath);
417 }
418 *lpp++ = ep->nm3_opath;
419 }
420
421 /* list termination indicator is a null pointer */
422 *lpp = NULL;
423
424 return (save);
425 }
426
427
428 /*
429 * mkrsp
430 *
431 * Make Restore Path.
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
469 if (!COMPBNDRY(pp) || !COMPBNDRY(sp))
470 /* An exception to the boundary rule */
471 /* (!(!*sp && (*(pp - 1)) == '/')) */
472 if (*sp || (*(pp - 1)) != '/')
473 return (NULL);
474
475 /* if pp shorter than sp, it should not be restored */
476 if (!*pp && *sp) {
477 sp += strspn(sp, "/");
478 if (strlen(sp) > 0)
479 return (NULL);
480 }
481 }
482
483 if (np)
484 np += strspn(np, "/");
485 else
486 np = "";
487
488 if (!tlm_cat_path(bp, np, pp)) {
489 NDMP_LOG(LOG_ERR, "Restore path too long %s/%s.", np, pp);
490 return (NULL);
491 }
492
493 return (bp);
494 }
495
496
497 /*
498 * mknewname
499 *
500 * This is used as callback for creating the restore path. This function
501 * can handle both single destination and multiple restore paths.
502 *
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
505 * in some way.
506 */
507 char *
508 mknewname(struct rs_name_maker *rnp, char *buf, int idx, char *path)
509 {
510 char *rv;
511 ndmp_lbr_params_t *nlp;
512 mem_ndmp_name_v3_t *ep;
513
514 rv = NULL;
515 if (!buf) {
516 NDMP_LOG(LOG_DEBUG, "buf is NULL");
517 } else if (!path) {
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");
523 } else
524 if (!ndmp_full_restore_path) {
525 if (idx < 0 || idx >= (int)nlp->nlp_nfiles) {
526 NDMP_LOG(LOG_DEBUG,
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))) {
531 NDMP_LOG(LOG_DEBUG,
532 "nlist entry %d is NULL", idx);
533 } else {
534 rv = mkrsp(buf, path, ep->nm3_opath,
535 ep->nm3_dpath);
536
537 NDMP_LOG(LOG_DEBUG,
538 "idx %d org \"%s\" dst \"%s\"",
539 idx, ep->nm3_opath, ep->nm3_dpath);
540 if (rv) {
541 NDMP_LOG(LOG_DEBUG,
542 "path \"%s\": \"%s\"", path, rv);
543 } else {
544 NDMP_LOG(LOG_DEBUG,
545 "path \"%s\": NULL", path);
546 }
547 }
548 } else {
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);
552 rv = NULL;
553 } else {
554 rv = buf;
555 NDMP_LOG(LOG_DEBUG,
556 "path \"%s\": \"%s\"", path, rv);
557 }
558 }
559
560 return (rv);
561 }
562
563
564 /*
565 * chopslash
566 *
567 * Remove the slash from the end of the given path
568 */
569 static void
570 chopslash(char *cp)
571 {
572 int ln;
573
574 if (!cp || !*cp)
575 return;
576
604 }
605
606 return (bp);
607 }
608
609
610 /*
611 * voliswr
612 *
613 * Is the volume writable?
614 */
615 static int
616 voliswr(char *path)
617 {
618 int rv;
619
620 if (!path)
621 return (0);
622
623 rv = !fs_is_rdonly(path) && !fs_is_chkpntvol(path);
624 NDMP_LOG(LOG_DEBUG, "%d path \"%s\"", rv, path);
625 return (rv);
626
627 }
628
629
630 /*
631 * is_valid_backup_dir_v3
632 *
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.
641 *
642 * Parameters:
643 * params (input) - pointer to the parameters structure.
644 * bkpath (input) - the backup path
773 /*
774 * log_bk_params_v3
775 *
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.
779 *
780 * Parameters:
781 * session (input) - pointer to the session
782 * params (input) - pointer to the parameters structure
783 * nlp (input) - pointer to the nlp structure
784 *
785 * Returns:
786 * void
787 */
788 static void
789 log_bk_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
790 ndmp_lbr_params_t *nlp)
791 {
792 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Backing up \"%s\".\n",
793 nlp->nlp_backup_path);
794
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);
799
800 MOD_LOGV3(params, NDMP_LOG_NORMAL, "File history: %c.\n",
801 NDMP_YORN(NLP_ISSET(nlp, NLPF_FH)));
802
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);
809 else {
810 MOD_LOGV3(params, NDMP_LOG_ERROR,
811 "Internal error: backup level not defined for \"%s\".\n",
812 nlp->nlp_backup_path);
813 }
819 *
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.
823 *
824 * Parameters:
825 * params (input) - pointer to the parameters structure
826 * nlp (input) - pointer to the nlp structure
827 *
828 * Returns:
829 * void
830 */
831 static void
832 get_update_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
833 {
834 char *envp;
835
836 envp = MOD_GETENV(params, "UPDATE");
837 if (!envp) {
838 NLP_SET(nlp, NLPF_UPDATE);
839 NDMP_LOG(LOG_DEBUG,
840 "env(UPDATE) not defined, default to TRUE");
841 } else {
842 NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp);
843 if (IS_YORT(*envp))
844 NLP_SET(nlp, NLPF_UPDATE);
845 else
846 NLP_UNSET(nlp, NLPF_UPDATE);
847 }
848 }
849
850
851 /*
852 * get_hist_env_v3
853 *
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.
857 *
858 * Parameters:
859 * params (input) - pointer to the parameters structure
860 * nlp (input) - pointer to the nlp structure
861 *
862 * Returns:
863 * void
864 */
865 static void
866 get_hist_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
867 {
868 char *envp;
869
870 envp = MOD_GETENV(params, "HIST");
871 if (!envp) {
872 NDMP_LOG(LOG_DEBUG, "env(HIST) not defined");
873 NLP_UNSET(nlp, NLPF_FH);
874 } else {
875 NDMP_LOG(LOG_DEBUG, "env(HIST): \"%s\"", envp);
876 if (IS_YORT(*envp) || IS_F(*envp))
877 NLP_SET(nlp, NLPF_FH);
878 else
879 NLP_UNSET(nlp, NLPF_FH);
880
881 /* Force file format if specified */
882 if (IS_F(*envp)) {
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;
887 }
888 }
889 }
890
891
892 /*
893 * get_exc_env_v3
894 *
895 * Gets the EXCLUDE environment variable and breaks it
896 * into strings. The separator of the EXCLUDE environment
897 * variable is the ',' character.
898 *
899 * Parameters:
900 * params (input) - pointer to the parameters structure
901 * nlp (input) - pointer to the nlp structure
902 *
903 * Returns:
904 * void
905 */
906 static void
907 get_exc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
908 {
909 char *envp;
910
911 envp = MOD_GETENV(params, "EXCLUDE");
912 if (!envp) {
913 NDMP_LOG(LOG_DEBUG, "env(EXCLUDE) not defined");
914 nlp->nlp_exl = NULL;
915 } else {
916 NDMP_LOG(LOG_DEBUG, "env(EXCLUDE): \"%s\"", envp);
917 nlp->nlp_exl = split_env(envp, ',');
918 prl(nlp->nlp_exl);
919 }
920 }
921
922
923 /*
924 * get_inc_env_v3
925 *
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
929 * character.
930 *
931 * Parameters:
932 * params (input) - pointer to the parameters structure
933 * nlp (input) - pointer to the nlp structure
934 *
935 * Returns:
936 * void
937 */
938 static void
939 get_inc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
940 {
941 char *envp;
942
943 envp = MOD_GETENV(params, "FILES");
944 if (!envp) {
945 NDMP_LOG(LOG_DEBUG, "env(FILES) not defined");
946 nlp->nlp_inc = NULL;
947 } else {
948 NDMP_LOG(LOG_DEBUG, "env(FILES): \"%s\"", envp);
949 nlp->nlp_inc = split_env(envp, ' ');
950 prl(nlp->nlp_inc);
951 }
952 }
953
954
955 /*
956 * get_direct_env_v3
957 *
958 * Gets the DIRECT environment variable that shows if the fh_info should
959 * be sent to the client or not.
960 *
961 * Parameters:
962 * params (input) - pointer to the parameters structure
963 * nlp (input) - pointer to the nlp structure
964 *
965 * Returns:
966 * void
967 */
968 static void
969 get_direct_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
970 {
971 char *envp;
972
973 /*
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.
978 */
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");
984 return;
985 }
986
987 /*
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.
992 */
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);
996 } else {
997
998 envp = MOD_GETENV(params, "DIRECT");
999 if (!envp) {
1000 NDMP_LOG(LOG_DEBUG, "env(DIRECT) not defined");
1001 NLP_UNSET(nlp, NLPF_DIRECT);
1002 } else {
1003 NDMP_LOG(LOG_DEBUG, "env(DIRECT): \"%s\"", envp);
1004 if (IS_YORT(*envp)) {
1005 NLP_SET(nlp, NLPF_DIRECT);
1006 NDMP_LOG(LOG_DEBUG,
1007 "Direct Access Restore Enabled");
1008 } else {
1009 NLP_UNSET(nlp, NLPF_DIRECT);
1010 NDMP_LOG(LOG_DEBUG,
1011 "Direct Access Restore Disabled");
1012 }
1013 }
1014 }
1015
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");
1020 else
1021 MOD_LOGV3(params, NDMP_LOG_NORMAL,
1022 "Running Restore with Direct Access Restore");
1023 } else {
1024 if (params->mp_operation == NDMP_DATA_OP_BACKUP)
1025 MOD_LOGV3(params, NDMP_LOG_NORMAL,
1026 "Direct Access Restore is not supported");
1027 else
1028 MOD_LOGV3(params, NDMP_LOG_NORMAL,
1029 "Running Restore without Direct Access Restore");
1030 }
1070 return (NDMP_ILLEGAL_ARGS_ERR);
1071
1072 if (MOD_GETENV(params, "LEVEL")) {
1073 MOD_LOGV3(params, NDMP_LOG_WARNING,
1074 "Both BASE_DATE and LEVEL environment variables "
1075 "defined.\n");
1076 MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
1077 "BASE_DATE is being used for this backup.\n");
1078 }
1079
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",
1084 basedate);
1085 return (NDMP_ILLEGAL_ARGS_ERR);
1086 }
1087
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);
1092
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 "
1105 "hard-limit.\n");
1106 MOD_LOGCONTV3(params, NDMP_LOG_ERROR,
1107 "Token sequence: %u, hard-limit: %u.\n",
1108 seq, NDMP_TOKSEQ_HLIMIT);
1109 } else {
1110 rv = NDMP_NO_ERR;
1111 /*
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.
1215 *
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.
1220 *
1221 * LEVEL environment variable can hold only one character.
1222 * If its length is longer than 1, an error is returned.
1223 */
1224 envp = MOD_GETENV(params, "BASE_DATE");
1225 if (envp)
1226 return (get_date_token_v3(params, nlp, envp));
1227
1228
1229 envp = MOD_GETENV(params, "LEVEL");
1230 if (!envp) {
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;
1236 nlp->nlp_ldate = 0;
1237 nlp->nlp_clevel = 0;
1238 /*
1239 * The value of nlp_cdate will be set to the checkpoint
1240 * creation time after it is created.
1241 */
1242 return (NDMP_NO_ERR);
1243 }
1244
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);
1249 }
1250
1251 if (IS_LBR_BKTYPE(*envp))
1293 * Parameters:
1294 * params (input) - pointer to the parameters structure
1295 * nlp (input) - pointer to the nlp structure
1296 *
1297 * Returns:
1298 * void
1299 */
1300 static void
1301 save_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1302 {
1303 char val[QUAD_DECIMAL_LEN];
1304 u_longlong_t tok;
1305
1306 if (!params || !nlp)
1307 return;
1308
1309 nlp->nlp_tokseq++;
1310 tok = ((u_longlong_t)nlp->nlp_tokseq << 32) | nlp->nlp_cdate;
1311 (void) snprintf(val, sizeof (val), "%llu", tok);
1312
1313 NDMP_LOG(LOG_DEBUG, "tok: %lld %s", tok, val);
1314
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);
1325 }
1326 }
1327
1328
1329 /*
1330 * save_lbr_bk_v3
1331 *
1332 * Append the backup type and date in the DMP_NAME file for
1333 * LBR-type backup if any file is specified.
1334 *
1335 * Parameters:
1336 * params (input) - pointer to the parameters structure
1337 * nlp (input) - pointer to the nlp structure
1338 *
1339 * Returns:
1340 * void
1341 */
1342 static void
1343 save_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1344 {
1345 if (!params || !nlp)
1346 return;
1347
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);
1355 }
1356 }
1357
1358
1359 /*
1360 * save_level_v3
1361 *
1362 * Save the date and level of the current backup in the dumpdates
1363 * file.
1364 *
1365 * Parameters:
1366 * params (input) - pointer to the parameters structure
1367 * nlp (input) - pointer to the nlp structure
1368 *
1369 * Returns:
1370 * void
1371 */
1372 static void
1373 save_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1374 {
1375 if (!params || !nlp)
1376 return;
1377
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");
1383 }
1384 }
1385
1386
1387 /*
1388 * save_backup_date_v3
1389 *
1390 * A dispatcher function to call the corresponding save function
1391 * based on the backup type.
1392 *
1393 * Parameters:
1394 * params (input) - pointer to the parameters structure
1395 * nlp (input) - pointer to the nlp structure
1396 *
1397 * Returns:
1398 * void
1399 */
1410 else if (NLP_ISSET(nlp, NLPF_LEVELBK))
1411 save_level_v3(params, nlp);
1412 else {
1413 MOD_LOGV3(params, NDMP_LOG_ERROR,
1414 "Internal error: lost backup level type for \"%s\".\n",
1415 nlp->nlp_backup_path);
1416 }
1417 }
1418
1419
1420 /*
1421 * backup_alloc_structs_v3
1422 *
1423 * Create the structures for V3 backup. This includes:
1424 * Job stats
1425 * Reader writer IPC
1426 * File history callback structure
1427 *
1428 * Parameters:
1429 * session (input) - pointer to the session
1430 * jname (input) - name assigned to the current backup for
1431 * job stats strucure
1432 *
1433 * Returns:
1434 * 0: on success
1435 * -1: otherwise
1436 */
1437 static int
1438 backup_alloc_structs_v3(ndmpd_session_t *session, char *jname)
1439 {
1440 int n;
1441 long xfer_size;
1442 ndmp_lbr_params_t *nlp;
1443 tlm_commands_t *cmds;
1444
1445 nlp = ndmp_get_nlp(session);
1446 if (!nlp) {
1447 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1448 return (-1);
1449 }
1450
1451 nlp->nlp_jstat = tlm_new_job_stats(jname);
1452 if (!nlp->nlp_jstat) {
1453 NDMP_LOG(LOG_DEBUG, "Creating job stats");
1454 return (-1);
1455 }
1456
1457 cmds = &nlp->nlp_cmds;
1458 (void) memset(cmds, 0, sizeof (*cmds));
1459
1460 xfer_size = ndmp_buffer_get_size(session);
1461 if (xfer_size < 512*KILOBYTE) {
1462 /*
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.
1466 */
1467 n = 512 * KILOBYTE / xfer_size;
1468 if (n <= 0)
1469 n = 1;
1470 xfer_size *= n;
1471 NDMP_LOG(LOG_DEBUG, "Adjusted read size: %d",
1472 xfer_size);
1473 }
1474
1475 cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, xfer_size);
1476 if (!cmds->tcs_command) {
1477 tlm_un_ref_job_stats(jname);
1478 return (-1);
1479 }
1480
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);
1486 return (-1);
1487 }
1488 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
1489 nlp->nlp_restored = NULL;
1490
1491 return (0);
1492 }
1493
1494
1495 /*
1496 * restore_alloc_structs_v3
1497 *
1498 * Create the structures for V3 Restore. This includes:
1499 * Job stats
1500 * Reader writer IPC
1501 * File recovery callback structure
1502 *
1503 * Parameters:
1504 * session (input) - pointer to the session
1505 * jname (input) - name assigned to the current backup for
1506 * job stats strucure
1507 *
1508 * Returns:
1509 * 0: on success
1510 * -1: otherwise
1511 */
1512 int
1513 restore_alloc_structs_v3(ndmpd_session_t *session, char *jname)
1514 {
1515 long xfer_size;
1516 ndmp_lbr_params_t *nlp;
1517 tlm_commands_t *cmds;
1518
1519 nlp = ndmp_get_nlp(session);
1520 if (!nlp) {
1521 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1522 return (-1);
1523 }
1524
1525 /* this is used in ndmpd_path_restored_v3() */
1526 nlp->nlp_lastidx = -1;
1527
1528 nlp->nlp_jstat = tlm_new_job_stats(jname);
1529 if (!nlp->nlp_jstat) {
1530 NDMP_LOG(LOG_DEBUG, "Creating job stats");
1531 return (-1);
1532 }
1533
1534 cmds = &nlp->nlp_cmds;
1535 (void) memset(cmds, 0, sizeof (*cmds));
1536
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);
1541 return (-1);
1542 }
1543
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);
1549 return (-1);
1550 }
1551 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
1552
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);
1559 return (-1);
1560 }
1561
1562 return (0);
1563 }
1564
1565
1566 /*
1567 * free_structs_v3
1568 *
1569 * Release the resources allocated by backup_alloc_structs_v3
1570 * function.
1571 *
1572 * Parameters:
1573 * session (input) - pointer to the session
1574 * jname (input) - name assigned to the current backup for
1575 * job stats strucure
1576 *
1577 * Returns:
1578 * void
1579 */
1580 /*ARGSUSED*/
1581 static void
1582 free_structs_v3(ndmpd_session_t *session, char *jname)
1583 {
1584 ndmp_lbr_params_t *nlp;
1585 tlm_commands_t *cmds;
1586
1587 nlp = ndmp_get_nlp(session);
1588 if (!nlp) {
1589 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1590 return;
1591 }
1592 cmds = &nlp->nlp_cmds;
1593 if (!cmds) {
1594 NDMP_LOG(LOG_DEBUG, "cmds == NULL");
1595 return;
1596 }
1597
1598 if (nlp->nlp_logcallbacks) {
1599 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
1600 nlp->nlp_logcallbacks = NULL;
1601 } else
1602 NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL");
1603
1604 if (cmds->tcs_command) {
1605 if (cmds->tcs_command->tc_buffers != NULL)
1606 tlm_release_reader_writer_ipc(cmds->tcs_command);
1607 else
1608 NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL");
1609 cmds->tcs_command = NULL;
1610 } else
1611 NDMP_LOG(LOG_DEBUG, "COMMAND == NULL");
1612
1613 if (nlp->nlp_bkmap >= 0) {
1614 (void) dbm_free(nlp->nlp_bkmap);
1615 nlp->nlp_bkmap = -1;
1616 }
1617
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);
1621 } else {
1622 (void) bm_free(nlp->nlp_rsbm);
1623 nlp->nlp_rsbm = -1;
1624 }
1625 }
1626 }
1627
1628
1629 /*
1630 * backup_dirv3
1631 *
1632 * Backup a directory and update the bytes processed field of the
1633 * data server.
1634 *
1635 * Parameters:
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
1639 *
1640 * Returns:
1641 * 0: on success
1642 * != 0: otherwise
1643 */
1644 static int
1645 backup_dirv3(bk_param_v3_t *bpp, fst_node_t *pnp,
1646 fst_node_t *enp)
1647 {
1648 longlong_t apos, bpos;
1649 acl_t *aclp = NULL;
1650 char *acltp;
1651 struct stat64 st;
1652 char fullpath[TLM_MAX_PATH_NAME];
1653 char *p;
1654
1655 if (!bpp || !pnp || !enp) {
1656 NDMP_LOG(LOG_DEBUG, "Invalid argument");
1657 return (-1);
1658 }
1659
1660 NDMP_LOG(LOG_DEBUG, "d(%s)", bpp->bp_tmp);
1661
1662 if (lstat64(bpp->bp_tmp, &st) != 0)
1663 return (0);
1664
1665 if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) {
1666 NDMP_LOG(LOG_DEBUG, "acl_get error errno=%d", errno);
1667 return (-1);
1668 }
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);
1673 acl_free(aclp);
1674 free(acltp);
1675 } else {
1676 *bpp->bp_tlmacl->acl_info.attr_info = '\0';
1677 }
1678
1679 bpos = tlm_get_data_offset(bpp->bp_lcmd);
1680
1681 p = bpp->bp_tmp + strlen(bpp->bp_chkpnm);
1682 if (*p == '/')
1683 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s%s",
1684 bpp->bp_unchkpnm, p);
1685 else
1686 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s",
1701 /*
1702 * backup_filev3
1703 *
1704 * Backup a file and update the bytes processed field of the
1705 * data server.
1706 *
1707 * Parameters:
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
1711 *
1712 * Returns:
1713 * 0: on success
1714 * != 0: otherwise
1715 */
1716 static int
1717 backup_filev3(bk_param_v3_t *bpp, fst_node_t *pnp,
1718 fst_node_t *enp)
1719 {
1720 char *ent;
1721 longlong_t rv;
1722 longlong_t apos, bpos;
1723 acl_t *aclp = NULL;
1724 char *acltp;
1725 struct stat64 st;
1726 char fullpath[TLM_MAX_PATH_NAME];
1727 char *p;
1728
1729 if (!bpp || !pnp || !enp) {
1730 NDMP_LOG(LOG_DEBUG, "Invalid argument");
1731 return (-1);
1732 }
1733
1734 NDMP_LOG(LOG_DEBUG, "f(%s)", bpp->bp_tmp);
1735
1736 if (lstat64(bpp->bp_tmp, &st) != 0)
1737 return (0);
1738
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");
1742 return (-1);
1743 }
1744
1745 if (aclp &&
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);
1750 acl_free(aclp);
1751 free(acltp);
1752 } else {
1753 *bpp->bp_tlmacl->acl_info.attr_info = '\0';
1754 }
1755 }
1756
1757 bpos = tlm_get_data_offset(bpp->bp_lcmd);
1758 ent = enp->tn_path ? enp->tn_path : "";
1759
1760 p = pnp->tn_path + strlen(bpp->bp_chkpnm);
1761 if (*p == '/')
1786 * - The bpp itself.
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.
1791 *
1792 * Parameters:
1793 * bpp (input) - pointer to the backup parameters structure
1794 *
1795 * Returns:
1796 * 0: if everything's OK
1797 * != 0: otherwise
1798 */
1799 static int
1800 check_bk_args(bk_param_v3_t *bpp)
1801 {
1802 int rv;
1803
1804 if (!bpp) {
1805 rv = -1;
1806 NDMP_LOG(LOG_DEBUG, "Lost bpp");
1807 } else if (!bpp->bp_session) {
1808 rv = -1;
1809 NDMP_LOG(LOG_DEBUG, "Session is NULL");
1810 } else if (bpp->bp_session->ns_eof) {
1811 rv = -1;
1812 NDMP_LOG(LOG_INFO,
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");
1817 return (-1);
1818 } else if (bpp->bp_session->ns_data.dd_abort) {
1819 rv = -1;
1820 NDMP_LOG(LOG_INFO, "Backup aborted \"%s\"",
1821 bpp->bp_nlp->nlp_backup_path);
1822 } else
1823 rv = 0;
1824
1825 return (rv);
1826 }
1827
1828
1829 /*
1830 * shouldskip
1831 *
1832 * Determines if the current entry should be skipped or it
1833 * should be backed up.
1834 *
1835 * Parameters:
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
1841 *
1842 * Returns:
1843 * TRUE: if the entry should not be backed up
1844 * FALSE: otherwise
1845 */
1846 static boolean_t
1847 shouldskip(bk_param_v3_t *bpp, fst_node_t *pnp,
1848 fst_node_t *enp, int *errp)
1849 {
1850 char *ent;
1851 boolean_t rv;
1852 struct stat64 *estp;
1853
1854 if (!bpp || !pnp || !enp || !errp) {
1855 NDMP_LOG(LOG_DEBUG, "Invalid argument");
1856 return (TRUE);
1857 }
1858
1859 if (!enp->tn_path) {
1860 ent = "";
1861 estp = pnp->tn_st;
1862 } else {
1863 ent = enp->tn_path;
1864 estp = enp->tn_st;
1865 }
1866
1867 /*
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.
1871 */
1872 if (!dbm_getone(bpp->bp_nlp->nlp_bkmap, (u_longlong_t)estp->st_ino)) {
1873 rv = TRUE;
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)) {
1878 rv = TRUE;
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)) {
1883 rv = TRUE;
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)) {
1889 rv = TRUE;
1890 *errp = 0;
1891 NDMP_LOG(LOG_DEBUG, "!in \"%s/%s\"", pnp->tn_path, ent);
1892 } else
1893 rv = FALSE;
1894
1895 return (rv);
1896 }
1897
1898
1899 /*
1900 * ischngd
1901 *
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
1906 * up.
1907 *
1908 * By setting ndmp_force_bk_dirs global variable to a non-zero
1909 * value, directories are backed up anyways.
1910 *
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.
1914 *
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.
1918 */
1919 static boolean_t
1920 ischngd(struct stat64 *stp, time_t t, ndmp_lbr_params_t *nlp)
1921 {
1922 boolean_t rv;
1923
1924 if (!stp) {
1925 rv = FALSE;
1926 NDMP_LOG(LOG_DEBUG, "stp is NULL");
1927 } else if (!nlp) {
1928 rv = FALSE;
1929 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
1930 } else if (t == 0) {
1931 /*
1932 * if we are doing base backup then we do not need to
1933 * check the time, for we should backup everything.
1934 */
1935 rv = TRUE;
1936 NDMP_LOG(LOG_DEBUG, "Base Backup");
1937 } else if (S_ISDIR(stp->st_mode) && ndmp_force_bk_dirs) {
1938 rv = TRUE;
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))) {
1944 /*
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
1948 * TRUE.
1949 *
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.
1958 */
1959 rv = TRUE;
1960 NDMP_LOG(LOG_DEBUG, "p(%lu)", (u_longlong_t)stp->st_ino);
1961 } else if (stp->st_mtime > t) {
1962 rv = TRUE;
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)) {
1967 rv = FALSE;
1968 NDMP_LOG(LOG_DEBUG, "ign c(%lu): %lu > %lu",
1969 (uint_t)stp->st_ino, (uint_t)stp->st_ctime,
1970 (uint_t)t);
1971 } else {
1972 rv = TRUE;
1973 NDMP_LOG(LOG_DEBUG, "c(%lu): %lu > %lu",
1974 (uint_t)stp->st_ino, (uint_t)stp->st_ctime,
1975 (uint_t)t);
1976 }
1977 } else {
1978 rv = FALSE;
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);
1982 }
1983
1984 return (rv);
1985 }
1986
1987
1988 /*
1989 * iscreated
1990 *
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
1994 */
1995 /*ARGSUSED*/
1996 int iscreated(ndmp_lbr_params_t *nlp, char *name, tlm_acls_t *tacl,
1997 time_t t)
1998 {
1999 int ret;
2000 acl_t *aclp = NULL;
2001 char *acltp;
2002
2003 NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
2004 if (NLP_INCLMTIME(nlp) == FALSE)
2005 return (0);
2006
2007 ret = acl_get(name, ACL_NO_TRIVIAL, &aclp);
2008 if (ret != 0) {
2009 NDMP_LOG(LOG_DEBUG,
2010 "Error getting the acl information: err %d", ret);
2011 return (0);
2012 }
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,
2016 TLM_MAX_ACL_TXT);
2017 acl_free(aclp);
2018 free(acltp);
2019 }
2020
2021 /* Need to add support for last mtime */
2022
2023 return (0);
2024 }
2025
2026 /*
2027 * size_cb
2028 *
2029 * The callback function for calculating the size of
2075 rv = check_bk_args(bpp);
2076 if (rv != 0)
2077 return (rv);
2078
2079 stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2080 if (shouldskip(bpp, pnp, enp, &rv))
2081 return (rv);
2082
2083 if (enp->tn_path) {
2084 ent = enp->tn_path;
2085 stp = enp->tn_st;
2086 fhp = enp->tn_fh;
2087 } else {
2088 ent = "";
2089 stp = pnp->tn_st;
2090 fhp = pnp->tn_fh;
2091 }
2092
2093
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);
2096 return (FST_SKIP);
2097 }
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;
2102 } else {
2103 NDMP_LOG(LOG_DEBUG, "Unknown backup type on \"%s/%s\"",
2104 pnp->tn_path, ent);
2105 return (-1);
2106 }
2107
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,
2111 bpp->bp_tmp, stp);
2112
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);
2117 }
2118 } else {
2119 if (ischngd(stp, t, bpp->bp_nlp) ||
2120 iscreated(bpp->bp_nlp, bpp->bp_tmp, bpp->bp_tlmacl, t)) {
2121 rv = 0;
2122 (void) memcpy(&bpp->bp_tlmacl->acl_attr, stp,
2123 sizeof (struct stat64));
2160 bpp = (bk_param_v3_t *)arg;
2161 rv = check_bk_args(bpp);
2162 if (rv != 0)
2163 return (rv);
2164
2165 stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2166 if (shouldskip(bpp, pnp, enp, &rv))
2167 return (rv);
2168
2169 if (enp->tn_path) {
2170 ent = enp->tn_path;
2171 stp = enp->tn_st;
2172 fhp = enp->tn_fh;
2173 } else {
2174 ent = "";
2175 stp = pnp->tn_st;
2176 fhp = pnp->tn_fh;
2177 }
2178
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);
2181 return (FST_SKIP);
2182 }
2183 if (!NLP_ISSET(bpp->bp_nlp, NLPF_LBRBK)) {
2184 NDMP_LOG(LOG_DEBUG, "!NLPF_LBRBK");
2185 return (-1);
2186 }
2187
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,
2191 bpp->bp_tmp, stp);
2192
2193 if (SHOULD_LBRBK(bpp)) {
2194 bpp->bp_tlmacl->acl_attr = *stp;
2195 rv = backup_dirv3(bpp, pnp, enp);
2196 }
2197 } else if (SHOULD_LBRBK(bpp)) {
2198 rv = 0;
2199 bpp->bp_tlmacl->acl_attr = *stp;
2200 bpp->bp_tlmacl->acl_fil_fh = *fhp;
2201 (void) backup_filev3(bpp, pnp, enp);
2202 }
2203
2204 return (rv);
2205 }
2206
2207
2208 /*
2209 * backup_reader_v3
2210 *
2211 * The reader thread for the backup. It sets up the callback
2212 * parameters and traverses the backup hierarchy in level-order
2213 * way.
2214 *
2215 * Parameters:
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
2220 *
2221 * Returns:
2222 * 0: on success
2223 * != 0: otherwise
2224 */
2225 static int
2226 backup_reader_v3(backup_reader_arg_t *argp)
2227 {
2228 int rv;
2229 tlm_cmd_t *lcmd;
2230 tlm_acls_t tlm_acls;
2231 longlong_t bpos, n;
2232 bk_param_v3_t bp;
2233 fs_traverse_t ft;
2234 char *jname;
2235 ndmp_lbr_params_t *nlp;
2236 tlm_commands_t *cmds;
2237
2238 if (!argp)
2239 return (-1);
2240
2241 jname = argp->br_jname;
2242 nlp = argp->br_nlp;
2243 cmds = argp->br_cmds;
2244
2245 rv = 0;
2246 lcmd = cmds->tcs_command;
2247 lcmd->tc_ref++;
2248 cmds->tcs_reader_count++;
2249
2250 (void) memset(&tlm_acls, 0, sizeof (tlm_acls));
2251
2252 /* NDMP parameters */
2253 bp.bp_session = nlp->nlp_session;
2254 bp.bp_nlp = nlp;
2255
2256 /* LBR-related parameters */
2257 bp.bp_js = tlm_ref_job_stats(jname);
2258 bp.bp_cmds = cmds;
2259 bp.bp_lcmd = lcmd;
2260 bp.bp_tlmacl = &tlm_acls;
2261 bp.bp_opr = 0;
2262
2263 /* release the parent thread, after referencing the job stats */
2264 (void) pthread_barrier_wait(&argp->br_barrier);
2265
2266 bp.bp_tmp = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
2267 if (!bp.bp_tmp)
2268 return (-1);
2269
2270 /*
2271 * Make the checkpointed paths for traversing the
2272 * backup hierarchy, if we make the checkpoint.
2273 */
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);
2280 return (-1);
2281 }
2282 (void) tlm_build_snapshot_name(nlp->nlp_backup_path,
2283 bp.bp_chkpnm, nlp->nlp_jstat->js_job_name);
2284 } else {
2285 tlm_acls.acl_checkpointed = FALSE;
2286 bp.bp_chkpnm = nlp->nlp_backup_path;
2287 }
2288 bp.bp_excls = ndmpd_make_exc_list();
2289
2290 /* set traversing arguments */
2291 ft.ft_path = nlp->nlp_backup_path;
2292 ft.ft_lpath = bp.bp_chkpnm;
2293
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;
2301
2302 NDMP_LOG(LOG_DEBUG, "bp_opr %x clr_arc %c",
2303 bp.bp_opr, NDMP_YORN(tlm_acls.acl_clear_archive));
2304 } else {
2305 rv = -1;
2306 MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR,
2307 "Unknow backup type.\n");
2308 }
2309 ft.ft_arg = &bp;
2310 ft.ft_logfp = (ft_log_t)ndmp_log;
2311 ft.ft_flags = FST_VERBOSE | FST_STOP_ONERR;
2312
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;
2316
2317 if (rv == 0) {
2318 /* start traversing the hierarchy and actual backup */
2319 rv = traverse_level(&ft);
2320 if (rv == 0) {
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;
2325 nlp->nlp_session->
2326 ns_data.dd_module.dm_stats.ms_bytes_processed += n;
2327 } else {
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);
2332 }
2333 }
2334
2335 if (!NLP_ISCHKPNTED(nlp))
2336 NDMP_FREE(bp.bp_chkpnm);
2337 NDMP_FREE(bp.bp_tmp);
2338 NDMP_FREE(bp.bp_excls);
2339
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);
2344 return (rv);
2345
2346 }
2347
2348
2349 /*
2350 * tar_backup_v3
2351 *
2352 * Traverse the backup hierarchy if needed and make the bitmap.
2353 * Then launch reader and writer threads to do the actual backup.
2354 *
2355 * Parameters:
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
2360 *
2361 * Returns:
2362 * 0: on success
2363 * != 0: otherwise
2364 */
2365 static int
2366 tar_backup_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
2367 ndmp_lbr_params_t *nlp, char *jname)
2368 {
2369 tlm_commands_t *cmds;
2370 backup_reader_arg_t arg;
2371 pthread_t rdtp;
2372 char info[256];
2373 int result;
2374 ndmp_context_t nctx;
2375 int err;
2376
2377 if (ndmp_get_bk_dir_ino(nlp))
2378 return (-1);
2379
2380 result = err = 0;
2381
2382 /* exit as if there was an internal error */
2383 if (session->ns_eof)
2384 return (-1);
2385
2386 if (!session->ns_data.dd_abort) {
2387 if (backup_alloc_structs_v3(session, jname) < 0) {
2388 nlp->nlp_bkmap = -1;
2389 return (-1);
2390 }
2391
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;
2396 }
2397 free_structs_v3(session, jname);
2398 return (-1);
2399 }
2400
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;
2404
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;
2409
2410 if (ndmp_write_utf8magic(cmds->tcs_command) < 0) {
2411 free_structs_v3(session, jname);
2412 return (-1);
2413 }
2414
2415 NDMP_LOG(LOG_DEBUG,
2416 "Backing up \"%s\" started.", nlp->nlp_backup_path);
2417
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");
2430 goto backup_out;
2431 }
2432 }
2433
2434 (void) memset(&arg, 0, sizeof (backup_reader_arg_t));
2435 arg.br_jname = jname;
2436 arg.br_nlp = nlp;
2437 arg.br_cmds = cmds;
2438
2439 (void) pthread_barrier_init(&arg.br_barrier, 0, 2);
2440
2441 err = pthread_create(&rdtp, NULL, (funct_t)backup_reader_v3,
2442 (void *)&arg);
2443 if (err == 0) {
2444 (void) pthread_barrier_wait(&arg.br_barrier);
2445 (void) pthread_barrier_destroy(&arg.br_barrier);
2446 } else {
2447 (void) pthread_barrier_destroy(&arg.br_barrier);
2448 free_structs_v3(session, jname);
2449 NDMP_LOG(LOG_DEBUG, "Launch backup_reader_v3: %m");
2450 return (-1);
2451 }
2452
2453 if ((err = ndmp_tar_writer(session, params, cmds)) != 0)
2454 result = EIO;
2455
2456 nlp->nlp_jstat->js_stop_time = time(NULL);
2457
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);
2466
2467 ndmp_wait_for_reader(cmds);
2468 (void) pthread_join(rdtp, NULL);
2469
2470 /* exit as if there was an internal error */
2471 if (session->ns_eof) {
2472 result = EPIPE;
2473 err = -1;
2474 }
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);
2482 }
2483 }
2484
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);
2490 NDMP_LOG(LOG_DEBUG,
2491 "Backing up \"%s\" aborted.", nlp->nlp_backup_path);
2492 err = -1;
2493 } else {
2494
2495 backup_out:
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");
2501 return (-1);
2502 }
2503 }
2504
2505 free_structs_v3(session, jname);
2506 return (err);
2507 }
2508
2509 /*
2510 * get_backup_size
2511 *
2512 * Find the estimate of backup size. This is used to get an estimate
2513 * of the progress of backup during NDMP backup.
2514 */
2515 void
2516 get_backup_size(ndmp_bkup_size_arg_t *sarg)
2517 {
2518 fs_traverse_t ft;
2519 u_longlong_t bk_size;
2520 char spath[PATH_MAX];
2521 int rv;
2522
2523 bk_size = 0;
2524 if (fs_is_chkpntvol(sarg->bs_path)) {
2525 ft.ft_path = sarg->bs_path;
2526 } else {
2527 (void) tlm_build_snapshot_name(sarg->bs_path,
2528 spath, sarg->bs_jname);
2529 ft.ft_path = spath;
2530 }
2531
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;
2537
2538 if ((rv = traverse_level(&ft)) != 0) {
2539 NDMP_LOG(LOG_DEBUG, "bksize err=%d", rv);
2540 bk_size = 0;
2541 } else {
2542 NDMP_LOG(LOG_DEBUG, "bksize %lld, %lldKB, %lldMB\n",
2543 bk_size, bk_size / 1024, bk_size /(1024 * 1024));
2544 }
2545 sarg->bs_session->ns_data.dd_data_size = bk_size;
2546 }
2547
2548 /*
2549 * get_rs_path_v3
2550 *
2551 * Find the restore path
2552 */
2553 ndmp_error
2554 get_rs_path_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
2555 {
2556 char *dp;
2557 ndmp_error rv;
2558 mem_ndmp_name_v3_t *ep;
2559 int i, nm_cnt;
2560 char *nm_dpath_list[MULTIPLE_DEST_DIRS];
2561 static char mdest_buf[256];
2562
2563 *mdest_buf = 0;
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);
2567 if (!ep) {
2568 NDMP_LOG(LOG_DEBUG, "Can't get Nlist[%d]", i);
2569 return (NDMP_ILLEGAL_ARGS_ERR);
2570 }
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;
2574 }
2575
2576 multiple_dest_restore = (nm_cnt > 1);
2577 nlp->nlp_restore_path = mdest_buf;
2578
2579 for (i = 1; i < nm_cnt + 1; i++) {
2580 if (ISDEFINED(nm_dpath_list[i]))
2581 dp = nm_dpath_list[i];
2582 else
2583 /* the default destination path is backup directory */
2584 dp = nlp->nlp_backup_path;
2585
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);
2596 } else {
2597 rv = NDMP_NO_ERR;
2598 (void) strlcat(nlp->nlp_restore_path, dp,
2599 sizeof (mdest_buf));
2600 NDMP_LOG(LOG_DEBUG, "rspath: \"%s\"", dp);
2601 }
2602
2603 /*
2604 * Exit if there is an error or it is not a multiple
2605 * destination restore mode
2606 */
2607 if (rv != NDMP_NO_ERR || !multiple_dest_restore)
2608 break;
2609
2610 if (i < nm_cnt)
2611 (void) strlcat(nlp->nlp_restore_path, ", ",
2612 sizeof (mdest_buf));
2613 }
2614
2615 return (rv);
2616 }
2617
2618
2619 /*
2620 * fix_nlist_v3
2750 bp = joinpath(buf, nlp->nlp_backup_path, ep->nm3_opath);
2751 if (!bp) {
2752 /*
2753 * Note: The same problem of above with long path.
2754 */
2755 MOD_LOGV3(params, NDMP_LOG_ERROR,
2756 "Path too long(%s/%s)",
2757 nlp->nlp_backup_path, ep->nm3_opath);
2758 continue;
2759 }
2760 cp = strdup(bp);
2761 if (!cp) {
2762 MOD_LOGV3(params, NDMP_LOG_ERROR,
2763 "Insufficient memory.\n");
2764 rv = NDMP_NO_MEM_ERR;
2765 break;
2766 }
2767 NDMP_FREE(ep->nm3_opath);
2768 ep->nm3_opath = cp;
2769
2770 NDMP_LOG(LOG_DEBUG, "orig[%d]: \"%s\"", i, ep->nm3_opath);
2771 if (ep->nm3_dpath) {
2772 NDMP_LOG(LOG_DEBUG,
2773 "dest[%d]: \"%s\"", i, ep->nm3_dpath);
2774 } else {
2775 NDMP_LOG(LOG_DEBUG, "dest[%d]: \"%s\"", i, "NULL");
2776 }
2777 }
2778
2779 free(buf);
2780
2781 return (rv);
2782 }
2783
2784
2785 /*
2786 * allvalidfh
2787 *
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).
2791 */
2792 static boolean_t
2793 allvalidfh(ndmpd_session_t *session, ndmpd_module_params_t *params)
2794 {
2795 int i, n;
2850
2851 if (NLP_ISSET(nlp, NLPF_DIRECT))
2852 MOD_LOGV3(params, NDMP_LOG_NORMAL,
2853 "Direct Access Restore.\n");
2854 }
2855
2856
2857 /*
2858 * send_unrecovered_list_v3
2859 *
2860 * Create the list of files that were in restore list but
2861 * not recovered due to some errors.
2862 */
2863 int
2864 send_unrecovered_list_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
2865 {
2866 int i, rv;
2867 int err;
2868
2869 if (!params) {
2870 NDMP_LOG(LOG_DEBUG, "params == NULL");
2871 return (-1);
2872 }
2873 if (!nlp) {
2874 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2875 return (-1);
2876 }
2877
2878 if (nlp->nlp_lastidx != -1) {
2879 if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)nlp->nlp_lastidx))
2880 err = ENOENT;
2881 else
2882 err = 0;
2883 (void) ndmp_send_recovery_stat_v3(params, nlp,
2884 nlp->nlp_lastidx, err);
2885 nlp->nlp_lastidx = -1;
2886 }
2887
2888 rv = 0;
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);
2892 if (rv < 0)
2893 break;
2894 }
2895 }
2896
2897 return (rv);
2898 }
2899
2900
2901
2902 /*
2903 * restore_dar_alloc_structs_v3
2904 *
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.
2908 *
2909 * Parameters:
2910 * session (input) - pointer to the session
2911 * jname (input) - Job name
2912 *
2913 * Returns:
2914 * 0: on success
2915 * -1: on error
2916 */
2917 int
2918 restore_dar_alloc_structs_v3(ndmpd_session_t *session, char *jname)
2919 {
2920 long xfer_size;
2921 ndmp_lbr_params_t *nlp;
2922 tlm_commands_t *cmds;
2923
2924 nlp = ndmp_get_nlp(session);
2925 if (!nlp) {
2926 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2927 return (-1);
2928 }
2929
2930 cmds = &nlp->nlp_cmds;
2931 (void) memset(cmds, 0, sizeof (*cmds));
2932
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);
2937 return (-1);
2938 }
2939
2940 return (0);
2941 }
2942
2943
2944 /*
2945 * free_dar_structs_v3
2946 *
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.
2949 *
2950 * Parameters:
2951 * session (input) - pointer to the session
2952 * jname (input) - job name
2953 *
2954 * Returns:
2955 * NONE
2956 */
2957 /*ARGSUSED*/
2958 static void
2959 free_dar_structs_v3(ndmpd_session_t *session, char *jname)
2960 {
2961 ndmp_lbr_params_t *nlp;
2962 tlm_commands_t *cmds;
2963
2964 nlp = ndmp_get_nlp(session);
2965 if (!nlp) {
2966 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2967 return;
2968 }
2969 cmds = &nlp->nlp_cmds;
2970 if (!cmds) {
2971 NDMP_LOG(LOG_DEBUG, "cmds == NULL");
2972 return;
2973 }
2974
2975 if (cmds->tcs_command) {
2976 if (cmds->tcs_command->tc_buffers != NULL)
2977 tlm_release_reader_writer_ipc(cmds->tcs_command);
2978 else
2979 NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL");
2980 cmds->tcs_command = NULL;
2981 } else
2982 NDMP_LOG(LOG_DEBUG, "COMMAND == NULL");
2983 }
2984
2985
2986 /*
2987 * ndmp_dar_tar_init_v3
2988 *
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.
2992 *
2993 * Parameters:
2994 * session (input) - pointer to the session
2995 * nlp (input) - pointer to the nlp structure
2996 *
2997 * Returns:
2998 * char pointer: on success
2999 * NULL: on error
3000 */
3001 static char *ndmpd_dar_tar_init_v3(ndmpd_session_t *session,
3002 ndmp_lbr_params_t *nlp)
3003 {
3004 char *jname;
3005
3006 jname = ndmp_malloc(TLM_MAX_BACKUP_JOB_NAME);
3007
3008 if (!jname)
3009 return (NULL);
3010
3011 (void) ndmp_new_job_name(jname);
3012
3013 if (!nlp) {
3014 free(jname);
3015 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3016 return (NULL);
3017 }
3018
3019 nlp->nlp_jstat = tlm_new_job_stats(jname);
3020 if (!nlp->nlp_jstat) {
3021 free(jname);
3022 NDMP_LOG(LOG_DEBUG, "Creating job stats");
3023 return (NULL);
3024 }
3025
3026 nlp->nlp_jstat->js_start_ltime = time(NULL);
3027 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
3028
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);
3033 free(jname);
3034 return (NULL);
3035 }
3036 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
3037
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);
3043 free(jname);
3044 return (NULL);
3045 }
3046
3047 /* this is used in ndmpd_path_restored_v3() */
3048 nlp->nlp_lastidx = -1;
3049
3050 NDMP_LOG(LOG_DEBUG, "Restoring from %s tape(s).",
3051 ndmp_data_get_mover_mode(session));
3052
3053 return (jname);
3054 }
3055
3056 /*
3057 * ndmpd_dar_tar_end_v3
3058 *
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.
3061 *
3062 * Parameters:
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
3067 *
3068 * Returns:
3069 * 0: on success
3070 * -1: on error
3071 */
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)
3074 {
3075 int err = 0;
3076
3077
3078 NDMP_LOG(LOG_DEBUG, "lastidx %d", nlp->nlp_lastidx);
3079
3080 /* nothing restored. */
3081 (void) send_unrecovered_list_v3(params, nlp);
3082
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;
3088 } else {
3089 NDMP_LOG(LOG_DEBUG, "JSTAT == NULL");
3090 }
3091
3092 if (nlp->nlp_logcallbacks) {
3093 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
3094 nlp->nlp_logcallbacks = NULL;
3095 } else {
3096 NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL");
3097 }
3098
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");
3102 err = EINTR;
3103 } else {
3104 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
3105 (nlp->nlp_restore_path) ? nlp->nlp_restore_path :
3106 "NULL", err);
3107 }
3108
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);
3112 } else {
3113 (void) bm_free(nlp->nlp_rsbm);
3114 nlp->nlp_rsbm = -1;
3115 }
3116 }
3117
3118 free(jname);
3119
3120 return (err);
3121 }
3122
3123
3124 /*
3125 * ndmpd_dar_tar_v3
3126 *
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.
3132 *
3133 * Parameters:
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
3139 *
3140 * Returns:
3141 * 0: on success
3142 * -1: on error
3143 */
3144 static int
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)
3147 {
3148 char *excl;
3149 char **sels;
3150 int flags;
3151 int err;
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;
3156 pthread_t rdtp;
3157 ndmp_context_t nctx;
3158 mem_ndmp_name_v3_t *ep;
3159
3160 err = 0;
3161
3162 /*
3163 * We have to allocate and deallocate buffers every time we
3164 * run the restore, for we need to flush the buffers.
3165 */
3166 if (restore_dar_alloc_structs_v3(session, jname) < 0)
3167 return (-1);
3168
3169 sels = setupsels(session, params, nlp, dar_index);
3170 if (!sels) {
3171 free_dar_structs_v3(session, jname);
3172 return (-1);
3173 }
3174 excl = NULL;
3175 flags = RSFLG_OVR_ALWAYS;
3176 rn.rn_nlp = nlp;
3177 rn.rn_fp = mknewname;
3178
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;
3184
3185 arg.tr_session = session;
3186 arg.tr_mod_params = params;
3187 arg.tr_cmds = cmds;
3188
3189 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
3190 (void *)&arg);
3191 if (err == 0) {
3192 tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
3193 } else {
3194 NDMP_LOG(LOG_DEBUG, "launch ndmp_tar_reader: %m");
3195 return (-1);
3196 }
3197
3198 cmds->tcs_command->tc_ref++;
3199 cmds->tcs_writer_count++;
3200
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,
3209 dar_index - 1);
3210
3211 if ((err = ndmp_pl->np_pre_restore(ndmp_pl, &nctx,
3212 ep->nm3_opath, ep->nm3_dpath))
3213 != 0) {
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);
3219 goto restore_out;
3220 }
3221 }
3222
3223 if (tm_tar_ops.tm_getdir != NULL) {
3224 char errbuf[256];
3225
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);
3230 /*
3231 * If the fatal error from tm_getdir looks like an
3232 * errno code, we send the error description to DMA.
3233 */
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",
3238 errbuf);
3239 }
3240 }
3241
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);
3246
3247 ndmp_wait_for_reader(cmds);
3248 (void) pthread_join(rdtp, NULL);
3249
3250 /*
3251 * If this is the last DAR entry and it is a three-way
3252 * restore then we should close the connection.
3253 */
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);
3258 }
3259
3260 /* exit as if there was an internal error */
3261 if (session->ns_eof)
3262 err = -1;
3263 restore_out:
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");
3269 err = -1;
3270 }
3271 }
3272
3273 NDMP_FREE(sels);
3274
3275 free_dar_structs_v3(session, jname);
3276
3277 return (err);
3278 }
3279
3280 /*
3281 * ndmpd_dar_locate_windwos_v3
3282 *
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.
3286 *
3287 * Parameters:
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
3292 *
3293 * Returns:
3294 * 0: on success
3295 * -1: on error
3296 */
3297 static int
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)
3300 {
3301 int ret = 0;
3302
3303
3304 for (; ; ) {
3305 ret = (*params->mp_seek_func)(session, fh_info, len);
3306
3307 NDMP_LOG(LOG_DEBUG, "ret %d", ret);
3308 if (ret == 0) /* Seek was done successfully */
3309 break;
3310 else if (ret < 0) {
3311 NDMP_LOG(LOG_DEBUG, "Seek error");
3312 break;
3313 }
3314
3315 /*
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
3320 * window.
3321 */
3322 continue;
3323 }
3324 return (ret);
3325 }
3326
3327 /*
3328 * ndmpd_rs_dar_tar_v3
3329 *
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
3352 int n = session->ns_data.dd_nlist_len;
3353 int i, ret = 0;
3354 int result = 0;
3355
3356 jname = ndmpd_dar_tar_init_v3(session, nlp);
3357
3358 if (!jname)
3359 return (-1);
3360
3361 /*
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)
3366 */
3367 len = tlm_tarhdr_size();
3368
3369 for (i = 0; i < n; ++i) {
3370 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
3371 if (!ep) {
3372 NDMP_LOG(LOG_DEBUG, "ep NULL, i %d", i);
3373 continue;
3374 }
3375 NDMP_LOG(LOG_DEBUG,
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",
3379 ep->nm3_fh_info);
3380
3381 /*
3382 * We should seek till finding the window in which file
3383 * is located.
3384 */
3385 ret = ndmpd_dar_locate_window_v3(session, params,
3386 ep->nm3_fh_info, len);
3387
3388 if (ret < 0) /* If seek fails, restore should be aborted */
3389 break;
3390 /*
3391 * We are inside the target window.
3392 * for each restore we will use one entry as selection list
3393 */
3394 if ((ret = ndmpd_dar_tar_v3(session, params, nlp, jname, i+1))
3395 != 0)
3396 result = EIO;
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);
3401 }
3402
3403 NDMP_LOG(LOG_DEBUG, "End of restore list");
3404
3405 (void) ndmpd_dar_tar_end_v3(session, params, nlp, jname);
3406
3407 return (ret);
3408 }
3409
3410 /*
3411 * ndmp_plugin_pre_restore
3412 *
3413 * Wrapper for pre-restore callback with multiple path
3414 */
3415 static int
3416 ndmp_plugin_pre_restore(ndmp_context_t *ctxp, ndmpd_module_params_t *params,
3417 int ncount)
3418 {
3419 mem_ndmp_name_v3_t *ep;
3420 int err;
3421 int i;
3422
3423 for (i = 0; i < ncount; i++) {
3441 *
3442 * /backup/path/ -> /backup/path
3443 * /backup/path/. -> /backup/path
3444 * /backup/path/../path/ -> /backup/path
3445 * /link-to-backup-path -> /backup/path
3446 *
3447 * Returns:
3448 * Pointer to the new path (allocated)
3449 * NULL if the path doesnt exist
3450 */
3451 static char *
3452 get_absolute_path(const char *bkpath)
3453 {
3454 char *pbuf;
3455 char *rv;
3456
3457 if (!(pbuf = ndmp_malloc(TLM_MAX_PATH_NAME)))
3458 return (NULL);
3459
3460 if ((rv = realpath(bkpath, pbuf)) == NULL) {
3461 NDMP_LOG(LOG_DEBUG, "Invalid path [%s] err=%d",
3462 bkpath, errno);
3463 }
3464 return (rv);
3465 }
3466
3467 /*
3468 * Expands the format string and logs the resulting message to the
3469 * remote DMA
3470 */
3471 void
3472 ndmp_log_dma(ndmp_context_t *nctx, ndmp_log_dma_type_t lt, const char *fmt, ...)
3473 {
3474 va_list ap;
3475 char buf[256];
3476 ndmpd_module_params_t *params;
3477
3478 if (nctx == NULL ||
3479 (params = (ndmpd_module_params_t *)nctx->nc_params) == NULL)
3480 return;
3481
3489
3490 /*
3491 * ndmpd_rs_sar_tar_v3
3492 *
3493 * Main non-DAR restore function. It will try to restore all the entries
3494 * that have been backed up.
3495 *
3496 * Parameters:
3497 * session (input) - pointer to the session
3498 * params (input) - pointer to the parameters structure
3499 * nlp (input) - pointer to the nlp structure
3500 *
3501 * Returns:
3502 * 0: on success
3503 * -1: on error
3504 */
3505 static int
3506 ndmpd_rs_sar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3507 ndmp_lbr_params_t *nlp)
3508 {
3509 char jname[TLM_MAX_BACKUP_JOB_NAME];
3510 char *excl;
3511 char **sels;
3512 int flags;
3513 int err;
3514 tlm_commands_t *cmds;
3515 struct rs_name_maker rn;
3516 ndmp_tar_reader_arg_t arg;
3517 pthread_t rdtp;
3518 int result;
3519 ndmp_context_t nctx;
3520
3521 result = err = 0;
3522 (void) ndmp_new_job_name(jname);
3523 if (restore_alloc_structs_v3(session, jname) < 0)
3524 return (-1);
3525
3526 sels = setupsels(session, params, nlp, 0);
3527 if (!sels) {
3528 free_structs_v3(session, jname);
3529 return (-1);
3530 }
3531 excl = NULL;
3532 flags = RSFLG_OVR_ALWAYS;
3533 rn.rn_nlp = nlp;
3534 rn.rn_fp = mknewname;
3535
3536 nlp->nlp_jstat->js_start_ltime = time(NULL);
3537 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
3538
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;
3544
3545 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" started.",
3546 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3547
3548 arg.tr_session = session;
3549 arg.tr_mod_params = params;
3550 arg.tr_cmds = cmds;
3551 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
3552 (void *)&arg);
3553 if (err == 0) {
3554 tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
3555 } else {
3556 NDMP_LOG(LOG_DEBUG, "Launch ndmp_tar_reader: %m");
3557 free_structs_v3(session, jname);
3558 return (-1);
3559 }
3560
3561 if (!ndmp_check_utf8magic(cmds->tcs_command)) {
3562 NDMP_LOG(LOG_DEBUG, "UTF8Magic not found!");
3563 } else {
3564 NDMP_LOG(LOG_DEBUG, "UTF8Magic found");
3565 }
3566
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,
3575 nlp->nlp_nfiles))
3576 != 0) {
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);
3582 goto restore_out;
3583 }
3584 }
3585
3586 cmds->tcs_command->tc_ref++;
3587 cmds->tcs_writer_count++;
3588
3589 if (tm_tar_ops.tm_getdir != NULL) {
3590 char errbuf[256];
3591
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);
3595 /*
3596 * If the fatal error from tm_getdir looks like an
3597 * errno code, we send the error description to DMA.
3598 */
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",
3603 errbuf);
3604 }
3605 }
3606
3607 cmds->tcs_writer_count--;
3608 cmds->tcs_command->tc_ref--;
3609 nlp->nlp_jstat->js_stop_time = time(NULL);
3610
3611 /* Send the list of un-recovered files/dirs to the client. */
3612 (void) send_unrecovered_list_v3(params, nlp);
3613
3614 ndmp_stop_local_reader(session, cmds);
3615 ndmp_wait_for_reader(cmds);
3616 (void) pthread_join(rdtp, NULL);
3617
3618 ndmp_stop_remote_reader(session);
3619
3620 /* exit as if there was an internal error */
3621 if (session->ns_eof)
3622 err = -1;
3623 if (err == -1)
3624 result = EIO;
3625 }
3626
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");
3631 result = EINTR;
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);
3636 err = -1;
3637 } else {
3638 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
3639 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL",
3640 err);
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);
3645
3646 restore_out:
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");
3652 err = -1;
3653 }
3654 }
3655
3656 NDMP_FREE(sels);
3657 free_structs_v3(session, jname);
3658
3659 return (err);
3660 }
3661
3662
3663 /*
3664 * ndmp_backup_get_params_v3
3665 *
3666 * Get the backup parameters from the NDMP env variables
3667 * and log them in the system log and as normal messages
3668 * to the DMA.
3669 *
3670 * Parameters:
3671 * session (input) - pointer to the session
3672 * params (input) - pointer to the parameters structure
3673 *
3674 * Returns:
3675 * NDMP_NO_ERR: on success
3676 * != NDMP_NO_ERR: otherwise
3677 */
3678 ndmp_error
3679 ndmp_backup_get_params_v3(ndmpd_session_t *session,
3680 ndmpd_module_params_t *params)
3681 {
3682 ndmp_lbr_params_t *nlp;
3683
3684 if (!session || !params)
3685 return (NDMP_ILLEGAL_ARGS_ERR);
3686
3687 nlp = ndmp_get_nlp(session);
3688 if (!nlp) {
3689 MOD_LOGV3(params, NDMP_LOG_ERROR,
3690 "Internal error: NULL nlp.\n");
3691 return (NDMP_ILLEGAL_ARGS_ERR);
3692 } else {
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);
3696 }
3697
3698 nlp->nlp_backup_path = get_absolute_path(nlp->nlp_backup_path);
3699 if (!nlp->nlp_backup_path)
3700 return (NDMP_ILLEGAL_ARGS_ERR);
3701
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);
3706 else
3707 NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
3708
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);
3713 } else {
3714 NLP_UNSET(nlp, NLPF_IGNCTIME);
3715 }
3716
3717 if (ndmp_include_lmtime == TRUE) {
3718 NDMP_LOG(LOG_DEBUG, "including st_lmtime");
3719 NLP_SET(nlp, NLPF_INCLMTIME);
3720 } else {
3721 NLP_UNSET(nlp, NLPF_INCLMTIME);
3722 }
3723
3724 NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
3725
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));
3731 }
3732
3733
3734 /*
3735 * ndmpd_tar_backup_starter_v3
3736 *
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.
3741 *
3742 * Parameters:
3743 * params (input) - pointer to the parameters structure
3744 *
3745 * Returns:
3746 * 0: on success
3747 * != 0: otherwise
3748 */
3749 int
3750 ndmpd_tar_backup_starter_v3(void *arg)
3751 {
3752 ndmpd_module_params_t *params = arg;
3753 int err;
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;
3758 pthread_t tid;
3759
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);
3764
3765 err = 0;
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);
3771 err = -1;
3772 }
3773
3774 NDMP_LOG(LOG_DEBUG, "err %d, chkpnted %c",
3775 err, NDMP_YORN(NLP_ISCHKPNTED(nlp)));
3776
3777 if (err == 0) {
3778 sarg.bs_session = session;
3779 sarg.bs_jname = jname;
3780 sarg.bs_path = nlp->nlp_backup_path;
3781
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);
3786
3787 err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate, jname);
3788 if (err != 0) {
3789 NDMP_LOG(LOG_DEBUG, "err %d", err);
3790 } else {
3791 log_bk_params_v3(session, params, nlp);
3792 err = tar_backup_v3(session, params, nlp, jname);
3793 }
3794 }
3795
3796 if (!NLP_ISCHKPNTED(nlp))
3797 (void) ndmp_remove_snapshot(nlp->nlp_backup_path, jname);
3798
3799 NDMP_LOG(LOG_DEBUG, "err %d, update %c",
3800 err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
3801
3802 if (err == 0)
3803 save_backup_date_v3(params, nlp);
3804
3805 MOD_DONE(params, err);
3806
3807 /* nlp_params is allocated in start_backup_v3() */
3808 NDMP_FREE(nlp->nlp_params);
3809 NDMP_FREE(nlp->nlp_backup_path);
3810
3811 NS_DEC(nbk);
3812 ndmp_session_unref(session);
3813 return (err);
3814
3815 }
3816
3817
3818 /*
3819 * ndmpd_tar_backup_abort_v3
3820 *
3821 * Abort the backup operation and stop the reader thread.
3822 *
3823 * Parameters:
3824 * module_cookie (input) - pointer to the nlp structure
3825 *
3826 * Returns:
3827 * 0: always
3828 */
3829 int
3830 ndmpd_tar_backup_abort_v3(void *module_cookie)
3831 {
3832 ndmp_lbr_params_t *nlp;
3833
3834 nlp = (ndmp_lbr_params_t *)module_cookie;
3851 *
3852 * Get the parameters specified for recovery such as restore path, type
3853 * of restore (DAR, non-DAR) etc
3854 *
3855 * Parameters:
3856 * session (input) - pointer to the session
3857 * params (input) - pointer to the parameters structure
3858 *
3859 * Returns:
3860 * NDMP_NO_ERR: on success
3861 * != NDMP_NO_ERR: otherwise
3862 */
3863 ndmp_error
3864 ndmp_restore_get_params_v3(ndmpd_session_t *session,
3865 ndmpd_module_params_t *params)
3866 {
3867 ndmp_error rv;
3868 ndmp_lbr_params_t *nlp;
3869
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);
3882 } else {
3883 rv = NDMP_NO_ERR;
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 */
3888 NDMP_LOG(LOG_DEBUG,
3889 "Can't have RECURSIVE and DIRECT together");
3890 rv = NDMP_ILLEGAL_ARGS_ERR;
3891 return (rv);
3892 }
3893
3894 /*
3895 * DAR can be done if all the fh_info's are valid.
3896 */
3897 if (allvalidfh(session, params)) {
3898 ndmp_sort_nlist_v3(session);
3899 } else {
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);
3904 }
3905 }
3906
3907 log_rs_params_v3(session, params, nlp);
3908 }
|
20 *
21 * - Neither the name of The Storage Networking Industry Association (SNIA)
22 * nor the names of its contributors may be used to endorse or promote
23 * products derived from this software without specific prior written
24 * permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40 /* Copyright 2017 Nexenta Systems, Inc. All rights reserved. */
41
42 #include <sys/stat.h>
43 #include <sys/types.h>
44 #include <sys/time.h>
45 #include <syslog.h>
46 #include <ctype.h>
47 #include <sys/socket.h>
48 #include <sys/acl.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51 #include <errno.h>
52 #include <stdio.h>
53 #include <string.h>
54 #include <time.h>
55 #include <cstack.h>
56 #include "ndmp.h"
57 #include "ndmpd.h"
58 #include <bitmap.h>
59 #include <traverse.h>
60
61
62 /*
63 * Maximum length of the string-representation of u_longlong_t type.
64 */
65 #define QUAD_DECIMAL_LEN 20
98 } bk_param_v3_t;
99
100
101 /*
102 * Multiple destination restore mode
103 */
104 #define MULTIPLE_DEST_DIRS 128
105
106 int multiple_dest_restore = 0;
107
108 /*
109 * Plug-in module ops
110 */
111 ndmp_plugin_t *ndmp_pl;
112
113 /*
114 * NDMP exclusion list
115 */
116 char **ndmp_excl_list = NULL;
117
118 extern boolean_t fs_is_checkpointed(ndmp_lbr_params_t *);
119
120 /*
121 * split_env
122 *
123 * Splits the string into list of sections separated by the
124 * sep character.
125 *
126 * Parameters:
127 * envp (input) - the environment variable that should be broken
128 * sep (input) - the separator character
129 *
130 * Returns:
131 * Array of character pointers: On success. The array is allocated
132 * as well as all its entries. They all should be freed by the
133 * caller.
134 * NULL: on error
135 */
136 static char **
137 split_env(char *envp, char sep)
138 {
139 char *bp, *cp, *ep;
222 return (cpp);
223 }
224
225
226 /*
227 * prl
228 *
229 * Print the array of character pointers passed to it. This is
230 * used for debugging purpose.
231 *
232 * Parameters:
233 * lpp (input) - pointer to the array of strings
234 *
235 * Returns:
236 * void
237 */
238 static void
239 prl(char **lpp)
240 {
241 if (!lpp) {
242 syslog(LOG_DEBUG, "empty");
243 return;
244 }
245
246 while (*lpp)
247 syslog(LOG_DEBUG, "\"%s\"", *lpp++);
248 }
249
250
251 /*
252 * inlist
253 *
254 * Looks through all the strings of the array to see if the ent
255 * matches any of the strings. The strings are patterns.
256 *
257 * Parameters:
258 * lpp (input) - pointer to the array of strings
259 * ent (input) - the entry to be matched
260 *
261 * Returns:
262 * TRUE: if there is a match
263 * FALSE: invalid argument or no match
264 */
265 static boolean_t
266 inlist(char **lpp, char *ent)
267 {
268 if (!lpp || !ent) {
269 syslog(LOG_DEBUG, "empty list");
270 return (FALSE);
271 }
272
273 while (*lpp) {
274 /*
275 * Fixing the sync_sort NDMPV3 problem, it sends the inclusion
276 * like "./" which we should skip the "./"
277 */
278 char *pattern = *lpp;
279 if (strncmp(pattern, "./", 2) == 0)
280 pattern += 2;
281
282 syslog(LOG_DEBUG, "pattern %s, ent %s", pattern, ent);
283
284 if (match(pattern, ent)) {
285 syslog(LOG_DEBUG, "match(%s,%s)", pattern, ent);
286 return (TRUE);
287 }
288 lpp++;
289 }
290
291 syslog(LOG_DEBUG, "no match");
292 return (FALSE);
293 }
294
295
296 /*
297 * inexl
298 *
299 * Checks if the entry is in the list. This is used for exclusion
300 * list. If the exclusion list is empty, FALSE should be returned
301 * showing that nothing should be excluded by default.
302 *
303 * Parameters:
304 * lpp (input) - pointer to the array of strings
305 * ent (input) - the entry to be matched
306 *
307 * Returns:
308 * TRUE: if there is a match
309 * FALSE: invalid argument or no match
310 *
311 */
397 lpp += start; /* Next selection entry will be in lpp[start] */
398 } else {
399 start = 0;
400 end = n;
401 }
402
403 for (i = start; i < end; i++) {
404 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
405 if (!ep)
406 continue;
407
408 /*
409 * Check for clients that send original path as "."(like
410 * CA products). In this situation opath is something like
411 * "/v1/." and we should change it to "/v1/"
412 */
413 len = strlen(ep->nm3_opath);
414 if (len > 1 && ep->nm3_opath[len-2] == '/' &&
415 ep->nm3_opath[len-1] == '.') {
416 ep->nm3_opath[len-1] = '\0';
417 syslog(LOG_DEBUG,
418 "nm3_opath changed from %s. to %s",
419 ep->nm3_opath, ep->nm3_opath);
420 }
421 *lpp++ = ep->nm3_opath;
422 }
423
424 /* list termination indicator is a null pointer */
425 *lpp = NULL;
426
427 return (save);
428 }
429
430
431 /*
432 * mkrsp
433 *
434 * Make Restore Path.
435 * It gets a path, a selection (with which the path has matched) a new
436 * name and makes a new name for the path.
437 * All the components of the path and the selection are skipped as long
472 if (!COMPBNDRY(pp) || !COMPBNDRY(sp))
473 /* An exception to the boundary rule */
474 /* (!(!*sp && (*(pp - 1)) == '/')) */
475 if (*sp || (*(pp - 1)) != '/')
476 return (NULL);
477
478 /* if pp shorter than sp, it should not be restored */
479 if (!*pp && *sp) {
480 sp += strspn(sp, "/");
481 if (strlen(sp) > 0)
482 return (NULL);
483 }
484 }
485
486 if (np)
487 np += strspn(np, "/");
488 else
489 np = "";
490
491 if (!tlm_cat_path(bp, np, pp)) {
492 syslog(LOG_ERR, "Restore path too long %s/%s.", np, pp);
493 return (NULL);
494 }
495
496 return (bp);
497 }
498
499
500 /*
501 * mknewname
502 *
503 * This is used as callback for creating the restore path. This function
504 * can handle both single destination and multiple restore paths.
505 *
506 * Make up the restore destination path for a particular file/directory, path,
507 * based on nm3_opath and nm3_dpath. path should have matched nm3_opath
508 * in some way.
509 */
510 char *
511 mknewname(struct rs_name_maker *rnp, char *buf, int idx, char *path)
512 {
513 char *rv;
514 ndmp_lbr_params_t *nlp;
515 mem_ndmp_name_v3_t *ep;
516
517 rv = NULL;
518 if (!buf) {
519 syslog(LOG_DEBUG, "buf is NULL");
520 } else if (!path) {
521 syslog(LOG_DEBUG, "path is NULL");
522 } else if ((nlp = rnp->rn_nlp) == 0) {
523 syslog(LOG_DEBUG, "rnp->rn_nlp is NULL");
524 } else if (!nlp->nlp_params) {
525 syslog(LOG_DEBUG, "nlp->nlp_params is NULL");
526 } else
527 if (!ndmp_full_restore_path) {
528 if (idx < 0 || idx >= (int)nlp->nlp_nfiles) {
529 syslog(LOG_DEBUG,
530 "Invalid idx %d range (0, %d)",
531 idx, nlp->nlp_nfiles);
532 } else if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(
533 nlp->nlp_params, idx))) {
534 syslog(LOG_DEBUG,
535 "nlist entry %d is NULL", idx);
536 } else {
537 rv = mkrsp(buf, path, ep->nm3_opath,
538 ep->nm3_dpath);
539 }
540 } else {
541 if (!tlm_cat_path(buf, nlp->nlp_restore_path, path)) {
542 syslog(LOG_ERR, "Path too long %s/%s.",
543 nlp->nlp_restore_path, path);
544 rv = NULL;
545 } else {
546 rv = buf;
547 }
548 }
549
550 return (rv);
551 }
552
553
554 /*
555 * chopslash
556 *
557 * Remove the slash from the end of the given path
558 */
559 static void
560 chopslash(char *cp)
561 {
562 int ln;
563
564 if (!cp || !*cp)
565 return;
566
594 }
595
596 return (bp);
597 }
598
599
600 /*
601 * voliswr
602 *
603 * Is the volume writable?
604 */
605 static int
606 voliswr(char *path)
607 {
608 int rv;
609
610 if (!path)
611 return (0);
612
613 rv = !fs_is_rdonly(path) && !fs_is_chkpntvol(path);
614 syslog(LOG_DEBUG, "%d path \"%s\"", rv, path);
615 return (rv);
616
617 }
618
619
620 /*
621 * is_valid_backup_dir_v3
622 *
623 * Checks the validity of the backup path. Backup path should
624 * have the following characteristics to be valid:
625 * 1) It should be an absolute path.
626 * 2) It should be a directory.
627 * 3) It should not be checkpoint root directory
628 * 4) If the file system is read-only, the backup path
629 * should be a checkpointed path. Checkpoint cannot
630 * be created on a read-only file system.
631 *
632 * Parameters:
633 * params (input) - pointer to the parameters structure.
634 * bkpath (input) - the backup path
763 /*
764 * log_bk_params_v3
765 *
766 * Dispatcher function which calls the appropriate function
767 * for logging the backup date and level in the system log
768 * and also send them as normal log message to the client.
769 *
770 * Parameters:
771 * session (input) - pointer to the session
772 * params (input) - pointer to the parameters structure
773 * nlp (input) - pointer to the nlp structure
774 *
775 * Returns:
776 * void
777 */
778 static void
779 log_bk_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
780 ndmp_lbr_params_t *nlp)
781 {
782 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Backing up \"%s\".\n",
783 NLP_ISCHKPNTED(nlp) ? nlp->nlp_mountpoint : nlp->nlp_backup_path);
784
785 if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_LOCAL)
786 MOD_LOGV3(params, NDMP_LOG_NORMAL,
787 "Tape record size: %d.\n",
788 session->ns_mover.md_record_size);
789
790 MOD_LOGV3(params, NDMP_LOG_NORMAL, "File history: %c.\n",
791 NDMP_YORN(NLP_ISSET(nlp, NLPF_FH)));
792
793 if (NLP_ISSET(nlp, NLPF_TOKENBK))
794 log_date_token_v3(params, nlp);
795 else if (NLP_ISSET(nlp, NLPF_LBRBK))
796 log_lbr_bk_v3(params, nlp);
797 else if (NLP_ISSET(nlp, NLPF_LEVELBK))
798 log_level_v3(params, nlp);
799 else {
800 MOD_LOGV3(params, NDMP_LOG_ERROR,
801 "Internal error: backup level not defined for \"%s\".\n",
802 nlp->nlp_backup_path);
803 }
809 *
810 * Is the UPDATE environment variable specified? If it is
811 * the corresponding flag is set in the flags field of the
812 * nlp structure, otherwise the flag is cleared.
813 *
814 * Parameters:
815 * params (input) - pointer to the parameters structure
816 * nlp (input) - pointer to the nlp structure
817 *
818 * Returns:
819 * void
820 */
821 static void
822 get_update_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
823 {
824 char *envp;
825
826 envp = MOD_GETENV(params, "UPDATE");
827 if (!envp) {
828 NLP_SET(nlp, NLPF_UPDATE);
829 syslog(LOG_DEBUG,
830 "env(UPDATE) not defined, default to TRUE");
831 } else {
832 syslog(LOG_DEBUG, "env(UPDATE): \"%s\"", envp);
833 if (IS_YORT(*envp))
834 NLP_SET(nlp, NLPF_UPDATE);
835 else
836 NLP_UNSET(nlp, NLPF_UPDATE);
837 }
838 }
839
840
841 /*
842 * get_hist_env_v3
843 *
844 * Is backup history requested? If it is, the corresponding
845 * flag is set in the flags field of the nlp structure, otherwise
846 * the flag is cleared.
847 *
848 * Parameters:
849 * params (input) - pointer to the parameters structure
850 * nlp (input) - pointer to the nlp structure
851 *
852 * Returns:
853 * void
854 */
855 static void
856 get_hist_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
857 {
858 char *envp;
859
860 envp = MOD_GETENV(params, "HIST");
861 if (!envp) {
862 syslog(LOG_DEBUG, "env(HIST) not defined");
863 NLP_UNSET(nlp, NLPF_FH);
864 } else {
865 syslog(LOG_DEBUG, "env(HIST): \"%s\"", envp);
866 if (IS_YORT(*envp) || IS_F(*envp))
867 NLP_SET(nlp, NLPF_FH);
868 else
869 NLP_UNSET(nlp, NLPF_FH);
870
871 /* Force file format if specified */
872 if (IS_F(*envp)) {
873 params->mp_file_history_path_func =
874 ndmpd_api_file_history_file_v3;
875 params->mp_file_history_dir_func = 0;
876 params->mp_file_history_node_func = 0;
877 }
878 }
879 }
880
881
882 /*
883 * get_exc_env_v3
884 *
885 * Gets the EXCLUDE environment variable and breaks it
886 * into strings. The separator of the EXCLUDE environment
887 * variable is the ',' character.
888 *
889 * Parameters:
890 * params (input) - pointer to the parameters structure
891 * nlp (input) - pointer to the nlp structure
892 *
893 * Returns:
894 * void
895 */
896 static void
897 get_exc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
898 {
899 char *envp;
900
901 envp = MOD_GETENV(params, "EXCLUDE");
902 if (!envp) {
903 syslog(LOG_DEBUG, "env(EXCLUDE) not defined");
904 nlp->nlp_exl = NULL;
905 } else {
906 syslog(LOG_DEBUG, "env(EXCLUDE): \"%s\"", envp);
907 nlp->nlp_exl = split_env(envp, ',');
908 prl(nlp->nlp_exl);
909 }
910 }
911
912
913 /*
914 * get_inc_env_v3
915 *
916 * Gets the FILES environment variable that shows which files
917 * should be backed up, and breaks it into strings. The
918 * separator of the FILES environment variable is the space
919 * character.
920 *
921 * Parameters:
922 * params (input) - pointer to the parameters structure
923 * nlp (input) - pointer to the nlp structure
924 *
925 * Returns:
926 * void
927 */
928 static void
929 get_inc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
930 {
931 char *envp;
932
933 envp = MOD_GETENV(params, "FILES");
934 if (!envp) {
935 syslog(LOG_DEBUG, "env(FILES) not defined");
936 nlp->nlp_inc = NULL;
937 } else {
938 syslog(LOG_DEBUG, "env(FILES): \"%s\"", envp);
939 nlp->nlp_inc = split_env(envp, ' ');
940 prl(nlp->nlp_inc);
941 }
942 }
943
944
945 /*
946 * get_direct_env_v3
947 *
948 * Gets the DIRECT environment variable that shows if the fh_info should
949 * be sent to the client or not.
950 *
951 * Parameters:
952 * params (input) - pointer to the parameters structure
953 * nlp (input) - pointer to the nlp structure
954 *
955 * Returns:
956 * void
957 */
958 static void
959 get_direct_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
960 {
961 char *envp;
962
963 /*
964 * We should send the fh_info to the DMA, unless it is specified
965 * in the request that we should not send fh_info.
966 * At the moment we do not support DAR on directories, so if the user
967 * needs to restore a directory they should disable the DAR.
968 */
969 if (params->mp_operation == NDMP_DATA_OP_RECOVER && !ndmp_dar_support) {
970 syslog(LOG_INFO, "Direct Access Restore Disabled");
971 NLP_UNSET(nlp, NLPF_DIRECT);
972 MOD_LOGV3(params, NDMP_LOG_NORMAL,
973 "DAR is disabled. Running Restore without DAR");
974 return;
975 }
976
977 /*
978 * Regardless of whether DIRECT is defined at backup time we send
979 * back the fh_info, for some clients do not use get_backup_attrs.
980 * If operation is restore we have to unset the DIRECT, for
981 * some clients do not set the MOVER window.
982 */
983 if (params->mp_operation == NDMP_DATA_OP_BACKUP) {
984 syslog(LOG_DEBUG, "backup default env(DIRECT): YES");
985 NLP_SET(nlp, NLPF_DIRECT);
986 } else {
987
988 envp = MOD_GETENV(params, "DIRECT");
989 if (!envp) {
990 syslog(LOG_DEBUG, "env(DIRECT) not defined");
991 NLP_UNSET(nlp, NLPF_DIRECT);
992 } else {
993 syslog(LOG_DEBUG, "env(DIRECT): \"%s\"", envp);
994 if (IS_YORT(*envp)) {
995 NLP_SET(nlp, NLPF_DIRECT);
996 syslog(LOG_DEBUG,
997 "Direct Access Restore Enabled");
998 } else {
999 NLP_UNSET(nlp, NLPF_DIRECT);
1000 syslog(LOG_DEBUG,
1001 "Direct Access Restore Disabled");
1002 }
1003 }
1004 }
1005
1006 if (NLP_ISSET(nlp, NLPF_DIRECT)) {
1007 if (params->mp_operation == NDMP_DATA_OP_BACKUP)
1008 MOD_LOGV3(params, NDMP_LOG_NORMAL,
1009 "Direct Access Restore information is supported");
1010 else
1011 MOD_LOGV3(params, NDMP_LOG_NORMAL,
1012 "Running Restore with Direct Access Restore");
1013 } else {
1014 if (params->mp_operation == NDMP_DATA_OP_BACKUP)
1015 MOD_LOGV3(params, NDMP_LOG_NORMAL,
1016 "Direct Access Restore is not supported");
1017 else
1018 MOD_LOGV3(params, NDMP_LOG_NORMAL,
1019 "Running Restore without Direct Access Restore");
1020 }
1060 return (NDMP_ILLEGAL_ARGS_ERR);
1061
1062 if (MOD_GETENV(params, "LEVEL")) {
1063 MOD_LOGV3(params, NDMP_LOG_WARNING,
1064 "Both BASE_DATE and LEVEL environment variables "
1065 "defined.\n");
1066 MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
1067 "BASE_DATE is being used for this backup.\n");
1068 }
1069
1070 tok = strtoll(basedate, &endp, 10);
1071 if (endp == basedate) {
1072 MOD_LOGV3(params, NDMP_LOG_ERROR,
1073 "Invalid BASE_DATE environment variable: \"%s\".\n",
1074 basedate);
1075 return (NDMP_ILLEGAL_ARGS_ERR);
1076 }
1077
1078 tstamp = tok & 0xffffffff;
1079 seq = (tok >> 32) & 0xffffffff;
1080
1081 if ((int)seq > ndmp_get_max_tok_seq()) {
1082 rv = NDMP_ILLEGAL_ARGS_ERR;
1083 MOD_LOGV3(params, NDMP_LOG_ERROR,
1084 "The sequence counter of the token exceeds the "
1085 "maximum permitted value.\n");
1086 MOD_LOGCONTV3(params, NDMP_LOG_ERROR,
1087 "Token sequence: %u, maxiumum value: %u.\n",
1088 seq, ndmp_get_max_tok_seq());
1089 } else if (seq >= NDMP_TOKSEQ_HLIMIT) {
1090 rv = NDMP_ILLEGAL_ARGS_ERR;
1091 MOD_LOGV3(params, NDMP_LOG_ERROR,
1092 "The sequence counter the of token exceeds the "
1093 "hard-limit.\n");
1094 MOD_LOGCONTV3(params, NDMP_LOG_ERROR,
1095 "Token sequence: %u, hard-limit: %u.\n",
1096 seq, NDMP_TOKSEQ_HLIMIT);
1097 } else {
1098 rv = NDMP_NO_ERR;
1099 /*
1199 * If the BASE_DATE env variable is specified use it, otherwise
1200 * look to see if LEVEL is specified. If LEVEL is not
1201 * specified either, backup level '0' must be made. Level backup
1202 * does not clear the archive bit.
1203 *
1204 * If LEVEL environment varaible is specified, values for
1205 * 'F', 'D', 'I' and 'A' (for 'Full', 'Differential',
1206 * 'Incremental', and 'Archive' is checked first. Then
1207 * level '0' to '9' will be checked.
1208 *
1209 * LEVEL environment variable can hold only one character.
1210 * If its length is longer than 1, an error is returned.
1211 */
1212 envp = MOD_GETENV(params, "BASE_DATE");
1213 if (envp)
1214 return (get_date_token_v3(params, nlp, envp));
1215
1216
1217 envp = MOD_GETENV(params, "LEVEL");
1218 if (!envp) {
1219 syslog(LOG_DEBUG, "env(LEVEL) not defined, default to 0");
1220 NLP_SET(nlp, NLPF_LEVELBK);
1221 NLP_UNSET(nlp, NLPF_LBRBK);
1222 NLP_UNSET(nlp, NLPF_TOKENBK);
1223 nlp->nlp_llevel = 0;
1224 nlp->nlp_ldate = 0;
1225 nlp->nlp_clevel = 0;
1226 /*
1227 * The value of nlp_cdate will be set to the checkpoint
1228 * creation time after it is created.
1229 */
1230 return (NDMP_NO_ERR);
1231 }
1232
1233 if (*(envp+1) != '\0') {
1234 MOD_LOGV3(params, NDMP_LOG_ERROR,
1235 "Invalid backup level \"%s\".\n", envp);
1236 return (NDMP_ILLEGAL_ARGS_ERR);
1237 }
1238
1239 if (IS_LBR_BKTYPE(*envp))
1281 * Parameters:
1282 * params (input) - pointer to the parameters structure
1283 * nlp (input) - pointer to the nlp structure
1284 *
1285 * Returns:
1286 * void
1287 */
1288 static void
1289 save_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1290 {
1291 char val[QUAD_DECIMAL_LEN];
1292 u_longlong_t tok;
1293
1294 if (!params || !nlp)
1295 return;
1296
1297 nlp->nlp_tokseq++;
1298 tok = ((u_longlong_t)nlp->nlp_tokseq << 32) | nlp->nlp_cdate;
1299 (void) snprintf(val, sizeof (val), "%llu", tok);
1300
1301 if (MOD_SETENV(params, "DUMP_DATE", val) != 0) {
1302 MOD_LOGV3(params, NDMP_LOG_ERROR,
1303 "Could not set DUMP_DATE to %s", val);
1304 } else if (!nlp->nlp_dmpnm) {
1305 syslog(LOG_DEBUG, "No log file defined");
1306 } else if (ndmpd_append_dumptime(nlp->nlp_dmpnm, nlp->nlp_backup_path,
1307 nlp->nlp_tokseq, nlp->nlp_tokdate) < 0) {
1308 MOD_LOGV3(params, NDMP_LOG_ERROR,
1309 "Saving backup date for \"%s\" in \"%s\".\n",
1310 nlp->nlp_backup_path, nlp->nlp_dmpnm);
1311 }
1312 }
1313
1314
1315 /*
1316 * save_lbr_bk_v3
1317 *
1318 * Append the backup type and date in the DMP_NAME file for
1319 * LBR-type backup if any file is specified.
1320 *
1321 * Parameters:
1322 * params (input) - pointer to the parameters structure
1323 * nlp (input) - pointer to the nlp structure
1324 *
1325 * Returns:
1326 * void
1327 */
1328 static void
1329 save_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1330 {
1331 if (!params || !nlp)
1332 return;
1333
1334 if (!nlp->nlp_dmpnm) {
1335 syslog(LOG_DEBUG, "No log file defined");
1336 } else if (ndmpd_append_dumptime(nlp->nlp_dmpnm, nlp->nlp_backup_path,
1337 nlp->nlp_clevel, nlp->nlp_cdate) < 0) {
1338 MOD_LOGV3(params, NDMP_LOG_ERROR,
1339 "Saving backup date for \"%s\" in \"%s\".\n",
1340 nlp->nlp_backup_path, nlp->nlp_dmpnm);
1341 }
1342 }
1343
1344
1345 /*
1346 * save_level_v3
1347 *
1348 * Save the date and level of the current backup in the dumpdates
1349 * file.
1350 *
1351 * Parameters:
1352 * params (input) - pointer to the parameters structure
1353 * nlp (input) - pointer to the nlp structure
1354 *
1355 * Returns:
1356 * void
1357 */
1358 static void
1359 save_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1360 {
1361 if (!params || !nlp)
1362 return;
1363
1364 if (!NLP_SHOULD_UPDATE(nlp)) {
1365 syslog(LOG_DEBUG, "update not requested");
1366 } else if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel,
1367 nlp->nlp_cdate) < 0) {
1368 MOD_LOGV3(params, NDMP_LOG_ERROR, "Logging backup date.\n");
1369 }
1370 }
1371
1372
1373 /*
1374 * save_backup_date_v3
1375 *
1376 * A dispatcher function to call the corresponding save function
1377 * based on the backup type.
1378 *
1379 * Parameters:
1380 * params (input) - pointer to the parameters structure
1381 * nlp (input) - pointer to the nlp structure
1382 *
1383 * Returns:
1384 * void
1385 */
1396 else if (NLP_ISSET(nlp, NLPF_LEVELBK))
1397 save_level_v3(params, nlp);
1398 else {
1399 MOD_LOGV3(params, NDMP_LOG_ERROR,
1400 "Internal error: lost backup level type for \"%s\".\n",
1401 nlp->nlp_backup_path);
1402 }
1403 }
1404
1405
1406 /*
1407 * backup_alloc_structs_v3
1408 *
1409 * Create the structures for V3 backup. This includes:
1410 * Job stats
1411 * Reader writer IPC
1412 * File history callback structure
1413 *
1414 * Parameters:
1415 * session (input) - pointer to the session
1416 *
1417 * Returns:
1418 * 0: on success
1419 * -1: otherwise
1420 */
1421 static int
1422 backup_alloc_structs_v3(ndmpd_session_t *session)
1423 {
1424 int n;
1425 long xfer_size;
1426 ndmp_lbr_params_t *nlp;
1427 tlm_commands_t *cmds;
1428
1429 nlp = ndmp_get_nlp(session);
1430 if (!nlp) {
1431 syslog(LOG_ERR, "nlp == NULL");
1432 return (-1);
1433 }
1434
1435 nlp->nlp_jstat = tlm_new_job_stats(nlp->nlp_job_name);
1436 if (!nlp->nlp_jstat) {
1437 syslog(LOG_ERR, "Creating job stats failed");
1438 return (-1);
1439 }
1440
1441 cmds = &nlp->nlp_cmds;
1442 (void) memset(cmds, 0, sizeof (*cmds));
1443
1444 xfer_size = ndmp_buffer_get_size(session);
1445 if (xfer_size < 512*KILOBYTE) {
1446 /*
1447 * Read multiple of mover_record_size near to 512K. This
1448 * will prevent the data being copied in the mover buffer
1449 * when we write the data.
1450 */
1451 n = 512 * KILOBYTE / xfer_size;
1452 if (n <= 0)
1453 n = 1;
1454 xfer_size *= n;
1455 syslog(LOG_DEBUG, "Adjusted read size: %d",
1456 xfer_size);
1457 }
1458
1459 cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, xfer_size);
1460 if (!cmds->tcs_command) {
1461 tlm_un_ref_job_stats(nlp->nlp_job_name);
1462 return (-1);
1463 }
1464
1465 nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
1466 ndmpd_fhpath_v3_cb, ndmpd_fhdir_v3_cb, ndmpd_fhnode_v3_cb);
1467 if (!nlp->nlp_logcallbacks) {
1468 tlm_release_reader_writer_ipc(cmds->tcs_command);
1469 tlm_un_ref_job_stats(nlp->nlp_job_name);
1470 return (-1);
1471 }
1472 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
1473 nlp->nlp_restored = NULL;
1474
1475 return (0);
1476 }
1477
1478
1479 /*
1480 * restore_alloc_structs_v3
1481 *
1482 * Create the structures for V3 Restore. This includes:
1483 * Job stats
1484 * Reader writer IPC
1485 * File recovery callback structure
1486 *
1487 * Parameters:
1488 * session (input) - pointer to the session
1489 *
1490 * Returns:
1491 * 0: on success
1492 * -1: otherwise
1493 */
1494 int
1495 restore_alloc_structs_v3(ndmpd_session_t *session)
1496 {
1497 long xfer_size;
1498 ndmp_lbr_params_t *nlp;
1499 tlm_commands_t *cmds;
1500
1501 nlp = ndmp_get_nlp(session);
1502 if (!nlp) {
1503 syslog(LOG_ERR, "nlp == NULL");
1504 return (-1);
1505 }
1506
1507 /* this is used in ndmpd_path_restored_v3() */
1508 nlp->nlp_lastidx = -1;
1509
1510 nlp->nlp_jstat = tlm_new_job_stats(nlp->nlp_job_name);
1511 if (!nlp->nlp_jstat) {
1512 syslog(LOG_ERR, "Creating job stats failed");
1513 return (-1);
1514 }
1515
1516 cmds = &nlp->nlp_cmds;
1517 (void) memset(cmds, 0, sizeof (*cmds));
1518
1519 xfer_size = ndmp_buffer_get_size(session);
1520 cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
1521 if (!cmds->tcs_command) {
1522 tlm_un_ref_job_stats(nlp->nlp_job_name);
1523 return (-1);
1524 }
1525
1526 nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
1527 ndmpd_path_restored_v3, NULL, NULL);
1528 if (!nlp->nlp_logcallbacks) {
1529 tlm_release_reader_writer_ipc(cmds->tcs_command);
1530 tlm_un_ref_job_stats(nlp->nlp_job_name);
1531 return (-1);
1532 }
1533 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
1534
1535 nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0);
1536 if (nlp->nlp_rsbm < 0) {
1537 syslog(LOG_ERR, "Out of memory.");
1538 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
1539 tlm_release_reader_writer_ipc(cmds->tcs_command);
1540 tlm_un_ref_job_stats(nlp->nlp_job_name);
1541 return (-1);
1542 }
1543
1544 return (0);
1545 }
1546
1547
1548 /*
1549 * free_structs_v3
1550 *
1551 * Release the resources allocated by backup_alloc_structs_v3
1552 * function.
1553 *
1554 * Parameters:
1555 * session (input) - pointer to the session
1556 *
1557 * Returns:
1558 * void
1559 */
1560 static void
1561 free_structs_v3(ndmpd_session_t *session)
1562 {
1563 ndmp_lbr_params_t *nlp;
1564 tlm_commands_t *cmds;
1565
1566 nlp = ndmp_get_nlp(session);
1567 if (!nlp) {
1568 syslog(LOG_DEBUG, "nlp == NULL");
1569 return;
1570 }
1571 cmds = &nlp->nlp_cmds;
1572 if (!cmds) {
1573 syslog(LOG_DEBUG, "cmds == NULL");
1574 return;
1575 }
1576
1577 if (nlp->nlp_logcallbacks) {
1578 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
1579 nlp->nlp_logcallbacks = NULL;
1580 } else
1581 syslog(LOG_DEBUG, "FH CALLBACKS == NULL");
1582
1583 if (cmds->tcs_command) {
1584 if (cmds->tcs_command->tc_buffers != NULL)
1585 tlm_release_reader_writer_ipc(cmds->tcs_command);
1586 else
1587 syslog(LOG_DEBUG, "BUFFERS == NULL");
1588 cmds->tcs_command = NULL;
1589 } else
1590 syslog(LOG_DEBUG, "COMMAND == NULL");
1591
1592 if (nlp->nlp_bkmap >= 0) {
1593 (void) dbm_free(nlp->nlp_bkmap);
1594 nlp->nlp_bkmap = -1;
1595 }
1596
1597 if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) {
1598 if (nlp->nlp_rsbm < 0) {
1599 syslog(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm);
1600 } else {
1601 (void) bm_free(nlp->nlp_rsbm);
1602 nlp->nlp_rsbm = -1;
1603 }
1604 }
1605 }
1606
1607
1608 /*
1609 * backup_dirv3
1610 *
1611 * Backup a directory and update the bytes processed field of the
1612 * data server.
1613 *
1614 * Parameters:
1615 * bpp (input) - pointer to the backup parameters structure
1616 * pnp (input) - pointer to the path node
1617 * enp (input) - pointer to the entry node
1618 *
1619 * Returns:
1620 * 0: on success
1621 * != 0: otherwise
1622 */
1623 static int
1624 backup_dirv3(bk_param_v3_t *bpp, fst_node_t *pnp,
1625 fst_node_t *enp)
1626 {
1627 longlong_t apos, bpos;
1628 acl_t *aclp = NULL;
1629 char *acltp;
1630 struct stat64 st;
1631 char fullpath[TLM_MAX_PATH_NAME];
1632 char *p;
1633
1634 if (!bpp || !pnp || !enp) {
1635 syslog(LOG_ERR, "Invalid argument in backup_dirv3");
1636 return (-1);
1637 }
1638
1639 if (lstat64(bpp->bp_tmp, &st) != 0)
1640 return (0);
1641
1642 if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) {
1643 syslog(LOG_DEBUG, "acl_get error errno=%d", errno);
1644 return (-1);
1645 }
1646 if (aclp && (acltp = acl_totext(aclp,
1647 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
1648 (void) strlcpy(bpp->bp_tlmacl->acl_info.attr_info,
1649 acltp, TLM_MAX_ACL_TXT);
1650 acl_free(aclp);
1651 free(acltp);
1652 } else {
1653 *bpp->bp_tlmacl->acl_info.attr_info = '\0';
1654 }
1655
1656 bpos = tlm_get_data_offset(bpp->bp_lcmd);
1657
1658 p = bpp->bp_tmp + strlen(bpp->bp_chkpnm);
1659 if (*p == '/')
1660 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s%s",
1661 bpp->bp_unchkpnm, p);
1662 else
1663 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s",
1678 /*
1679 * backup_filev3
1680 *
1681 * Backup a file and update the bytes processed field of the
1682 * data server.
1683 *
1684 * Parameters:
1685 * bpp (input) - pointer to the backup parameters structure
1686 * pnp (input) - pointer to the path node
1687 * enp (input) - pointer to the entry node
1688 *
1689 * Returns:
1690 * 0: on success
1691 * != 0: otherwise
1692 */
1693 static int
1694 backup_filev3(bk_param_v3_t *bpp, fst_node_t *pnp,
1695 fst_node_t *enp)
1696 {
1697 char *ent;
1698 int rv = -1;
1699 longlong_t apos, bpos;
1700 acl_t *aclp = NULL;
1701 char *acltp;
1702 struct stat64 st;
1703 char fullpath[TLM_MAX_PATH_NAME];
1704 char *p;
1705
1706 if (!bpp || !pnp || !enp) {
1707 syslog(LOG_ERR, "Invalid argument in backup_filev3");
1708 return (-1);
1709 }
1710
1711 if (lstat64(bpp->bp_tmp, &st) != 0)
1712 return (0);
1713
1714 if (!S_ISLNK(bpp->bp_tlmacl->acl_attr.st_mode)) {
1715 if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) {
1716 syslog(LOG_DEBUG, "acl_get error");
1717 return (-1);
1718 }
1719
1720 if (aclp &&
1721 (acltp = acl_totext(aclp,
1722 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
1723 (void) strlcpy(bpp->bp_tlmacl->acl_info.attr_info,
1724 acltp, TLM_MAX_ACL_TXT);
1725 acl_free(aclp);
1726 free(acltp);
1727 } else {
1728 *bpp->bp_tlmacl->acl_info.attr_info = '\0';
1729 }
1730 }
1731
1732 bpos = tlm_get_data_offset(bpp->bp_lcmd);
1733 ent = enp->tn_path ? enp->tn_path : "";
1734
1735 p = pnp->tn_path + strlen(bpp->bp_chkpnm);
1736 if (*p == '/')
1761 * - The bpp itself.
1762 * - If the session pointer of the bpp is valid.
1763 * - If the session connection to the DMA is closed.
1764 * - If the nlp pointer of the bpp is valid.
1765 * - If the backup is aborted.
1766 *
1767 * Parameters:
1768 * bpp (input) - pointer to the backup parameters structure
1769 *
1770 * Returns:
1771 * 0: if everything's OK
1772 * != 0: otherwise
1773 */
1774 static int
1775 check_bk_args(bk_param_v3_t *bpp)
1776 {
1777 int rv;
1778
1779 if (!bpp) {
1780 rv = -1;
1781 syslog(LOG_DEBUG, "Lost bpp");
1782 } else if (!bpp->bp_session) {
1783 rv = -1;
1784 syslog(LOG_DEBUG, "Session is NULL");
1785 } else if (bpp->bp_session->ns_eof) {
1786 rv = -1;
1787 syslog(LOG_INFO,
1788 "Connection client is closed for backup \"%s\"",
1789 bpp->bp_nlp->nlp_backup_path);
1790 } else if (!bpp->bp_nlp) {
1791 syslog(LOG_DEBUG, "Lost nlp");
1792 return (-1);
1793 } else if (bpp->bp_session->ns_data.dd_abort) {
1794 rv = -1;
1795 syslog(LOG_INFO, "Backup aborted \"%s\"",
1796 bpp->bp_nlp->nlp_backup_path);
1797 } else
1798 rv = 0;
1799
1800 return (rv);
1801 }
1802
1803
1804 /*
1805 * shouldskip
1806 *
1807 * Determines if the current entry should be skipped or it
1808 * should be backed up.
1809 *
1810 * Parameters:
1811 * bpp (input) - pointer to the backup parameters structure
1812 * pnp (input) - pointer to the path node
1813 * enp (input) - pointer to the entry node
1814 * errp (output) - pointer to the error value that should be
1815 * returned by the caller
1816 *
1817 * Returns:
1818 * TRUE: if the entry should not be backed up
1819 * FALSE: otherwise
1820 */
1821 static boolean_t
1822 shouldskip(bk_param_v3_t *bpp, fst_node_t *pnp,
1823 fst_node_t *enp, int *errp)
1824 {
1825 char *ent;
1826 boolean_t rv;
1827 struct stat64 *estp;
1828
1829 if (!bpp || !pnp || !enp || !errp) {
1830 syslog(LOG_DEBUG, "Invalid argument in shouldskip");
1831 return (TRUE);
1832 }
1833
1834 if (!enp->tn_path) {
1835 ent = "";
1836 estp = pnp->tn_st;
1837 } else {
1838 ent = enp->tn_path;
1839 estp = enp->tn_st;
1840 }
1841
1842 /*
1843 * When excluding or skipping entries, FST_SKIP should be
1844 * returned, otherwise, 0 should be returned to
1845 * get other entries in the directory of this entry.
1846 */
1847 if (!dbm_getone(bpp->bp_nlp->nlp_bkmap, (u_longlong_t)estp->st_ino)) {
1848 rv = TRUE;
1849 *errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;
1850 } else if (tlm_is_excluded(pnp->tn_path, ent, bpp->bp_excls)) {
1851 rv = TRUE;
1852 *errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;
1853 } else if (inexl(bpp->bp_nlp->nlp_exl, ent)) {
1854 rv = TRUE;
1855 *errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;
1856 } else if (!S_ISDIR(estp->st_mode) &&
1857 !ininc(bpp->bp_nlp->nlp_inc, ent)) {
1858 rv = TRUE;
1859 *errp = 0;
1860 } else
1861 rv = FALSE;
1862
1863 return (rv);
1864 }
1865
1866
1867 /*
1868 * ischngd
1869 *
1870 * Check if the object specified should be backed up or not.
1871 * If stp belongs to a directory and if it is marked in the
1872 * bitmap vector, it shows that either the directory itself is
1873 * modified or there is something below it that will be backed
1874 * up.
1875 *
1876 * By setting ndmp_force_bk_dirs global variable to a non-zero
1877 * value, directories are backed up anyways.
1878 *
1879 * Backing up the directories unconditionally helps
1880 * restoring the metadata of directories as well, when one
1881 * of the objects below them are being restored.
1882 *
1883 * For non-directory objects, if the modification or change
1884 * time of the object is after the date specified by the
1885 * bk_selector_t, the the object must be backed up.
1886 */
1887 static boolean_t
1888 ischngd(struct stat64 *stp, time_t t, ndmp_lbr_params_t *nlp)
1889 {
1890 boolean_t rv;
1891
1892 if (!stp) {
1893 rv = FALSE;
1894 syslog(LOG_DEBUG, "stp is NULL");
1895 } else if (!nlp) {
1896 rv = FALSE;
1897 syslog(LOG_DEBUG, "nlp is NULL");
1898 } else if (t == 0) {
1899 /*
1900 * if we are doing base backup then we do not need to
1901 * check the time, for we should backup everything.
1902 */
1903 rv = TRUE;
1904 } else if (S_ISDIR(stp->st_mode) && ndmp_force_bk_dirs) {
1905 rv = TRUE;
1906 } else if (S_ISDIR(stp->st_mode) &&
1907 dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino) &&
1908 ((NLP_ISDUMP(nlp) && ndmp_dump_path_node) ||
1909 (NLP_ISTAR(nlp) && ndmp_tar_path_node))) {
1910 /*
1911 * If the object is a directory and it leads to a modified
1912 * object (that should be backed up) and for that type of
1913 * backup the path nodes should be backed up, then return
1914 * TRUE.
1915 *
1916 * This is required by some DMAs like Backup Express, which
1917 * needs to receive ADD_NODE (for dump) or ADD_PATH (for tar)
1918 * for the intermediate directories of a modified object.
1919 * Other DMAs, like net_backup and net_worker, do not have such
1920 * requirement. This requirement makes sense for dump format
1921 * but for 'tar' format, it does not. In provision to the
1922 * NDMP-v4 spec, for 'tar' format the intermediate directories
1923 * need not to be reported.
1924 */
1925 rv = TRUE;
1926 } else if (stp->st_mtime > t) {
1927 rv = TRUE;
1928 } else if (stp->st_ctime > t) {
1929 if (NLP_IGNCTIME(nlp)) {
1930 rv = FALSE;
1931 syslog(LOG_DEBUG, "ign c(%lu): %lu > %lu",
1932 (uint_t)stp->st_ino, (uint_t)stp->st_ctime,
1933 (uint_t)t);
1934 } else {
1935 rv = TRUE;
1936 syslog(LOG_DEBUG, "c(%lu): %lu > %lu",
1937 (uint_t)stp->st_ino, (uint_t)stp->st_ctime,
1938 (uint_t)t);
1939 }
1940 } else {
1941 rv = FALSE;
1942 syslog(LOG_DEBUG, "mc(%lu): (%lu,%lu) < %lu",
1943 (uint_t)stp->st_ino, (uint_t)stp->st_mtime,
1944 (uint_t)stp->st_ctime, (uint_t)t);
1945 }
1946
1947 return (rv);
1948 }
1949
1950
1951 /*
1952 * iscreated
1953 *
1954 * This function is used to check last mtime (currently inside the ACL
1955 * structure) instead of ctime for checking if the file is to be backed up
1956 * or not. See option "inc.lmtime" for more details
1957 */
1958 /*ARGSUSED*/
1959 int iscreated(ndmp_lbr_params_t *nlp, char *name, tlm_acls_t *tacl,
1960 time_t t)
1961 {
1962 int ret;
1963 acl_t *aclp = NULL;
1964 char *acltp;
1965
1966 syslog(LOG_DEBUG, "flags %x", nlp->nlp_flags);
1967 if (NLP_INCLMTIME(nlp) == FALSE)
1968 return (0);
1969
1970 ret = acl_get(name, ACL_NO_TRIVIAL, &aclp);
1971 if (ret != 0) {
1972 syslog(LOG_DEBUG,
1973 "Error getting the acl information: err %d", ret);
1974 return (0);
1975 }
1976 if (aclp && (acltp = acl_totext(aclp,
1977 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
1978 (void) strlcpy(tacl->acl_info.attr_info, acltp,
1979 TLM_MAX_ACL_TXT);
1980 acl_free(aclp);
1981 free(acltp);
1982 }
1983
1984 /* Need to add support for last mtime */
1985
1986 return (0);
1987 }
1988
1989 /*
1990 * size_cb
1991 *
1992 * The callback function for calculating the size of
2038 rv = check_bk_args(bpp);
2039 if (rv != 0)
2040 return (rv);
2041
2042 stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2043 if (shouldskip(bpp, pnp, enp, &rv))
2044 return (rv);
2045
2046 if (enp->tn_path) {
2047 ent = enp->tn_path;
2048 stp = enp->tn_st;
2049 fhp = enp->tn_fh;
2050 } else {
2051 ent = "";
2052 stp = pnp->tn_st;
2053 fhp = pnp->tn_fh;
2054 }
2055
2056
2057 if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) {
2058 syslog(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent);
2059 return (FST_SKIP);
2060 }
2061 if (NLP_ISSET(bpp->bp_nlp, NLPF_TOKENBK))
2062 t = bpp->bp_nlp->nlp_tokdate;
2063 else if (NLP_ISSET(bpp->bp_nlp, NLPF_LEVELBK)) {
2064 t = bpp->bp_nlp->nlp_ldate;
2065 } else {
2066 syslog(LOG_ERR, "Unknown backup type on \"%s/%s\"",
2067 pnp->tn_path, ent);
2068 return (-1);
2069 }
2070
2071 if (S_ISDIR(stp->st_mode)) {
2072 bpp->bp_tlmacl->acl_dir_fh = *fhp;
2073 (void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks,
2074 bpp->bp_tmp, stp);
2075
2076 if (ischngd(stp, t, bpp->bp_nlp)) {
2077 (void) memcpy(&bpp->bp_tlmacl->acl_attr, stp,
2078 sizeof (struct stat64));
2079 rv = backup_dirv3(bpp, pnp, enp);
2080 }
2081 } else {
2082 if (ischngd(stp, t, bpp->bp_nlp) ||
2083 iscreated(bpp->bp_nlp, bpp->bp_tmp, bpp->bp_tlmacl, t)) {
2084 rv = 0;
2085 (void) memcpy(&bpp->bp_tlmacl->acl_attr, stp,
2086 sizeof (struct stat64));
2123 bpp = (bk_param_v3_t *)arg;
2124 rv = check_bk_args(bpp);
2125 if (rv != 0)
2126 return (rv);
2127
2128 stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2129 if (shouldskip(bpp, pnp, enp, &rv))
2130 return (rv);
2131
2132 if (enp->tn_path) {
2133 ent = enp->tn_path;
2134 stp = enp->tn_st;
2135 fhp = enp->tn_fh;
2136 } else {
2137 ent = "";
2138 stp = pnp->tn_st;
2139 fhp = pnp->tn_fh;
2140 }
2141
2142 if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) {
2143 syslog(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent);
2144 return (FST_SKIP);
2145 }
2146 if (!NLP_ISSET(bpp->bp_nlp, NLPF_LBRBK)) {
2147 syslog(LOG_DEBUG, "!NLPF_LBRBK");
2148 return (-1);
2149 }
2150
2151 if (S_ISDIR(stp->st_mode)) {
2152 bpp->bp_tlmacl->acl_dir_fh = *fhp;
2153 (void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks,
2154 bpp->bp_tmp, stp);
2155
2156 if (SHOULD_LBRBK(bpp)) {
2157 bpp->bp_tlmacl->acl_attr = *stp;
2158 rv = backup_dirv3(bpp, pnp, enp);
2159 }
2160 } else if (SHOULD_LBRBK(bpp)) {
2161 rv = 0;
2162 bpp->bp_tlmacl->acl_attr = *stp;
2163 bpp->bp_tlmacl->acl_fil_fh = *fhp;
2164 (void) backup_filev3(bpp, pnp, enp);
2165 }
2166
2167 return (rv);
2168 }
2169
2170
2171 /*
2172 * backup_reader_v3
2173 *
2174 * The reader thread for the backup. It sets up the callback
2175 * parameters and traverses the backup hierarchy in level-order
2176 * way.
2177 *
2178 * Parameters:
2179 * argp (input) - backup reader argument
2180 *
2181 * Returns:
2182 * 0: on success
2183 * != 0: otherwise
2184 */
2185 static int
2186 backup_reader_v3(backup_reader_arg_t *argp)
2187 {
2188 int rv;
2189 tlm_cmd_t *lcmd;
2190 tlm_acls_t tlm_acls;
2191 longlong_t bpos, n;
2192 bk_param_v3_t bp;
2193 fs_traverse_t ft;
2194 ndmp_lbr_params_t *nlp;
2195 tlm_commands_t *cmds;
2196 int rc;
2197
2198 if (!argp)
2199 return (-1);
2200
2201 nlp = argp->br_nlp;
2202 cmds = argp->br_cmds;
2203
2204 rv = 0;
2205 lcmd = cmds->tcs_command;
2206 lcmd->tc_ref++;
2207 cmds->tcs_reader_count++;
2208
2209 (void) memset(&tlm_acls, 0, sizeof (tlm_acls));
2210
2211 /* NDMP parameters */
2212 bp.bp_session = nlp->nlp_session;
2213 bp.bp_nlp = nlp;
2214
2215 /* LBR-related parameters */
2216 bp.bp_js = tlm_ref_job_stats(nlp->nlp_job_name);
2217 bp.bp_cmds = cmds;
2218 bp.bp_lcmd = lcmd;
2219 bp.bp_tlmacl = &tlm_acls;
2220 bp.bp_opr = 0;
2221
2222 /* release the parent thread, after referencing the job stats */
2223 rc = pthread_barrier_wait(&argp->br_barrier);
2224 if (rc == PTHREAD_BARRIER_SERIAL_THREAD) {
2225 (void) pthread_barrier_destroy(&argp->br_barrier);
2226 }
2227
2228 bp.bp_tmp = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
2229 if (!bp.bp_tmp)
2230 return (-1);
2231
2232 /*
2233 * Make the checkpointed paths for traversing the
2234 * backup hierarchy, if we make the checkpoint.
2235 */
2236 bp.bp_unchkpnm = nlp->nlp_backup_path;
2237 if (!NLP_ISCHKPNTED(nlp)) {
2238 tlm_acls.acl_checkpointed = FALSE;
2239 bp.bp_chkpnm = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
2240 if (!bp.bp_chkpnm) {
2241 NDMP_FREE(bp.bp_tmp);
2242 return (-1);
2243 }
2244 (void) tlm_build_snapshot_name(nlp->nlp_backup_path,
2245 bp.bp_chkpnm, nlp->nlp_jstat->js_job_name);
2246 } else {
2247 tlm_acls.acl_checkpointed = TRUE;
2248 bp.bp_chkpnm = nlp->nlp_mountpoint;
2249 }
2250 bp.bp_excls = ndmpd_make_exc_list();
2251
2252 /* set traversing arguments */
2253 ft.ft_path = nlp->nlp_backup_path;
2254 ft.ft_lpath = bp.bp_chkpnm;
2255
2256 if (NLP_ISSET(nlp, NLPF_TOKENBK) || NLP_ISSET(nlp, NLPF_LEVELBK)) {
2257 ft.ft_callbk = timebk_v3;
2258 tlm_acls.acl_clear_archive = FALSE;
2259 } else if (NLP_ISSET(nlp, NLPF_LBRBK)) {
2260 ft.ft_callbk = lbrbk_v3;
2261 tlm_acls.acl_clear_archive = FALSE;
2262
2263 syslog(LOG_DEBUG, "bp_opr %x clr_arc %c",
2264 bp.bp_opr, NDMP_YORN(tlm_acls.acl_clear_archive));
2265 } else {
2266 rv = -1;
2267 MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR,
2268 "Unknown backup type.\n");
2269 }
2270
2271 ft.ft_arg = &bp;
2272 ft.ft_logfp = (ft_log_t)syslog;
2273 ft.ft_flags = FST_VERBOSE | FST_STOP_ONERR;
2274
2275 syslog(LOG_DEBUG, "Traverse logical path [%s]", ft.ft_lpath);
2276
2277 /* take into account the header written to the stream so far */
2278 n = tlm_get_data_offset(lcmd);
2279 nlp->nlp_session->ns_data.dd_module.dm_stats.ms_bytes_processed = n;
2280
2281 if (rv == 0) {
2282 /* start traversing the hierarchy and actual backup */
2283 rv = traverse_level(&ft);
2284 if (rv == 0) {
2285 /* write the trailer and update the bytes processed */
2286 bpos = tlm_get_data_offset(lcmd);
2287 (void) write_tar_eof(lcmd);
2288 n = tlm_get_data_offset(lcmd) - bpos;
2289 nlp->nlp_session->
2290 ns_data.dd_module.dm_stats.ms_bytes_processed += n;
2291 } else {
2292 MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR,
2293 "Filesystem traverse error.\n");
2294 ndmpd_data_error(nlp->nlp_session,
2295 NDMP_DATA_HALT_INTERNAL_ERROR);
2296 }
2297 }
2298
2299 if (!NLP_ISCHKPNTED(nlp))
2300 NDMP_FREE(bp.bp_chkpnm);
2301 NDMP_FREE(bp.bp_tmp);
2302 NDMP_FREE(bp.bp_excls);
2303
2304 cmds->tcs_reader_count--;
2305 lcmd->tc_writer = TLM_STOP;
2306 tlm_release_reader_writer_ipc(lcmd);
2307 tlm_un_ref_job_stats(nlp->nlp_job_name);
2308
2309 return (rv);
2310 }
2311
2312
2313 /*
2314 * tar_backup_v3
2315 *
2316 * Traverse the backup hierarchy if needed and make the bitmap.
2317 * Then launch reader and writer threads to do the actual backup.
2318 *
2319 * Parameters:
2320 * session (input) - pointer to the session
2321 * params (input) - pointer to the parameters structure
2322 * nlp (input) - pointer to the nlp structure
2323 *
2324 * Returns:
2325 * 0: on success
2326 * != 0: otherwise
2327 */
2328 static int
2329 tar_backup_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
2330 ndmp_lbr_params_t *nlp)
2331 {
2332 tlm_commands_t *cmds;
2333 backup_reader_arg_t arg;
2334 pthread_t rdtp;
2335 char info[256];
2336 int result;
2337 ndmp_context_t nctx;
2338 int err;
2339 int rc;
2340
2341 if (ndmp_get_bk_dir_ino(nlp)) {
2342 syslog(LOG_ERR, "Couldn't get backup directory inode");
2343 return (-1);
2344 }
2345
2346 result = err = 0;
2347
2348 /* exit as if there was an internal error */
2349 if (session->ns_eof) {
2350 return (-1);
2351 }
2352 if (!session->ns_data.dd_abort) {
2353 if (backup_alloc_structs_v3(session) < 0) {
2354 nlp->nlp_bkmap = -1;
2355 return (-1);
2356 }
2357
2358 if (ndmpd_mark_inodes_v3(session, nlp) != 0) {
2359 if (nlp->nlp_bkmap != -1) {
2360 (void) dbm_free(nlp->nlp_bkmap);
2361 nlp->nlp_bkmap = -1;
2362 }
2363 free_structs_v3(session);
2364 return (-1);
2365 }
2366
2367 nlp->nlp_jstat->js_start_ltime = time(NULL);
2368 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
2369 nlp->nlp_jstat->js_chkpnt_time = nlp->nlp_cdate;
2370
2371 cmds = &nlp->nlp_cmds;
2372 cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
2373 cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
2374 cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
2375
2376 if (ndmp_write_utf8magic(cmds->tcs_command) < 0) {
2377 free_structs_v3(session);
2378 return (-1);
2379 }
2380
2381 syslog(LOG_DEBUG, "Backing up \"%s\" started.",
2382 NLP_ISCHKPNTED(nlp)
2383 ? nlp->nlp_mountpoint : nlp->nlp_backup_path);
2384
2385 /* Plug-in module */
2386 if (ndmp_pl != NULL &&
2387 ndmp_pl->np_pre_backup != NULL) {
2388 (void) memset(&nctx, 0, sizeof (ndmp_context_t));
2389 nctx.nc_plversion = ndmp_pl->np_plversion;
2390 nctx.nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
2391 nctx.nc_cmds = cmds;
2392 nctx.nc_params = params;
2393 nctx.nc_ddata = (void *) session;
2394 if ((err = ndmp_pl->np_pre_backup(ndmp_pl, &nctx,
2395 nlp->nlp_backup_path)) != 0) {
2396 syslog(LOG_ERR, "Pre-backup plug-in: %m");
2397 goto backup_out;
2398 }
2399 }
2400
2401 (void) memset(&arg, 0, sizeof (backup_reader_arg_t));
2402 arg.br_nlp = nlp;
2403 arg.br_cmds = cmds;
2404
2405 (void) pthread_barrier_init(&arg.br_barrier, 0, 2);
2406
2407 err = pthread_create(&rdtp, NULL, (funct_t)backup_reader_v3,
2408 (void *)&arg);
2409 if (err == 0) {
2410 rc = pthread_barrier_wait(&arg.br_barrier);
2411 if (rc == PTHREAD_BARRIER_SERIAL_THREAD) {
2412 (void) pthread_barrier_destroy(&arg.br_barrier);
2413 }
2414 } else {
2415 (void) pthread_barrier_destroy(&arg.br_barrier);
2416 free_structs_v3(session);
2417 syslog(LOG_ERR, "Launch backup_reader_v3 failed on %s",
2418 nlp->nlp_job_name);
2419 return (-1);
2420 }
2421
2422 if ((err = ndmp_tar_writer(session, params, cmds)) != 0)
2423 result = EIO;
2424
2425 nlp->nlp_jstat->js_stop_time = time(NULL);
2426
2427 (void) snprintf(info, sizeof (info),
2428 "Runtime [%s] %lu bytes (%lu): %d seconds\n",
2429 nlp->nlp_backup_path,
2430 session->ns_data.dd_module.dm_stats.ms_bytes_processed,
2431 session->ns_data.dd_module.dm_stats.ms_bytes_processed,
2432 nlp->nlp_jstat->js_stop_time -
2433 nlp->nlp_jstat->js_start_ltime);
2434 MOD_LOGV3(params, NDMP_LOG_NORMAL, info);
2435
2436 ndmp_wait_for_reader(cmds);
2437 (void) pthread_join(rdtp, NULL);
2438 /* exit as if there was an internal error */
2439 if (session->ns_eof) {
2440 result = EPIPE;
2441 err = -1;
2442 }
2443 if (!session->ns_data.dd_abort) {
2444 ndmpd_audit_backup(session->ns_connection,
2445 nlp->nlp_backup_path,
2446 session->ns_data.dd_data_addr.addr_type,
2447 session->ns_tape.td_adapter_name, result);
2448 syslog(LOG_DEBUG, "Backing up \"%s\" Finished.",
2449 NLP_ISCHKPNTED(nlp) ?
2450 nlp->nlp_mountpoint : nlp->nlp_backup_path);
2451 }
2452 }
2453
2454 if (session->ns_data.dd_abort) {
2455 ndmpd_audit_backup(session->ns_connection,
2456 nlp->nlp_backup_path,
2457 session->ns_data.dd_data_addr.addr_type,
2458 session->ns_tape.td_adapter_name, EINTR);
2459 syslog(LOG_INFO, "Backing up \"%s\" aborted.",
2460 NLP_ISCHKPNTED(nlp) ?
2461 nlp->nlp_mountpoint : nlp->nlp_backup_path);
2462 err = -1;
2463 } else {
2464
2465 backup_out:
2466 /* Plug-in module */
2467 if (ndmp_pl != NULL &&
2468 ndmp_pl->np_post_backup != NULL &&
2469 ndmp_pl->np_post_backup(ndmp_pl, &nctx, err) == -1) {
2470 syslog(LOG_ERR, "Post-backup plug-in: %m");
2471 return (-1);
2472 }
2473 }
2474
2475 free_structs_v3(session);
2476 return (err);
2477 }
2478
2479 /*
2480 * get_backup_size
2481 *
2482 * Find the estimate of backup size. This is used to get an estimate
2483 * of the progress of backup during NDMP backup.
2484 */
2485 void
2486 get_backup_size(ndmp_lbr_params_t *nlp)
2487 {
2488 fs_traverse_t ft;
2489 u_longlong_t bk_size = 0;
2490 char buf[256];
2491 char spath[PATH_MAX];
2492 int rv;
2493
2494 if (NLP_ISCHKPNTED(nlp)) {
2495 ft.ft_path = nlp->nlp_mountpoint;
2496 } else {
2497 (void) tlm_build_snapshot_name(nlp->nlp_backup_path,
2498 spath, nlp->nlp_job_name);
2499 ft.ft_path = spath;
2500 }
2501
2502 ft.ft_lpath = ft.ft_path;
2503 ft.ft_callbk = size_cb;
2504 ft.ft_arg = &bk_size;
2505 ft.ft_logfp = (ft_log_t)syslog;
2506 ft.ft_flags = FST_VERBOSE;
2507
2508 if ((rv = traverse_level(&ft)) != 0) {
2509 syslog(LOG_DEBUG, "bksize err=%d", rv);
2510 syslog(LOG_DEBUG, "[%s] backup will be reported as [0]\n",
2511 nlp->nlp_job_name, buf);
2512 bk_size = 0;
2513 } else {
2514 (void) zfs_nicenum(bk_size, buf, sizeof (buf));
2515 syslog(LOG_DEBUG, "[%s] backup size is [%s]\n",
2516 nlp->nlp_job_name, buf);
2517 }
2518
2519 nlp->nlp_session->ns_data.dd_data_size = bk_size;
2520 }
2521
2522 /*
2523 * get_rs_path_v3
2524 *
2525 * Find the restore path
2526 */
2527 ndmp_error
2528 get_rs_path_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
2529 {
2530 char *dp;
2531 ndmp_error rv = -1;
2532 mem_ndmp_name_v3_t *ep;
2533 int i, nm_cnt;
2534 char *nm_dpath_list[MULTIPLE_DEST_DIRS];
2535 static char mdest_buf[256];
2536
2537 *mdest_buf = 0;
2538 *nm_dpath_list = "";
2539 for (i = 0, nm_cnt = 0; i < (int)nlp->nlp_nfiles; i++) {
2540 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
2541 if (!ep) {
2542 syslog(LOG_ERR, "Can't get Nlist[%d]", i);
2543 return (NDMP_ILLEGAL_ARGS_ERR);
2544 }
2545 if (strcmp(nm_dpath_list[nm_cnt], ep->nm3_dpath) != 0 &&
2546 nm_cnt < MULTIPLE_DEST_DIRS - 1)
2547 nm_dpath_list[++nm_cnt] = ep->nm3_dpath;
2548 }
2549
2550 multiple_dest_restore = (nm_cnt > 1);
2551 nlp->nlp_restore_path = mdest_buf;
2552
2553 for (i = 1; i < nm_cnt + 1; i++) {
2554 if (ISDEFINED(nm_dpath_list[i]))
2555 dp = nm_dpath_list[i];
2556 else
2557 /* the default destination path is backup directory */
2558 dp = nlp->nlp_backup_path;
2559
2560 /* check the destination directory exists and is writable */
2561 if (!fs_volexist(dp)) {
2562 rv = NDMP_ILLEGAL_ARGS_ERR;
2563 MOD_LOGV3(params, NDMP_LOG_ERROR,
2564 "Invalid destination path volume \"%s\".\n", dp);
2565 } else if (!voliswr(dp)) {
2566 rv = NDMP_ILLEGAL_ARGS_ERR;
2567 MOD_LOGV3(params, NDMP_LOG_ERROR,
2568 "The destination path volume"
2569 " is not writable \"%s\".\n", dp);
2570 } else {
2571 rv = NDMP_NO_ERR;
2572 (void) strlcat(nlp->nlp_restore_path, dp,
2573 sizeof (mdest_buf));
2574 syslog(LOG_DEBUG, "rspath: \"%s\"", dp);
2575 }
2576
2577 /*
2578 * Exit if there is an error or it is not a multiple
2579 * destination restore mode
2580 */
2581 if (rv != NDMP_NO_ERR || !multiple_dest_restore)
2582 break;
2583
2584 if (i < nm_cnt)
2585 (void) strlcat(nlp->nlp_restore_path, ", ",
2586 sizeof (mdest_buf));
2587 }
2588
2589 return (rv);
2590 }
2591
2592
2593 /*
2594 * fix_nlist_v3
2724 bp = joinpath(buf, nlp->nlp_backup_path, ep->nm3_opath);
2725 if (!bp) {
2726 /*
2727 * Note: The same problem of above with long path.
2728 */
2729 MOD_LOGV3(params, NDMP_LOG_ERROR,
2730 "Path too long(%s/%s)",
2731 nlp->nlp_backup_path, ep->nm3_opath);
2732 continue;
2733 }
2734 cp = strdup(bp);
2735 if (!cp) {
2736 MOD_LOGV3(params, NDMP_LOG_ERROR,
2737 "Insufficient memory.\n");
2738 rv = NDMP_NO_MEM_ERR;
2739 break;
2740 }
2741 NDMP_FREE(ep->nm3_opath);
2742 ep->nm3_opath = cp;
2743
2744 syslog(LOG_DEBUG, "orig[%d]: \"%s\"", i, ep->nm3_opath);
2745 if (ep->nm3_dpath) {
2746 syslog(LOG_DEBUG,
2747 "dest[%d]: \"%s\"", i, ep->nm3_dpath);
2748 } else {
2749 syslog(LOG_INFO, "dest[%d]: \"%s\"", i, "NULL");
2750 }
2751 }
2752
2753 free(buf);
2754
2755 return (rv);
2756 }
2757
2758
2759 /*
2760 * allvalidfh
2761 *
2762 * Run a sanity check on the file history info. The file history
2763 * info is the offset of the record starting the entry on the tape
2764 * and is used in DAR (direct access restore mode).
2765 */
2766 static boolean_t
2767 allvalidfh(ndmpd_session_t *session, ndmpd_module_params_t *params)
2768 {
2769 int i, n;
2824
2825 if (NLP_ISSET(nlp, NLPF_DIRECT))
2826 MOD_LOGV3(params, NDMP_LOG_NORMAL,
2827 "Direct Access Restore.\n");
2828 }
2829
2830
2831 /*
2832 * send_unrecovered_list_v3
2833 *
2834 * Create the list of files that were in restore list but
2835 * not recovered due to some errors.
2836 */
2837 int
2838 send_unrecovered_list_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
2839 {
2840 int i, rv;
2841 int err;
2842
2843 if (!params) {
2844 syslog(LOG_ERR, "params == NULL");
2845 return (-1);
2846 }
2847 if (!nlp) {
2848 syslog(LOG_ERR, "nlp == NULL");
2849 return (-1);
2850 }
2851
2852 if (nlp->nlp_lastidx != -1) {
2853 if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)nlp->nlp_lastidx))
2854 err = ENOENT;
2855 else
2856 err = 0;
2857 (void) ndmp_send_recovery_stat_v3(params, nlp,
2858 nlp->nlp_lastidx, err);
2859 nlp->nlp_lastidx = -1;
2860 }
2861
2862 rv = 0;
2863 for (i = 0; i < (int)nlp->nlp_nfiles; i++) {
2864 if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)i)) {
2865 rv = ndmp_send_recovery_stat_v3(params, nlp, i, ENOENT);
2866 if (rv < 0)
2867 break;
2868 }
2869 }
2870
2871 return (rv);
2872 }
2873
2874
2875
2876 /*
2877 * restore_dar_alloc_structs_v3
2878 *
2879 * Allocates the necessary structures for running DAR restore.
2880 * It just creates the reader writer IPC.
2881 * This function is called for each entry in the restore entry list.
2882 *
2883 * Parameters:
2884 * session (input) - pointer to the session
2885 *
2886 * Returns:
2887 * 0: on success
2888 * -1: on error
2889 */
2890 int
2891 restore_dar_alloc_structs_v3(ndmpd_session_t *session)
2892 {
2893 long xfer_size;
2894 ndmp_lbr_params_t *nlp;
2895 tlm_commands_t *cmds;
2896
2897 nlp = ndmp_get_nlp(session);
2898 if (!nlp) {
2899 syslog(LOG_ERR, "nlp == NULL");
2900 return (-1);
2901 }
2902
2903 cmds = &nlp->nlp_cmds;
2904 (void) memset(cmds, 0, sizeof (*cmds));
2905
2906 xfer_size = ndmp_buffer_get_size(session);
2907 cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
2908 if (!cmds->tcs_command) {
2909 tlm_un_ref_job_stats(nlp->nlp_job_name);
2910 return (-1);
2911 }
2912
2913 return (0);
2914 }
2915
2916
2917 /*
2918 * free_dar_structs_v3
2919 *
2920 * To free the structures were created by restore_dar_alloc_structs_v3.
2921 * This funnction is called for each entry in restore entry list.
2922 *
2923 * Parameters:
2924 * session (input) - pointer to the session
2925 *
2926 * Returns:
2927 * NONE
2928 */
2929 /*ARGSUSED*/
2930 static void
2931 free_dar_structs_v3(ndmpd_session_t *session)
2932 {
2933 ndmp_lbr_params_t *nlp;
2934 tlm_commands_t *cmds;
2935
2936 nlp = ndmp_get_nlp(session);
2937 if (!nlp) {
2938 syslog(LOG_DEBUG, "nlp == NULL");
2939 return;
2940 }
2941 cmds = &nlp->nlp_cmds;
2942 if (!cmds) {
2943 syslog(LOG_DEBUG, "cmds == NULL");
2944 return;
2945 }
2946
2947 if (cmds->tcs_command) {
2948 if (cmds->tcs_command->tc_buffers != NULL)
2949 tlm_release_reader_writer_ipc(cmds->tcs_command);
2950 else
2951 syslog(LOG_DEBUG, "BUFFERS == NULL");
2952 cmds->tcs_command = NULL;
2953 } else
2954 syslog(LOG_DEBUG, "COMMAND == NULL");
2955 }
2956
2957
2958 /*
2959 * ndmp_dar_tar_init_v3
2960 *
2961 * Constructor for the DAR restore. Creates job name, allocates structures
2962 * needed for keeping the statistics, and reports the start of restore action.
2963 * It is called once for each DAR restore request.
2964 *
2965 * Parameters:
2966 * session (input) - pointer to the session
2967 * nlp (input) - pointer to the nlp structure
2968 *
2969 * Returns:
2970 * char pointer: on success
2971 * NULL: on error
2972 */
2973 static char *ndmpd_dar_tar_init_v3(ndmpd_session_t *session,
2974 ndmp_lbr_params_t *nlp)
2975 {
2976 char *jname;
2977
2978 jname = ndmp_malloc(TLM_MAX_BACKUP_JOB_NAME);
2979
2980 if (!jname)
2981 return (NULL);
2982
2983 if (ndmp_new_job_name(jname, TLM_MAX_BACKUP_JOB_NAME) <= 0) {
2984 free(jname);
2985 return (NULL);
2986 }
2987
2988 if (!nlp) {
2989 free(jname);
2990 syslog(LOG_DEBUG, "nlp == NULL");
2991 return (NULL);
2992 }
2993
2994 nlp->nlp_jstat = tlm_new_job_stats(jname);
2995 if (!nlp->nlp_jstat) {
2996 free(jname);
2997 syslog(LOG_DEBUG, "Creating job stats");
2998 return (NULL);
2999 }
3000
3001 nlp->nlp_jstat->js_start_ltime = time(NULL);
3002 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
3003
3004 nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
3005 ndmpd_path_restored_v3, NULL, NULL);
3006 if (!nlp->nlp_logcallbacks) {
3007 tlm_un_ref_job_stats(jname);
3008 free(jname);
3009 return (NULL);
3010 }
3011 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
3012
3013 nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0);
3014 if (nlp->nlp_rsbm < 0) {
3015 syslog(LOG_ERR, "Out of memory.");
3016 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
3017 tlm_un_ref_job_stats(jname);
3018 free(jname);
3019 return (NULL);
3020 }
3021
3022 /* this is used in ndmpd_path_restored_v3() */
3023 nlp->nlp_lastidx = -1;
3024
3025 syslog(LOG_DEBUG, "Restoring from %s tape(s).",
3026 ndmp_data_get_mover_mode(session));
3027
3028 return (jname);
3029 }
3030
3031 /*
3032 * ndmpd_dar_tar_end_v3
3033 *
3034 * Deconstructor for the DAR restore. This function is called once per
3035 * DAR request. It deallocates memories allocated by ndmpd_dar_tar_init_v3.
3036 *
3037 * Parameters:
3038 * session (input) - pointer to the session
3039 * params (input) - pointer to the parameters structure
3040 * nlp (input) - pointer to the nlp structure
3041 * jname(input) - job name
3042 *
3043 * Returns:
3044 * 0: on success
3045 * -1: on error
3046 */
3047 static int ndmpd_dar_tar_end_v3(ndmpd_session_t *session,
3048 ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, char *jname)
3049 {
3050 int err = 0;
3051
3052
3053 syslog(LOG_DEBUG, "lastidx %d", nlp->nlp_lastidx);
3054
3055 /* nothing restored. */
3056 (void) send_unrecovered_list_v3(params, nlp);
3057
3058 if (nlp->nlp_jstat) {
3059 nlp->nlp_bytes_total =
3060 (u_longlong_t)nlp->nlp_jstat->js_bytes_total;
3061 tlm_un_ref_job_stats(jname);
3062 nlp->nlp_jstat = NULL;
3063 } else {
3064 syslog(LOG_DEBUG, "JSTAT == NULL");
3065 }
3066
3067 if (nlp->nlp_logcallbacks) {
3068 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
3069 nlp->nlp_logcallbacks = NULL;
3070 } else {
3071 syslog(LOG_DEBUG, "FH CALLBACKS == NULL");
3072 }
3073
3074 if (session->ns_data.dd_abort) {
3075 syslog(LOG_DEBUG, "Restoring to \"%s\" aborted.",
3076 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3077 err = EINTR;
3078 } else {
3079 syslog(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
3080 (nlp->nlp_restore_path) ? nlp->nlp_restore_path :
3081 "NULL", err);
3082 }
3083
3084 if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) {
3085 if (nlp->nlp_rsbm < 0) {
3086 syslog(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm);
3087 } else {
3088 (void) bm_free(nlp->nlp_rsbm);
3089 nlp->nlp_rsbm = -1;
3090 }
3091 }
3092
3093 free(jname);
3094
3095 return (err);
3096 }
3097
3098
3099 /*
3100 * ndmpd_dar_tar_v3
3101 *
3102 * This function is called for each entry in DAR entry list. The window
3103 * is already located and we should be in the right position to read
3104 * the data from the tape.
3105 * For each entry we setup selection list; so that, if the file name from
3106 * tape is not as the name client asked for, error be returned.
3107 *
3108 * Parameters:
3109 * session (input) - pointer to the session
3110 * params (input) - pointer to the parameters structure
3111 * nlp (input) - pointer to the nlp structure
3112 * dar_index(input) - Index of this entry in the restore list
3113 *
3114 * Returns:
3115 * 0: on success
3116 * -1: on error
3117 */
3118 static int
3119 ndmpd_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3120 ndmp_lbr_params_t *nlp, int dar_index)
3121 {
3122 char *excl;
3123 char **sels;
3124 int flags;
3125 int err;
3126 tlm_commands_t *cmds;
3127 struct rs_name_maker rn;
3128 int data_addr_type = session->ns_data.dd_data_addr.addr_type;
3129 ndmp_tar_reader_arg_t arg;
3130 pthread_t rdtp;
3131 ndmp_context_t nctx;
3132 mem_ndmp_name_v3_t *ep;
3133
3134 err = 0;
3135
3136 /*
3137 * We have to allocate and deallocate buffers every time we
3138 * run the restore, for we need to flush the buffers.
3139 */
3140 if (restore_dar_alloc_structs_v3(session) < 0)
3141 return (-1);
3142
3143 sels = setupsels(session, params, nlp, dar_index);
3144 if (!sels) {
3145 free_dar_structs_v3(session);
3146 return (-1);
3147 }
3148 excl = NULL;
3149 flags = RSFLG_OVR_ALWAYS;
3150 rn.rn_nlp = nlp;
3151 rn.rn_fp = mknewname;
3152
3153 if (!session->ns_data.dd_abort) {
3154 cmds = &nlp->nlp_cmds;
3155 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
3156 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
3157 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
3158
3159 arg.tr_session = session;
3160 arg.tr_mod_params = params;
3161 arg.tr_cmds = cmds;
3162
3163 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
3164 (void *)&arg);
3165 if (err == 0) {
3166 tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
3167 } else {
3168 syslog(LOG_ERR, "launch ndmp_tar_reader failed");
3169 return (-1);
3170 }
3171
3172 cmds->tcs_command->tc_ref++;
3173 cmds->tcs_writer_count++;
3174
3175 /* Plug-in module */
3176 if (ndmp_pl != NULL &&
3177 ndmp_pl->np_pre_restore != NULL) {
3178 (void) memset(&nctx, 0, sizeof (ndmp_context_t));
3179 nctx.nc_cmds = cmds;
3180 nctx.nc_params = params;
3181 nctx.nc_ddata = (void *) session;
3182 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params,
3183 dar_index - 1);
3184
3185 if ((err = ndmp_pl->np_pre_restore(ndmp_pl, &nctx,
3186 ep->nm3_opath, ep->nm3_dpath))
3187 != 0) {
3188 syslog(LOG_ERR, "Pre-restore plug-in: %m");
3189 ndmp_stop_local_reader(session, cmds);
3190 ndmp_wait_for_reader(cmds);
3191 (void) pthread_join(rdtp, NULL);
3192 ndmp_stop_remote_reader(session);
3193 goto restore_out;
3194 }
3195 }
3196
3197 if (tm_tar_ops.tm_getdir != NULL) {
3198 char errbuf[256];
3199
3200 err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
3201 nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags,
3202 dar_index, nlp->nlp_mountpoint,
3203 session->hardlink_q);
3204 /*
3205 * If the fatal error from tm_getdir looks like an
3206 * errno code, we send the error description to DMA.
3207 */
3208 if (err > 0 && strerror_r(err, errbuf,
3209 sizeof (errbuf)) == 0) {
3210 MOD_LOGV3(params, NDMP_LOG_ERROR,
3211 "Fatal error during the restore: %s\n",
3212 errbuf);
3213 }
3214 }
3215
3216 cmds->tcs_writer_count--;
3217 cmds->tcs_command->tc_ref--;
3218 syslog(LOG_DEBUG, "stop local reader.");
3219 ndmp_stop_local_reader(session, cmds);
3220
3221 ndmp_wait_for_reader(cmds);
3222 (void) pthread_join(rdtp, NULL);
3223
3224 /*
3225 * If this is the last DAR entry and it is a three-way
3226 * restore then we should close the connection.
3227 */
3228 if ((data_addr_type == NDMP_ADDR_TCP) &&
3229 (dar_index == (int)session->ns_data.dd_nlist_len)) {
3230 syslog(LOG_DEBUG, "stop remote reader.");
3231 ndmp_stop_remote_reader(session);
3232 }
3233
3234 /* exit as if there was an internal error */
3235 if (session->ns_eof)
3236 err = -1;
3237 restore_out:
3238 /* Plug-in module */
3239 if (ndmp_pl != NULL &&
3240 ndmp_pl->np_post_restore != NULL &&
3241 ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) {
3242 syslog(LOG_DEBUG, "Post-restore plug-in: %m");
3243 err = -1;
3244 }
3245 }
3246
3247 NDMP_FREE(sels);
3248
3249 free_dar_structs_v3(session);
3250
3251 return (err);
3252 }
3253
3254 /*
3255 * ndmpd_dar_locate_windwos_v3
3256 *
3257 * Locating the right window in which the requested file is backed up.
3258 * We should go through windows to find the exact location, for the
3259 * file can be located in for example 10th window after the current window.
3260 *
3261 * Parameters:
3262 * session (input) - pointer to the session
3263 * params (input) - pointer to the parameters structure
3264 * fh_info (input) - index from the beginning of the backup stream
3265 * len (input) - Length of the mover window
3266 *
3267 * Returns:
3268 * 0: on success
3269 * -1: on error
3270 */
3271 static int
3272 ndmpd_dar_locate_window_v3(ndmpd_session_t *session,
3273 ndmpd_module_params_t *params, u_longlong_t fh_info, u_longlong_t len)
3274 {
3275 int ret = 0;
3276
3277
3278 for (; ; ) {
3279 ret = (*params->mp_seek_func)(session, fh_info, len);
3280
3281 syslog(LOG_DEBUG, "ret %d", ret);
3282 if (ret == 0) /* Seek was done successfully */
3283 break;
3284 else if (ret < 0) {
3285 syslog(LOG_ERR,
3286 "Seek error in ndmpd_dar_locate_window_v3");
3287 break;
3288 }
3289
3290 /*
3291 * DMA moved to a new window.
3292 * If we are reading the remainig of the file from
3293 * new window, seek is handled by ndmpd_local_read_v3.
3294 * Here we should continue the seek inside the new
3295 * window.
3296 */
3297 continue;
3298 }
3299 return (ret);
3300 }
3301
3302 /*
3303 * ndmpd_rs_dar_tar_v3
3304 *
3305 * Main DAR function. It calls the constructor, then for each entry it
3306 * calls the locate_window_v3 to find the exact position of the file. Then
3327 int n = session->ns_data.dd_nlist_len;
3328 int i, ret = 0;
3329 int result = 0;
3330
3331 jname = ndmpd_dar_tar_init_v3(session, nlp);
3332
3333 if (!jname)
3334 return (-1);
3335
3336 /*
3337 * We set the length = sizeof (tlm_tar_hdr_t)
3338 * This is important for three-way DAR restore, for we should
3339 * read the header first (If we ask for more data then we have
3340 * to read and discard the remaining data in the socket)
3341 */
3342 len = tlm_tarhdr_size();
3343
3344 for (i = 0; i < n; ++i) {
3345 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
3346 if (!ep) {
3347 syslog(LOG_DEBUG, "ep NULL, i %d", i);
3348 continue;
3349 }
3350 syslog(LOG_DEBUG,
3351 "restoring opath %s, dpath %s, fh_info %lld",
3352 ep->nm3_opath ? ep->nm3_opath : "NULL",
3353 ep->nm3_dpath ? ep->nm3_dpath : "NULL",
3354 ep->nm3_fh_info);
3355
3356 /*
3357 * We should seek till finding the window in which file
3358 * is located.
3359 */
3360 ret = ndmpd_dar_locate_window_v3(session, params,
3361 ep->nm3_fh_info, len);
3362
3363 if (ret < 0) /* If seek fails, restore should be aborted */
3364 break;
3365 /*
3366 * We are inside the target window.
3367 * for each restore we will use one entry as selection list
3368 */
3369 if ((ret = ndmpd_dar_tar_v3(session, params, nlp, i+1))
3370 != 0)
3371 result = EIO;
3372 ndmpd_audit_restore(session->ns_connection,
3373 ep->nm3_opath ? ep->nm3_opath : "NULL",
3374 session->ns_data.dd_data_addr.addr_type,
3375 session->ns_tape.td_adapter_name, result);
3376 }
3377
3378 syslog(LOG_DEBUG, "End of restore list");
3379
3380 (void) ndmpd_dar_tar_end_v3(session, params, nlp, jname);
3381
3382 return (ret);
3383 }
3384
3385 /*
3386 * ndmp_plugin_pre_restore
3387 *
3388 * Wrapper for pre-restore callback with multiple path
3389 */
3390 static int
3391 ndmp_plugin_pre_restore(ndmp_context_t *ctxp, ndmpd_module_params_t *params,
3392 int ncount)
3393 {
3394 mem_ndmp_name_v3_t *ep;
3395 int err;
3396 int i;
3397
3398 for (i = 0; i < ncount; i++) {
3416 *
3417 * /backup/path/ -> /backup/path
3418 * /backup/path/. -> /backup/path
3419 * /backup/path/../path/ -> /backup/path
3420 * /link-to-backup-path -> /backup/path
3421 *
3422 * Returns:
3423 * Pointer to the new path (allocated)
3424 * NULL if the path doesnt exist
3425 */
3426 static char *
3427 get_absolute_path(const char *bkpath)
3428 {
3429 char *pbuf;
3430 char *rv;
3431
3432 if (!(pbuf = ndmp_malloc(TLM_MAX_PATH_NAME)))
3433 return (NULL);
3434
3435 if ((rv = realpath(bkpath, pbuf)) == NULL) {
3436 syslog(LOG_ERR, "Invalid path [%s] err=%d",
3437 bkpath, errno);
3438 }
3439 return (rv);
3440 }
3441
3442 /*
3443 * Expands the format string and logs the resulting message to the
3444 * remote DMA
3445 */
3446 void
3447 ndmp_log_dma(ndmp_context_t *nctx, ndmp_log_dma_type_t lt, const char *fmt, ...)
3448 {
3449 va_list ap;
3450 char buf[256];
3451 ndmpd_module_params_t *params;
3452
3453 if (nctx == NULL ||
3454 (params = (ndmpd_module_params_t *)nctx->nc_params) == NULL)
3455 return;
3456
3464
3465 /*
3466 * ndmpd_rs_sar_tar_v3
3467 *
3468 * Main non-DAR restore function. It will try to restore all the entries
3469 * that have been backed up.
3470 *
3471 * Parameters:
3472 * session (input) - pointer to the session
3473 * params (input) - pointer to the parameters structure
3474 * nlp (input) - pointer to the nlp structure
3475 *
3476 * Returns:
3477 * 0: on success
3478 * -1: on error
3479 */
3480 static int
3481 ndmpd_rs_sar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3482 ndmp_lbr_params_t *nlp)
3483 {
3484 char *excl;
3485 char **sels;
3486 int flags;
3487 int err;
3488 tlm_commands_t *cmds;
3489 struct rs_name_maker rn;
3490 ndmp_tar_reader_arg_t arg;
3491 pthread_t rdtp;
3492 int result;
3493 ndmp_context_t nctx;
3494
3495 result = err = 0;
3496
3497 if (restore_alloc_structs_v3(session) < 0) {
3498 return (-1);
3499 }
3500 sels = setupsels(session, params, nlp, 0);
3501 if (!sels) {
3502 free_structs_v3(session);
3503 return (-1);
3504 }
3505 excl = NULL;
3506 flags = RSFLG_OVR_ALWAYS;
3507 rn.rn_nlp = nlp;
3508 rn.rn_fp = mknewname;
3509
3510 nlp->nlp_jstat->js_start_ltime = time(NULL);
3511 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
3512
3513 if (!session->ns_data.dd_abort && !session->ns_data.dd_abort) {
3514 cmds = &nlp->nlp_cmds;
3515 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
3516 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
3517 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
3518
3519 syslog(LOG_DEBUG, "Restoring to \"%s\" started.",
3520 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3521
3522 arg.tr_session = session;
3523 arg.tr_mod_params = params;
3524 arg.tr_cmds = cmds;
3525 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
3526 (void *)&arg);
3527 if (err == 0) {
3528 tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
3529 } else {
3530 syslog(LOG_ERR, "Launch ndmp_tar_reader failed");
3531 free_structs_v3(session);
3532 return (-1);
3533 }
3534
3535 if (!ndmp_check_utf8magic(cmds->tcs_command)) {
3536 syslog(LOG_DEBUG, "UTF8Magic not found!");
3537 } else {
3538 syslog(LOG_DEBUG, "UTF8Magic found");
3539 }
3540
3541 /* Plug-in module */
3542 if (ndmp_pl != NULL &&
3543 ndmp_pl->np_pre_restore != NULL) {
3544 (void) memset(&nctx, 0, sizeof (ndmp_context_t));
3545 nctx.nc_cmds = cmds;
3546 nctx.nc_params = params;
3547 nctx.nc_ddata = (void *) session;
3548 if ((err = ndmp_plugin_pre_restore(&nctx, params,
3549 nlp->nlp_nfiles))
3550 != 0) {
3551 syslog(LOG_ERR, "Pre-restore plug-in: %m");
3552 ndmp_stop_local_reader(session, cmds);
3553 ndmp_wait_for_reader(cmds);
3554 (void) pthread_join(rdtp, NULL);
3555 ndmp_stop_remote_reader(session);
3556 goto restore_out;
3557 }
3558 }
3559
3560 cmds->tcs_command->tc_ref++;
3561 cmds->tcs_writer_count++;
3562
3563 if (tm_tar_ops.tm_getdir != NULL) {
3564 char errbuf[256];
3565
3566 err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
3567 nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags, 0,
3568 nlp->nlp_mountpoint, session->hardlink_q);
3569 /*
3570 * If the fatal error from tm_getdir looks like an
3571 * errno code, we send the error description to DMA.
3572 */
3573 if (err > 0 && strerror_r(err, errbuf,
3574 sizeof (errbuf)) == 0) {
3575 MOD_LOGV3(params, NDMP_LOG_ERROR,
3576 "Fatal error during the restore: %s\n",
3577 errbuf);
3578 }
3579 }
3580
3581 cmds->tcs_writer_count--;
3582 cmds->tcs_command->tc_ref--;
3583 nlp->nlp_jstat->js_stop_time = time(NULL);
3584
3585 /* Send the list of un-recovered files/dirs to the client. */
3586 (void) send_unrecovered_list_v3(params, nlp);
3587
3588 ndmp_stop_local_reader(session, cmds);
3589 ndmp_wait_for_reader(cmds);
3590 (void) pthread_join(rdtp, NULL);
3591
3592 ndmp_stop_remote_reader(session);
3593
3594 /* exit as if there was an internal error */
3595 if (session->ns_eof)
3596 err = -1;
3597 if (err == -1)
3598 result = EIO;
3599 }
3600
3601 (void) send_unrecovered_list_v3(params, nlp); /* nothing restored. */
3602 if (session->ns_data.dd_abort) {
3603 syslog(LOG_DEBUG, "Restoring to \"%s\" aborted.",
3604 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3605 result = EINTR;
3606 ndmpd_audit_restore(session->ns_connection,
3607 nlp->nlp_restore_path,
3608 session->ns_data.dd_data_addr.addr_type,
3609 session->ns_tape.td_adapter_name, result);
3610 err = -1;
3611 } else {
3612 syslog(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
3613 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL",
3614 err);
3615 ndmpd_audit_restore(session->ns_connection,
3616 nlp->nlp_restore_path,
3617 session->ns_data.dd_data_addr.addr_type,
3618 session->ns_tape.td_adapter_name, result);
3619
3620 restore_out:
3621 /* Plug-in module */
3622 if (ndmp_pl != NULL &&
3623 ndmp_pl->np_post_restore != NULL &&
3624 ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) {
3625 syslog(LOG_DEBUG, "Post-restore plug-in: %m");
3626 err = -1;
3627 }
3628 }
3629
3630 NDMP_FREE(sels);
3631 free_structs_v3(session);
3632
3633 return (err);
3634 }
3635
3636
3637 /*
3638 * ndmp_backup_get_params_v3
3639 *
3640 * Get the backup parameters from the NDMP env variables
3641 * and log them in the system log and as normal messages
3642 * to the DMA.
3643 *
3644 * Parameters:
3645 * session (input) - pointer to the session
3646 * params (input) - pointer to the parameters structure
3647 *
3648 * Returns:
3649 * NDMP_NO_ERR: on success
3650 * != NDMP_NO_ERR: otherwise
3651 */
3652 ndmp_error
3653 ndmp_backup_get_params_v3(ndmpd_session_t *session,
3654 ndmpd_module_params_t *params)
3655 {
3656 ndmp_lbr_params_t *nlp;
3657
3658 if (!session || !params)
3659 return (NDMP_ILLEGAL_ARGS_ERR);
3660
3661 nlp = ndmp_get_nlp(session);
3662 if (!nlp) {
3663 MOD_LOGV3(params, NDMP_LOG_ERROR,
3664 "Internal error: NULL nlp.\n");
3665 return (NDMP_ILLEGAL_ARGS_ERR);
3666 } else {
3667 if (!(nlp->nlp_backup_path = get_backup_path_v3(params)) ||
3668 !is_valid_backup_dir_v3(params, nlp->nlp_backup_path))
3669 return (NDMP_ILLEGAL_ARGS_ERR);
3670 }
3671 nlp->nlp_backup_path = get_absolute_path(nlp->nlp_backup_path);
3672 if (!nlp->nlp_backup_path)
3673 return (NDMP_ILLEGAL_ARGS_ERR);
3674
3675 /*
3676 * Assume volume is not checkpointed unless found to be below
3677 */
3678 NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
3679
3680 /*
3681 * Get the zfs volume name from the backup path and store in
3682 * nlp_vol.
3683 */
3684 if (get_zfsvolname(nlp->nlp_vol,
3685 sizeof (nlp->nlp_vol), nlp->nlp_backup_path) == -1) {
3686 syslog(LOG_ERR,
3687 "Cannot get volume from [%s] on create",
3688 nlp->nlp_backup_path);
3689 NDMP_FREE(nlp->nlp_params);
3690 return (-1);
3691 }
3692
3693 /*
3694 * Find out if this data is already checkpointed via. an AutoSync
3695 * or HPR snapshot. If it is, set the flag, and extract the snapshot
3696 * name to use as the nlp_job_name otherwise use the normal
3697 * 'NdmpBackup-nnnn' format.
3698 */
3699 if (fs_is_checkpointed(nlp) &&
3700 (ndmp_autosync_support || ndmp_hpr_support)) {
3701 NLP_SET(nlp, NLPF_CHKPNTED_PATH);
3702 syslog(LOG_DEBUG, ">>>> Checkpointed dataset found <<<<");
3703 }
3704
3705 (void) ndmp_new_job_name(nlp->nlp_job_name,
3706 sizeof (nlp->nlp_job_name));
3707
3708 syslog(LOG_DEBUG, "New backup job name [%s]",
3709 nlp->nlp_job_name);
3710
3711 /* Should the st_ctime be ignored when backing up? */
3712 if (ndmp_ignore_ctime) {
3713 syslog(LOG_DEBUG, "ignoring st_ctime");
3714 NLP_SET(nlp, NLPF_IGNCTIME);
3715 } else {
3716 NLP_UNSET(nlp, NLPF_IGNCTIME);
3717 }
3718
3719 if (ndmp_include_lmtime == TRUE) {
3720 syslog(LOG_DEBUG, "including st_lmtime");
3721 NLP_SET(nlp, NLPF_INCLMTIME);
3722 } else {
3723 NLP_UNSET(nlp, NLPF_INCLMTIME);
3724 }
3725
3726 syslog(LOG_DEBUG, "flags %x", nlp->nlp_flags);
3727
3728 get_hist_env_v3(params, nlp);
3729 get_exc_env_v3(params, nlp);
3730 get_inc_env_v3(params, nlp);
3731 get_direct_env_v3(params, nlp);
3732 return (get_backup_level_v3(params, nlp));
3733 }
3734
3735
3736 /*
3737 * ndmpd_tar_backup_starter_v3
3738 *
3739 * Create the checkpoint for the backup and do the backup,
3740 * then remove the backup checkpoint if we created it.
3741 * Save the backup time information based on the backup
3742 * type and stop the data server.
3743 *
3744 * Parameters:
3745 * params (input) - pointer to the parameters structure
3746 *
3747 * Returns:
3748 * 0: on success
3749 * != 0: otherwise
3750 */
3751 int
3752 ndmpd_tar_backup_starter_v3(void *arg)
3753 {
3754 ndmpd_module_params_t *params = arg;
3755 int err;
3756 ndmpd_session_t *session;
3757 ndmp_lbr_params_t *nlp;
3758
3759 session = (ndmpd_session_t *)(params->mp_daemon_cookie);
3760 *(params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
3761 ndmp_session_ref(session);
3762
3763 pthread_cleanup_push(backup_dataset_destroy, nlp);
3764
3765 err = 0;
3766 if (backup_dataset_create(nlp) < 0) {
3767 MOD_LOGV3(params, NDMP_LOG_ERROR,
3768 "Creating checkpoint on \"%s\".\n",
3769 nlp->nlp_backup_path);
3770 err = -1;
3771 }
3772
3773 syslog(LOG_DEBUG, "BACKUP STARTED [%s]", nlp->nlp_snapname);
3774
3775 if (err == 0) {
3776 /* Get an estimate of the data size */
3777 (void) get_backup_size(nlp);
3778
3779 err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate);
3780 if (err != 0) {
3781 syslog(LOG_ERR,
3782 "Failed to get current backup time %d", err);
3783 } else {
3784 log_bk_params_v3(session, params, nlp);
3785 err = tar_backup_v3(session, params, nlp);
3786 }
3787 }
3788
3789 pthread_cleanup_pop(B_TRUE);
3790
3791 if (err == 0)
3792 save_backup_date_v3(params, nlp);
3793
3794 MOD_DONE(params, err);
3795
3796 /* nlp_params is allocated in start_backup_v3() */
3797 NDMP_FREE(nlp->nlp_params);
3798 NDMP_FREE(nlp->nlp_backup_path);
3799
3800 NS_DEC(nbk);
3801 ndmp_session_unref(session);
3802 syslog(LOG_DEBUG, "BACKUP COMPLETE [%s] (as jobname %s)",
3803 nlp->nlp_snapname, nlp->nlp_job_name);
3804 return (err);
3805 }
3806
3807
3808 /*
3809 * ndmpd_tar_backup_abort_v3
3810 *
3811 * Abort the backup operation and stop the reader thread.
3812 *
3813 * Parameters:
3814 * module_cookie (input) - pointer to the nlp structure
3815 *
3816 * Returns:
3817 * 0: always
3818 */
3819 int
3820 ndmpd_tar_backup_abort_v3(void *module_cookie)
3821 {
3822 ndmp_lbr_params_t *nlp;
3823
3824 nlp = (ndmp_lbr_params_t *)module_cookie;
3841 *
3842 * Get the parameters specified for recovery such as restore path, type
3843 * of restore (DAR, non-DAR) etc
3844 *
3845 * Parameters:
3846 * session (input) - pointer to the session
3847 * params (input) - pointer to the parameters structure
3848 *
3849 * Returns:
3850 * NDMP_NO_ERR: on success
3851 * != NDMP_NO_ERR: otherwise
3852 */
3853 ndmp_error
3854 ndmp_restore_get_params_v3(ndmpd_session_t *session,
3855 ndmpd_module_params_t *params)
3856 {
3857 ndmp_error rv;
3858 ndmp_lbr_params_t *nlp;
3859
3860 if (!(nlp = ndmp_get_nlp(session))) {
3861 syslog(LOG_DEBUG, "nlp is NULL");
3862 rv = NDMP_ILLEGAL_ARGS_ERR;
3863 } else if (!(nlp->nlp_backup_path = get_backup_path_v3(params)))
3864 rv = NDMP_ILLEGAL_ARGS_ERR;
3865 else if ((nlp->nlp_nfiles = session->ns_data.dd_nlist_len) == 0) {
3866 syslog(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
3867 rv = NDMP_ILLEGAL_ARGS_ERR;
3868 } else if (get_rs_path_v3(params, nlp) != NDMP_NO_ERR) {
3869 rv = NDMP_ILLEGAL_ARGS_ERR;
3870 } else if ((rv = fix_nlist_v3(session, params, nlp)) != NDMP_NO_ERR) {
3871 syslog(LOG_DEBUG, "fix_nlist_v3: %d", rv);
3872 } else {
3873 rv = NDMP_NO_ERR;
3874 get_direct_env_v3(params, nlp);
3875 if (NLP_ISSET(nlp, NLPF_DIRECT)) {
3876 if (NLP_ISSET(nlp, NLPF_RECURSIVE)) {
3877 /* Currently we dont support DAR on directory */
3878 syslog(LOG_DEBUG,
3879 "Can't have RECURSIVE and DIRECT together");
3880 rv = NDMP_ILLEGAL_ARGS_ERR;
3881 return (rv);
3882 }
3883
3884 /*
3885 * DAR can be done if all the fh_info's are valid.
3886 */
3887 if (allvalidfh(session, params)) {
3888 ndmp_sort_nlist_v3(session);
3889 } else {
3890 MOD_LOGV3(params, NDMP_LOG_WARNING,
3891 "Cannot do direct access recovery. "
3892 "Some 'fh_info'es are not valid.\n");
3893 NLP_UNSET(nlp, NLPF_DIRECT);
3894 }
3895 }
3896
3897 log_rs_params_v3(session, params, nlp);
3898 }
|