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