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 int
backup_reader_v3(backup_reader_arg_t * argp)2226 backup_reader_v3(backup_reader_arg_t *argp)
2227 {
2228 int rv;
2229 tlm_cmd_t *lcmd;
2230 tlm_acls_t tlm_acls;
2231 longlong_t bpos, n;
2232 bk_param_v3_t bp;
2233 fs_traverse_t ft;
2234 char *jname;
2235 ndmp_lbr_params_t *nlp;
2236 tlm_commands_t *cmds;
2237
2238 if (!argp)
2239 return (-1);
2240
2241 jname = argp->br_jname;
2242 nlp = argp->br_nlp;
2243 cmds = argp->br_cmds;
2244
2245 rv = 0;
2246 lcmd = cmds->tcs_command;
2247 lcmd->tc_ref++;
2248 cmds->tcs_reader_count++;
2249
2250 (void) memset(&tlm_acls, 0, sizeof (tlm_acls));
2251
2252 /* NDMP parameters */
2253 bp.bp_session = nlp->nlp_session;
2254 bp.bp_nlp = nlp;
2255
2256 /* LBR-related parameters */
2257 bp.bp_js = tlm_ref_job_stats(jname);
2258 bp.bp_cmds = cmds;
2259 bp.bp_lcmd = lcmd;
2260 bp.bp_tlmacl = &tlm_acls;
2261 bp.bp_opr = 0;
2262
2263 /* release the parent thread, after referencing the job stats */
2264 (void) pthread_barrier_wait(&argp->br_barrier);
2265
2266 bp.bp_tmp = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
2267 if (!bp.bp_tmp)
2268 return (-1);
2269
2270 /*
2271 * Make the checkpointed paths for traversing the
2272 * backup hierarchy, if we make the checkpoint.
2273 */
2274 bp.bp_unchkpnm = nlp->nlp_backup_path;
2275 if (!NLP_ISCHKPNTED(nlp)) {
2276 tlm_acls.acl_checkpointed = TRUE;
2277 bp.bp_chkpnm = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
2278 if (!bp.bp_chkpnm) {
2279 NDMP_FREE(bp.bp_tmp);
2280 return (-1);
2281 }
2282 (void) tlm_build_snapshot_name(nlp->nlp_backup_path,
2283 bp.bp_chkpnm, nlp->nlp_jstat->js_job_name);
2284 } else {
2285 tlm_acls.acl_checkpointed = FALSE;
2286 bp.bp_chkpnm = nlp->nlp_backup_path;
2287 }
2288 bp.bp_excls = ndmpd_make_exc_list();
2289
2290 /* set traversing arguments */
2291 ft.ft_path = nlp->nlp_backup_path;
2292 ft.ft_lpath = bp.bp_chkpnm;
2293
2294 NDMP_LOG(LOG_DEBUG, "path %s lpath %s", ft.ft_path, ft.ft_lpath);
2295 if (NLP_ISSET(nlp, NLPF_TOKENBK) || NLP_ISSET(nlp, NLPF_LEVELBK)) {
2296 ft.ft_callbk = timebk_v3;
2297 tlm_acls.acl_clear_archive = FALSE;
2298 } else if (NLP_ISSET(nlp, NLPF_LBRBK)) {
2299 ft.ft_callbk = lbrbk_v3;
2300 tlm_acls.acl_clear_archive = FALSE;
2301
2302 NDMP_LOG(LOG_DEBUG, "bp_opr %x clr_arc %c",
2303 bp.bp_opr, NDMP_YORN(tlm_acls.acl_clear_archive));
2304 } else {
2305 rv = -1;
2306 MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR,
2307 "Unknow backup type.\n");
2308 }
2309 ft.ft_arg = &bp;
2310 ft.ft_logfp = (ft_log_t)ndmp_log;
2311 ft.ft_flags = FST_VERBOSE | FST_STOP_ONERR;
2312
2313 /* take into account the header written to the stream so far */
2314 n = tlm_get_data_offset(lcmd);
2315 nlp->nlp_session->ns_data.dd_module.dm_stats.ms_bytes_processed = n;
2316
2317 if (rv == 0) {
2318 /* start traversing the hierarchy and actual backup */
2319 rv = traverse_level(&ft);
2320 if (rv == 0) {
2321 /* write the trailer and update the bytes processed */
2322 bpos = tlm_get_data_offset(lcmd);
2323 (void) write_tar_eof(lcmd);
2324 n = tlm_get_data_offset(lcmd) - bpos;
2325 nlp->nlp_session->
2326 ns_data.dd_module.dm_stats.ms_bytes_processed += n;
2327 } else {
2328 MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR,
2329 "Filesystem traverse error.\n");
2330 ndmpd_data_error(nlp->nlp_session,
2331 NDMP_DATA_HALT_INTERNAL_ERROR);
2332 }
2333 }
2334
2335 if (!NLP_ISCHKPNTED(nlp))
2336 NDMP_FREE(bp.bp_chkpnm);
2337 NDMP_FREE(bp.bp_tmp);
2338 NDMP_FREE(bp.bp_excls);
2339
2340 cmds->tcs_reader_count--;
2341 lcmd->tc_writer = TLM_STOP;
2342 tlm_release_reader_writer_ipc(lcmd);
2343 tlm_un_ref_job_stats(jname);
2344 return (rv);
2345
2346 }
2347
2348
2349 /*
2350 * tar_backup_v3
2351 *
2352 * Traverse the backup hierarchy if needed and make the bitmap.
2353 * Then launch reader and writer threads to do the actual backup.
2354 *
2355 * Parameters:
2356 * session (input) - pointer to the session
2357 * params (input) - pointer to the parameters structure
2358 * nlp (input) - pointer to the nlp structure
2359 * jname (input) - job name
2360 *
2361 * Returns:
2362 * 0: on success
2363 * != 0: otherwise
2364 */
2365 static int
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, (funct_t)backup_reader_v3,
2442 (void *)&arg);
2443 if (err == 0) {
2444 (void) pthread_barrier_wait(&arg.br_barrier);
2445 (void) pthread_barrier_destroy(&arg.br_barrier);
2446 } else {
2447 (void) pthread_barrier_destroy(&arg.br_barrier);
2448 free_structs_v3(session, jname);
2449 NDMP_LOG(LOG_DEBUG, "Launch backup_reader_v3: %m");
2450 return (-1);
2451 }
2452
2453 if ((err = ndmp_tar_writer(session, params, cmds)) != 0)
2454 result = EIO;
2455
2456 nlp->nlp_jstat->js_stop_time = time(NULL);
2457
2458 (void) snprintf(info, sizeof (info),
2459 "Runtime [%s] %llu bytes (%llu): %d seconds\n",
2460 nlp->nlp_backup_path,
2461 session->ns_data.dd_module.dm_stats.ms_bytes_processed,
2462 session->ns_data.dd_module.dm_stats.ms_bytes_processed,
2463 nlp->nlp_jstat->js_stop_time -
2464 nlp->nlp_jstat->js_start_ltime);
2465 MOD_LOGV3(params, NDMP_LOG_NORMAL, info);
2466
2467 ndmp_wait_for_reader(cmds);
2468 (void) pthread_join(rdtp, NULL);
2469
2470 /* exit as if there was an internal error */
2471 if (session->ns_eof) {
2472 result = EPIPE;
2473 err = -1;
2474 }
2475 if (!session->ns_data.dd_abort) {
2476 ndmpd_audit_backup(session->ns_connection,
2477 nlp->nlp_backup_path,
2478 session->ns_data.dd_data_addr.addr_type,
2479 session->ns_tape.td_adapter_name, result);
2480 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" Finished.",
2481 nlp->nlp_backup_path);
2482 }
2483 }
2484
2485 if (session->ns_data.dd_abort) {
2486 ndmpd_audit_backup(session->ns_connection,
2487 nlp->nlp_backup_path,
2488 session->ns_data.dd_data_addr.addr_type,
2489 session->ns_tape.td_adapter_name, EINTR);
2490 NDMP_LOG(LOG_DEBUG,
2491 "Backing up \"%s\" aborted.", nlp->nlp_backup_path);
2492 err = -1;
2493 } else {
2494
2495 backup_out:
2496 /* Plug-in module */
2497 if (ndmp_pl != NULL &&
2498 ndmp_pl->np_post_backup != NULL &&
2499 ndmp_pl->np_post_backup(ndmp_pl, &nctx, err) == -1) {
2500 NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m");
2501 return (-1);
2502 }
2503 }
2504
2505 free_structs_v3(session, jname);
2506 return (err);
2507 }
2508
2509 /*
2510 * get_backup_size
2511 *
2512 * Find the estimate of backup size. This is used to get an estimate
2513 * of the progress of backup during NDMP backup.
2514 */
2515 void
get_backup_size(ndmp_bkup_size_arg_t * sarg)2516 get_backup_size(ndmp_bkup_size_arg_t *sarg)
2517 {
2518 fs_traverse_t ft;
2519 u_longlong_t bk_size;
2520 char spath[PATH_MAX];
2521 int rv;
2522
2523 bk_size = 0;
2524 if (fs_is_chkpntvol(sarg->bs_path)) {
2525 ft.ft_path = sarg->bs_path;
2526 } else {
2527 (void) tlm_build_snapshot_name(sarg->bs_path,
2528 spath, sarg->bs_jname);
2529 ft.ft_path = spath;
2530 }
2531
2532 ft.ft_lpath = ft.ft_path;
2533 ft.ft_callbk = size_cb;
2534 ft.ft_arg = &bk_size;
2535 ft.ft_logfp = (ft_log_t)ndmp_log;
2536 ft.ft_flags = FST_VERBOSE;
2537
2538 if ((rv = traverse_level(&ft)) != 0) {
2539 NDMP_LOG(LOG_DEBUG, "bksize err=%d", rv);
2540 bk_size = 0;
2541 } else {
2542 NDMP_LOG(LOG_DEBUG, "bksize %lld, %lldKB, %lldMB\n",
2543 bk_size, bk_size / 1024, bk_size /(1024 * 1024));
2544 }
2545 sarg->bs_session->ns_data.dd_data_size = bk_size;
2546 }
2547
2548 /*
2549 * get_rs_path_v3
2550 *
2551 * Find the restore path
2552 */
2553 ndmp_error
get_rs_path_v3(ndmpd_module_params_t * params,ndmp_lbr_params_t * nlp)2554 get_rs_path_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
2555 {
2556 char *dp;
2557 ndmp_error rv;
2558 mem_ndmp_name_v3_t *ep;
2559 int i, nm_cnt;
2560 char *nm_dpath_list[MULTIPLE_DEST_DIRS];
2561 static char mdest_buf[256];
2562
2563 *mdest_buf = 0;
2564 *nm_dpath_list = "";
2565 for (i = 0, nm_cnt = 0; i < (int)nlp->nlp_nfiles; i++) {
2566 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
2567 if (!ep) {
2568 NDMP_LOG(LOG_DEBUG, "Can't get Nlist[%d]", i);
2569 return (NDMP_ILLEGAL_ARGS_ERR);
2570 }
2571 if (strcmp(nm_dpath_list[nm_cnt], ep->nm3_dpath) != 0 &&
2572 nm_cnt < MULTIPLE_DEST_DIRS - 1)
2573 nm_dpath_list[++nm_cnt] = ep->nm3_dpath;
2574 }
2575
2576 multiple_dest_restore = (nm_cnt > 1);
2577 nlp->nlp_restore_path = mdest_buf;
2578
2579 for (i = 1; i < nm_cnt + 1; i++) {
2580 if (ISDEFINED(nm_dpath_list[i]))
2581 dp = nm_dpath_list[i];
2582 else
2583 /* the default destination path is backup directory */
2584 dp = nlp->nlp_backup_path;
2585
2586 /* check the destination directory exists and is writable */
2587 if (!fs_volexist(dp)) {
2588 rv = NDMP_ILLEGAL_ARGS_ERR;
2589 MOD_LOGV3(params, NDMP_LOG_ERROR,
2590 "Invalid destination path volume \"%s\".\n", dp);
2591 } else if (!voliswr(dp)) {
2592 rv = NDMP_ILLEGAL_ARGS_ERR;
2593 MOD_LOGV3(params, NDMP_LOG_ERROR,
2594 "The destination path volume"
2595 " is not writable \"%s\".\n", dp);
2596 } else {
2597 rv = NDMP_NO_ERR;
2598 (void) strlcat(nlp->nlp_restore_path, dp,
2599 sizeof (mdest_buf));
2600 NDMP_LOG(LOG_DEBUG, "rspath: \"%s\"", dp);
2601 }
2602
2603 /*
2604 * Exit if there is an error or it is not a multiple
2605 * destination restore mode
2606 */
2607 if (rv != NDMP_NO_ERR || !multiple_dest_restore)
2608 break;
2609
2610 if (i < nm_cnt)
2611 (void) strlcat(nlp->nlp_restore_path, ", ",
2612 sizeof (mdest_buf));
2613 }
2614
2615 return (rv);
2616 }
2617
2618
2619 /*
2620 * fix_nlist_v3
2621 *
2622 * Check if the recovery list is valid and fix it if there are some
2623 * unspecified entries in it. It checks for original, destination
2624 * and new path for all NDMP names provided inside the list.
2625 *
2626 * V3: dpath is the destination directory. If newnm is not NULL, the
2627 * destination path is dpath/newnm. Otherwise the destination path is
2628 * dpath/opath_last_node, where opath_last_node is the last node in opath.
2629 *
2630 * V4: If newnm is not NULL, dpath is the destination directory, and
2631 * dpath/newnm is the destination path. If newnm is NULL, dpath is
2632 * the destination path (opath is not involved in forming destination path).
2633 */
2634 ndmp_error
fix_nlist_v3(ndmpd_session_t * session,ndmpd_module_params_t * params,ndmp_lbr_params_t * nlp)2635 fix_nlist_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
2636 ndmp_lbr_params_t *nlp)
2637 {
2638 char *cp, *buf, *bp;
2639 int i, n;
2640 int iswrbk;
2641 int bvexists;
2642 ndmp_error rv;
2643 mem_ndmp_name_v3_t *ep;
2644 char *dp;
2645 char *nm;
2646 int existsvol;
2647 int isrwdst;
2648
2649 buf = ndmp_malloc(TLM_MAX_PATH_NAME);
2650 if (!buf) {
2651 MOD_LOGV3(params, NDMP_LOG_ERROR, "Insufficient memory.\n");
2652 return (NDMP_NO_MEM_ERR);
2653 }
2654
2655 bvexists = fs_volexist(nlp->nlp_backup_path);
2656 iswrbk = voliswr(nlp->nlp_backup_path);
2657
2658 rv = NDMP_NO_ERR;
2659 n = session->ns_data.dd_nlist_len;
2660 for (i = 0; i < n; i++) {
2661 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
2662 if (!ep)
2663 continue;
2664
2665 /* chop off the trailing slashes */
2666 chopslash(ep->nm3_opath);
2667
2668 chopslash(ep->nm3_dpath);
2669 chopslash(ep->nm3_newnm);
2670
2671 /* existing and non-empty destination path */
2672 if (ISDEFINED(ep->nm3_dpath)) {
2673 dp = ep->nm3_dpath;
2674 existsvol = fs_volexist(dp);
2675 isrwdst = voliswr(dp);
2676 } else {
2677 /* the default destination path is backup directory */
2678 dp = nlp->nlp_backup_path;
2679 existsvol = bvexists;
2680 isrwdst = iswrbk;
2681 }
2682
2683 /* check the destination directory exists and is writable */
2684 if (!existsvol) {
2685 rv = NDMP_ILLEGAL_ARGS_ERR;
2686 MOD_LOGV3(params, NDMP_LOG_ERROR,
2687 "Invalid destination path volume "
2688 "\"%s\".\n", dp);
2689 break;
2690 }
2691 if (!isrwdst) {
2692 rv = NDMP_ILLEGAL_ARGS_ERR;
2693 MOD_LOGV3(params, NDMP_LOG_ERROR,
2694 "The destination path volume is not "
2695 "writable \"%s\".\n", dp);
2696 break;
2697 }
2698
2699 /*
2700 * If new name is not specified, the default new name is
2701 * the last component of the original path, if any
2702 * (except in V4).
2703 */
2704 if (ISDEFINED(ep->nm3_newnm)) {
2705 nm = ep->nm3_newnm;
2706 } else {
2707 char *p, *q;
2708
2709 /*
2710 * Find the last component of nm3_opath.
2711 * nm3_opath has no trailing '/'.
2712 */
2713 p = strrchr(ep->nm3_opath, '/');
2714 nm = p ? p + 1 : ep->nm3_opath;
2715
2716 /*
2717 * In DDAR the last component could
2718 * be repeated in nm3_dpath
2719 */
2720 q = strrchr(ep->nm3_dpath, '/');
2721 q = q ? q + 1 : ep->nm3_dpath;
2722 if (strcmp(nm, q) == 0)
2723 nm = NULL;
2724
2725 }
2726
2727 bp = joinpath(buf, dp, nm);
2728 if (!bp) {
2729 /*
2730 * Note: What should be done with this entry?
2731 * We leave it untouched for now, hence no path in
2732 * the backup image matches with this entry and will
2733 * be reported as not found.
2734 */
2735 MOD_LOGV3(params, NDMP_LOG_ERROR,
2736 "Destination path too long(%s/%s)", dp, nm);
2737 continue;
2738 }
2739 cp = strdup(bp);
2740 if (!cp) {
2741 MOD_LOGV3(params, NDMP_LOG_ERROR,
2742 "Insufficient memory.\n");
2743 rv = NDMP_NO_MEM_ERR;
2744 break;
2745 }
2746 free(ep->nm3_dpath);
2747 ep->nm3_dpath = cp;
2748 NDMP_FREE(ep->nm3_newnm);
2749
2750 bp = joinpath(buf, nlp->nlp_backup_path, ep->nm3_opath);
2751 if (!bp) {
2752 /*
2753 * Note: The same problem of above with long path.
2754 */
2755 MOD_LOGV3(params, NDMP_LOG_ERROR,
2756 "Path too long(%s/%s)",
2757 nlp->nlp_backup_path, ep->nm3_opath);
2758 continue;
2759 }
2760 cp = strdup(bp);
2761 if (!cp) {
2762 MOD_LOGV3(params, NDMP_LOG_ERROR,
2763 "Insufficient memory.\n");
2764 rv = NDMP_NO_MEM_ERR;
2765 break;
2766 }
2767 NDMP_FREE(ep->nm3_opath);
2768 ep->nm3_opath = cp;
2769
2770 NDMP_LOG(LOG_DEBUG, "orig[%d]: \"%s\"", i, ep->nm3_opath);
2771 if (ep->nm3_dpath) {
2772 NDMP_LOG(LOG_DEBUG,
2773 "dest[%d]: \"%s\"", i, ep->nm3_dpath);
2774 } else {
2775 NDMP_LOG(LOG_DEBUG, "dest[%d]: \"%s\"", i, "NULL");
2776 }
2777 }
2778
2779 free(buf);
2780
2781 return (rv);
2782 }
2783
2784
2785 /*
2786 * allvalidfh
2787 *
2788 * Run a sanity check on the file history info. The file history
2789 * info is the offset of the record starting the entry on the tape
2790 * and is used in DAR (direct access restore mode).
2791 */
2792 static boolean_t
allvalidfh(ndmpd_session_t * session,ndmpd_module_params_t * params)2793 allvalidfh(ndmpd_session_t *session, ndmpd_module_params_t *params)
2794 {
2795 int i, n;
2796 boolean_t rv;
2797 mem_ndmp_name_v3_t *ep;
2798
2799 rv = TRUE;
2800 n = session->ns_data.dd_nlist_len;
2801 for (i = 0; i < n; i++) {
2802 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
2803 if (!ep)
2804 continue;
2805 /*
2806 * The fh_info's sent from the client are multiples
2807 * of RECORDSIZE which is 512 bytes.
2808 *
2809 * All our fh_info's are at the RECORDSIZE boundary. If there
2810 * is any fh_info that is less than RECORDSIZE (this covers 0
2811 * and -1 values too), then the result is that DAR cannot be
2812 * done.
2813 */
2814 if (ep->nm3_fh_info < RECORDSIZE ||
2815 ep->nm3_fh_info % RECORDSIZE != 0) {
2816 rv = FALSE;
2817 break;
2818 }
2819 }
2820
2821 return (rv);
2822 }
2823
2824
2825 /*
2826 * log_rs_params_v3
2827 *
2828 * Log a copy of all values of the restore parameters
2829 */
2830 void
log_rs_params_v3(ndmpd_session_t * session,ndmpd_module_params_t * params,ndmp_lbr_params_t * nlp)2831 log_rs_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
2832 ndmp_lbr_params_t *nlp)
2833 {
2834 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Restoring to \"%s\".\n",
2835 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
2836
2837 if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) {
2838 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Tape server: local.\n");
2839 MOD_LOGV3(params, NDMP_LOG_NORMAL,
2840 "Tape record size: %d.\n",
2841 session->ns_mover.md_record_size);
2842 } else if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP)
2843 MOD_LOGV3(params, NDMP_LOG_NORMAL,
2844 "Tape server: remote at %s:%d.\n",
2845 inet_ntoa(IN_ADDR(session->ns_data.dd_data_addr.tcp_ip_v3)),
2846 session->ns_data.dd_data_addr.tcp_port_v3);
2847 else
2848 MOD_LOGV3(params, NDMP_LOG_ERROR,
2849 "Unknown tape server address type.\n");
2850
2851 if (NLP_ISSET(nlp, NLPF_DIRECT))
2852 MOD_LOGV3(params, NDMP_LOG_NORMAL,
2853 "Direct Access Restore.\n");
2854 }
2855
2856
2857 /*
2858 * send_unrecovered_list_v3
2859 *
2860 * Create the list of files that were in restore list but
2861 * not recovered due to some errors.
2862 */
2863 int
send_unrecovered_list_v3(ndmpd_module_params_t * params,ndmp_lbr_params_t * nlp)2864 send_unrecovered_list_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
2865 {
2866 int i, rv;
2867 int err;
2868
2869 if (!params) {
2870 NDMP_LOG(LOG_DEBUG, "params == NULL");
2871 return (-1);
2872 }
2873 if (!nlp) {
2874 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2875 return (-1);
2876 }
2877
2878 if (nlp->nlp_lastidx != -1) {
2879 if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)nlp->nlp_lastidx))
2880 err = ENOENT;
2881 else
2882 err = 0;
2883 (void) ndmp_send_recovery_stat_v3(params, nlp,
2884 nlp->nlp_lastidx, err);
2885 nlp->nlp_lastidx = -1;
2886 }
2887
2888 rv = 0;
2889 for (i = 0; i < (int)nlp->nlp_nfiles; i++) {
2890 if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)i)) {
2891 rv = ndmp_send_recovery_stat_v3(params, nlp, i, ENOENT);
2892 if (rv < 0)
2893 break;
2894 }
2895 }
2896
2897 return (rv);
2898 }
2899
2900
2901
2902 /*
2903 * restore_dar_alloc_structs_v3
2904 *
2905 * Allocates the necessary structures for running DAR restore.
2906 * It just creates the reader writer IPC.
2907 * This function is called for each entry in the restore entry list.
2908 *
2909 * Parameters:
2910 * session (input) - pointer to the session
2911 * jname (input) - Job name
2912 *
2913 * Returns:
2914 * 0: on success
2915 * -1: on error
2916 */
2917 int
restore_dar_alloc_structs_v3(ndmpd_session_t * session,char * jname)2918 restore_dar_alloc_structs_v3(ndmpd_session_t *session, char *jname)
2919 {
2920 long xfer_size;
2921 ndmp_lbr_params_t *nlp;
2922 tlm_commands_t *cmds;
2923
2924 nlp = ndmp_get_nlp(session);
2925 if (!nlp) {
2926 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2927 return (-1);
2928 }
2929
2930 cmds = &nlp->nlp_cmds;
2931 (void) memset(cmds, 0, sizeof (*cmds));
2932
2933 xfer_size = ndmp_buffer_get_size(session);
2934 cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
2935 if (!cmds->tcs_command) {
2936 tlm_un_ref_job_stats(jname);
2937 return (-1);
2938 }
2939
2940 return (0);
2941 }
2942
2943
2944 /*
2945 * free_dar_structs_v3
2946 *
2947 * To free the structures were created by restore_dar_alloc_structs_v3.
2948 * This funnction is called for each entry in restore entry list.
2949 *
2950 * Parameters:
2951 * session (input) - pointer to the session
2952 * jname (input) - job name
2953 *
2954 * Returns:
2955 * NONE
2956 */
2957 /*ARGSUSED*/
2958 static void
free_dar_structs_v3(ndmpd_session_t * session,char * jname)2959 free_dar_structs_v3(ndmpd_session_t *session, char *jname)
2960 {
2961 ndmp_lbr_params_t *nlp;
2962 tlm_commands_t *cmds;
2963
2964 nlp = ndmp_get_nlp(session);
2965 if (!nlp) {
2966 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2967 return;
2968 }
2969 cmds = &nlp->nlp_cmds;
2970 if (!cmds) {
2971 NDMP_LOG(LOG_DEBUG, "cmds == NULL");
2972 return;
2973 }
2974
2975 if (cmds->tcs_command) {
2976 if (cmds->tcs_command->tc_buffers != NULL)
2977 tlm_release_reader_writer_ipc(cmds->tcs_command);
2978 else
2979 NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL");
2980 cmds->tcs_command = NULL;
2981 } else
2982 NDMP_LOG(LOG_DEBUG, "COMMAND == NULL");
2983 }
2984
2985
2986 /*
2987 * ndmp_dar_tar_init_v3
2988 *
2989 * Constructor for the DAR restore. Creates job name, allocates structures
2990 * needed for keeping the statistics, and reports the start of restore action.
2991 * It is called once for each DAR restore request.
2992 *
2993 * Parameters:
2994 * session (input) - pointer to the session
2995 * nlp (input) - pointer to the nlp structure
2996 *
2997 * Returns:
2998 * char pointer: on success
2999 * NULL: on error
3000 */
ndmpd_dar_tar_init_v3(ndmpd_session_t * session,ndmp_lbr_params_t * nlp)3001 static char *ndmpd_dar_tar_init_v3(ndmpd_session_t *session,
3002 ndmp_lbr_params_t *nlp)
3003 {
3004 char *jname;
3005
3006 jname = ndmp_malloc(TLM_MAX_BACKUP_JOB_NAME);
3007
3008 if (!jname)
3009 return (NULL);
3010
3011 (void) ndmp_new_job_name(jname);
3012
3013 if (!nlp) {
3014 free(jname);
3015 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3016 return (NULL);
3017 }
3018
3019 nlp->nlp_jstat = tlm_new_job_stats(jname);
3020 if (!nlp->nlp_jstat) {
3021 free(jname);
3022 NDMP_LOG(LOG_DEBUG, "Creating job stats");
3023 return (NULL);
3024 }
3025
3026 nlp->nlp_jstat->js_start_ltime = time(NULL);
3027 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
3028
3029 nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
3030 ndmpd_path_restored_v3, NULL, NULL);
3031 if (!nlp->nlp_logcallbacks) {
3032 tlm_un_ref_job_stats(jname);
3033 free(jname);
3034 return (NULL);
3035 }
3036 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
3037
3038 nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0);
3039 if (nlp->nlp_rsbm < 0) {
3040 NDMP_LOG(LOG_ERR, "Out of memory.");
3041 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
3042 tlm_un_ref_job_stats(jname);
3043 free(jname);
3044 return (NULL);
3045 }
3046
3047 /* this is used in ndmpd_path_restored_v3() */
3048 nlp->nlp_lastidx = -1;
3049
3050 NDMP_LOG(LOG_DEBUG, "Restoring from %s tape(s).",
3051 ndmp_data_get_mover_mode(session));
3052
3053 return (jname);
3054 }
3055
3056 /*
3057 * ndmpd_dar_tar_end_v3
3058 *
3059 * Deconstructor for the DAR restore. This function is called once per
3060 * DAR request. It deallocates memories allocated by ndmpd_dar_tar_init_v3.
3061 *
3062 * Parameters:
3063 * session (input) - pointer to the session
3064 * params (input) - pointer to the parameters structure
3065 * nlp (input) - pointer to the nlp structure
3066 * jname(input) - job name
3067 *
3068 * Returns:
3069 * 0: on success
3070 * -1: on error
3071 */
ndmpd_dar_tar_end_v3(ndmpd_session_t * session,ndmpd_module_params_t * params,ndmp_lbr_params_t * nlp,char * jname)3072 static int ndmpd_dar_tar_end_v3(ndmpd_session_t *session,
3073 ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, char *jname)
3074 {
3075 int err = 0;
3076
3077
3078 NDMP_LOG(LOG_DEBUG, "lastidx %d", nlp->nlp_lastidx);
3079
3080 /* nothing restored. */
3081 (void) send_unrecovered_list_v3(params, nlp);
3082
3083 if (nlp->nlp_jstat) {
3084 nlp->nlp_bytes_total =
3085 (u_longlong_t)nlp->nlp_jstat->js_bytes_total;
3086 tlm_un_ref_job_stats(jname);
3087 nlp->nlp_jstat = NULL;
3088 } else {
3089 NDMP_LOG(LOG_DEBUG, "JSTAT == NULL");
3090 }
3091
3092 if (nlp->nlp_logcallbacks) {
3093 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
3094 nlp->nlp_logcallbacks = NULL;
3095 } else {
3096 NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL");
3097 }
3098
3099 if (session->ns_data.dd_abort) {
3100 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
3101 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3102 err = EINTR;
3103 } else {
3104 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
3105 (nlp->nlp_restore_path) ? nlp->nlp_restore_path :
3106 "NULL", err);
3107 }
3108
3109 if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) {
3110 if (nlp->nlp_rsbm < 0) {
3111 NDMP_LOG(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm);
3112 } else {
3113 (void) bm_free(nlp->nlp_rsbm);
3114 nlp->nlp_rsbm = -1;
3115 }
3116 }
3117
3118 free(jname);
3119
3120 return (err);
3121 }
3122
3123
3124 /*
3125 * ndmpd_dar_tar_v3
3126 *
3127 * This function is called for each entry in DAR entry list. The window
3128 * is already located and we should be in the right position to read
3129 * the data from the tape.
3130 * For each entry we setup selection list; so that, if the file name from
3131 * tape is not as the name client asked for, error be returned.
3132 *
3133 * Parameters:
3134 * session (input) - pointer to the session
3135 * params (input) - pointer to the parameters structure
3136 * nlp (input) - pointer to the nlp structure
3137 * jname (input) - job name
3138 * dar_index(input) - Index of this entry in the restore list
3139 *
3140 * Returns:
3141 * 0: on success
3142 * -1: on error
3143 */
3144 static int
ndmpd_dar_tar_v3(ndmpd_session_t * session,ndmpd_module_params_t * params,ndmp_lbr_params_t * nlp,char * jname,int dar_index)3145 ndmpd_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3146 ndmp_lbr_params_t *nlp, char *jname, int dar_index)
3147 {
3148 char *excl;
3149 char **sels;
3150 int flags;
3151 int err;
3152 tlm_commands_t *cmds;
3153 struct rs_name_maker rn;
3154 int data_addr_type = session->ns_data.dd_data_addr.addr_type;
3155 ndmp_tar_reader_arg_t arg;
3156 pthread_t rdtp;
3157 ndmp_context_t nctx;
3158 mem_ndmp_name_v3_t *ep;
3159
3160 err = 0;
3161
3162 /*
3163 * We have to allocate and deallocate buffers every time we
3164 * run the restore, for we need to flush the buffers.
3165 */
3166 if (restore_dar_alloc_structs_v3(session, jname) < 0)
3167 return (-1);
3168
3169 sels = setupsels(session, params, nlp, dar_index);
3170 if (!sels) {
3171 free_dar_structs_v3(session, jname);
3172 return (-1);
3173 }
3174 excl = NULL;
3175 flags = RSFLG_OVR_ALWAYS;
3176 rn.rn_nlp = nlp;
3177 rn.rn_fp = mknewname;
3178
3179 if (!session->ns_data.dd_abort) {
3180 cmds = &nlp->nlp_cmds;
3181 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
3182 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
3183 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
3184
3185 arg.tr_session = session;
3186 arg.tr_mod_params = params;
3187 arg.tr_cmds = cmds;
3188
3189 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
3190 (void *)&arg);
3191 if (err == 0) {
3192 tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
3193 } else {
3194 NDMP_LOG(LOG_DEBUG, "launch ndmp_tar_reader: %m");
3195 return (-1);
3196 }
3197
3198 cmds->tcs_command->tc_ref++;
3199 cmds->tcs_writer_count++;
3200
3201 /* Plug-in module */
3202 if (ndmp_pl != NULL &&
3203 ndmp_pl->np_pre_restore != NULL) {
3204 (void) memset(&nctx, 0, sizeof (ndmp_context_t));
3205 nctx.nc_cmds = cmds;
3206 nctx.nc_params = params;
3207 nctx.nc_ddata = (void *) session;
3208 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params,
3209 dar_index - 1);
3210
3211 if ((err = ndmp_pl->np_pre_restore(ndmp_pl, &nctx,
3212 ep->nm3_opath, ep->nm3_dpath))
3213 != 0) {
3214 NDMP_LOG(LOG_ERR, "Pre-restore plug-in: %m");
3215 ndmp_stop_local_reader(session, cmds);
3216 ndmp_wait_for_reader(cmds);
3217 (void) pthread_join(rdtp, NULL);
3218 ndmp_stop_remote_reader(session);
3219 goto restore_out;
3220 }
3221 }
3222
3223 if (tm_tar_ops.tm_getdir != NULL) {
3224 char errbuf[256];
3225
3226 err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
3227 nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags,
3228 dar_index, nlp->nlp_backup_path,
3229 session->hardlink_q);
3230 /*
3231 * If the fatal error from tm_getdir looks like an
3232 * errno code, we send the error description to DMA.
3233 */
3234 if (err > 0 && strerror_r(err, errbuf,
3235 sizeof (errbuf)) == 0) {
3236 MOD_LOGV3(params, NDMP_LOG_ERROR,
3237 "Fatal error during the restore: %s\n",
3238 errbuf);
3239 }
3240 }
3241
3242 cmds->tcs_writer_count--;
3243 cmds->tcs_command->tc_ref--;
3244 NDMP_LOG(LOG_DEBUG, "stop local reader.");
3245 ndmp_stop_local_reader(session, cmds);
3246
3247 ndmp_wait_for_reader(cmds);
3248 (void) pthread_join(rdtp, NULL);
3249
3250 /*
3251 * If this is the last DAR entry and it is a three-way
3252 * restore then we should close the connection.
3253 */
3254 if ((data_addr_type == NDMP_ADDR_TCP) &&
3255 (dar_index == (int)session->ns_data.dd_nlist_len)) {
3256 NDMP_LOG(LOG_DEBUG, "stop remote reader.");
3257 ndmp_stop_remote_reader(session);
3258 }
3259
3260 /* exit as if there was an internal error */
3261 if (session->ns_eof)
3262 err = -1;
3263 restore_out:
3264 /* Plug-in module */
3265 if (ndmp_pl != NULL &&
3266 ndmp_pl->np_post_restore != NULL &&
3267 ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) {
3268 NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
3269 err = -1;
3270 }
3271 }
3272
3273 NDMP_FREE(sels);
3274
3275 free_dar_structs_v3(session, jname);
3276
3277 return (err);
3278 }
3279
3280 /*
3281 * ndmpd_dar_locate_windwos_v3
3282 *
3283 * Locating the right window in which the requested file is backed up.
3284 * We should go through windows to find the exact location, for the
3285 * file can be located in for example 10th window after the current window.
3286 *
3287 * Parameters:
3288 * session (input) - pointer to the session
3289 * params (input) - pointer to the parameters structure
3290 * fh_info (input) - index from the beginning of the backup stream
3291 * len (input) - Length of the mover window
3292 *
3293 * Returns:
3294 * 0: on success
3295 * -1: on error
3296 */
3297 static int
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, (funct_t)ndmp_tar_reader,
3552 (void *)&arg);
3553 if (err == 0) {
3554 tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
3555 } else {
3556 NDMP_LOG(LOG_DEBUG, "Launch ndmp_tar_reader: %m");
3557 free_structs_v3(session, jname);
3558 return (-1);
3559 }
3560
3561 if (!ndmp_check_utf8magic(cmds->tcs_command)) {
3562 NDMP_LOG(LOG_DEBUG, "UTF8Magic not found!");
3563 } else {
3564 NDMP_LOG(LOG_DEBUG, "UTF8Magic found");
3565 }
3566
3567 /* Plug-in module */
3568 if (ndmp_pl != NULL &&
3569 ndmp_pl->np_pre_restore != NULL) {
3570 (void) memset(&nctx, 0, sizeof (ndmp_context_t));
3571 nctx.nc_cmds = cmds;
3572 nctx.nc_params = params;
3573 nctx.nc_ddata = (void *) session;
3574 if ((err = ndmp_plugin_pre_restore(&nctx, params,
3575 nlp->nlp_nfiles))
3576 != 0) {
3577 NDMP_LOG(LOG_ERR, "Pre-restore plug-in: %m");
3578 ndmp_stop_local_reader(session, cmds);
3579 ndmp_wait_for_reader(cmds);
3580 (void) pthread_join(rdtp, NULL);
3581 ndmp_stop_remote_reader(session);
3582 goto restore_out;
3583 }
3584 }
3585
3586 cmds->tcs_command->tc_ref++;
3587 cmds->tcs_writer_count++;
3588
3589 if (tm_tar_ops.tm_getdir != NULL) {
3590 char errbuf[256];
3591
3592 err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
3593 nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags, 0,
3594 nlp->nlp_backup_path, session->hardlink_q);
3595 /*
3596 * If the fatal error from tm_getdir looks like an
3597 * errno code, we send the error description to DMA.
3598 */
3599 if (err > 0 && strerror_r(err, errbuf,
3600 sizeof (errbuf)) == 0) {
3601 MOD_LOGV3(params, NDMP_LOG_ERROR,
3602 "Fatal error during the restore: %s\n",
3603 errbuf);
3604 }
3605 }
3606
3607 cmds->tcs_writer_count--;
3608 cmds->tcs_command->tc_ref--;
3609 nlp->nlp_jstat->js_stop_time = time(NULL);
3610
3611 /* Send the list of un-recovered files/dirs to the client. */
3612 (void) send_unrecovered_list_v3(params, nlp);
3613
3614 ndmp_stop_local_reader(session, cmds);
3615 ndmp_wait_for_reader(cmds);
3616 (void) pthread_join(rdtp, NULL);
3617
3618 ndmp_stop_remote_reader(session);
3619
3620 /* exit as if there was an internal error */
3621 if (session->ns_eof)
3622 err = -1;
3623 if (err == -1)
3624 result = EIO;
3625 }
3626
3627 (void) send_unrecovered_list_v3(params, nlp); /* nothing restored. */
3628 if (session->ns_data.dd_abort) {
3629 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
3630 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3631 result = EINTR;
3632 ndmpd_audit_restore(session->ns_connection,
3633 nlp->nlp_restore_path,
3634 session->ns_data.dd_data_addr.addr_type,
3635 session->ns_tape.td_adapter_name, result);
3636 err = -1;
3637 } else {
3638 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
3639 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL",
3640 err);
3641 ndmpd_audit_restore(session->ns_connection,
3642 nlp->nlp_restore_path,
3643 session->ns_data.dd_data_addr.addr_type,
3644 session->ns_tape.td_adapter_name, result);
3645
3646 restore_out:
3647 /* Plug-in module */
3648 if (ndmp_pl != NULL &&
3649 ndmp_pl->np_post_restore != NULL &&
3650 ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) {
3651 NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
3652 err = -1;
3653 }
3654 }
3655
3656 NDMP_FREE(sels);
3657 free_structs_v3(session, jname);
3658
3659 return (err);
3660 }
3661
3662
3663 /*
3664 * ndmp_backup_get_params_v3
3665 *
3666 * Get the backup parameters from the NDMP env variables
3667 * and log them in the system log and as normal messages
3668 * to the DMA.
3669 *
3670 * Parameters:
3671 * session (input) - pointer to the session
3672 * params (input) - pointer to the parameters structure
3673 *
3674 * Returns:
3675 * NDMP_NO_ERR: on success
3676 * != NDMP_NO_ERR: otherwise
3677 */
3678 ndmp_error
ndmp_backup_get_params_v3(ndmpd_session_t * session,ndmpd_module_params_t * params)3679 ndmp_backup_get_params_v3(ndmpd_session_t *session,
3680 ndmpd_module_params_t *params)
3681 {
3682 ndmp_lbr_params_t *nlp;
3683
3684 if (!session || !params)
3685 return (NDMP_ILLEGAL_ARGS_ERR);
3686
3687 nlp = ndmp_get_nlp(session);
3688 if (!nlp) {
3689 MOD_LOGV3(params, NDMP_LOG_ERROR,
3690 "Internal error: NULL nlp.\n");
3691 return (NDMP_ILLEGAL_ARGS_ERR);
3692 } else {
3693 if (!(nlp->nlp_backup_path = get_backup_path_v3(params)) ||
3694 !is_valid_backup_dir_v3(params, nlp->nlp_backup_path))
3695 return (NDMP_ILLEGAL_ARGS_ERR);
3696 }
3697
3698 nlp->nlp_backup_path = get_absolute_path(nlp->nlp_backup_path);
3699 if (!nlp->nlp_backup_path)
3700 return (NDMP_ILLEGAL_ARGS_ERR);
3701
3702 if (fs_is_chkpntvol(nlp->nlp_backup_path) ||
3703 fs_is_rdonly(nlp->nlp_backup_path) ||
3704 !fs_is_chkpnt_enabled(nlp->nlp_backup_path))
3705 NLP_SET(nlp, NLPF_CHKPNTED_PATH);
3706 else
3707 NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
3708
3709 /* Should the st_ctime be ignored when backing up? */
3710 if (ndmp_ignore_ctime) {
3711 NDMP_LOG(LOG_DEBUG, "ignoring st_ctime");
3712 NLP_SET(nlp, NLPF_IGNCTIME);
3713 } else {
3714 NLP_UNSET(nlp, NLPF_IGNCTIME);
3715 }
3716
3717 if (ndmp_include_lmtime == TRUE) {
3718 NDMP_LOG(LOG_DEBUG, "including st_lmtime");
3719 NLP_SET(nlp, NLPF_INCLMTIME);
3720 } else {
3721 NLP_UNSET(nlp, NLPF_INCLMTIME);
3722 }
3723
3724 NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
3725
3726 get_hist_env_v3(params, nlp);
3727 get_exc_env_v3(params, nlp);
3728 get_inc_env_v3(params, nlp);
3729 get_direct_env_v3(params, nlp);
3730 return (get_backup_level_v3(params, nlp));
3731 }
3732
3733
3734 /*
3735 * ndmpd_tar_backup_starter_v3
3736 *
3737 * Create the checkpoint for the backup and do the backup,
3738 * then remove the backup checkpoint if we created it.
3739 * Save the backup time information based on the backup
3740 * type and stop the data server.
3741 *
3742 * Parameters:
3743 * params (input) - pointer to the parameters structure
3744 *
3745 * Returns:
3746 * 0: on success
3747 * != 0: otherwise
3748 */
3749 int
ndmpd_tar_backup_starter_v3(void * arg)3750 ndmpd_tar_backup_starter_v3(void *arg)
3751 {
3752 ndmpd_module_params_t *params = arg;
3753 int err;
3754 ndmpd_session_t *session;
3755 ndmp_lbr_params_t *nlp;
3756 char jname[TLM_MAX_BACKUP_JOB_NAME];
3757 ndmp_bkup_size_arg_t sarg;
3758 pthread_t tid;
3759
3760 session = (ndmpd_session_t *)(params->mp_daemon_cookie);
3761 *(params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
3762 ndmp_session_ref(session);
3763 (void) ndmp_new_job_name(jname);
3764
3765 err = 0;
3766 if (!NLP_ISCHKPNTED(nlp) &&
3767 ndmp_create_snapshot(nlp->nlp_backup_path, jname) < 0) {
3768 MOD_LOGV3(params, NDMP_LOG_ERROR,
3769 "Creating checkpoint on \"%s\".\n",
3770 nlp->nlp_backup_path);
3771 err = -1;
3772 }
3773
3774 NDMP_LOG(LOG_DEBUG, "err %d, chkpnted %c",
3775 err, NDMP_YORN(NLP_ISCHKPNTED(nlp)));
3776
3777 if (err == 0) {
3778 sarg.bs_session = session;
3779 sarg.bs_jname = jname;
3780 sarg.bs_path = nlp->nlp_backup_path;
3781
3782 /* Get an estimate of the data size */
3783 if (pthread_create(&tid, NULL, (funct_t)get_backup_size,
3784 (void *)&sarg) == 0)
3785 (void) pthread_detach(tid);
3786
3787 err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate, jname);
3788 if (err != 0) {
3789 NDMP_LOG(LOG_DEBUG, "err %d", err);
3790 } else {
3791 log_bk_params_v3(session, params, nlp);
3792 err = tar_backup_v3(session, params, nlp, jname);
3793 }
3794 }
3795
3796 if (!NLP_ISCHKPNTED(nlp))
3797 (void) ndmp_remove_snapshot(nlp->nlp_backup_path, jname);
3798
3799 NDMP_LOG(LOG_DEBUG, "err %d, update %c",
3800 err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
3801
3802 if (err == 0)
3803 save_backup_date_v3(params, nlp);
3804
3805 MOD_DONE(params, err);
3806
3807 /* nlp_params is allocated in start_backup_v3() */
3808 NDMP_FREE(nlp->nlp_params);
3809 NDMP_FREE(nlp->nlp_backup_path);
3810
3811 NS_DEC(nbk);
3812 ndmp_session_unref(session);
3813 return (err);
3814
3815 }
3816
3817
3818 /*
3819 * ndmpd_tar_backup_abort_v3
3820 *
3821 * Abort the backup operation and stop the reader thread.
3822 *
3823 * Parameters:
3824 * module_cookie (input) - pointer to the nlp structure
3825 *
3826 * Returns:
3827 * 0: always
3828 */
3829 int
ndmpd_tar_backup_abort_v3(void * module_cookie)3830 ndmpd_tar_backup_abort_v3(void *module_cookie)
3831 {
3832 ndmp_lbr_params_t *nlp;
3833
3834 nlp = (ndmp_lbr_params_t *)module_cookie;
3835 if (nlp && nlp->nlp_session) {
3836 if (nlp->nlp_session->ns_data.dd_data_addr.addr_type ==
3837 NDMP_ADDR_TCP &&
3838 nlp->nlp_session->ns_data.dd_sock != -1) {
3839 (void) close(nlp->nlp_session->ns_data.dd_sock);
3840 nlp->nlp_session->ns_data.dd_sock = -1;
3841 }
3842 ndmp_stop_reader_thread(nlp->nlp_session);
3843 }
3844
3845 return (0);
3846 }
3847
3848
3849 /*
3850 * ndmp_restore_get_params_v3
3851 *
3852 * Get the parameters specified for recovery such as restore path, type
3853 * of restore (DAR, non-DAR) etc
3854 *
3855 * Parameters:
3856 * session (input) - pointer to the session
3857 * params (input) - pointer to the parameters structure
3858 *
3859 * Returns:
3860 * NDMP_NO_ERR: on success
3861 * != NDMP_NO_ERR: otherwise
3862 */
3863 ndmp_error
ndmp_restore_get_params_v3(ndmpd_session_t * session,ndmpd_module_params_t * params)3864 ndmp_restore_get_params_v3(ndmpd_session_t *session,
3865 ndmpd_module_params_t *params)
3866 {
3867 ndmp_error rv;
3868 ndmp_lbr_params_t *nlp;
3869
3870 if (!(nlp = ndmp_get_nlp(session))) {
3871 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
3872 rv = NDMP_ILLEGAL_ARGS_ERR;
3873 } else if (!(nlp->nlp_backup_path = get_backup_path_v3(params)))
3874 rv = NDMP_ILLEGAL_ARGS_ERR;
3875 else if ((nlp->nlp_nfiles = session->ns_data.dd_nlist_len) == 0) {
3876 NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
3877 rv = NDMP_ILLEGAL_ARGS_ERR;
3878 } else if (get_rs_path_v3(params, nlp) != NDMP_NO_ERR) {
3879 rv = NDMP_ILLEGAL_ARGS_ERR;
3880 } else if ((rv = fix_nlist_v3(session, params, nlp)) != NDMP_NO_ERR) {
3881 NDMP_LOG(LOG_DEBUG, "fix_nlist_v3: %d", rv);
3882 } else {
3883 rv = NDMP_NO_ERR;
3884 get_direct_env_v3(params, nlp);
3885 if (NLP_ISSET(nlp, NLPF_DIRECT)) {
3886 if (NLP_ISSET(nlp, NLPF_RECURSIVE)) {
3887 /* Currently we dont support DAR on directory */
3888 NDMP_LOG(LOG_DEBUG,
3889 "Can't have RECURSIVE and DIRECT together");
3890 rv = NDMP_ILLEGAL_ARGS_ERR;
3891 return (rv);
3892 }
3893
3894 /*
3895 * DAR can be done if all the fh_info's are valid.
3896 */
3897 if (allvalidfh(session, params)) {
3898 ndmp_sort_nlist_v3(session);
3899 } else {
3900 MOD_LOGV3(params, NDMP_LOG_WARNING,
3901 "Cannot do direct access recovery. "
3902 "Some 'fh_info'es are not valid.\n");
3903 NLP_UNSET(nlp, NLPF_DIRECT);
3904 }
3905 }
3906
3907 log_rs_params_v3(session, params, nlp);
3908 }
3909
3910 return (rv);
3911 }
3912
3913
3914 /*
3915 * ndmpd_tar_restore_starter_v3
3916 *
3917 * The main restore starter function. It will start a DAR or
3918 * non-DAR recovery based on the parameters. (V3 and V4 only)
3919 *
3920 * Parameters:
3921 * params (input) - pointer to the parameters structure
3922 *
3923 * Returns:
3924 * NDMP_NO_ERR: on success
3925 * != NDMP_NO_ERR: otherwise
3926 */
3927 int
ndmpd_tar_restore_starter_v3(void * arg)3928 ndmpd_tar_restore_starter_v3(void *arg)
3929 {
3930 ndmpd_module_params_t *params = arg;
3931 int err;
3932 ndmpd_session_t *session;
3933 ndmp_lbr_params_t *nlp;
3934
3935
3936 session = (ndmpd_session_t *)(params->mp_daemon_cookie);
3937 *(params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
3938 ndmp_session_ref(session);
3939
3940 if (NLP_ISSET(nlp, NLPF_DIRECT))
3941 err = ndmpd_rs_dar_tar_v3(session, params, nlp);
3942 else
3943 err = ndmpd_rs_sar_tar_v3(session, params, nlp);
3944
3945 MOD_DONE(params, err);
3946
3947 NS_DEC(nrs);
3948 /* nlp_params is allocated in start_recover() */
3949 NDMP_FREE(nlp->nlp_params);
3950 ndmp_session_unref(session);
3951 return (err);
3952
3953 }
3954
3955 /*
3956 * ndmp_tar_restore_abort_v3
3957 *
3958 * Restore abort function (V3 and V4 only)
3959 *
3960 * Parameters:
3961 * module_cookie (input) - pointer to nlp
3962 *
3963 * Returns:
3964 * 0
3965 */
3966 int
ndmpd_tar_restore_abort_v3(void * module_cookie)3967 ndmpd_tar_restore_abort_v3(void *module_cookie)
3968 {
3969 ndmp_lbr_params_t *nlp;
3970
3971 nlp = (ndmp_lbr_params_t *)module_cookie;
3972 if (nlp != NULL && nlp->nlp_session != NULL) {
3973 if (nlp->nlp_session->ns_data.dd_mover.addr_type ==
3974 NDMP_ADDR_TCP &&
3975 nlp->nlp_session->ns_data.dd_sock != -1) {
3976 (void) close(nlp->nlp_session->ns_data.dd_sock);
3977 nlp->nlp_session->ns_data.dd_sock = -1;
3978 }
3979 ndmp_stop_writer_thread(nlp->nlp_session);
3980 }
3981
3982 return (0);
3983 }
3984