dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / ndmpd / ndmp / ndmpd_tar3.c
blobd3e89d5a3debd0f9e6bba71cca0227815893013f
1 /*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
5 /*
6 * BSD 3 Clause License
8 * Copyright (c) 2007, The Storage Networking Industry Association.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * - Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
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.
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40 /* Copyright 2014 Nexenta Systems, Inc. All rights reserved. */
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>
62 * Maximum length of the string-representation of u_longlong_t type.
64 #define QUAD_DECIMAL_LEN 20
67 /* Is Y=yes or T=true */
68 #define IS_YORT(c) (strchr("YT", toupper(c)))
70 /* Is F=file format (vs D=node-dir format) */
71 #define IS_F(c) (toupper(c) == 'F')
74 * If path is defined.
76 #define ISDEFINED(cp) ((cp) && *(cp))
77 #define SHOULD_LBRBK(bpp) (!((bpp)->bp_opr & TLM_OP_CHOOSE_ARCHIVE))
80 * Component boundary means end of path or on a '/'. At this
81 * point both paths should be on component boundary.
83 #define COMPBNDRY(p) (!*(p) || (*p) == '/')
85 typedef struct bk_param_v3 {
86 ndmpd_session_t *bp_session;
87 ndmp_lbr_params_t *bp_nlp;
88 tlm_job_stats_t *bp_js;
89 tlm_cmd_t *bp_lcmd;
90 tlm_commands_t *bp_cmds;
91 tlm_acls_t *bp_tlmacl;
92 int bp_opr;
93 char *bp_tmp;
94 char *bp_chkpnm;
95 char **bp_excls;
96 char *bp_unchkpnm;
97 } bk_param_v3_t;
101 * Multiple destination restore mode
103 #define MULTIPLE_DEST_DIRS 128
105 int multiple_dest_restore = 0;
108 * Plug-in module ops
110 ndmp_plugin_t *ndmp_pl;
113 * NDMP exclusion list
115 char **ndmp_excl_list = NULL;
118 * split_env
120 * Splits the string into list of sections separated by the
121 * sep character.
123 * Parameters:
124 * envp (input) - the environment variable that should be broken
125 * sep (input) - the separator character
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
133 static char **
134 split_env(char *envp, char sep)
136 char *bp, *cp, *ep;
137 char *save;
138 char **cpp;
139 int n;
141 if (!envp)
142 return (NULL);
144 while (isspace(*envp))
145 envp++;
147 if (!*envp)
148 return (NULL);
150 bp = save = strdup(envp);
151 if (!bp)
152 return (NULL);
155 * Since the env variable is not empty, it contains at least one
156 * component
158 n = 1;
159 while ((cp = strchr(bp, sep))) {
160 if (cp > save && *(cp-1) != '\\')
161 n++;
163 bp = cp + 1;
166 n++; /* for the terminating NULL pointer */
167 cpp = ndmp_malloc(sizeof (char *) * n);
168 if (!cpp) {
169 free(save);
170 return (NULL);
173 (void) memset(cpp, 0, n * sizeof (char *));
174 n = 0;
175 cp = bp = ep = save;
176 while (*cp)
177 if (*cp == sep) {
178 *ep = '\0';
179 if (strlen(bp) > 0) {
180 cpp[n] = strdup(bp);
181 if (!cpp[n++]) {
182 tlm_release_list(cpp);
183 cpp = NULL;
184 break;
187 ep = bp = ++cp;
188 } else if (*cp == '\\') {
189 ++cp;
190 if (*cp == 'n') { /* "\n" */
191 *ep++ = '\n';
192 cp++;
193 } else if (*cp == 't') { /* "\t" */
194 *ep++ = '\t';
195 cp++;
196 } else
197 *ep++ = *cp++;
198 } else
199 *ep++ = *cp++;
201 *ep = '\0';
202 if (cpp) {
203 if (strlen(bp) > 0) {
204 cpp[n] = strdup(bp);
205 if (!cpp[n++]) {
206 tlm_release_list(cpp);
207 cpp = NULL;
208 } else
209 cpp[n] = NULL;
212 if (n == 0 && cpp != NULL) {
213 tlm_release_list(cpp);
214 cpp = NULL;
218 free(save);
219 return (cpp);
224 * prl
226 * Print the array of character pointers passed to it. This is
227 * used for debugging purpose.
229 * Parameters:
230 * lpp (input) - pointer to the array of strings
232 * Returns:
233 * void
235 static void
236 prl(char **lpp)
238 if (!lpp) {
239 NDMP_LOG(LOG_DEBUG, "empty");
240 return;
243 while (*lpp)
244 NDMP_LOG(LOG_DEBUG, "\"%s\"", *lpp++);
249 * inlist
251 * Looks through all the strings of the array to see if the ent
252 * matches any of the strings. The strings are patterns.
254 * Parameters:
255 * lpp (input) - pointer to the array of strings
256 * ent (input) - the entry to be matched
258 * Returns:
259 * TRUE: if there is a match
260 * FALSE: invalid argument or no match
262 static boolean_t
263 inlist(char **lpp, char *ent)
265 if (!lpp || !ent) {
266 NDMP_LOG(LOG_DEBUG, "empty list");
267 return (FALSE);
270 while (*lpp) {
272 * Fixing the sync_sort NDMPV3 problem, it sends the inclusion
273 * like "./" which we should skip the "./"
275 char *pattern = *lpp;
276 if (strncmp(pattern, "./", 2) == 0)
277 pattern += 2;
279 NDMP_LOG(LOG_DEBUG, "pattern %s, ent %s", pattern, ent);
281 if (match(pattern, ent)) {
282 NDMP_LOG(LOG_DEBUG, "match(%s,%s)", pattern, ent);
283 return (TRUE);
285 lpp++;
288 NDMP_LOG(LOG_DEBUG, "no match");
289 return (FALSE);
294 * inexl
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.
300 * Parameters:
301 * lpp (input) - pointer to the array of strings
302 * ent (input) - the entry to be matched
304 * Returns:
305 * TRUE: if there is a match
306 * FALSE: invalid argument or no match
309 static boolean_t
310 inexl(char **lpp, char *ent)
312 if (!lpp || !ent)
313 return (FALSE);
315 return (inlist(lpp, ent));
320 * ininc
322 * Checks if the entry is in the list. This is used for inclusion
323 * list. If the inclusion list is empty, TRUE should be returned
324 * showing that everything should be included by default.
326 * Parameters:
327 * lpp (input) - pointer to the array of strings
328 * ent (input) - the entry to be matched
330 * Returns:
331 * TRUE: if there is a match or the list is empty
332 * FALSE: no match
334 static boolean_t
335 ininc(char **lpp, char *ent)
337 if (!lpp || !ent || !*ent)
338 return (TRUE);
340 return (inlist(lpp, ent));
345 * setupsels
347 * Set up the selection list for Local B/R functions. A new array of
348 * "char *" is created and the pointers point to the original paths of
349 * the Nlist.
351 * Parameters:
352 * session (input) - pointer to the session
353 * params (input) - pointer to the parameters structure
354 * nlp (input) - pointer to the nlp structure
355 * index(input) - If not zero is the DAR entry position
357 * Returns:
358 * list pointer: on success
359 * NULL: on error
361 /*ARGSUSED*/
362 char **
363 setupsels(ndmpd_session_t *session, ndmpd_module_params_t *params,
364 ndmp_lbr_params_t *nlp, int index)
366 char **lpp, **save;
367 int i, n;
368 int len;
369 int start, end;
370 mem_ndmp_name_v3_t *ep;
372 n = session->ns_data.dd_nlist_len;
374 save = lpp = ndmp_malloc(sizeof (char *) * (n + 1));
375 if (!lpp) {
376 MOD_LOGV3(params, NDMP_LOG_ERROR, "Insufficient memory.\n");
377 return (NULL);
380 if (index) { /* DAR, just one entry */
382 * We have to setup a list of strings that will not match any
383 * file. One DAR entry will be added in the right position later
384 * in this function.
385 * When the match is called from tar_getdir the
386 * location of the selection that matches the entry is
387 * important
389 for (i = 0; i < n; ++i)
390 *(lpp+i) = " ";
391 n = 1;
392 start = index-1;
393 end = start+1;
394 lpp += start; /* Next selection entry will be in lpp[start] */
395 } else {
396 start = 0;
397 end = n;
400 for (i = start; i < end; i++) {
401 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
402 if (!ep)
403 continue;
406 * Check for clients that send original path as "."(like
407 * CA products). In this situation opath is something like
408 * "/v1/." and we should change it to "/v1/"
410 len = strlen(ep->nm3_opath);
411 if (len > 1 && ep->nm3_opath[len-2] == '/' &&
412 ep->nm3_opath[len-1] == '.') {
413 ep->nm3_opath[len-1] = '\0';
414 NDMP_LOG(LOG_DEBUG,
415 "nm3_opath changed from %s. to %s",
416 ep->nm3_opath, ep->nm3_opath);
418 *lpp++ = ep->nm3_opath;
421 /* list termination indicator is a null pointer */
422 *lpp = NULL;
424 return (save);
429 * mkrsp
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
435 * as they are the same. If either of the path or selection are not on
436 * a component boundary, the match was reported falsefully and no new name
437 * is generated(Except the situation in which both path and selection
438 * end with trailing '/' and selection is the prefix of the path).
439 * Otherwise, the remaining of the path is appended to the
440 * new name. The result is saved in the buffer passed.
442 * Parameters:
443 * bp (output) - pointer to the result buffer
444 * pp (input) - pointer to the path
445 * sp (input) - pointer to the selection
446 * np (input) - pointer to the new name
448 * Returns:
449 * pointer to the bp: on success
450 * NULL: otherwise
452 char *
453 mkrsp(char *bp, char *pp, char *sp, char *np)
455 if (!bp || !pp)
456 return (NULL);
459 pp += strspn(pp, "/");
460 if (sp) {
461 sp += strspn(sp, "/");
463 /* skip as much as match */
464 while (*sp && *pp && *sp == *pp) {
465 sp++;
466 pp++;
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);
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);
483 if (np)
484 np += strspn(np, "/");
485 else
486 np = "";
488 if (!tlm_cat_path(bp, np, pp)) {
489 NDMP_LOG(LOG_ERR, "Restore path too long %s/%s.", np, pp);
490 return (NULL);
493 return (bp);
498 * mknewname
500 * This is used as callback for creating the restore path. This function
501 * can handle both single destination and multiple restore paths.
503 * Make up the restore destination path for a particular file/directory, path,
504 * based on nm3_opath and nm3_dpath. path should have matched nm3_opath
505 * in some way.
507 char *
508 mknewname(struct rs_name_maker *rnp, char *buf, int idx, char *path)
510 char *rv;
511 ndmp_lbr_params_t *nlp;
512 mem_ndmp_name_v3_t *ep;
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);
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);
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);
560 return (rv);
565 * chopslash
567 * Remove the slash from the end of the given path
569 static void
570 chopslash(char *cp)
572 int ln;
574 if (!cp || !*cp)
575 return;
577 ln = strlen(cp);
578 cp += ln - 1; /* end of the string */
579 while (ln > 0 && *cp == '/') {
580 *cp-- = '\0';
581 ln--;
587 * joinpath
589 * Join two given paths
591 static char *
592 joinpath(char *bp, char *pp, char *np)
594 if (pp && *pp) {
595 if (np && *np)
596 (void) tlm_cat_path(bp, pp, np);
597 else
598 (void) strlcpy(bp, pp, TLM_MAX_PATH_NAME);
599 } else {
600 if (np && *np)
601 (void) strlcpy(bp, np, TLM_MAX_PATH_NAME);
602 else
603 bp = NULL;
606 return (bp);
611 * voliswr
613 * Is the volume writable?
615 static int
616 voliswr(char *path)
618 int rv;
620 if (!path)
621 return (0);
623 rv = !fs_is_rdonly(path) && !fs_is_chkpntvol(path);
624 NDMP_LOG(LOG_DEBUG, "%d path \"%s\"", rv, path);
625 return (rv);
631 * is_valid_backup_dir_v3
633 * Checks the validity of the backup path. Backup path should
634 * have the following characteristics to be valid:
635 * 1) It should be an absolute path.
636 * 2) It should be a directory.
637 * 3) It should not be checkpoint root directory
638 * 4) If the file system is read-only, the backup path
639 * should be a checkpointed path. Checkpoint cannot
640 * be created on a read-only file system.
642 * Parameters:
643 * params (input) - pointer to the parameters structure.
644 * bkpath (input) - the backup path
646 * Returns:
647 * TRUE: if everything's OK
648 * FALSE: otherwise.
650 static boolean_t
651 is_valid_backup_dir_v3(ndmpd_module_params_t *params, char *bkpath)
653 char *msg;
654 struct stat64 st;
656 if (*bkpath != '/') {
657 MOD_LOGV3(params, NDMP_LOG_ERROR,
658 "Relative backup path not allowed \"%s\".\n", bkpath);
659 return (FALSE);
661 if (stat64(bkpath, &st) < 0) {
662 msg = strerror(errno);
663 MOD_LOGV3(params, NDMP_LOG_ERROR, "\"%s\" %s.\n",
664 bkpath, msg);
665 return (FALSE);
667 if (!S_ISDIR(st.st_mode)) {
668 /* only directories can be specified as the backup path */
669 MOD_LOGV3(params, NDMP_LOG_ERROR,
670 "\"%s\" is not a directory.\n", bkpath);
671 return (FALSE);
673 if (fs_is_rdonly(bkpath) && !fs_is_chkpntvol(bkpath) &&
674 fs_is_chkpnt_enabled(bkpath)) {
675 /* it is not a chkpnted path */
676 MOD_LOGV3(params, NDMP_LOG_ERROR,
677 "\"%s\" is not a checkpointed path.\n", bkpath);
678 return (FALSE);
681 return (TRUE);
686 * log_date_token_v3
688 * Log the token sequence number and also the date of the
689 * last backup for token-based backup in the system log
690 * and also send them as normal log to the client.
692 * Parameters:
693 * params (input) - pointer to the parameters structure
694 * nlp (input) - pointer to the nlp structure
696 * Returns:
697 * void
699 static void
700 log_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
702 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Token sequence counter: %d.\n",
703 nlp->nlp_tokseq);
705 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Date of the last backup: %s.\n",
706 cctime(&nlp->nlp_tokdate));
708 if (nlp->nlp_dmpnm) {
709 MOD_LOGV3(params, NDMP_LOG_NORMAL,
710 "Backup date log file name: \"%s\".\n", nlp->nlp_dmpnm);
716 * log_lbr_bk_v3
718 * Log the backup level and data of the backup for LBR-type
719 * backup in the system log and also send them as normal log
720 * to the client.
722 * Parameters:
723 * params (input) - pointer to the parameters structure
724 * nlp (input) - pointer to the nlp structure
726 * Returns:
727 * void
729 static void
730 log_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
732 MOD_LOGV3(params, NDMP_LOG_NORMAL,
733 "Date of this level '%c': %s.\n", nlp->nlp_clevel,
734 cctime(&nlp->nlp_cdate));
736 if (nlp->nlp_dmpnm) {
737 MOD_LOGV3(params, NDMP_LOG_NORMAL,
738 "Backup date log file name: \"%s\".\n", nlp->nlp_dmpnm);
744 * log_level_v3
746 * Log the backup level and date of the last and the current
747 * backup for level-type backup in the system log and also
748 * send them as normal log to the client.
750 * Parameters:
751 * params (input) - pointer to the parameters structure
752 * nlp (input) - pointer to the nlp structure
754 * Returns:
755 * void
757 static void
758 log_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
760 MOD_LOGV3(params, NDMP_LOG_NORMAL,
761 "Date of the last level '%u': %s.\n", nlp->nlp_llevel,
762 cctime(&nlp->nlp_ldate));
764 MOD_LOGV3(params, NDMP_LOG_NORMAL,
765 "Date of this level '%u': %s.\n", nlp->nlp_clevel,
766 cctime(&nlp->nlp_cdate));
768 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Update: %s.\n",
769 NDMP_TORF(NLP_ISSET(nlp, NLPF_UPDATE)));
774 * log_bk_params_v3
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.
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
785 * Returns:
786 * void
788 static void
789 log_bk_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
790 ndmp_lbr_params_t *nlp)
792 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Backing up \"%s\".\n",
793 nlp->nlp_backup_path);
795 if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_LOCAL)
796 MOD_LOGV3(params, NDMP_LOG_NORMAL,
797 "Tape record size: %d.\n",
798 session->ns_mover.md_record_size);
800 MOD_LOGV3(params, NDMP_LOG_NORMAL, "File history: %c.\n",
801 NDMP_YORN(NLP_ISSET(nlp, NLPF_FH)));
803 if (NLP_ISSET(nlp, NLPF_TOKENBK))
804 log_date_token_v3(params, nlp);
805 else if (NLP_ISSET(nlp, NLPF_LBRBK))
806 log_lbr_bk_v3(params, nlp);
807 else if (NLP_ISSET(nlp, NLPF_LEVELBK))
808 log_level_v3(params, nlp);
809 else {
810 MOD_LOGV3(params, NDMP_LOG_ERROR,
811 "Internal error: backup level not defined for \"%s\".\n",
812 nlp->nlp_backup_path);
818 * get_update_env_v3
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.
824 * Parameters:
825 * params (input) - pointer to the parameters structure
826 * nlp (input) - pointer to the nlp structure
828 * Returns:
829 * void
831 static void
832 get_update_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
834 char *envp;
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);
852 * get_hist_env_v3
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.
858 * Parameters:
859 * params (input) - pointer to the parameters structure
860 * nlp (input) - pointer to the nlp structure
862 * Returns:
863 * void
865 static void
866 get_hist_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
868 char *envp;
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);
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;
893 * get_exc_env_v3
895 * Gets the EXCLUDE environment variable and breaks it
896 * into strings. The separator of the EXCLUDE environment
897 * variable is the ',' character.
899 * Parameters:
900 * params (input) - pointer to the parameters structure
901 * nlp (input) - pointer to the nlp structure
903 * Returns:
904 * void
906 static void
907 get_exc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
909 char *envp;
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);
924 * get_inc_env_v3
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.
931 * Parameters:
932 * params (input) - pointer to the parameters structure
933 * nlp (input) - pointer to the nlp structure
935 * Returns:
936 * void
938 static void
939 get_inc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
941 char *envp;
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);
956 * get_direct_env_v3
958 * Gets the DIRECT environment variable that shows if the fh_info should
959 * be sent to the client or not.
961 * Parameters:
962 * params (input) - pointer to the parameters structure
963 * nlp (input) - pointer to the nlp structure
965 * Returns:
966 * void
968 static void
969 get_direct_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
971 char *envp;
974 * We should send the fh_info to the DMA, unless it is specified
975 * in the request that we should not send fh_info.
976 * At the moment we do not support DAR on directories, so if the user
977 * needs to restore a directory they should disable the DAR.
979 if (params->mp_operation == NDMP_DATA_OP_RECOVER && !ndmp_dar_support) {
980 NDMP_LOG(LOG_DEBUG, "Direct Access Restore Disabled");
981 NLP_UNSET(nlp, NLPF_DIRECT);
982 MOD_LOGV3(params, NDMP_LOG_NORMAL,
983 "DAR is disabled. Running Restore without DAR");
984 return;
988 * Regardless of whether DIRECT is defined at backup time we send
989 * back the fh_info, for some clients do not use get_backup_attrs.
990 * If operation is restore we have to unset the DIRECT, for
991 * some clients do not set the MOVER window.
993 if (params->mp_operation == NDMP_DATA_OP_BACKUP) {
994 NDMP_LOG(LOG_DEBUG, "backup default env(DIRECT): YES");
995 NLP_SET(nlp, NLPF_DIRECT);
996 } else {
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");
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");
1035 * get_date_token_v3
1037 * Parse the token passed as the argument. Evaluate it and
1038 * issue any warning or error if needed. Save the date and
1039 * token sequence in the nlp structure fields. The sequence
1040 * number in the token should be less than hard-limit. If
1041 * it's between soft and hard limit, a warning is issued.
1042 * There is a configurable limit which should be less than
1043 * the soft-limit saved in ndmp_max_tok_seq variable.
1045 * The NLPF_TOKENBK flag is set in the nlp flags field to
1046 * show that the backup type is token-based.
1048 * Parameters:
1049 * params (input) - pointer to the parameters structure
1050 * nlp (input) - pointer to the nlp structure
1051 * basedate (input) - the value of the BASE_DATE environment
1052 * variable.
1054 * Returns:
1055 * NDMP_NO_ERR: on success
1056 * != NDMP_NO_ERR: Otherwise
1059 static ndmp_error
1060 get_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp,
1061 char *basedate)
1063 char *endp;
1064 uint_t seq;
1065 ndmp_error rv;
1066 time_t tstamp;
1067 u_longlong_t tok;
1069 if (!params || !nlp || !basedate || !*basedate)
1070 return (NDMP_ILLEGAL_ARGS_ERR);
1072 if (MOD_GETENV(params, "LEVEL")) {
1073 MOD_LOGV3(params, NDMP_LOG_WARNING,
1074 "Both BASE_DATE and LEVEL environment variables "
1075 "defined.\n");
1076 MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
1077 "BASE_DATE is being used for this backup.\n");
1080 tok = strtoll(basedate, &endp, 10);
1081 if (endp == basedate) {
1082 MOD_LOGV3(params, NDMP_LOG_ERROR,
1083 "Invalid BASE_DATE environment variable: \"%s\".\n",
1084 basedate);
1085 return (NDMP_ILLEGAL_ARGS_ERR);
1088 tstamp = tok & 0xffffffff;
1089 seq = (tok >> 32) & 0xffffffff;
1090 NDMP_LOG(LOG_DEBUG, "basedate \"%s\" %lld seq %u tstamp %u",
1091 basedate, tok, seq, tstamp);
1093 if ((int)seq > ndmp_get_max_tok_seq()) {
1094 rv = NDMP_ILLEGAL_ARGS_ERR;
1095 MOD_LOGV3(params, NDMP_LOG_ERROR,
1096 "The sequence counter of the token exceeds the "
1097 "maximum permitted value.\n");
1098 MOD_LOGCONTV3(params, NDMP_LOG_ERROR,
1099 "Token sequence: %u, maxiumum value: %u.\n",
1100 seq, ndmp_get_max_tok_seq());
1101 } else if (seq >= NDMP_TOKSEQ_HLIMIT) {
1102 rv = NDMP_ILLEGAL_ARGS_ERR;
1103 MOD_LOGV3(params, NDMP_LOG_ERROR,
1104 "The sequence counter the of token exceeds the "
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;
1112 * Issue a warning if the seq is equal to the maximum
1113 * permitted seq number or equal to the soft-limit.
1115 if (seq == NDMP_TOKSEQ_SLIMIT) {
1116 MOD_LOGV3(params, NDMP_LOG_WARNING,
1117 "The sequence counter of the token has reached "
1118 "the soft-limit.\n");
1119 MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
1120 "Token sequence: %u, soft-limit: %u.\n",
1121 seq, NDMP_TOKSEQ_SLIMIT);
1122 } else if ((int)seq == ndmp_get_max_tok_seq()) {
1123 MOD_LOGV3(params, NDMP_LOG_WARNING,
1124 "The sequence counter of the token has reached "
1125 "the maximum permitted value.\n");
1126 MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
1127 "Token sequence: %u, maxiumum value: %u.\n",
1128 seq, ndmp_get_max_tok_seq());
1132 * The current seq is equal to the seq field of the
1133 * token. It will be increased after successful backup
1134 * before setting the DUMP_DATE environment variable.
1136 nlp->nlp_dmpnm = MOD_GETENV(params, "DMP_NAME");
1137 NLP_SET(nlp, NLPF_TOKENBK);
1138 NLP_UNSET(nlp, NLPF_LEVELBK);
1139 NLP_UNSET(nlp, NLPF_LBRBK);
1140 nlp->nlp_tokseq = seq;
1141 nlp->nlp_tokdate = tstamp;
1143 * The value of nlp_cdate will be set to the checkpoint
1144 * creation time after it is created.
1148 return (rv);
1153 * get_lbr_bk_v3
1155 * Sets the level fields of the nlp structures for
1156 * LBR-type backup. The NLPF_LBRBK flag of the
1157 * nlp flags is also set to show the backup type.
1159 * Parameters:
1160 * params (input) - pointer to the parameters structure
1161 * nlp (input) - pointer to the nlp structure
1162 * type (input) - the backup level: 'F', 'A', 'I', 'D' or
1163 * their lower-case values.
1165 * Returns:
1166 * NDMP_NO_ERR: on success
1167 * != NDMP_NO_ERR: Otherwise
1169 static ndmp_error
1170 get_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, char *type)
1172 if (!params || !nlp || !type || !*type)
1173 return (NDMP_ILLEGAL_ARGS_ERR);
1175 NLP_SET(nlp, NLPF_LBRBK);
1176 NLP_UNSET(nlp, NLPF_TOKENBK);
1177 NLP_UNSET(nlp, NLPF_LEVELBK);
1178 nlp->nlp_dmpnm = MOD_GETENV(params, "DMP_NAME");
1179 nlp->nlp_llevel = toupper(*type);
1180 nlp->nlp_ldate = (time_t)0;
1181 nlp->nlp_clevel = nlp->nlp_llevel;
1182 (void) time(&nlp->nlp_cdate);
1184 return (NDMP_NO_ERR);
1189 * get_backup_level_v3
1191 * Gets the backup level from the environment variables. If
1192 * BASE_DATE is specified, it will be used, otherwise LEVEL
1193 * will be used. If neither is specified, LEVEL = '0' is
1194 * assumed.
1196 * Parameters:
1197 * params (input) - pointer to the parameters structure
1198 * nlp (input) - pointer to the nlp structure
1200 * Returns:
1201 * NDMP_NO_ERR: on success
1202 * != NDMP_NO_ERR: Otherwise
1204 static ndmp_error
1205 get_backup_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1207 char *envp;
1208 ndmp_error rv;
1211 * If the BASE_DATE env variable is specified use it, otherwise
1212 * look to see if LEVEL is specified. If LEVEL is not
1213 * specified either, backup level '0' must be made. Level backup
1214 * does not clear the archive bit.
1216 * If LEVEL environment varaible is specified, values for
1217 * 'F', 'D', 'I' and 'A' (for 'Full', 'Differential',
1218 * 'Incremental', and 'Archive' is checked first. Then
1219 * level '0' to '9' will be checked.
1221 * LEVEL environment variable can hold only one character.
1222 * If its length is longer than 1, an error is returned.
1224 envp = MOD_GETENV(params, "BASE_DATE");
1225 if (envp)
1226 return (get_date_token_v3(params, nlp, envp));
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;
1239 * The value of nlp_cdate will be set to the checkpoint
1240 * creation time after it is created.
1242 return (NDMP_NO_ERR);
1245 if (*(envp+1) != '\0') {
1246 MOD_LOGV3(params, NDMP_LOG_ERROR,
1247 "Invalid backup level \"%s\".\n", envp);
1248 return (NDMP_ILLEGAL_ARGS_ERR);
1251 if (IS_LBR_BKTYPE(*envp))
1252 return (get_lbr_bk_v3(params, nlp, envp));
1254 if (!isdigit(*envp)) {
1255 MOD_LOGV3(params, NDMP_LOG_ERROR,
1256 "Invalid backup level \"%s\".\n", envp);
1257 return (NDMP_ILLEGAL_ARGS_ERR);
1260 NLP_SET(nlp, NLPF_LEVELBK);
1261 NLP_UNSET(nlp, NLPF_LBRBK);
1262 NLP_UNSET(nlp, NLPF_TOKENBK);
1263 nlp->nlp_llevel = *envp - '0';
1264 nlp->nlp_ldate = 0;
1265 nlp->nlp_clevel = nlp->nlp_llevel;
1267 * The value of nlp_cdate will be set to the checkpoint
1268 * creation time after it is created.
1270 if (ndmpd_get_dumptime(nlp->nlp_backup_path, &nlp->nlp_llevel,
1271 &nlp->nlp_ldate) < 0) {
1272 MOD_LOGV3(params, NDMP_LOG_ERROR,
1273 "Getting dumpdates for %s level '%c'.\n",
1274 nlp->nlp_backup_path, *envp);
1275 return (NDMP_NO_MEM_ERR);
1276 } else {
1277 get_update_env_v3(params, nlp);
1278 rv = NDMP_NO_ERR;
1281 return (rv);
1286 * save_date_token_v3
1288 * Make the value of DUMP_DATE env variable and append the values
1289 * of the current backup in the file specified with the DMP_NAME
1290 * env variable if any file is specified. The file will be
1291 * relative name in the backup directory path.
1293 * Parameters:
1294 * params (input) - pointer to the parameters structure
1295 * nlp (input) - pointer to the nlp structure
1297 * Returns:
1298 * void
1300 static void
1301 save_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1303 char val[QUAD_DECIMAL_LEN];
1304 u_longlong_t tok;
1306 if (!params || !nlp)
1307 return;
1309 nlp->nlp_tokseq++;
1310 tok = ((u_longlong_t)nlp->nlp_tokseq << 32) | nlp->nlp_cdate;
1311 (void) snprintf(val, sizeof (val), "%llu", tok);
1313 NDMP_LOG(LOG_DEBUG, "tok: %lld %s", tok, val);
1315 if (MOD_SETENV(params, "DUMP_DATE", val) != 0) {
1316 MOD_LOGV3(params, NDMP_LOG_ERROR,
1317 "Could not set DUMP_DATE to %s", val);
1318 } else if (!nlp->nlp_dmpnm) {
1319 NDMP_LOG(LOG_DEBUG, "No log file defined");
1320 } else if (ndmpd_append_dumptime(nlp->nlp_dmpnm, nlp->nlp_backup_path,
1321 nlp->nlp_tokseq, nlp->nlp_tokdate) < 0) {
1322 MOD_LOGV3(params, NDMP_LOG_ERROR,
1323 "Saving backup date for \"%s\" in \"%s\".\n",
1324 nlp->nlp_backup_path, nlp->nlp_dmpnm);
1330 * save_lbr_bk_v3
1332 * Append the backup type and date in the DMP_NAME file for
1333 * LBR-type backup if any file is specified.
1335 * Parameters:
1336 * params (input) - pointer to the parameters structure
1337 * nlp (input) - pointer to the nlp structure
1339 * Returns:
1340 * void
1342 static void
1343 save_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1345 if (!params || !nlp)
1346 return;
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);
1360 * save_level_v3
1362 * Save the date and level of the current backup in the dumpdates
1363 * file.
1365 * Parameters:
1366 * params (input) - pointer to the parameters structure
1367 * nlp (input) - pointer to the nlp structure
1369 * Returns:
1370 * void
1372 static void
1373 save_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1375 if (!params || !nlp)
1376 return;
1378 if (!NLP_SHOULD_UPDATE(nlp)) {
1379 NDMP_LOG(LOG_DEBUG, "update not requested");
1380 } else if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel,
1381 nlp->nlp_cdate) < 0) {
1382 MOD_LOGV3(params, NDMP_LOG_ERROR, "Logging backup date.\n");
1388 * save_backup_date_v3
1390 * A dispatcher function to call the corresponding save function
1391 * based on the backup type.
1393 * Parameters:
1394 * params (input) - pointer to the parameters structure
1395 * nlp (input) - pointer to the nlp structure
1397 * Returns:
1398 * void
1400 static void
1401 save_backup_date_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1403 if (!params || !nlp)
1404 return;
1406 if (NLP_ISSET(nlp, NLPF_TOKENBK))
1407 save_date_token_v3(params, nlp);
1408 else if (NLP_ISSET(nlp, NLPF_LBRBK))
1409 save_lbr_bk_v3(params, nlp);
1410 else if (NLP_ISSET(nlp, NLPF_LEVELBK))
1411 save_level_v3(params, nlp);
1412 else {
1413 MOD_LOGV3(params, NDMP_LOG_ERROR,
1414 "Internal error: lost backup level type for \"%s\".\n",
1415 nlp->nlp_backup_path);
1421 * backup_alloc_structs_v3
1423 * Create the structures for V3 backup. This includes:
1424 * Job stats
1425 * Reader writer IPC
1426 * File history callback structure
1428 * Parameters:
1429 * session (input) - pointer to the session
1430 * jname (input) - name assigned to the current backup for
1431 * job stats strucure
1433 * Returns:
1434 * 0: on success
1435 * -1: otherwise
1437 static int
1438 backup_alloc_structs_v3(ndmpd_session_t *session, char *jname)
1440 int n;
1441 long xfer_size;
1442 ndmp_lbr_params_t *nlp;
1443 tlm_commands_t *cmds;
1445 nlp = ndmp_get_nlp(session);
1446 if (!nlp) {
1447 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1448 return (-1);
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);
1457 cmds = &nlp->nlp_cmds;
1458 (void) memset(cmds, 0, sizeof (*cmds));
1460 xfer_size = ndmp_buffer_get_size(session);
1461 if (xfer_size < 512*KILOBYTE) {
1463 * Read multiple of mover_record_size near to 512K. This
1464 * will prevent the data being copied in the mover buffer
1465 * when we write the data.
1467 n = 512 * KILOBYTE / xfer_size;
1468 if (n <= 0)
1469 n = 1;
1470 xfer_size *= n;
1471 NDMP_LOG(LOG_DEBUG, "Adjusted read size: %d",
1472 xfer_size);
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);
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);
1488 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
1489 nlp->nlp_restored = NULL;
1491 return (0);
1496 * restore_alloc_structs_v3
1498 * Create the structures for V3 Restore. This includes:
1499 * Job stats
1500 * Reader writer IPC
1501 * File recovery callback structure
1503 * Parameters:
1504 * session (input) - pointer to the session
1505 * jname (input) - name assigned to the current backup for
1506 * job stats strucure
1508 * Returns:
1509 * 0: on success
1510 * -1: otherwise
1513 restore_alloc_structs_v3(ndmpd_session_t *session, char *jname)
1515 long xfer_size;
1516 ndmp_lbr_params_t *nlp;
1517 tlm_commands_t *cmds;
1519 nlp = ndmp_get_nlp(session);
1520 if (!nlp) {
1521 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1522 return (-1);
1525 /* this is used in ndmpd_path_restored_v3() */
1526 nlp->nlp_lastidx = -1;
1528 nlp->nlp_jstat = tlm_new_job_stats(jname);
1529 if (!nlp->nlp_jstat) {
1530 NDMP_LOG(LOG_DEBUG, "Creating job stats");
1531 return (-1);
1534 cmds = &nlp->nlp_cmds;
1535 (void) memset(cmds, 0, sizeof (*cmds));
1537 xfer_size = ndmp_buffer_get_size(session);
1538 cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
1539 if (!cmds->tcs_command) {
1540 tlm_un_ref_job_stats(jname);
1541 return (-1);
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);
1551 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
1553 nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0);
1554 if (nlp->nlp_rsbm < 0) {
1555 NDMP_LOG(LOG_ERR, "Out of memory.");
1556 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
1557 tlm_release_reader_writer_ipc(cmds->tcs_command);
1558 tlm_un_ref_job_stats(jname);
1559 return (-1);
1562 return (0);
1567 * free_structs_v3
1569 * Release the resources allocated by backup_alloc_structs_v3
1570 * function.
1572 * Parameters:
1573 * session (input) - pointer to the session
1574 * jname (input) - name assigned to the current backup for
1575 * job stats strucure
1577 * Returns:
1578 * void
1580 /*ARGSUSED*/
1581 static void
1582 free_structs_v3(ndmpd_session_t *session, char *jname)
1584 ndmp_lbr_params_t *nlp;
1585 tlm_commands_t *cmds;
1587 nlp = ndmp_get_nlp(session);
1588 if (!nlp) {
1589 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1590 return;
1592 cmds = &nlp->nlp_cmds;
1593 if (!cmds) {
1594 NDMP_LOG(LOG_DEBUG, "cmds == NULL");
1595 return;
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");
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");
1613 if (nlp->nlp_bkmap >= 0) {
1614 (void) dbm_free(nlp->nlp_bkmap);
1615 nlp->nlp_bkmap = -1;
1618 if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) {
1619 if (nlp->nlp_rsbm < 0) {
1620 NDMP_LOG(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm);
1621 } else {
1622 (void) bm_free(nlp->nlp_rsbm);
1623 nlp->nlp_rsbm = -1;
1630 * backup_dirv3
1632 * Backup a directory and update the bytes processed field of the
1633 * data server.
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
1640 * Returns:
1641 * 0: on success
1642 * != 0: otherwise
1644 static int
1645 backup_dirv3(bk_param_v3_t *bpp, fst_node_t *pnp,
1646 fst_node_t *enp)
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;
1655 if (!bpp || !pnp || !enp) {
1656 NDMP_LOG(LOG_DEBUG, "Invalid argument");
1657 return (-1);
1660 NDMP_LOG(LOG_DEBUG, "d(%s)", bpp->bp_tmp);
1662 if (lstat64(bpp->bp_tmp, &st) != 0)
1663 return (0);
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);
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';
1679 bpos = tlm_get_data_offset(bpp->bp_lcmd);
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",
1687 bpp->bp_unchkpnm, p);
1689 if (tm_tar_ops.tm_putdir != NULL)
1690 (void) (tm_tar_ops.tm_putdir)(fullpath, bpp->bp_tlmacl,
1691 bpp->bp_lcmd, bpp->bp_js);
1693 apos = tlm_get_data_offset(bpp->bp_lcmd);
1694 bpp->bp_session->ns_data.dd_module.dm_stats.ms_bytes_processed +=
1695 apos - bpos;
1697 return (0);
1702 * backup_filev3
1704 * Backup a file and update the bytes processed field of the
1705 * data server.
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
1712 * Returns:
1713 * 0: on success
1714 * != 0: otherwise
1716 static int
1717 backup_filev3(bk_param_v3_t *bpp, fst_node_t *pnp,
1718 fst_node_t *enp)
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;
1729 if (!bpp || !pnp || !enp) {
1730 NDMP_LOG(LOG_DEBUG, "Invalid argument");
1731 return (-1);
1734 NDMP_LOG(LOG_DEBUG, "f(%s)", bpp->bp_tmp);
1736 if (lstat64(bpp->bp_tmp, &st) != 0)
1737 return (0);
1739 if (!S_ISLNK(bpp->bp_tlmacl->acl_attr.st_mode)) {
1740 if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) {
1741 NDMP_LOG(LOG_DEBUG, "acl_get error");
1742 return (-1);
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';
1757 bpos = tlm_get_data_offset(bpp->bp_lcmd);
1758 ent = enp->tn_path ? enp->tn_path : "";
1760 p = pnp->tn_path + strlen(bpp->bp_chkpnm);
1761 if (*p == '/')
1762 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s%s",
1763 bpp->bp_unchkpnm, p);
1764 else
1765 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s",
1766 bpp->bp_unchkpnm, p);
1768 if (tm_tar_ops.tm_putfile != NULL)
1769 rv = (tm_tar_ops.tm_putfile)(fullpath, ent, pnp->tn_path,
1770 bpp->bp_tlmacl, bpp->bp_cmds, bpp->bp_lcmd, bpp->bp_js,
1771 bpp->bp_session->hardlink_q);
1773 apos = tlm_get_data_offset(bpp->bp_lcmd);
1774 bpp->bp_session->ns_data.dd_module.dm_stats.ms_bytes_processed +=
1775 apos - bpos;
1777 return (rv < 0 ? rv : 0);
1782 * check_bk_args
1784 * Check the argument of the bpp. This is shared function between
1785 * timebk_v3 and lbrbk_v3 functions. The checks include:
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.
1792 * Parameters:
1793 * bpp (input) - pointer to the backup parameters structure
1795 * Returns:
1796 * 0: if everything's OK
1797 * != 0: otherwise
1799 static int
1800 check_bk_args(bk_param_v3_t *bpp)
1802 int rv;
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;
1825 return (rv);
1830 * shouldskip
1832 * Determines if the current entry should be skipped or it
1833 * should be backed up.
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
1842 * Returns:
1843 * TRUE: if the entry should not be backed up
1844 * FALSE: otherwise
1846 static boolean_t
1847 shouldskip(bk_param_v3_t *bpp, fst_node_t *pnp,
1848 fst_node_t *enp, int *errp)
1850 char *ent;
1851 boolean_t rv;
1852 struct stat64 *estp;
1854 if (!bpp || !pnp || !enp || !errp) {
1855 NDMP_LOG(LOG_DEBUG, "Invalid argument");
1856 return (TRUE);
1859 if (!enp->tn_path) {
1860 ent = "";
1861 estp = pnp->tn_st;
1862 } else {
1863 ent = enp->tn_path;
1864 estp = enp->tn_st;
1868 * When excluding or skipping entries, FST_SKIP should be
1869 * returned, otherwise, 0 should be returned to
1870 * get other entries in the directory of this entry.
1872 if (!dbm_getone(bpp->bp_nlp->nlp_bkmap, (u_longlong_t)estp->st_ino)) {
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;
1895 return (rv);
1900 * ischngd
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.
1908 * By setting ndmp_force_bk_dirs global variable to a non-zero
1909 * value, directories are backed up anyways.
1911 * Backing up the directories unconditionally helps
1912 * restoring the metadata of directories as well, when one
1913 * of the objects below them are being restored.
1915 * For non-directory objects, if the modification or change
1916 * time of the object is after the date specified by the
1917 * bk_selector_t, the the object must be backed up.
1919 static boolean_t
1920 ischngd(struct stat64 *stp, time_t t, ndmp_lbr_params_t *nlp)
1922 boolean_t rv;
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) {
1932 * if we are doing base backup then we do not need to
1933 * check the time, for we should backup everything.
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))) {
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.
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.
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);
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);
1984 return (rv);
1989 * iscreated
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
1995 /*ARGSUSED*/
1996 int iscreated(ndmp_lbr_params_t *nlp, char *name, tlm_acls_t *tacl,
1997 time_t t)
1999 int ret;
2000 acl_t *aclp = NULL;
2001 char *acltp;
2003 NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
2004 if (NLP_INCLMTIME(nlp) == FALSE)
2005 return (0);
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);
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);
2021 /* Need to add support for last mtime */
2023 return (0);
2027 * size_cb
2029 * The callback function for calculating the size of
2030 * the backup path. This is used to get an estimate
2031 * of the progress of backup during NDMP backup
2033 static int
2034 size_cb(void *arg, fst_node_t *pnp, fst_node_t *enp)
2036 struct stat64 *stp;
2038 stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2039 *((u_longlong_t *)arg) += stp->st_size;
2041 return (0);
2045 * timebk_v3
2047 * The callback function for backing up objects based on
2048 * their time stamp. This is shared between token-based
2049 * and level-based backup, which look at the time stamps
2050 * of the objects to determine if they should be backed
2051 * up.
2053 * Parameters:
2054 * arg (input) - pointer to the backup parameters structure
2055 * pnp (input) - pointer to the path node
2056 * enp (input) - pointer to the entry node
2058 * Returns:
2059 * 0: if backup should continue
2060 * -1: if the backup should be stopped
2061 * FST_SKIP: if backing up the current directory is enough
2063 static int
2064 timebk_v3(void *arg, fst_node_t *pnp, fst_node_t *enp)
2066 char *ent;
2067 int rv;
2068 time_t t;
2069 bk_param_v3_t *bpp;
2070 struct stat64 *stp;
2071 fs_fhandle_t *fhp;
2073 bpp = (bk_param_v3_t *)arg;
2075 rv = check_bk_args(bpp);
2076 if (rv != 0)
2077 return (rv);
2079 stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2080 if (shouldskip(bpp, pnp, enp, &rv))
2081 return (rv);
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;
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);
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);
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);
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);
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));
2124 bpp->bp_tlmacl->acl_fil_fh = *fhp;
2125 (void) backup_filev3(bpp, pnp, enp);
2129 return (rv);
2134 * lbrbk_v3
2136 * The callback function for backing up objects based on
2137 * their archive directory bit. This is used in LBR-type
2138 * backup. In which the objects are backed up if their
2139 * archive bit is set.
2141 * Parameters:
2142 * arg (input) - pointer to the backup parameters structure
2143 * pnp (input) - pointer to the path node
2144 * enp (input) - pointer to the entry node
2146 * Returns:
2147 * 0: if backup should continue
2148 * -1: if the backup should be stopped
2149 * FST_SKIP: if backing up the current directory is enough
2151 static int
2152 lbrbk_v3(void *arg, fst_node_t *pnp, fst_node_t *enp)
2154 char *ent;
2155 int rv;
2156 bk_param_v3_t *bpp;
2157 struct stat64 *stp;
2158 fs_fhandle_t *fhp;
2160 bpp = (bk_param_v3_t *)arg;
2161 rv = check_bk_args(bpp);
2162 if (rv != 0)
2163 return (rv);
2165 stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2166 if (shouldskip(bpp, pnp, enp, &rv))
2167 return (rv);
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;
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);
2183 if (!NLP_ISSET(bpp->bp_nlp, NLPF_LBRBK)) {
2184 NDMP_LOG(LOG_DEBUG, "!NLPF_LBRBK");
2185 return (-1);
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);
2193 if (SHOULD_LBRBK(bpp)) {
2194 bpp->bp_tlmacl->acl_attr = *stp;
2195 rv = backup_dirv3(bpp, pnp, enp);
2197 } else if (SHOULD_LBRBK(bpp)) {
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);
2204 return (rv);
2209 * backup_reader_v3
2211 * The reader thread for the backup. It sets up the callback
2212 * parameters and traverses the backup hierarchy in level-order
2213 * way.
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
2221 * Returns:
2222 * 0: on success
2223 * != 0: otherwise
2225 static int
2226 backup_reader_v3(backup_reader_arg_t *argp)
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;
2238 if (!argp)
2239 return (-1);
2241 jname = argp->br_jname;
2242 nlp = argp->br_nlp;
2243 cmds = argp->br_cmds;
2245 rv = 0;
2246 lcmd = cmds->tcs_command;
2247 lcmd->tc_ref++;
2248 cmds->tcs_reader_count++;
2250 (void) memset(&tlm_acls, 0, sizeof (tlm_acls));
2252 /* NDMP parameters */
2253 bp.bp_session = nlp->nlp_session;
2254 bp.bp_nlp = nlp;
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;
2263 /* release the parent thread, after referencing the job stats */
2264 (void) pthread_barrier_wait(&argp->br_barrier);
2266 bp.bp_tmp = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
2267 if (!bp.bp_tmp)
2268 return (-1);
2271 * Make the checkpointed paths for traversing the
2272 * backup hierarchy, if we make the checkpoint.
2274 bp.bp_unchkpnm = nlp->nlp_backup_path;
2275 if (!NLP_ISCHKPNTED(nlp)) {
2276 tlm_acls.acl_checkpointed = TRUE;
2277 bp.bp_chkpnm = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
2278 if (!bp.bp_chkpnm) {
2279 NDMP_FREE(bp.bp_tmp);
2280 return (-1);
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;
2288 bp.bp_excls = ndmpd_make_exc_list();
2290 /* set traversing arguments */
2291 ft.ft_path = nlp->nlp_backup_path;
2292 ft.ft_lpath = bp.bp_chkpnm;
2294 NDMP_LOG(LOG_DEBUG, "path %s lpath %s", ft.ft_path, ft.ft_lpath);
2295 if (NLP_ISSET(nlp, NLPF_TOKENBK) || NLP_ISSET(nlp, NLPF_LEVELBK)) {
2296 ft.ft_callbk = timebk_v3;
2297 tlm_acls.acl_clear_archive = FALSE;
2298 } else if (NLP_ISSET(nlp, NLPF_LBRBK)) {
2299 ft.ft_callbk = lbrbk_v3;
2300 tlm_acls.acl_clear_archive = FALSE;
2302 NDMP_LOG(LOG_DEBUG, "bp_opr %x clr_arc %c",
2303 bp.bp_opr, NDMP_YORN(tlm_acls.acl_clear_archive));
2304 } else {
2305 rv = -1;
2306 MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR,
2307 "Unknow backup type.\n");
2309 ft.ft_arg = &bp;
2310 ft.ft_logfp = (ft_log_t)ndmp_log;
2311 ft.ft_flags = FST_VERBOSE | FST_STOP_ONERR;
2313 /* take into account the header written to the stream so far */
2314 n = tlm_get_data_offset(lcmd);
2315 nlp->nlp_session->ns_data.dd_module.dm_stats.ms_bytes_processed = n;
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);
2335 if (!NLP_ISCHKPNTED(nlp))
2336 NDMP_FREE(bp.bp_chkpnm);
2337 NDMP_FREE(bp.bp_tmp);
2338 NDMP_FREE(bp.bp_excls);
2340 cmds->tcs_reader_count--;
2341 lcmd->tc_writer = TLM_STOP;
2342 tlm_release_reader_writer_ipc(lcmd);
2343 tlm_un_ref_job_stats(jname);
2344 return (rv);
2350 * tar_backup_v3
2352 * Traverse the backup hierarchy if needed and make the bitmap.
2353 * Then launch reader and writer threads to do the actual backup.
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
2361 * Returns:
2362 * 0: on success
2363 * != 0: otherwise
2365 static int
2366 tar_backup_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
2367 ndmp_lbr_params_t *nlp, char *jname)
2369 tlm_commands_t *cmds;
2370 backup_reader_arg_t arg;
2371 pthread_t rdtp;
2372 char info[256];
2373 int result;
2374 ndmp_context_t nctx;
2375 int err;
2377 if (ndmp_get_bk_dir_ino(nlp))
2378 return (-1);
2380 result = err = 0;
2382 /* exit as if there was an internal error */
2383 if (session->ns_eof)
2384 return (-1);
2386 if (!session->ns_data.dd_abort) {
2387 if (backup_alloc_structs_v3(session, jname) < 0) {
2388 nlp->nlp_bkmap = -1;
2389 return (-1);
2392 if (ndmpd_mark_inodes_v3(session, nlp) != 0) {
2393 if (nlp->nlp_bkmap != -1) {
2394 (void) dbm_free(nlp->nlp_bkmap);
2395 nlp->nlp_bkmap = -1;
2397 free_structs_v3(session, jname);
2398 return (-1);
2401 nlp->nlp_jstat->js_start_ltime = time(NULL);
2402 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
2403 nlp->nlp_jstat->js_chkpnt_time = nlp->nlp_cdate;
2405 cmds = &nlp->nlp_cmds;
2406 cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
2407 cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
2408 cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
2410 if (ndmp_write_utf8magic(cmds->tcs_command) < 0) {
2411 free_structs_v3(session, jname);
2412 return (-1);
2415 NDMP_LOG(LOG_DEBUG,
2416 "Backing up \"%s\" started.", nlp->nlp_backup_path);
2418 /* Plug-in module */
2419 if (ndmp_pl != NULL &&
2420 ndmp_pl->np_pre_backup != NULL) {
2421 (void) memset(&nctx, 0, sizeof (ndmp_context_t));
2422 nctx.nc_plversion = ndmp_pl->np_plversion;
2423 nctx.nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
2424 nctx.nc_cmds = cmds;
2425 nctx.nc_params = params;
2426 nctx.nc_ddata = (void *) session;
2427 if ((err = ndmp_pl->np_pre_backup(ndmp_pl, &nctx,
2428 nlp->nlp_backup_path)) != 0) {
2429 NDMP_LOG(LOG_ERR, "Pre-backup plug-in: %m");
2430 goto backup_out;
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;
2439 (void) pthread_barrier_init(&arg.br_barrier, 0, 2);
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);
2453 if ((err = ndmp_tar_writer(session, params, cmds)) != 0)
2454 result = EIO;
2456 nlp->nlp_jstat->js_stop_time = time(NULL);
2458 (void) snprintf(info, sizeof (info),
2459 "Runtime [%s] %llu bytes (%llu): %d seconds\n",
2460 nlp->nlp_backup_path,
2461 session->ns_data.dd_module.dm_stats.ms_bytes_processed,
2462 session->ns_data.dd_module.dm_stats.ms_bytes_processed,
2463 nlp->nlp_jstat->js_stop_time -
2464 nlp->nlp_jstat->js_start_ltime);
2465 MOD_LOGV3(params, NDMP_LOG_NORMAL, info);
2467 ndmp_wait_for_reader(cmds);
2468 (void) pthread_join(rdtp, NULL);
2470 /* exit as if there was an internal error */
2471 if (session->ns_eof) {
2472 result = EPIPE;
2473 err = -1;
2475 if (!session->ns_data.dd_abort) {
2476 ndmpd_audit_backup(session->ns_connection,
2477 nlp->nlp_backup_path,
2478 session->ns_data.dd_data_addr.addr_type,
2479 session->ns_tape.td_adapter_name, result);
2480 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" Finished.",
2481 nlp->nlp_backup_path);
2485 if (session->ns_data.dd_abort) {
2486 ndmpd_audit_backup(session->ns_connection,
2487 nlp->nlp_backup_path,
2488 session->ns_data.dd_data_addr.addr_type,
2489 session->ns_tape.td_adapter_name, EINTR);
2490 NDMP_LOG(LOG_DEBUG,
2491 "Backing up \"%s\" aborted.", nlp->nlp_backup_path);
2492 err = -1;
2493 } else {
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);
2505 free_structs_v3(session, jname);
2506 return (err);
2510 * get_backup_size
2512 * Find the estimate of backup size. This is used to get an estimate
2513 * of the progress of backup during NDMP backup.
2515 void
2516 get_backup_size(ndmp_bkup_size_arg_t *sarg)
2518 fs_traverse_t ft;
2519 u_longlong_t bk_size;
2520 char spath[PATH_MAX];
2521 int rv;
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;
2532 ft.ft_lpath = ft.ft_path;
2533 ft.ft_callbk = size_cb;
2534 ft.ft_arg = &bk_size;
2535 ft.ft_logfp = (ft_log_t)ndmp_log;
2536 ft.ft_flags = FST_VERBOSE;
2538 if ((rv = traverse_level(&ft)) != 0) {
2539 NDMP_LOG(LOG_DEBUG, "bksize err=%d", rv);
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));
2545 sarg->bs_session->ns_data.dd_data_size = bk_size;
2549 * get_rs_path_v3
2551 * Find the restore path
2553 ndmp_error
2554 get_rs_path_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
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];
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);
2571 if (strcmp(nm_dpath_list[nm_cnt], ep->nm3_dpath) != 0 &&
2572 nm_cnt < MULTIPLE_DEST_DIRS - 1)
2573 nm_dpath_list[++nm_cnt] = ep->nm3_dpath;
2576 multiple_dest_restore = (nm_cnt > 1);
2577 nlp->nlp_restore_path = mdest_buf;
2579 for (i = 1; i < nm_cnt + 1; i++) {
2580 if (ISDEFINED(nm_dpath_list[i]))
2581 dp = nm_dpath_list[i];
2582 else
2583 /* the default destination path is backup directory */
2584 dp = nlp->nlp_backup_path;
2586 /* check the destination directory exists and is writable */
2587 if (!fs_volexist(dp)) {
2588 rv = NDMP_ILLEGAL_ARGS_ERR;
2589 MOD_LOGV3(params, NDMP_LOG_ERROR,
2590 "Invalid destination path volume \"%s\".\n", dp);
2591 } else if (!voliswr(dp)) {
2592 rv = NDMP_ILLEGAL_ARGS_ERR;
2593 MOD_LOGV3(params, NDMP_LOG_ERROR,
2594 "The destination path volume"
2595 " is not writable \"%s\".\n", dp);
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);
2604 * Exit if there is an error or it is not a multiple
2605 * destination restore mode
2607 if (rv != NDMP_NO_ERR || !multiple_dest_restore)
2608 break;
2610 if (i < nm_cnt)
2611 (void) strlcat(nlp->nlp_restore_path, ", ",
2612 sizeof (mdest_buf));
2615 return (rv);
2620 * fix_nlist_v3
2622 * Check if the recovery list is valid and fix it if there are some
2623 * unspecified entries in it. It checks for original, destination
2624 * and new path for all NDMP names provided inside the list.
2626 * V3: dpath is the destination directory. If newnm is not NULL, the
2627 * destination path is dpath/newnm. Otherwise the destination path is
2628 * dpath/opath_last_node, where opath_last_node is the last node in opath.
2630 * V4: If newnm is not NULL, dpath is the destination directory, and
2631 * dpath/newnm is the destination path. If newnm is NULL, dpath is
2632 * the destination path (opath is not involved in forming destination path).
2634 ndmp_error
2635 fix_nlist_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
2636 ndmp_lbr_params_t *nlp)
2638 char *cp, *buf, *bp;
2639 int i, n;
2640 int iswrbk;
2641 int bvexists;
2642 ndmp_error rv;
2643 mem_ndmp_name_v3_t *ep;
2644 char *dp;
2645 char *nm;
2646 int existsvol;
2647 int isrwdst;
2649 buf = ndmp_malloc(TLM_MAX_PATH_NAME);
2650 if (!buf) {
2651 MOD_LOGV3(params, NDMP_LOG_ERROR, "Insufficient memory.\n");
2652 return (NDMP_NO_MEM_ERR);
2655 bvexists = fs_volexist(nlp->nlp_backup_path);
2656 iswrbk = voliswr(nlp->nlp_backup_path);
2658 rv = NDMP_NO_ERR;
2659 n = session->ns_data.dd_nlist_len;
2660 for (i = 0; i < n; i++) {
2661 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
2662 if (!ep)
2663 continue;
2665 /* chop off the trailing slashes */
2666 chopslash(ep->nm3_opath);
2668 chopslash(ep->nm3_dpath);
2669 chopslash(ep->nm3_newnm);
2671 /* existing and non-empty destination path */
2672 if (ISDEFINED(ep->nm3_dpath)) {
2673 dp = ep->nm3_dpath;
2674 existsvol = fs_volexist(dp);
2675 isrwdst = voliswr(dp);
2676 } else {
2677 /* the default destination path is backup directory */
2678 dp = nlp->nlp_backup_path;
2679 existsvol = bvexists;
2680 isrwdst = iswrbk;
2683 /* check the destination directory exists and is writable */
2684 if (!existsvol) {
2685 rv = NDMP_ILLEGAL_ARGS_ERR;
2686 MOD_LOGV3(params, NDMP_LOG_ERROR,
2687 "Invalid destination path volume "
2688 "\"%s\".\n", dp);
2689 break;
2691 if (!isrwdst) {
2692 rv = NDMP_ILLEGAL_ARGS_ERR;
2693 MOD_LOGV3(params, NDMP_LOG_ERROR,
2694 "The destination path volume is not "
2695 "writable \"%s\".\n", dp);
2696 break;
2700 * If new name is not specified, the default new name is
2701 * the last component of the original path, if any
2702 * (except in V4).
2704 if (ISDEFINED(ep->nm3_newnm)) {
2705 nm = ep->nm3_newnm;
2706 } else {
2707 char *p, *q;
2710 * Find the last component of nm3_opath.
2711 * nm3_opath has no trailing '/'.
2713 p = strrchr(ep->nm3_opath, '/');
2714 nm = p ? p + 1 : ep->nm3_opath;
2717 * In DDAR the last component could
2718 * be repeated in nm3_dpath
2720 q = strrchr(ep->nm3_dpath, '/');
2721 q = q ? q + 1 : ep->nm3_dpath;
2722 if (strcmp(nm, q) == 0)
2723 nm = NULL;
2727 bp = joinpath(buf, dp, nm);
2728 if (!bp) {
2730 * Note: What should be done with this entry?
2731 * We leave it untouched for now, hence no path in
2732 * the backup image matches with this entry and will
2733 * be reported as not found.
2735 MOD_LOGV3(params, NDMP_LOG_ERROR,
2736 "Destination path too long(%s/%s)", dp, nm);
2737 continue;
2739 cp = strdup(bp);
2740 if (!cp) {
2741 MOD_LOGV3(params, NDMP_LOG_ERROR,
2742 "Insufficient memory.\n");
2743 rv = NDMP_NO_MEM_ERR;
2744 break;
2746 free(ep->nm3_dpath);
2747 ep->nm3_dpath = cp;
2748 NDMP_FREE(ep->nm3_newnm);
2750 bp = joinpath(buf, nlp->nlp_backup_path, ep->nm3_opath);
2751 if (!bp) {
2753 * Note: The same problem of above with long path.
2755 MOD_LOGV3(params, NDMP_LOG_ERROR,
2756 "Path too long(%s/%s)",
2757 nlp->nlp_backup_path, ep->nm3_opath);
2758 continue;
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;
2767 NDMP_FREE(ep->nm3_opath);
2768 ep->nm3_opath = cp;
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");
2779 free(buf);
2781 return (rv);
2786 * allvalidfh
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).
2792 static boolean_t
2793 allvalidfh(ndmpd_session_t *session, ndmpd_module_params_t *params)
2795 int i, n;
2796 boolean_t rv;
2797 mem_ndmp_name_v3_t *ep;
2799 rv = TRUE;
2800 n = session->ns_data.dd_nlist_len;
2801 for (i = 0; i < n; i++) {
2802 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
2803 if (!ep)
2804 continue;
2806 * The fh_info's sent from the client are multiples
2807 * of RECORDSIZE which is 512 bytes.
2809 * All our fh_info's are at the RECORDSIZE boundary. If there
2810 * is any fh_info that is less than RECORDSIZE (this covers 0
2811 * and -1 values too), then the result is that DAR cannot be
2812 * done.
2814 if (ep->nm3_fh_info < RECORDSIZE ||
2815 ep->nm3_fh_info % RECORDSIZE != 0) {
2816 rv = FALSE;
2817 break;
2821 return (rv);
2826 * log_rs_params_v3
2828 * Log a copy of all values of the restore parameters
2830 void
2831 log_rs_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
2832 ndmp_lbr_params_t *nlp)
2834 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Restoring to \"%s\".\n",
2835 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
2837 if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) {
2838 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Tape server: local.\n");
2839 MOD_LOGV3(params, NDMP_LOG_NORMAL,
2840 "Tape record size: %d.\n",
2841 session->ns_mover.md_record_size);
2842 } else if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP)
2843 MOD_LOGV3(params, NDMP_LOG_NORMAL,
2844 "Tape server: remote at %s:%d.\n",
2845 inet_ntoa(IN_ADDR(session->ns_data.dd_data_addr.tcp_ip_v3)),
2846 session->ns_data.dd_data_addr.tcp_port_v3);
2847 else
2848 MOD_LOGV3(params, NDMP_LOG_ERROR,
2849 "Unknown tape server address type.\n");
2851 if (NLP_ISSET(nlp, NLPF_DIRECT))
2852 MOD_LOGV3(params, NDMP_LOG_NORMAL,
2853 "Direct Access Restore.\n");
2858 * send_unrecovered_list_v3
2860 * Create the list of files that were in restore list but
2861 * not recovered due to some errors.
2864 send_unrecovered_list_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
2866 int i, rv;
2867 int err;
2869 if (!params) {
2870 NDMP_LOG(LOG_DEBUG, "params == NULL");
2871 return (-1);
2873 if (!nlp) {
2874 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2875 return (-1);
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;
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;
2897 return (rv);
2903 * restore_dar_alloc_structs_v3
2905 * Allocates the necessary structures for running DAR restore.
2906 * It just creates the reader writer IPC.
2907 * This function is called for each entry in the restore entry list.
2909 * Parameters:
2910 * session (input) - pointer to the session
2911 * jname (input) - Job name
2913 * Returns:
2914 * 0: on success
2915 * -1: on error
2918 restore_dar_alloc_structs_v3(ndmpd_session_t *session, char *jname)
2920 long xfer_size;
2921 ndmp_lbr_params_t *nlp;
2922 tlm_commands_t *cmds;
2924 nlp = ndmp_get_nlp(session);
2925 if (!nlp) {
2926 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2927 return (-1);
2930 cmds = &nlp->nlp_cmds;
2931 (void) memset(cmds, 0, sizeof (*cmds));
2933 xfer_size = ndmp_buffer_get_size(session);
2934 cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
2935 if (!cmds->tcs_command) {
2936 tlm_un_ref_job_stats(jname);
2937 return (-1);
2940 return (0);
2945 * free_dar_structs_v3
2947 * To free the structures were created by restore_dar_alloc_structs_v3.
2948 * This funnction is called for each entry in restore entry list.
2950 * Parameters:
2951 * session (input) - pointer to the session
2952 * jname (input) - job name
2954 * Returns:
2955 * NONE
2957 /*ARGSUSED*/
2958 static void
2959 free_dar_structs_v3(ndmpd_session_t *session, char *jname)
2961 ndmp_lbr_params_t *nlp;
2962 tlm_commands_t *cmds;
2964 nlp = ndmp_get_nlp(session);
2965 if (!nlp) {
2966 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2967 return;
2969 cmds = &nlp->nlp_cmds;
2970 if (!cmds) {
2971 NDMP_LOG(LOG_DEBUG, "cmds == NULL");
2972 return;
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");
2987 * ndmp_dar_tar_init_v3
2989 * Constructor for the DAR restore. Creates job name, allocates structures
2990 * needed for keeping the statistics, and reports the start of restore action.
2991 * It is called once for each DAR restore request.
2993 * Parameters:
2994 * session (input) - pointer to the session
2995 * nlp (input) - pointer to the nlp structure
2997 * Returns:
2998 * char pointer: on success
2999 * NULL: on error
3001 static char *ndmpd_dar_tar_init_v3(ndmpd_session_t *session,
3002 ndmp_lbr_params_t *nlp)
3004 char *jname;
3006 jname = ndmp_malloc(TLM_MAX_BACKUP_JOB_NAME);
3008 if (!jname)
3009 return (NULL);
3011 (void) ndmp_new_job_name(jname);
3013 if (!nlp) {
3014 free(jname);
3015 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3016 return (NULL);
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);
3026 nlp->nlp_jstat->js_start_ltime = time(NULL);
3027 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
3029 nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
3030 ndmpd_path_restored_v3, NULL, NULL);
3031 if (!nlp->nlp_logcallbacks) {
3032 tlm_un_ref_job_stats(jname);
3033 free(jname);
3034 return (NULL);
3036 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
3038 nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0);
3039 if (nlp->nlp_rsbm < 0) {
3040 NDMP_LOG(LOG_ERR, "Out of memory.");
3041 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
3042 tlm_un_ref_job_stats(jname);
3043 free(jname);
3044 return (NULL);
3047 /* this is used in ndmpd_path_restored_v3() */
3048 nlp->nlp_lastidx = -1;
3050 NDMP_LOG(LOG_DEBUG, "Restoring from %s tape(s).",
3051 ndmp_data_get_mover_mode(session));
3053 return (jname);
3057 * ndmpd_dar_tar_end_v3
3059 * Deconstructor for the DAR restore. This function is called once per
3060 * DAR request. It deallocates memories allocated by ndmpd_dar_tar_init_v3.
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
3068 * Returns:
3069 * 0: on success
3070 * -1: on error
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)
3075 int err = 0;
3078 NDMP_LOG(LOG_DEBUG, "lastidx %d", nlp->nlp_lastidx);
3080 /* nothing restored. */
3081 (void) send_unrecovered_list_v3(params, nlp);
3083 if (nlp->nlp_jstat) {
3084 nlp->nlp_bytes_total =
3085 (u_longlong_t)nlp->nlp_jstat->js_bytes_total;
3086 tlm_un_ref_job_stats(jname);
3087 nlp->nlp_jstat = NULL;
3088 } else {
3089 NDMP_LOG(LOG_DEBUG, "JSTAT == NULL");
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");
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);
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;
3118 free(jname);
3120 return (err);
3125 * ndmpd_dar_tar_v3
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.
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
3140 * Returns:
3141 * 0: on success
3142 * -1: on error
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)
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;
3160 err = 0;
3163 * We have to allocate and deallocate buffers every time we
3164 * run the restore, for we need to flush the buffers.
3166 if (restore_dar_alloc_structs_v3(session, jname) < 0)
3167 return (-1);
3169 sels = setupsels(session, params, nlp, dar_index);
3170 if (!sels) {
3171 free_dar_structs_v3(session, jname);
3172 return (-1);
3174 excl = NULL;
3175 flags = RSFLG_OVR_ALWAYS;
3176 rn.rn_nlp = nlp;
3177 rn.rn_fp = mknewname;
3179 if (!session->ns_data.dd_abort) {
3180 cmds = &nlp->nlp_cmds;
3181 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
3182 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
3183 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
3185 arg.tr_session = session;
3186 arg.tr_mod_params = params;
3187 arg.tr_cmds = cmds;
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);
3198 cmds->tcs_command->tc_ref++;
3199 cmds->tcs_writer_count++;
3201 /* Plug-in module */
3202 if (ndmp_pl != NULL &&
3203 ndmp_pl->np_pre_restore != NULL) {
3204 (void) memset(&nctx, 0, sizeof (ndmp_context_t));
3205 nctx.nc_cmds = cmds;
3206 nctx.nc_params = params;
3207 nctx.nc_ddata = (void *) session;
3208 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params,
3209 dar_index - 1);
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;
3223 if (tm_tar_ops.tm_getdir != NULL) {
3224 char errbuf[256];
3226 err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
3227 nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags,
3228 dar_index, nlp->nlp_backup_path,
3229 session->hardlink_q);
3231 * If the fatal error from tm_getdir looks like an
3232 * errno code, we send the error description to DMA.
3234 if (err > 0 && strerror_r(err, errbuf,
3235 sizeof (errbuf)) == 0) {
3236 MOD_LOGV3(params, NDMP_LOG_ERROR,
3237 "Fatal error during the restore: %s\n",
3238 errbuf);
3242 cmds->tcs_writer_count--;
3243 cmds->tcs_command->tc_ref--;
3244 NDMP_LOG(LOG_DEBUG, "stop local reader.");
3245 ndmp_stop_local_reader(session, cmds);
3247 ndmp_wait_for_reader(cmds);
3248 (void) pthread_join(rdtp, NULL);
3251 * If this is the last DAR entry and it is a three-way
3252 * restore then we should close the connection.
3254 if ((data_addr_type == NDMP_ADDR_TCP) &&
3255 (dar_index == (int)session->ns_data.dd_nlist_len)) {
3256 NDMP_LOG(LOG_DEBUG, "stop remote reader.");
3257 ndmp_stop_remote_reader(session);
3260 /* exit as if there was an internal error */
3261 if (session->ns_eof)
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;
3273 NDMP_FREE(sels);
3275 free_dar_structs_v3(session, jname);
3277 return (err);
3281 * ndmpd_dar_locate_windwos_v3
3283 * Locating the right window in which the requested file is backed up.
3284 * We should go through windows to find the exact location, for the
3285 * file can be located in for example 10th window after the current window.
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
3293 * Returns:
3294 * 0: on success
3295 * -1: on error
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)
3301 int ret = 0;
3304 for (; ; ) {
3305 ret = (*params->mp_seek_func)(session, fh_info, len);
3307 NDMP_LOG(LOG_DEBUG, "ret %d", ret);
3308 if (ret == 0) /* Seek was done successfully */
3309 break;
3310 else if (ret < 0) {
3311 NDMP_LOG(LOG_DEBUG, "Seek error");
3312 break;
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.
3322 continue;
3324 return (ret);
3328 * ndmpd_rs_dar_tar_v3
3330 * Main DAR function. It calls the constructor, then for each entry it
3331 * calls the locate_window_v3 to find the exact position of the file. Then
3332 * it restores the file.
3333 * When all restore requests are done it calls the deconstructor to clean
3334 * everything up.
3336 * Parameters:
3337 * session (input) - pointer to the session
3338 * params (input) - pointer to the parameters structure
3339 * nlp (input) - pointer to the nlp structure
3341 * Returns:
3342 * 0: on success
3343 * -1: on error
3345 static int
3346 ndmpd_rs_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3347 ndmp_lbr_params_t *nlp)
3349 mem_ndmp_name_v3_t *ep;
3350 u_longlong_t len;
3351 char *jname;
3352 int n = session->ns_data.dd_nlist_len;
3353 int i, ret = 0;
3354 int result = 0;
3356 jname = ndmpd_dar_tar_init_v3(session, nlp);
3358 if (!jname)
3359 return (-1);
3362 * We set the length = sizeof (tlm_tar_hdr_t)
3363 * This is important for three-way DAR restore, for we should
3364 * read the header first (If we ask for more data then we have
3365 * to read and discard the remaining data in the socket)
3367 len = tlm_tarhdr_size();
3369 for (i = 0; i < n; ++i) {
3370 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
3371 if (!ep) {
3372 NDMP_LOG(LOG_DEBUG, "ep NULL, i %d", i);
3373 continue;
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);
3382 * We should seek till finding the window in which file
3383 * is located.
3385 ret = ndmpd_dar_locate_window_v3(session, params,
3386 ep->nm3_fh_info, len);
3388 if (ret < 0) /* If seek fails, restore should be aborted */
3389 break;
3391 * We are inside the target window.
3392 * for each restore we will use one entry as selection list
3394 if ((ret = ndmpd_dar_tar_v3(session, params, nlp, jname, i+1))
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);
3403 NDMP_LOG(LOG_DEBUG, "End of restore list");
3405 (void) ndmpd_dar_tar_end_v3(session, params, nlp, jname);
3407 return (ret);
3411 * ndmp_plugin_pre_restore
3413 * Wrapper for pre-restore callback with multiple path
3415 static int
3416 ndmp_plugin_pre_restore(ndmp_context_t *ctxp, ndmpd_module_params_t *params,
3417 int ncount)
3419 mem_ndmp_name_v3_t *ep;
3420 int err;
3421 int i;
3423 for (i = 0; i < ncount; i++) {
3424 if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i)))
3425 continue;
3426 if ((err = ndmp_pl->np_pre_restore(ndmp_pl, ctxp,
3427 ep->nm3_opath, ep->nm3_dpath)) != 0)
3428 return (err);
3431 return (0);
3435 * get_absolute_path
3437 * Get resolved path name which does not involve ".", ".." or extra
3438 * "/" or symbolic links.
3440 * e.g.
3442 * /backup/path/ -> /backup/path
3443 * /backup/path/. -> /backup/path
3444 * /backup/path/../path/ -> /backup/path
3445 * /link-to-backup-path -> /backup/path
3447 * Returns:
3448 * Pointer to the new path (allocated)
3449 * NULL if the path doesnt exist
3451 static char *
3452 get_absolute_path(const char *bkpath)
3454 char *pbuf;
3455 char *rv;
3457 if (!(pbuf = ndmp_malloc(TLM_MAX_PATH_NAME)))
3458 return (NULL);
3460 if ((rv = realpath(bkpath, pbuf)) == NULL) {
3461 NDMP_LOG(LOG_DEBUG, "Invalid path [%s] err=%d",
3462 bkpath, errno);
3464 return (rv);
3468 * Expands the format string and logs the resulting message to the
3469 * remote DMA
3471 void
3472 ndmp_log_dma(ndmp_context_t *nctx, ndmp_log_dma_type_t lt, const char *fmt, ...)
3474 va_list ap;
3475 char buf[256];
3476 ndmpd_module_params_t *params;
3478 if (nctx == NULL ||
3479 (params = (ndmpd_module_params_t *)nctx->nc_params) == NULL)
3480 return;
3482 va_start(ap, fmt);
3483 (void) vsnprintf(buf, sizeof (buf), fmt, ap);
3484 va_end(ap);
3486 MOD_LOGV3(params, (ndmp_log_type)lt, "%s", buf);
3491 * ndmpd_rs_sar_tar_v3
3493 * Main non-DAR restore function. It will try to restore all the entries
3494 * that have been backed up.
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
3501 * Returns:
3502 * 0: on success
3503 * -1: on error
3505 static int
3506 ndmpd_rs_sar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3507 ndmp_lbr_params_t *nlp)
3509 char jname[TLM_MAX_BACKUP_JOB_NAME];
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;
3521 result = err = 0;
3522 (void) ndmp_new_job_name(jname);
3523 if (restore_alloc_structs_v3(session, jname) < 0)
3524 return (-1);
3526 sels = setupsels(session, params, nlp, 0);
3527 if (!sels) {
3528 free_structs_v3(session, jname);
3529 return (-1);
3531 excl = NULL;
3532 flags = RSFLG_OVR_ALWAYS;
3533 rn.rn_nlp = nlp;
3534 rn.rn_fp = mknewname;
3536 nlp->nlp_jstat->js_start_ltime = time(NULL);
3537 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
3539 if (!session->ns_data.dd_abort && !session->ns_data.dd_abort) {
3540 cmds = &nlp->nlp_cmds;
3541 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
3542 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
3543 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
3545 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" started.",
3546 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3548 arg.tr_session = session;
3549 arg.tr_mod_params = params;
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);
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");
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;
3586 cmds->tcs_command->tc_ref++;
3587 cmds->tcs_writer_count++;
3589 if (tm_tar_ops.tm_getdir != NULL) {
3590 char errbuf[256];
3592 err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
3593 nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags, 0,
3594 nlp->nlp_backup_path, session->hardlink_q);
3596 * If the fatal error from tm_getdir looks like an
3597 * errno code, we send the error description to DMA.
3599 if (err > 0 && strerror_r(err, errbuf,
3600 sizeof (errbuf)) == 0) {
3601 MOD_LOGV3(params, NDMP_LOG_ERROR,
3602 "Fatal error during the restore: %s\n",
3603 errbuf);
3607 cmds->tcs_writer_count--;
3608 cmds->tcs_command->tc_ref--;
3609 nlp->nlp_jstat->js_stop_time = time(NULL);
3611 /* Send the list of un-recovered files/dirs to the client. */
3612 (void) send_unrecovered_list_v3(params, nlp);
3614 ndmp_stop_local_reader(session, cmds);
3615 ndmp_wait_for_reader(cmds);
3616 (void) pthread_join(rdtp, NULL);
3618 ndmp_stop_remote_reader(session);
3620 /* exit as if there was an internal error */
3621 if (session->ns_eof)
3622 err = -1;
3623 if (err == -1)
3624 result = EIO;
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);
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;
3656 NDMP_FREE(sels);
3657 free_structs_v3(session, jname);
3659 return (err);
3664 * ndmp_backup_get_params_v3
3666 * Get the backup parameters from the NDMP env variables
3667 * and log them in the system log and as normal messages
3668 * to the DMA.
3670 * Parameters:
3671 * session (input) - pointer to the session
3672 * params (input) - pointer to the parameters structure
3674 * Returns:
3675 * NDMP_NO_ERR: on success
3676 * != NDMP_NO_ERR: otherwise
3678 ndmp_error
3679 ndmp_backup_get_params_v3(ndmpd_session_t *session,
3680 ndmpd_module_params_t *params)
3682 ndmp_lbr_params_t *nlp;
3684 if (!session || !params)
3685 return (NDMP_ILLEGAL_ARGS_ERR);
3687 nlp = ndmp_get_nlp(session);
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);
3698 nlp->nlp_backup_path = get_absolute_path(nlp->nlp_backup_path);
3699 if (!nlp->nlp_backup_path)
3700 return (NDMP_ILLEGAL_ARGS_ERR);
3702 if (fs_is_chkpntvol(nlp->nlp_backup_path) ||
3703 fs_is_rdonly(nlp->nlp_backup_path) ||
3704 !fs_is_chkpnt_enabled(nlp->nlp_backup_path))
3705 NLP_SET(nlp, NLPF_CHKPNTED_PATH);
3706 else
3707 NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
3709 /* Should the st_ctime be ignored when backing up? */
3710 if (ndmp_ignore_ctime) {
3711 NDMP_LOG(LOG_DEBUG, "ignoring st_ctime");
3712 NLP_SET(nlp, NLPF_IGNCTIME);
3713 } else {
3714 NLP_UNSET(nlp, NLPF_IGNCTIME);
3717 if (ndmp_include_lmtime == TRUE) {
3718 NDMP_LOG(LOG_DEBUG, "including st_lmtime");
3719 NLP_SET(nlp, NLPF_INCLMTIME);
3720 } else {
3721 NLP_UNSET(nlp, NLPF_INCLMTIME);
3724 NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
3726 get_hist_env_v3(params, nlp);
3727 get_exc_env_v3(params, nlp);
3728 get_inc_env_v3(params, nlp);
3729 get_direct_env_v3(params, nlp);
3730 return (get_backup_level_v3(params, nlp));
3735 * ndmpd_tar_backup_starter_v3
3737 * Create the checkpoint for the backup and do the backup,
3738 * then remove the backup checkpoint if we created it.
3739 * Save the backup time information based on the backup
3740 * type and stop the data server.
3742 * Parameters:
3743 * params (input) - pointer to the parameters structure
3745 * Returns:
3746 * 0: on success
3747 * != 0: otherwise
3750 ndmpd_tar_backup_starter_v3(void *arg)
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;
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);
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;
3774 NDMP_LOG(LOG_DEBUG, "err %d, chkpnted %c",
3775 err, NDMP_YORN(NLP_ISCHKPNTED(nlp)));
3777 if (err == 0) {
3778 sarg.bs_session = session;
3779 sarg.bs_jname = jname;
3780 sarg.bs_path = nlp->nlp_backup_path;
3782 /* Get an estimate of the data size */
3783 if (pthread_create(&tid, NULL, (funct_t)get_backup_size,
3784 (void *)&sarg) == 0)
3785 (void) pthread_detach(tid);
3787 err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate, jname);
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);
3796 if (!NLP_ISCHKPNTED(nlp))
3797 (void) ndmp_remove_snapshot(nlp->nlp_backup_path, jname);
3799 NDMP_LOG(LOG_DEBUG, "err %d, update %c",
3800 err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
3802 if (err == 0)
3803 save_backup_date_v3(params, nlp);
3805 MOD_DONE(params, err);
3807 /* nlp_params is allocated in start_backup_v3() */
3808 NDMP_FREE(nlp->nlp_params);
3809 NDMP_FREE(nlp->nlp_backup_path);
3811 NS_DEC(nbk);
3812 ndmp_session_unref(session);
3813 return (err);
3819 * ndmpd_tar_backup_abort_v3
3821 * Abort the backup operation and stop the reader thread.
3823 * Parameters:
3824 * module_cookie (input) - pointer to the nlp structure
3826 * Returns:
3827 * 0: always
3830 ndmpd_tar_backup_abort_v3(void *module_cookie)
3832 ndmp_lbr_params_t *nlp;
3834 nlp = (ndmp_lbr_params_t *)module_cookie;
3835 if (nlp && nlp->nlp_session) {
3836 if (nlp->nlp_session->ns_data.dd_data_addr.addr_type ==
3837 NDMP_ADDR_TCP &&
3838 nlp->nlp_session->ns_data.dd_sock != -1) {
3839 (void) close(nlp->nlp_session->ns_data.dd_sock);
3840 nlp->nlp_session->ns_data.dd_sock = -1;
3842 ndmp_stop_reader_thread(nlp->nlp_session);
3845 return (0);
3850 * ndmp_restore_get_params_v3
3852 * Get the parameters specified for recovery such as restore path, type
3853 * of restore (DAR, non-DAR) etc
3855 * Parameters:
3856 * session (input) - pointer to the session
3857 * params (input) - pointer to the parameters structure
3859 * Returns:
3860 * NDMP_NO_ERR: on success
3861 * != NDMP_NO_ERR: otherwise
3863 ndmp_error
3864 ndmp_restore_get_params_v3(ndmpd_session_t *session,
3865 ndmpd_module_params_t *params)
3867 ndmp_error rv;
3868 ndmp_lbr_params_t *nlp;
3870 if (!(nlp = ndmp_get_nlp(session))) {
3871 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
3872 rv = NDMP_ILLEGAL_ARGS_ERR;
3873 } else if (!(nlp->nlp_backup_path = get_backup_path_v3(params)))
3874 rv = NDMP_ILLEGAL_ARGS_ERR;
3875 else if ((nlp->nlp_nfiles = session->ns_data.dd_nlist_len) == 0) {
3876 NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
3877 rv = NDMP_ILLEGAL_ARGS_ERR;
3878 } else if (get_rs_path_v3(params, nlp) != NDMP_NO_ERR) {
3879 rv = NDMP_ILLEGAL_ARGS_ERR;
3880 } else if ((rv = fix_nlist_v3(session, params, nlp)) != NDMP_NO_ERR) {
3881 NDMP_LOG(LOG_DEBUG, "fix_nlist_v3: %d", rv);
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);
3895 * DAR can be done if all the fh_info's are valid.
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);
3907 log_rs_params_v3(session, params, nlp);
3910 return (rv);
3915 * ndmpd_tar_restore_starter_v3
3917 * The main restore starter function. It will start a DAR or
3918 * non-DAR recovery based on the parameters. (V3 and V4 only)
3920 * Parameters:
3921 * params (input) - pointer to the parameters structure
3923 * Returns:
3924 * NDMP_NO_ERR: on success
3925 * != NDMP_NO_ERR: otherwise
3928 ndmpd_tar_restore_starter_v3(void *arg)
3930 ndmpd_module_params_t *params = arg;
3931 int err;
3932 ndmpd_session_t *session;
3933 ndmp_lbr_params_t *nlp;
3936 session = (ndmpd_session_t *)(params->mp_daemon_cookie);
3937 *(params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
3938 ndmp_session_ref(session);
3940 if (NLP_ISSET(nlp, NLPF_DIRECT))
3941 err = ndmpd_rs_dar_tar_v3(session, params, nlp);
3942 else
3943 err = ndmpd_rs_sar_tar_v3(session, params, nlp);
3945 MOD_DONE(params, err);
3947 NS_DEC(nrs);
3948 /* nlp_params is allocated in start_recover() */
3949 NDMP_FREE(nlp->nlp_params);
3950 ndmp_session_unref(session);
3951 return (err);
3956 * ndmp_tar_restore_abort_v3
3958 * Restore abort function (V3 and V4 only)
3960 * Parameters:
3961 * module_cookie (input) - pointer to nlp
3963 * Returns:
3967 ndmpd_tar_restore_abort_v3(void *module_cookie)
3969 ndmp_lbr_params_t *nlp;
3971 nlp = (ndmp_lbr_params_t *)module_cookie;
3972 if (nlp != NULL && nlp->nlp_session != NULL) {
3973 if (nlp->nlp_session->ns_data.dd_mover.addr_type ==
3974 NDMP_ADDR_TCP &&
3975 nlp->nlp_session->ns_data.dd_sock != -1) {
3976 (void) close(nlp->nlp_session->ns_data.dd_sock);
3977 nlp->nlp_session->ns_data.dd_sock = -1;
3979 ndmp_stop_writer_thread(nlp->nlp_session);
3982 return (0);