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