1 /*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4
5 /*
6 * BSD 3 Clause License
7 *
8 * Copyright (c) 2007, The Storage Networking Industry Association.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * - Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * - Neither the name of The Storage Networking Industry Association (SNIA)
22 * nor the names of its contributors may be used to endorse or promote
23 * products derived from this software without specific prior written
24 * permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40 /* Copyright 2014 Nexenta Systems, Inc. All rights reserved. */
41
42 #include <sys/stat.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <errno.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <unistd.h>
49 #include <time.h>
50 #include <cstack.h>
51 #include <dirent.h>
52 #include <traverse.h>
53 #include "bitmap.h"
54 #include "ndmpd.h"
55 #include "tlm_buffers.h"
56
57
58 typedef struct ndmp_run_args {
59 char *nr_chkp_nm;
60 char *nr_unchkp_nm;
61 char **nr_excls;
62 } ndmp_run_args_t;
63
64
67 *
68 * Allocate the structures before performing backup
69 *
70 * Parameters:
71 * sesison (input) - session handle
72 * jname (input) - backup job name
73 *
74 * Returns:
75 * 0: on success
76 * -1: otherwise
77 */
78 static int
79 backup_create_structs(ndmpd_session_t *session, char *jname)
80 {
81 int n;
82 long xfer_size;
83 ndmp_lbr_params_t *nlp;
84 tlm_commands_t *cmds;
85
86 if ((nlp = ndmp_get_nlp(session)) == NULL) {
87 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
88 return (-1);
89 }
90
91 if ((nlp->nlp_jstat = tlm_new_job_stats(jname)) == NULL) {
92 NDMP_LOG(LOG_DEBUG, "Creating job stats");
93 return (-1);
94 }
95
96 cmds = &nlp->nlp_cmds;
97 (void) memset(cmds, 0, sizeof (*cmds));
98
99 xfer_size = ndmp_buffer_get_size(session);
100 if (xfer_size < 512*KILOBYTE) {
101 /*
102 * Read multiple of mover_record_size near to 512K. This
103 * will prevent the data being copied in the mover buffer
104 * when we write the data.
105 */
106 if ((n = (512 * KILOBYTE/xfer_size)) <= 0)
107 n = 1;
108 xfer_size *= n;
109 NDMP_LOG(LOG_DEBUG, "Adjusted read size: %d", xfer_size);
110 }
111
112 cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, xfer_size);
113 if (cmds->tcs_command == NULL) {
114 NDMP_LOG(LOG_DEBUG, "Error creating ipc buffers");
115 tlm_un_ref_job_stats(jname);
116 return (-1);
117 }
118
119 nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
120 ndmpd_file_history_path,
121 ndmpd_file_history_dir,
122 ndmpd_file_history_node);
123 if (nlp->nlp_logcallbacks == NULL) {
124 tlm_release_reader_writer_ipc(cmds->tcs_command);
125 tlm_un_ref_job_stats(jname);
126 return (-1);
127 }
128 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
129
130 return (0);
131 }
132
133
134 /*
136 *
137 * Allocate structures for performing a restore
138 *
139 * Parameters:
140 * sesison (input) - session handle
141 * jname (input) - backup job name
142 *
143 * Returns:
144 * 0: on success
145 * -1: otherwise
146 */
147 static int
148 restore_create_structs(ndmpd_session_t *session, char *jname)
149 {
150 int i;
151 long xfer_size;
152 ndmp_lbr_params_t *nlp;
153 tlm_commands_t *cmds;
154
155 if ((nlp = ndmp_get_nlp(session)) == NULL) {
156 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
157 return (-1);
158 }
159 if ((nlp->nlp_jstat = tlm_new_job_stats(jname)) == NULL) {
160 NDMP_LOG(LOG_DEBUG, "Creating job stats");
161 return (-1);
162 }
163
164 cmds = &nlp->nlp_cmds;
165 (void) memset(cmds, 0, sizeof (*cmds));
166
167 xfer_size = ndmp_buffer_get_size(session);
168 cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
169 if (cmds->tcs_command == NULL) {
170 NDMP_LOG(LOG_DEBUG, "Error creating ipc buffers");
171 tlm_un_ref_job_stats(jname);
172 return (-1);
173 }
174
175 nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
176 ndmpd_path_restored, NULL, NULL);
177 if (nlp->nlp_logcallbacks == NULL) {
178 tlm_release_reader_writer_ipc(cmds->tcs_command);
179 tlm_un_ref_job_stats(jname);
180 return (-1);
181 }
182 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
183
184 nlp->nlp_restored = ndmp_malloc(sizeof (boolean_t) * nlp->nlp_nfiles);
185 if (nlp->nlp_restored == NULL) {
186 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
187 tlm_release_reader_writer_ipc(cmds->tcs_command);
188 tlm_un_ref_job_stats(jname);
189 return (-1);
190 }
198 /*
199 * send_unrecovered_list
200 *
201 * Creates a list of restored files
202 *
203 * Parameters:
204 * params (input) - NDMP parameters
205 * nlp (input) - NDMP/LBR parameters
206 *
207 * Returns:
208 * 0: on success
209 * -1: otherwise
210 */
211 static int
212 send_unrecovered_list(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
213 {
214 int i, rv;
215 ndmp_name *ent;
216
217 if (params == NULL) {
218 NDMP_LOG(LOG_DEBUG, "params == NULL");
219 return (-1);
220 }
221 if (nlp == NULL) {
222 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
223 return (-1);
224 }
225
226 rv = 0;
227 for (i = 0; i < (int)nlp->nlp_nfiles; i++) {
228 NDMP_LOG(LOG_DEBUG, "nlp->nlp_restored[%d]: %s", i,
229 nlp->nlp_restored[i] ? "TRUE" : "FALSE");
230
231 if (!nlp->nlp_restored[i]) {
232 ent = (ndmp_name *)MOD_GETNAME(params, i);
233 if (ent == NULL) {
234 NDMP_LOG(LOG_DEBUG, "ent == NULL");
235 rv = -1;
236 break;
237 }
238 if (ent->name == NULL) {
239 NDMP_LOG(LOG_DEBUG, "ent->name == NULL");
240 rv = -1;
241 break;
242 }
243
244 NDMP_LOG(LOG_DEBUG, "ent.name: \"%s\"", ent->name);
245
246 rv = MOD_FILERECOVERD(params, ent->name, ENOENT);
247 if (rv < 0)
248 break;
249 }
250 }
251
252 return (rv);
253 }
254
255
256 /*
257 * backup_release_structs
258 *
259 * Deallocated the NDMP/LBR specific parameters
260 *
261 * Parameters:
262 * session (input) - session handle
263 *
264 * Returns:
265 * void
266 */
267 /*ARGSUSED*/
268 static void
269 backup_release_structs(ndmpd_session_t *session)
270 {
271 ndmp_lbr_params_t *nlp;
272 tlm_commands_t *cmds;
273
274 if ((nlp = ndmp_get_nlp(session)) == NULL) {
275 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
276 return;
277 }
278 cmds = &nlp->nlp_cmds;
279 if (cmds == NULL) {
280 NDMP_LOG(LOG_DEBUG, "cmds == NULL");
281 return;
282 }
283
284 if (nlp->nlp_logcallbacks != NULL) {
285 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
286 nlp->nlp_logcallbacks = NULL;
287 } else {
288 NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL");
289 }
290
291 if (cmds->tcs_command != NULL) {
292 if (cmds->tcs_command->tc_buffers != NULL)
293 tlm_release_reader_writer_ipc(cmds->tcs_command);
294 else
295 NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL");
296 cmds->tcs_command = NULL;
297 } else {
298 NDMP_LOG(LOG_DEBUG, "COMMAND == NULL");
299 }
300
301 if (nlp->nlp_bkmap >= 0) {
302 (void) dbm_free(nlp->nlp_bkmap);
303 nlp->nlp_bkmap = -1;
304 }
305
306 if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER &&
307 nlp->nlp_restored != NULL) {
308 free(nlp->nlp_restored);
309 nlp->nlp_restored = NULL;
310 } else {
311 NDMP_LOG(LOG_DEBUG, "nlp_restored == NULL");
312 }
313 }
314
315 /*
316 * ndmp_write_utf8magic
317 *
318 * Write a magic pattern to the tar header. This is used
319 * as a crest to indicate that tape belongs to us.
320 */
321 int
322 ndmp_write_utf8magic(tlm_cmd_t *cmd)
323 {
324 char *cp;
325 long actual_size;
326
327 if (cmd->tc_buffers == NULL) {
328 NDMP_LOG(LOG_DEBUG, "cmd->tc_buffers == NULL");
329 return (-1);
330 }
331
332 cp = tlm_get_write_buffer(RECORDSIZE, &actual_size,
333 cmd->tc_buffers, TRUE);
334 if (actual_size < RECORDSIZE) {
335 NDMP_LOG(LOG_DEBUG, "Couldn't get enough buffer");
336 return (-1);
337 }
338
339 (void) strlcpy(cp, NDMPUTF8MAGIC, RECORDSIZE);
340 return (0);
341 }
342
343
344 /*
345 * timecmp
346 *
347 * This callback function is used during backup. It checks
348 * if the object specified by the 'attr' should be backed
349 * up or not.
350 *
351 * Directories are backed up anyways for dump format.
352 * If this function is called, then the directory is
353 * marked in the bitmap vector, it shows that either the
354 * directory itself is modified or there is something below
355 * it that will be backed up.
360 * By setting ndmp_force_bk_dirs global variable to a non-zero
361 * value, directories are backed up anyways.
362 *
363 * Backing up the directories unconditionally, helps
364 * restoring the metadata of directories as well, when one
365 * of the objects below them are being restored.
366 *
367 * For non-directory objects, if the modification or change
368 * time of the object is after the date specified by the
369 * bk_selector_t, the the object must be backed up.
370 *
371 */
372 static boolean_t
373 timecmp(bk_selector_t *bksp,
374 struct stat64 *attr)
375 {
376 ndmp_lbr_params_t *nlp;
377
378 nlp = (ndmp_lbr_params_t *)bksp->bs_cookie;
379 if (S_ISDIR(attr->st_mode) && ndmp_force_bk_dirs) {
380 NDMP_LOG(LOG_DEBUG, "d(%lu)",
381 (uint_t)attr->st_ino);
382 return (TRUE);
383 }
384 if (S_ISDIR(attr->st_mode) &&
385 dbm_getone(nlp->nlp_bkmap, (u_longlong_t)attr->st_ino) &&
386 ((NLP_ISDUMP(nlp) && ndmp_dump_path_node) ||
387 (NLP_ISTAR(nlp) && ndmp_tar_path_node))) {
388 /*
389 * If the object is a directory and it leads to a modified
390 * object (that should be backed up) and for that type of
391 * backup the path nodes should be backed up, then return
392 * TRUE.
393 *
394 * This is required by some DMAs like Backup Express, which
395 * needs to receive ADD_NODE (for dump) or ADD_PATH (for tar)
396 * for the intermediate directories of a modified object.
397 * Other DMAs, like net_backup and net_worker, do not have such
398 * requirement. This requirement makes sense for dump format
399 * but for 'tar' format, it does not. In provision to the
400 * NDMP-v4 spec, for 'tar' format the intermediate directories
401 * need not to be reported.
402 */
403 NDMP_LOG(LOG_DEBUG, "p(%lu)", (u_longlong_t)attr->st_ino);
404 return (TRUE);
405 }
406 if (attr->st_mtime > bksp->bs_ldate) {
407 NDMP_LOG(LOG_DEBUG, "m(%lu): %lu > %lu",
408 (uint_t)attr->st_ino, (uint_t)attr->st_mtime,
409 (uint_t)bksp->bs_ldate);
410 return (TRUE);
411 }
412 if (attr->st_ctime > bksp->bs_ldate) {
413 if (NLP_IGNCTIME(nlp)) {
414 NDMP_LOG(LOG_DEBUG, "ign c(%lu): %lu > %lu",
415 (uint_t)attr->st_ino, (uint_t)attr->st_ctime,
416 (uint_t)bksp->bs_ldate);
417 return (FALSE);
418 }
419 NDMP_LOG(LOG_DEBUG, "c(%lu): %lu > %lu",
420 (uint_t)attr->st_ino, (uint_t)attr->st_ctime,
421 (uint_t)bksp->bs_ldate);
422 return (TRUE);
423 }
424 NDMP_LOG(LOG_DEBUG, "mc(%lu): (%lu,%lu) < %lu",
425 (uint_t)attr->st_ino, (uint_t)attr->st_mtime,
426 (uint_t)attr->st_ctime, (uint_t)bksp->bs_ldate);
427 return (FALSE);
428 }
429
430
431 /*
432 * get_acl_info
433 *
434 * load up all the access and attribute info
435 */
436 static int
437 get_acl_info(char *name, tlm_acls_t *tlm_acls)
438 {
439 int erc;
440 acl_t *aclp = NULL;
441 char *acltp;
442
443 erc = lstat64(name, &tlm_acls->acl_attr);
444 if (erc != 0) {
445 NDMP_LOG(LOG_ERR, "Could not find file %s.", name);
446 erc = TLM_NO_SOURCE_FILE;
447 return (erc);
448 }
449 erc = acl_get(name, ACL_NO_TRIVIAL, &aclp);
450 if (erc != 0) {
451 NDMP_LOG(LOG_DEBUG,
452 "Could not read ACL for file [%s]", name);
453 erc = TLM_NO_SOURCE_FILE;
454 return (erc);
455 }
456 if (aclp && (acltp = acl_totext(aclp,
457 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
458 (void) strlcpy(tlm_acls->acl_info.attr_info, acltp,
459 TLM_MAX_ACL_TXT);
460 acl_free(aclp);
461 free(acltp);
462 }
463 return (erc);
464 }
465 /*
466 * get_dir_acl_info
467 *
468 * load up all ACL and attr info about a directory
469 */
470 static int
471 get_dir_acl_info(char *dir, tlm_acls_t *tlm_acls, tlm_job_stats_t *js)
472 {
473 int erc;
474 char *checkpointed_dir;
475 char root_dir[TLM_VOLNAME_MAX_LENGTH];
476 char *spot;
477 char *fil;
478 acl_t *aclp = NULL;
479 char *acltp;
480
481 checkpointed_dir = ndmp_malloc(TLM_MAX_PATH_NAME);
482 if (checkpointed_dir == NULL)
483 return (-1);
484
485 if (tlm_acls->acl_checkpointed)
486 fil = tlm_build_snapshot_name(dir, checkpointed_dir,
487 js->js_job_name);
488 else
489 fil = dir;
490 erc = lstat64(fil, &tlm_acls->acl_attr);
491 if (erc != 0) {
492 NDMP_LOG(LOG_ERR, "Could not find directory %s.", dir);
493 free(checkpointed_dir);
494 return (-1);
495 }
496
497 spot = strchr(&fil[1], '/');
498 if (spot == NULL) {
499 (void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH);
500 } else {
501 *spot = 0;
502 (void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH);
503 *spot = '/';
504 }
505 if (strcmp(root_dir, tlm_acls->acl_root_dir) != 0) {
506 struct stat64 attr;
507
508 erc = lstat64(root_dir, &attr);
509 if (erc != 0) {
510 NDMP_LOG(LOG_ERR, "Cannot find root directory %s.",
511 root_dir);
512 free(checkpointed_dir);
513 return (-1);
514 }
515 (void) strlcpy(tlm_acls->acl_root_dir, root_dir,
516 TLM_VOLNAME_MAX_LENGTH);
517 }
518 erc = acl_get(fil, ACL_NO_TRIVIAL, &aclp);
519 if (erc != 0) {
520 NDMP_LOG(LOG_DEBUG,
521 "Could not read metadata for directory [%s]", dir);
522 free(checkpointed_dir);
523 return (-1);
524 }
525 if (aclp && (acltp = acl_totext(aclp,
526 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
527 (void) strlcpy(tlm_acls->acl_info.attr_info, acltp,
528 TLM_MAX_ACL_TXT);
529 acl_free(aclp);
530 free(acltp);
531 }
532
533 free(checkpointed_dir);
534 return (0);
535 }
536
537 /*
538 * backup_dir
539 *
540 * Create a TAR entry record for a directory
541 */
542 static int
543 backup_dir(char *dir, tlm_acls_t *tlm_acls,
544 tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats,
545 bk_selector_t *bksp)
546 {
547 int erc;
548
549 NDMP_LOG(LOG_DEBUG, "\"%s\"", dir);
550
551 erc = get_dir_acl_info(dir, tlm_acls, job_stats);
552 if (erc != 0) {
553 NDMP_LOG(LOG_DEBUG,
554 "Could not read directory info for %s", dir);
555 job_stats->js_errors++;
556 } else {
557 /*
558 * See if the directory must be backed up.
559 */
560 if (bksp && !(*bksp->bs_fn)(bksp, &tlm_acls->acl_attr)) {
561 NDMP_LOG(LOG_DEBUG, "[%s] dir skipped", dir);
562 return (erc);
563 }
564
565 if (tm_tar_ops.tm_putdir != NULL)
566 (void) (tm_tar_ops.tm_putdir)(dir, tlm_acls,
567 local_commands, job_stats);
568 }
569
570 return (erc);
571 }
572
573
574 /*
575 * backup_file
576 *
577 * Create a TAR record entry for a file
578 */
579 static longlong_t
580 backup_file(char *dir, char *name, tlm_acls_t *tlm_acls,
581 tlm_commands_t *commands, tlm_cmd_t *local_commands,
582 tlm_job_stats_t *job_stats, bk_selector_t *bksp)
583 {
584
585 int erc;
586 char buf[TLM_MAX_PATH_NAME];
587 longlong_t rv;
588
589 NDMP_LOG(LOG_DEBUG, "\"%s/%s\"", dir, name);
590
591 (void) strlcpy(buf, dir, sizeof (buf));
592 (void) strlcat(buf, "/", sizeof (buf));
593 (void) strlcat(buf, name, sizeof (buf));
594
595 /*
596 * get_acl_info extracts file handle, attributes and ACLs of the file.
597 * This is not efficient when the attributes and file handle of
598 * the file is already known.
599 */
600 erc = get_acl_info(buf, tlm_acls);
601 if (erc != TLM_NO_ERRORS) {
602 NDMP_LOG(LOG_ERR, "Could not open file %s/%s.", dir, name);
603 return (-ENOENT);
604 }
605
606 /* Should the file be backed up? */
607 if (!bksp) {
608 NDMP_LOG(LOG_DEBUG,
609 "[%s/%s] has no selection criteria", dir, name);
610
611 } else if (!((*bksp->bs_fn)(bksp, &tlm_acls->acl_attr))) {
612 NDMP_LOG(LOG_DEBUG, "[%s/%s] file skipped", dir, name);
613 return (0);
614 }
615
616 /* Only the regular files and symbolic links can be backed up. */
617 if (!S_ISLNK(tlm_acls->acl_attr.st_mode) &&
618 !S_ISREG(tlm_acls->acl_attr.st_mode)) {
619 NDMP_LOG(LOG_DEBUG,
620 "Warning: skip backing up [%s][%s]", dir, name);
621 return (-EINVAL);
622 }
623
624
625 if (tm_tar_ops.tm_putfile != NULL)
626 rv = (tm_tar_ops.tm_putfile)(dir, name, tlm_acls, commands,
627 local_commands, job_stats);
628
629 return (rv);
630 }
631
632
633
634 /*
635 * backup_work
636 *
637 * Start the NDMP backup (V2 only).
638 */
639 int
641 ndmp_run_args_t *np, tlm_commands_t *commands,
642 ndmp_lbr_params_t *nlp)
643 {
644 struct full_dir_info dir_info; /* the blob to push/pop with cstack_t */
645 struct full_dir_info *t_dir_info, *p_dir_info;
646 struct stat64 ret_attr; /* attributes of current file name */
647 fs_fhandle_t ret_fh;
648 char *first_name; /* where the first name is located */
649 char *dname;
650 int erc;
651 int retval;
652 cstack_t *stk;
653 unsigned long fileid;
654 tlm_acls_t tlm_acls;
655 int dname_size;
656 longlong_t fsize;
657 bk_selector_t bks;
658 tlm_cmd_t *local_commands;
659 long dpos;
660
661 NDMP_LOG(LOG_DEBUG, "nr_chkpnted %d nr_ldate: %u bk_path: \"%s\"",
662 NLP_ISCHKPNTED(nlp), nlp->nlp_ldate, bk_path);
663
664 /* Get every name in this directory */
665 dname = ndmp_malloc(TLM_MAX_PATH_NAME);
666 if (dname == NULL)
667 return (-ENOMEM);
668
669 local_commands = commands->tcs_command;
670 retval = 0;
671 (void) memset(&bks, 0, sizeof (bks));
672 bks.bs_cookie = (void *)nlp;
673 bks.bs_level = nlp->nlp_clevel;
674 bks.bs_ldate = nlp->nlp_ldate;
675 bks.bs_fn = timecmp;
676
677 /*
678 * should we skip the whole thing?
679 */
680 if (tlm_is_excluded("", bk_path, np->nr_excls)) {
681 NDMP_LOG(LOG_DEBUG, "%s excluded", bk_path);
682 free(dname);
683 return (0);
684 }
685
686 /*
687 * Search for the top-level file-directory
688 */
689 if (NLP_ISCHKPNTED(nlp)) {
690 first_name = np->nr_chkp_nm;
691 (void) strlcpy(first_name, bk_path, TLM_MAX_PATH_NAME);
692 } else {
693 first_name = tlm_build_snapshot_name(bk_path, np->nr_chkp_nm,
694 nlp->nlp_jstat->js_job_name);
695 }
696
697 (void) memset(&ret_fh, 0, sizeof (ret_fh));
698 erc = fs_getstat(first_name, &ret_fh, &ret_attr);
699 if (erc != 0) {
700 NDMP_LOG(LOG_ERR, "Path %s not found.", first_name);
701 free(dname);
702 return (-EINVAL);
703 }
704
705 if ((stk = cstack_new()) == NULL) {
706 free(dname);
707 NDMP_LOG(LOG_DEBUG, "cstack_new failed");
708 return (-ENOMEM);
709 }
710 (void) strlcpy(dir_info.fd_dir_name, first_name, TLM_MAX_PATH_NAME);
711 (void) memcpy(&dir_info.fd_dir_fh, &ret_fh, sizeof (fs_fhandle_t));
712 p_dir_info = dup_dir_info(&dir_info);
713
714 /*
715 * Push the first name onto the stack so that we can pop it back
716 * off as part of the normal cycle
717 */
718 if (cstack_push(stk, p_dir_info, 0)) {
719 free(dname);
720 free(p_dir_info);
721 cstack_delete(stk);
722 NDMP_LOG(LOG_DEBUG, "cstack_push failed");
723 return (-ENOMEM);
724 }
725
726 (void) memset(&tlm_acls, 0, sizeof (tlm_acls));
727 /*
728 * Did NDMP create a checkpoint?
729 */
730 if (NLP_ISCHKPNTED(nlp) || fs_is_rdonly(bk_path)) {
731 tlm_acls.acl_checkpointed = FALSE;
732 } else {
733 /* Use the checkpoint created by NDMP */
734 tlm_acls.acl_checkpointed = TRUE;
735 }
736
737 /*
738 * This is level-backup. It never resets the archive bit.
739 */
740 tlm_acls.acl_clear_archive = FALSE;
741
742 NDMP_LOG(LOG_DEBUG, "acls.chkpnt: %c acls.clear_arcbit: %c",
743 NDMP_YORN(tlm_acls.acl_checkpointed),
744 NDMP_YORN(tlm_acls.acl_clear_archive));
745
746 while (commands->tcs_reader == TLM_BACKUP_RUN &&
747 local_commands->tc_reader == TLM_BACKUP_RUN &&
748 cstack_pop(stk, (void **)&p_dir_info, 0) == 0) {
749
750 if (NLP_ISCHKPNTED(nlp))
751 (void) strlcpy(np->nr_unchkp_nm,
752 p_dir_info->fd_dir_name, TLM_MAX_PATH_NAME);
753 else
754 (void) tlm_remove_checkpoint(p_dir_info->fd_dir_name,
755 np->nr_unchkp_nm);
756
757 (void) backup_dir(np->nr_unchkp_nm, &tlm_acls, local_commands,
758 job_stats, &bks);
759
760
761 while (commands->tcs_reader == TLM_BACKUP_RUN &&
762 local_commands->tc_reader == TLM_BACKUP_RUN) {
763
764 dname_size = TLM_MAX_PATH_NAME - 1;
765
766 NDMP_LOG(LOG_DEBUG,
767 "dir_name: %s", p_dir_info->fd_dir_name);
768
769 (void) memset(&ret_fh, 0, sizeof (ret_fh));
770 erc = fs_readdir(&p_dir_info->fd_dir_fh,
771 p_dir_info->fd_dir_name, &dpos,
772 dname, &dname_size, &ret_fh, &ret_attr);
773 if (erc == 0) {
774 fileid = ret_fh.fh_fid;
775 } else {
776 NDMP_LOG(LOG_DEBUG,
777 "Filesystem readdir in [%s]",
778 p_dir_info->fd_dir_name);
779 retval = -ENOENT;
780 break;
781 }
782
783 /* an empty name size marks the end of the list */
784 if (dname_size == 0)
785 break;
786 dname[dname_size] = '\0';
787
788 NDMP_LOG(LOG_DEBUG, "dname: \"%s\"", dname);
789
790 /*
791 * If name refers to a directory, push its file
792 * handle onto the stack (skip "." and "..").
793 */
794 if (rootfs_dot_or_dotdot(dname)) {
795 fileid = 0;
796 continue;
797 }
798
799 /*
800 * Skip the:
801 * non-dir entries which should not be backed up
802 * Or
803 * dir-type entries which have have nothing under
804 * their hierarchy to be backed up.
805 */
806 if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)fileid)) {
807 NDMP_LOG(LOG_DEBUG, "Skipping %s/%s",
808 p_dir_info->fd_dir_name, dname);
809 fileid = 0;
810 continue;
811 }
812
813 if (tlm_is_excluded(np->nr_unchkp_nm, dname,
814 np->nr_excls)) {
815 fileid = 0;
816 continue;
817 }
818 if (S_ISDIR(ret_attr.st_mode)) {
819 /*
820 * only directories get pushed onto this stack,
821 * so we do not have to test for regular files.
822 */
823 t_dir_info = tlm_new_dir_info(&ret_fh,
824 p_dir_info->fd_dir_name, dname);
825 if (t_dir_info == NULL) {
826 NDMP_LOG(LOG_DEBUG,
827 "While backing up [%s][%s]",
828 p_dir_info->fd_dir_name, dname);
829 } else if (cstack_push(stk, t_dir_info,
830 0) != 0) {
831 NDMP_LOG(LOG_DEBUG,
832 "No enough memory stack_push");
833 retval = -ENOMEM;
834 break;
835 }
836 } else if (S_ISREG(ret_attr.st_mode) ||
837 S_ISLNK(ret_attr.st_mode)) {
838
839 fsize = backup_file(np->nr_unchkp_nm, dname,
840 &tlm_acls, commands, local_commands,
841 job_stats, &bks);
842
843 if (fsize >= 0) {
844 job_stats->js_files_so_far++;
845 job_stats->js_bytes_total += fsize;
846 } else
847 job_stats->js_errors++;
848 fileid = 0;
849 }
850 }
851 fileid = 0;
901 }
902 return (rv);
903 }
904
905
906 /*
907 * ndmp_backup_reader
908 *
909 * Backup reader thread which uses backup_work to read and TAR
910 * the files/dirs to be backed up (V2 only)
911 */
912 static int
913 ndmp_backup_reader(tlm_commands_t *commands, ndmp_lbr_params_t *nlp,
914 char *job_name)
915 {
916 int retval;
917 ndmp_run_args_t np;
918 tlm_job_stats_t *job_stats;
919 tlm_cmd_t *local_commands;
920
921 NDMP_LOG(LOG_DEBUG, "bk_path: \"%s\"", nlp->nlp_backup_path);
922
923 local_commands = commands->tcs_command;
924 (void) memset(&np, 0, sizeof (np));
925 if (!malloc_paths(&np))
926 return (-1);
927 local_commands->tc_ref++;
928 commands->tcs_reader_count++;
929
930 job_stats = tlm_ref_job_stats(job_name);
931
932 retval = backup_work(nlp->nlp_backup_path, job_stats, &np,
933 commands, nlp);
934 write_tar_eof(local_commands);
935
936 commands->tcs_reader_count--;
937 local_commands->tc_writer = TLM_STOP;
938 tlm_release_reader_writer_ipc(local_commands);
939 tlm_un_ref_job_stats(job_name);
940
941 free_paths(&np);
945
946
947 /*
948 * ndmp_tar_writer
949 *
950 * The backup writer thread that writes the TAR records to the
951 * tape media (V2 only)
952 */
953 int
954 ndmp_tar_writer(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
955 tlm_commands_t *cmds)
956 {
957 int bidx, nw;
958 int err;
959 tlm_buffer_t *buf;
960 tlm_buffers_t *bufs;
961 tlm_cmd_t *lcmd; /* Local command */
962
963 err = 0;
964 if (session == NULL) {
965 NDMP_LOG(LOG_DEBUG, "session == NULL");
966 err = -1;
967 } else if (mod_params == NULL) {
968 NDMP_LOG(LOG_DEBUG, "mod_params == NULL");
969 err = -1;
970 } else if (cmds == NULL) {
971 NDMP_LOG(LOG_DEBUG, "cmds == NULL");
972 err = -1;
973 }
974
975 if (err != 0)
976 return (err);
977
978 lcmd = cmds->tcs_command;
979 bufs = lcmd->tc_buffers;
980
981 lcmd->tc_ref++;
982 cmds->tcs_writer_count++;
983
984 nw = 0;
985 buf = tlm_buffer_out_buf(bufs, &bidx);
986 while (cmds->tcs_writer != (int)TLM_ABORT &&
987 lcmd->tc_writer != (int)TLM_ABORT) {
988 if (buf->tb_full) {
989 NDMP_LOG(LOG_DEBUG, "w%d", bidx);
990
991 if (MOD_WRITE(mod_params, buf->tb_buffer_data,
992 buf->tb_buffer_size) != 0) {
993 NDMP_LOG(LOG_DEBUG,
994 "Writing buffer %d, pos: %lld",
995 bidx, session->ns_mover.md_position);
996 err = -1;
997 break;
998 }
999
1000 tlm_buffer_mark_empty(buf);
1001 (void) tlm_buffer_advance_out_idx(bufs);
1002 buf = tlm_buffer_out_buf(bufs, &bidx);
1003 tlm_buffer_release_out_buf(bufs);
1004 nw++;
1005 } else {
1006 if (lcmd->tc_writer != TLM_BACKUP_RUN) {
1007 /* No more data is comming; time to exit. */
1008 NDMP_LOG(LOG_DEBUG,
1009 "tc_writer!=TLM_BACKUP_RUN; time to exit");
1010 break;
1011 } else {
1012 NDMP_LOG(LOG_DEBUG, "W%d", bidx);
1013 tlm_buffer_in_buf_timed_wait(bufs, 100);
1014 }
1015 }
1016 }
1017
1018 NDMP_LOG(LOG_DEBUG, "nw: %d", nw);
1019 if (cmds->tcs_writer != (int)TLM_ABORT) {
1020 NDMP_LOG(LOG_DEBUG, "tcs_writer != TLM_ABORT");
1021 } else {
1022 NDMP_LOG(LOG_DEBUG, "tcs_writer == TLM_ABORT");
1023 }
1024
1025 if (lcmd->tc_writer != (int)TLM_ABORT) {
1026 NDMP_LOG(LOG_DEBUG, "tc_writer != TLM_ABORT");
1027 } else {
1028 NDMP_LOG(LOG_DEBUG, "tc_writer == TLM_ABORT");
1029 }
1030 cmds->tcs_writer_count--;
1031 lcmd->tc_reader = TLM_STOP;
1032 lcmd->tc_ref--;
1033
1034 return (err);
1035 }
1036
1037
1038 /*
1039 * read_one_buf
1040 *
1041 * Read one buffer from the tape
1042 */
1043 static int
1044 read_one_buf(ndmpd_module_params_t *mod_params, tlm_buffers_t *bufs,
1045 tlm_buffer_t *buf)
1046 {
1047 int rv;
1048
1049 if ((rv = MOD_READ(mod_params, buf->tb_buffer_data,
1071 ndmp_tar_reader(ndmp_tar_reader_arg_t *argp)
1072 {
1073 int bidx;
1074 int err;
1075 tlm_buffer_t *buf;
1076 tlm_buffers_t *bufs;
1077 tlm_cmd_t *lcmd; /* Local command */
1078 ndmpd_session_t *session;
1079 ndmpd_module_params_t *mod_params;
1080 tlm_commands_t *cmds;
1081
1082 if (!argp)
1083 return (-1);
1084
1085 session = argp->tr_session;
1086 mod_params = argp->tr_mod_params;
1087 cmds = argp->tr_cmds;
1088
1089 err = 0;
1090 if (session == NULL) {
1091 NDMP_LOG(LOG_DEBUG, "session == NULL");
1092 err = -1;
1093 } else if (cmds == NULL) {
1094 NDMP_LOG(LOG_DEBUG, "cmds == NULL");
1095 err = -1;
1096 }
1097
1098 if (err != 0) {
1099 tlm_cmd_signal(cmds->tcs_command, TLM_TAR_READER);
1100 return (err);
1101 }
1102
1103 lcmd = cmds->tcs_command;
1104 bufs = lcmd->tc_buffers;
1105
1106 lcmd->tc_ref++;
1107 cmds->tcs_reader_count++;
1108
1109 /*
1110 * Synchronize with our parent thread.
1111 */
1112 tlm_cmd_signal(cmds->tcs_command, TLM_TAR_READER);
1113
1114 buf = tlm_buffer_in_buf(bufs, &bidx);
1115 while (cmds->tcs_reader == TLM_RESTORE_RUN &&
1116 lcmd->tc_reader == TLM_RESTORE_RUN) {
1117
1118 if (buf->tb_full) {
1119 NDMP_LOG(LOG_DEBUG, "R%d", bidx);
1120 /*
1121 * The buffer is still full, wait for the consumer
1122 * thread to use it.
1123 */
1124 tlm_buffer_out_buf_timed_wait(bufs, 100);
1125 buf = tlm_buffer_in_buf(bufs, NULL);
1126 } else {
1127 NDMP_LOG(LOG_DEBUG, "r%d", bidx);
1128
1129 err = read_one_buf(mod_params, bufs, buf);
1130 if (err < 0) {
1131 NDMP_LOG(LOG_DEBUG,
1132 "Reading buffer %d, pos: %lld",
1133 bidx, session->ns_mover.md_position);
1134
1135 /* Force the writer to stop. */
1136 buf->tb_eot = buf->tb_eof = TRUE;
1137 break;
1138 } else if (err == 1) {
1139 NDMP_LOG(LOG_DEBUG,
1140 "operation aborted or session terminated");
1141 err = 0;
1142 break;
1143 }
1144
1145 buf = tlm_buffer_in_buf(bufs, &bidx);
1146 tlm_buffer_release_in_buf(bufs);
1147 }
1148 }
1149
1150 /*
1151 * If the consumer is waiting for us, wake it up so that it detects
1152 * we're quiting.
1153 */
1154 lcmd->tc_writer = TLM_STOP;
1155 tlm_buffer_release_in_buf(bufs);
1156 (void) usleep(1000);
1157
1158 /*
1159 * Clean up.
1162 lcmd->tc_ref--;
1163 return (err);
1164 }
1165
1166
1167 /*
1168 * ndmpd_tar_backup
1169 *
1170 * Check must have been done that backup work directory exists, before
1171 * calling this function.
1172 */
1173 static int
1174 ndmpd_tar_backup(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
1175 ndmp_lbr_params_t *nlp)
1176 {
1177 char jname[TLM_MAX_BACKUP_JOB_NAME];
1178 int err;
1179 tlm_commands_t *cmds;
1180
1181 if (mod_params->mp_operation != NDMP_DATA_OP_BACKUP) {
1182 NDMP_LOG(LOG_DEBUG,
1183 "mod_params->mp_operation != NDMP_DATA_OP_BACKUP");
1184 err = -1;
1185 } else {
1186 if (ndmpd_mark_inodes_v2(session, nlp) != 0)
1187 err = -1;
1188 else if (ndmp_get_bk_dir_ino(nlp))
1189 err = -1;
1190 else
1191 err = 0;
1192 }
1193
1194 if (err != 0)
1195 return (err);
1196
1197 (void) ndmp_new_job_name(jname);
1198 if (backup_create_structs(session, jname) < 0)
1199 return (-1);
1200
1201 nlp->nlp_jstat->js_start_ltime = time(NULL);
1202 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
1203 nlp->nlp_jstat->js_chkpnt_time = nlp->nlp_cdate;
1204
1205 if (!session->ns_data.dd_abort) {
1206
1207 cmds = &nlp->nlp_cmds;
1208 cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
1209 cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
1210 cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
1211
1212 if (ndmp_write_utf8magic(cmds->tcs_command) < 0) {
1213 backup_release_structs(session);
1214 return (-1);
1215 }
1216
1217 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" started.",
1218 nlp->nlp_backup_path);
1219
1220 err = ndmp_backup_reader(cmds, nlp, jname);
1221 if (err != 0) {
1222 backup_release_structs(session);
1223 NDMP_LOG(LOG_DEBUG, "Launch ndmp_backup_reader: %s",
1224 strerror(err));
1225 return (-1);
1226 }
1227
1228 /* Act as the writer thread. */
1229 err = ndmp_tar_writer(session, mod_params, cmds);
1230
1231 nlp->nlp_jstat->js_stop_time = time(NULL);
1232
1233 NDMP_LOG(LOG_DEBUG,
1234 "Runtime [%s] %llu bytes (%llu): %d seconds",
1235 nlp->nlp_backup_path, session->ns_mover.md_data_written,
1236 session->ns_mover.md_data_written,
1237 nlp->nlp_jstat->js_stop_time -
1238 nlp->nlp_jstat->js_start_ltime);
1239 MOD_LOG(mod_params,
1240 "Runtime [%s] %llu bytes (%llu): %d seconds",
1241 nlp->nlp_backup_path, session->ns_mover.md_data_written,
1242 session->ns_mover.md_data_written,
1243 nlp->nlp_jstat->js_stop_time -
1244 nlp->nlp_jstat->js_start_ltime);
1245
1246 if (session->ns_data.dd_abort)
1247 err = -1;
1248
1249 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" finished. (%d)",
1250 nlp->nlp_backup_path, err);
1251 } else {
1252 nlp->nlp_jstat->js_stop_time = time(NULL);
1253 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
1254 nlp->nlp_backup_path);
1255 err = 0;
1256 }
1257
1258 backup_release_structs(session);
1259 return (err);
1260 }
1261
1262
1263 /*
1264 * ndmpd_tar_restore
1265 *
1266 * Restore function that launches TAR reader thread to read from the
1267 * tape and writes the extracted files/dirs to the filesystem
1268 */
1269 static int
1270 ndmpd_tar_restore(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
1271 ndmp_lbr_params_t *nlp)
1272 {
1273 char jname[TLM_MAX_BACKUP_JOB_NAME];
1274 char *rspath;
1275 int err;
1276 tlm_commands_t *cmds;
1277 ndmp_tar_reader_arg_t arg;
1278 tlm_backup_restore_arg_t tlm_arg;
1279 ndmp_name *ent;
1280 pthread_t rdtp, wrtp;
1281 int i;
1282
1283 if (mod_params->mp_operation != NDMP_DATA_OP_RECOVER) {
1284 NDMP_LOG(LOG_DEBUG,
1285 "mod_params->mp_operation != NDMP_DATA_OP_RECOVER");
1286 return (-1);
1287 }
1288
1289 if (nlp->nlp_restore_path[0] != '\0')
1290 rspath = nlp->nlp_restore_path;
1291 else if (nlp->nlp_restore_bk_path[0] != '\0')
1292 rspath = nlp->nlp_restore_bk_path;
1293 else
1294 rspath = "";
1295
1296 (void) ndmp_new_job_name(jname);
1297 if (restore_create_structs(session, jname) < 0)
1298 return (-1);
1299
1300 nlp->nlp_jstat->js_start_ltime = time(NULL);
1301 nlp->nlp_jstat->js_start_time = time(NULL);
1302
1303 if (!session->ns_data.dd_abort) {
1304 cmds = &nlp->nlp_cmds;
1305 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
1306 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
1307 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
1308
1309 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" started.", rspath);
1310 NDMP_LOG(LOG_DEBUG, "Restoring from %s tape(s).",
1311 ndmp_data_get_mover_mode(session));
1312
1313 arg.tr_session = session;
1314 arg.tr_mod_params = mod_params;
1315 arg.tr_cmds = cmds;
1316
1317 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
1318 (void *)&arg);
1319 if (err == 0) {
1320 tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
1321 } else {
1322 NDMP_LOG(LOG_DEBUG, "Launch ndmp_tar_reader: %m");
1323 return (-1);
1324 }
1325
1326 if (!ndmp_check_utf8magic(cmds->tcs_command)) {
1327 NDMP_LOG(LOG_DEBUG, "UTF8Magic not found!");
1328 } else {
1329 NDMP_LOG(LOG_DEBUG, "UTF8Magic found");
1330 }
1331
1332 (void) memset(&tlm_arg, 0, sizeof (tlm_backup_restore_arg_t));
1333 (void) pthread_barrier_init(&tlm_arg.ba_barrier, 0, 2);
1334
1335 /*
1336 * Set up restore parameters
1337 */
1338 tlm_arg.ba_commands = cmds;
1339 tlm_arg.ba_cmd = cmds->tcs_command;
1340 tlm_arg.ba_job = nlp->nlp_jstat->js_job_name;
1341 tlm_arg.ba_dir = nlp->nlp_restore_path;
1342 for (i = 0; i < nlp->nlp_nfiles; i++) {
1343 ent = (ndmp_name *)MOD_GETNAME(mod_params, i);
1344 tlm_arg.ba_sels[i] = ent->name;
1345 }
1346
1347
1348 if (tm_tar_ops.tm_getfile != NULL) {
1349 err = pthread_create(&wrtp, NULL,
1350 (funct_t)tm_tar_ops.tm_getfile, (void *)&tlm_arg);
1351 } else {
1352 (void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1353 NDMP_LOG(LOG_DEBUG,
1354 "Thread create tm_getfile: ops NULL");
1355 return (-1);
1356 }
1357 if (err == 0) {
1358 (void) pthread_barrier_wait(&tlm_arg.ba_barrier);
1359 } else {
1360 (void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1361 NDMP_LOG(LOG_DEBUG, "thread create tm_getfile: %m");
1362 return (-1);
1363 }
1364
1365 (void) pthread_join(rdtp, NULL);
1366 (void) pthread_join(wrtp, NULL);
1367 (void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1368
1369 nlp->nlp_jstat->js_stop_time = time(NULL);
1370
1371 /* Send the list of un-recovered files/dirs to the client. */
1372 (void) send_unrecovered_list(mod_params, nlp);
1373
1374 ndmp_stop_local_reader(session, cmds);
1375 ndmp_wait_for_reader(cmds);
1376 ndmp_stop_remote_reader(session);
1377 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
1378 rspath, err);
1379 } else {
1380 nlp->nlp_jstat->js_stop_time = time(NULL);
1381
1382 /* nothing restored. */
1383 (void) send_unrecovered_list(mod_params, nlp);
1384 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
1385 rspath);
1386 err = -1;
1387 }
1388
1389 NDMP_FREE(nlp->nlp_restore_path);
1390 backup_release_structs(session);
1391
1392 return (err);
1393 }
1394
1395
1396 /*
1397 * prefixdir
1398 *
1399 * Extract the path for a given full path entry
1400 */
1401 static char *
1402 prefixdir(char *dir, char *suffix)
1403 {
1404 static char tmp[TLM_MAX_PATH_NAME];
1489 * Correct the entries in the restore list by appending the appropriate
1490 * path to them
1491 */
1492 static int
1493 correct_ents(ndmpd_module_params_t *params, int n, char *bkpath)
1494 {
1495 char *cp, *pathname;
1496 int i, len, rv;
1497 ndmp_name *ent;
1498
1499 if ((pathname = ndmp_malloc(TLM_MAX_PATH_NAME)) == NULL) {
1500 MOD_LOG(params, "Error: insufficient memory.\n");
1501 return (-1);
1502 }
1503
1504 rv = 0;
1505 /* Append the backup path to all the "ent[].name"s. */
1506 for (i = 0; i < n; i++) {
1507 ent = (ndmp_name *)MOD_GETNAME(params, i);
1508
1509 NDMP_LOG(LOG_DEBUG,
1510 "Old: ent[%d].name: \"%s\"", i, ent->name);
1511 NDMP_LOG(LOG_DEBUG,
1512 "Old: ent[%d].dest: \"%s\"", i, ent->dest);
1513
1514 /* remove trailing slash */
1515 len = strlen(ent->name);
1516 if (ent->name[len - 1] == '/')
1517 ent->name[len - 1] = '\0';
1518
1519 if (!tlm_cat_path(pathname, bkpath, ent->name)) {
1520 MOD_LOG(params, "Error: path too long.\n");
1521 rv = -1;
1522 break;
1523 }
1524
1525 /* Make a copy of the new string and save it in ent->name. */
1526 cp = strdup(pathname);
1527 if (cp == NULL) {
1528 MOD_LOG(params, "Error: insufficient memory.\n");
1529 rv = -1;
1530 break;
1531 }
1532 free(ent->name);
1533 ent->name = cp;
1534
1535 NDMP_LOG(LOG_DEBUG,
1536 "New: ent[%d].name: \"%s\"", i, ent->name);
1537 }
1538
1539 free(pathname);
1540 return (rv);
1541 }
1542
1543
1544 /*
1545 * check_restore_paths
1546 *
1547 * Go through the restore list and check the validity of the
1548 * restore path.
1549 */
1550 static int
1551 check_restore_paths(ndmpd_module_params_t *params, int n, char *rspath)
1552 {
1553 int i, rv;
1554 ndmp_name *ent;
1555
1556 rv = 0;
1557 if (rspath != NULL && *rspath != '\0') {
1558 NDMP_LOG(LOG_DEBUG, "rspath: \"%s\"", rspath);
1559 if (!fs_volexist(rspath)) {
1560 MOD_LOG(params,
1561 "Error: Invalid volume name for restore.");
1562 rv = -1;
1563 }
1564 } else {
1565 for (i = 0; i < n; i++) {
1566 ent = (ndmp_name *)MOD_GETNAME(params, i);
1567 NDMP_LOG(LOG_DEBUG,
1568 "ent[%d].name: \"%s\"", i, ent->name);
1569
1570 if (!fs_volexist(ent->name)) {
1571 MOD_LOG(params,
1572 "Error: Invalid volume name for restore.",
1573 ent->name);
1574 rv = -1;
1575 break;
1576 }
1577 }
1578 }
1579
1580 return (rv);
1581 }
1582
1583
1584 /*
1585 * check_backup_dir_validity
1586 *
1587 * Check if the backup directory is valid. Make sure it exists and
1624 ndmpd_module_params_t *params)
1625 {
1626 char *cp;
1627 int rv;
1628 ndmp_lbr_params_t *nlp;
1629
1630 /* Extract directory to be backed up from env variables */
1631 if ((nlp = ndmp_get_nlp(session)) == NULL) {
1632 MOD_LOG(params, "Error: Internal error: nlp == NULL.\n");
1633 return (NDMP_ILLEGAL_ARGS_ERR);
1634 }
1635 if ((nlp->nlp_backup_path = get_backup_path_v2(params)) == NULL)
1636 return (NDMP_FILE_NOT_FOUND_ERR);
1637
1638 if ((rv = check_backup_dir_validity(params,
1639 nlp->nlp_backup_path)) != NDMP_NO_ERR)
1640 return (rv);
1641
1642 /* Should the st_ctime be ignored when backing up? */
1643 if (ndmp_ignore_ctime) {
1644 NDMP_LOG(LOG_DEBUG, "ignoring st_ctime");
1645 NLP_SET(nlp, NLPF_IGNCTIME);
1646 } else
1647 NLP_UNSET(nlp, NLPF_IGNCTIME);
1648
1649 /* Should the st_lmtime be ignored when backing up? */
1650 if (ndmp_include_lmtime) {
1651 NDMP_LOG(LOG_DEBUG, "including st_lmtime");
1652 NLP_SET(nlp, NLPF_INCLMTIME);
1653 } else
1654 NLP_UNSET(nlp, NLPF_INCLMTIME);
1655
1656 NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
1657
1658 /* Is backup history requested? */
1659 cp = MOD_GETENV(params, "HIST");
1660 if (cp == NULL) {
1661 NDMP_LOG(LOG_DEBUG, "env(HIST) not specified");
1662 NLP_UNSET(nlp, NLPF_FH);
1663 } else {
1664 NDMP_LOG(LOG_DEBUG, "env(HIST): \"%s\"", cp);
1665
1666 if (strchr("t_ty_y", *cp))
1667 NLP_SET(nlp, NLPF_FH);
1668 else
1669 NLP_UNSET(nlp, NLPF_FH);
1670 }
1671
1672 nlp->nlp_clevel = 0;
1673 /* Is it an incremental backup? */
1674 cp = MOD_GETENV(params, "LEVEL");
1675 if (cp == NULL) {
1676 NDMP_LOG(LOG_DEBUG,
1677 "env(LEVEL) not specified, default to 0");
1678 } else if (*cp < '0' || *cp > '9' || *(cp+1) != '\0') {
1679 NDMP_LOG(LOG_DEBUG, "Invalid backup level '%s'", cp);
1680 return (NDMP_ILLEGAL_ARGS_ERR);
1681 } else
1682 nlp->nlp_clevel = *cp - '0';
1683
1684 /* Extract last backup time from the dumpdates file */
1685 nlp->nlp_llevel = nlp->nlp_clevel;
1686 nlp->nlp_ldate = 0;
1687 if (ndmpd_get_dumptime(nlp->nlp_backup_path, &nlp->nlp_llevel,
1688 &nlp->nlp_ldate) < 0) {
1689 MOD_LOG(params, "Error: getting dumpdate for %s level %d\n",
1690 nlp->nlp_backup_path, nlp->nlp_clevel);
1691 return (NDMP_NO_MEM_ERR);
1692 }
1693
1694 NDMP_LOG(LOG_DEBUG,
1695 "Date of this level %d on \"%s\": %s",
1696 nlp->nlp_clevel, nlp->nlp_backup_path, cctime(&nlp->nlp_cdate));
1697 NDMP_LOG(LOG_DEBUG,
1698 "Date of last level %d on \"%s\": %s",
1699 nlp->nlp_llevel, nlp->nlp_backup_path, cctime(&nlp->nlp_ldate));
1700
1701 /* Should the dumpdate file be updated? */
1702 cp = MOD_GETENV(params, "UPDATE");
1703 if (cp == NULL) {
1704 NDMP_LOG(LOG_DEBUG,
1705 "env(UPDATE) not specified, default to TRUE");
1706 NLP_SET(nlp, NLPF_UPDATE);
1707 } else {
1708 NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", cp);
1709 if (strchr("t_ty_y", *cp) != NULL)
1710 NLP_SET(nlp, NLPF_UPDATE);
1711 else
1712 NLP_UNSET(nlp, NLPF_UPDATE);
1713 }
1714
1715 return (NDMP_NO_ERR);
1716 }
1717
1718
1719
1720 /*
1721 * log_bk_params_v2
1722 *
1723 * Dump the value of the parameters in the log file for debugging.
1724 */
1725 void
1726 log_bk_params_v2(ndmpd_session_t *session, ndmpd_module_params_t *params,
1727 ndmp_lbr_params_t *nlp)
1728 {
1755 same_path(char *s, char *t)
1756 {
1757 boolean_t rv;
1758 int slen, tlen;
1759
1760 rv = FALSE;
1761 slen = strlen(s);
1762 tlen = strlen(t);
1763 if (slen == tlen && strcmp(s, t) == 0) {
1764 rv = TRUE;
1765 } else {
1766 if (slen == tlen - 1) {
1767 if (strncmp(s, t, slen) == 0 && t[tlen - 1] == '/')
1768 rv = TRUE;
1769 } else if (tlen == slen -1) {
1770 if (strncmp(s, t, tlen) == 0 && s[slen - 1] == '/')
1771 rv = TRUE;
1772 }
1773 }
1774
1775 NDMP_LOG(LOG_DEBUG, "rv: %d", rv);
1776 return (rv);
1777 }
1778
1779
1780 /*
1781 * ndmp_restore_extract_params
1782 *
1783 * Go through the restore parameters and check them and extract them
1784 * by setting NLP flags and other values.
1785 *
1786 * Parameters:
1787 *
1788 * Returns:
1789 * 0: on success
1790 * -1: otherwise
1791 */
1792 int
1793 ndmp_restore_extract_params(ndmpd_session_t *session,
1794 ndmpd_module_params_t *params)
1795 {
1796 char *bkpath, *rspath;
1797 ndmp_lbr_params_t *nlp;
1798
1799 if ((nlp = ndmp_get_nlp(session)) == NULL) {
1800 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1801 return (-1);
1802 }
1803
1804 /* Extract directory from where the backup was made. */
1805 if ((bkpath = get_backup_path_v2(params)) == NULL)
1806 return (NDMP_ILLEGAL_ARGS_ERR);
1807
1808 nlp->nlp_restore_bk_path = bkpath;
1809
1810 /* The number of the selections. */
1811 if ((nlp->nlp_nfiles = get_nfiles(session, params)) == 0)
1812 return (NDMP_ILLEGAL_ARGS_ERR);
1813
1814 NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
1815
1816 if ((rspath = get_restore_dest(params)) == NULL)
1817 return (NDMP_ILLEGAL_ARGS_ERR);
1818
1819 if (fs_is_rdonly(rspath)) {
1820 MOD_LOG(params,
1821 "Error: Can't restore to a read-only volume: \"%s\"\n",
1822 rspath);
1823 return (NDMP_ILLEGAL_ARGS_ERR);
1824 }
1825 if (fs_is_chkpntvol(rspath)) {
1826 MOD_LOG(params,
1827 "Error: Can't restore to a checkpoint: \"%s\"\n", rspath);
1828 return (NDMP_ILLEGAL_ARGS_ERR);
1829 }
1830
1831 if (same_path(bkpath, rspath))
1832 rspath = "";
1833
1834 if ((nlp->nlp_restore_path = strdup(rspath)) == NULL)
1861 */
1862 int
1863 ndmpd_tar_backup_starter(void *arg)
1864 {
1865 ndmpd_module_params_t *mod_params = arg;
1866 int err;
1867 ndmpd_session_t *session;
1868 ndmp_lbr_params_t *nlp;
1869
1870 session = (ndmpd_session_t *)(mod_params->mp_daemon_cookie);
1871 *(mod_params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
1872 ndmp_session_ref(session);
1873
1874 err = 0;
1875 if (fs_is_chkpntvol(nlp->nlp_backup_path) ||
1876 fs_is_rdonly(nlp->nlp_backup_path) ||
1877 !fs_is_chkpnt_enabled(nlp->nlp_backup_path))
1878 NLP_SET(nlp, NLPF_CHKPNTED_PATH);
1879 else {
1880 NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
1881 if (ndmp_create_snapshot(nlp->nlp_backup_path,
1882 nlp->nlp_jstat->js_job_name) < 0) {
1883 MOD_LOG(mod_params,
1884 "Error: creating checkpoint on %s\n",
1885 nlp->nlp_backup_path);
1886 /* -1 causes halt reason to become internal error. */
1887 err = -1;
1888 }
1889 }
1890
1891 NDMP_LOG(LOG_DEBUG, "NLPF_CHKPNTED_PATH: %c",
1892 NDMP_YORN(NLP_ISCHKPNTED(nlp)));
1893 NDMP_LOG(LOG_DEBUG, "err: %d, update %c",
1894 err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
1895
1896 if (err == 0) {
1897 err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate,
1898 nlp->nlp_jstat->js_job_name);
1899 if (err != 0) {
1900 NDMP_LOG(LOG_DEBUG, "err %d", err);
1901 } else {
1902 log_bk_params_v2(session, mod_params, nlp);
1903 err = ndmpd_tar_backup(session, mod_params, nlp);
1904 }
1905 }
1906
1907 if (nlp->nlp_bkmap >= 0) {
1908 (void) dbm_free(nlp->nlp_bkmap);
1909 nlp->nlp_bkmap = -1;
1910 }
1911
1912 if (!NLP_ISCHKPNTED(nlp))
1913 (void) ndmp_remove_snapshot(nlp->nlp_backup_path,
1914 nlp->nlp_jstat->js_job_name);
1915
1916 NDMP_LOG(LOG_DEBUG, "err %d, update %c",
1917 err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
1918
1919 if (err == 0 && NLP_SHOULD_UPDATE(nlp)) {
1920 if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel,
1921 nlp->nlp_cdate) < 0) {
1922 err = EPERM;
1923 MOD_LOG(mod_params,
1924 "Error: updating the dumpdates file on %s\n",
1925 nlp->nlp_backup_path);
1926 }
1927 }
1928
1929 MOD_DONE(mod_params, err);
1930
1931 /* nlp_params is allocated in start_backup() */
1932 NDMP_FREE(nlp->nlp_params);
1933
1934 NS_DEC(nbk);
1935 ndmp_session_unref(session);
1936 return (err);
|
1 /*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
4 */
5
6 /*
7 * BSD 3 Clause License
8 *
9 * Copyright (c) 2007, The Storage Networking Industry Association.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * - Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
21 *
22 * - Neither the name of The Storage Networking Industry Association (SNIA)
23 * nor the names of its contributors may be used to endorse or promote
24 * products derived from this software without specific prior written
25 * permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
41 /* Copyright 2017 Nexenta Systems, Inc. All rights reserved. */
42
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <syslog.h>
47 #include <errno.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <time.h>
52 #include <cstack.h>
53 #include <dirent.h>
54 #include <traverse.h>
55 #include "bitmap.h"
56 #include "ndmpd.h"
57 #include "tlm_buffers.h"
58
59
60 typedef struct ndmp_run_args {
61 char *nr_chkp_nm;
62 char *nr_unchkp_nm;
63 char **nr_excls;
64 } ndmp_run_args_t;
65
66
69 *
70 * Allocate the structures before performing backup
71 *
72 * Parameters:
73 * sesison (input) - session handle
74 * jname (input) - backup job name
75 *
76 * Returns:
77 * 0: on success
78 * -1: otherwise
79 */
80 static int
81 backup_create_structs(ndmpd_session_t *session, char *jname)
82 {
83 int n;
84 long xfer_size;
85 ndmp_lbr_params_t *nlp;
86 tlm_commands_t *cmds;
87
88 if ((nlp = ndmp_get_nlp(session)) == NULL) {
89 return (-1);
90 }
91
92 if ((nlp->nlp_jstat = tlm_new_job_stats(jname)) == NULL) {
93 return (-1);
94 }
95
96 cmds = &nlp->nlp_cmds;
97 (void) memset(cmds, 0, sizeof (*cmds));
98
99 xfer_size = ndmp_buffer_get_size(session);
100 if (xfer_size < 512*KILOBYTE) {
101 /*
102 * Read multiple of mover_record_size near to 512K. This
103 * will prevent the data being copied in the mover buffer
104 * when we write the data.
105 */
106 if ((n = (512 * KILOBYTE/xfer_size)) <= 0)
107 n = 1;
108 xfer_size *= n;
109 syslog(LOG_DEBUG, "Adjusted read size: %d", xfer_size);
110 }
111
112 cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, xfer_size);
113 if (cmds->tcs_command == NULL) {
114 syslog(LOG_ERR, "Error creating ipc buffers");
115 tlm_un_ref_job_stats(jname);
116 return (-1);
117 }
118
119 nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
120 ndmpd_file_history_path,
121 ndmpd_file_history_dir,
122 ndmpd_file_history_node);
123 if (nlp->nlp_logcallbacks == NULL) {
124 tlm_release_reader_writer_ipc(cmds->tcs_command);
125 tlm_un_ref_job_stats(jname);
126 return (-1);
127 }
128 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
129
130 return (0);
131 }
132
133
134 /*
136 *
137 * Allocate structures for performing a restore
138 *
139 * Parameters:
140 * sesison (input) - session handle
141 * jname (input) - backup job name
142 *
143 * Returns:
144 * 0: on success
145 * -1: otherwise
146 */
147 static int
148 restore_create_structs(ndmpd_session_t *session, char *jname)
149 {
150 int i;
151 long xfer_size;
152 ndmp_lbr_params_t *nlp;
153 tlm_commands_t *cmds;
154
155 if ((nlp = ndmp_get_nlp(session)) == NULL) {
156 return (-1);
157 }
158 if ((nlp->nlp_jstat = tlm_new_job_stats(jname)) == NULL) {
159 return (-1);
160 }
161
162 cmds = &nlp->nlp_cmds;
163 (void) memset(cmds, 0, sizeof (*cmds));
164
165 xfer_size = ndmp_buffer_get_size(session);
166 cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
167 if (cmds->tcs_command == NULL) {
168 syslog(LOG_ERR, "Error creating ipc buffers");
169 tlm_un_ref_job_stats(jname);
170 return (-1);
171 }
172
173 nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
174 ndmpd_path_restored, NULL, NULL);
175 if (nlp->nlp_logcallbacks == NULL) {
176 tlm_release_reader_writer_ipc(cmds->tcs_command);
177 tlm_un_ref_job_stats(jname);
178 return (-1);
179 }
180 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
181
182 nlp->nlp_restored = ndmp_malloc(sizeof (boolean_t) * nlp->nlp_nfiles);
183 if (nlp->nlp_restored == NULL) {
184 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
185 tlm_release_reader_writer_ipc(cmds->tcs_command);
186 tlm_un_ref_job_stats(jname);
187 return (-1);
188 }
196 /*
197 * send_unrecovered_list
198 *
199 * Creates a list of restored files
200 *
201 * Parameters:
202 * params (input) - NDMP parameters
203 * nlp (input) - NDMP/LBR parameters
204 *
205 * Returns:
206 * 0: on success
207 * -1: otherwise
208 */
209 static int
210 send_unrecovered_list(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
211 {
212 int i, rv;
213 ndmp_name *ent;
214
215 if (params == NULL) {
216 return (-1);
217 }
218 if (nlp == NULL) {
219 return (-1);
220 }
221
222 rv = 0;
223 for (i = 0; i < (int)nlp->nlp_nfiles; i++) {
224 syslog(LOG_DEBUG, "nlp->nlp_restored[%d]: %s", i,
225 nlp->nlp_restored[i] ? "TRUE" : "FALSE");
226
227 if (!nlp->nlp_restored[i]) {
228 ent = (ndmp_name *)MOD_GETNAME(params, i);
229 if (ent == NULL) {
230 rv = -1;
231 break;
232 }
233 if (ent->name == NULL) {
234 rv = -1;
235 break;
236 }
237
238 syslog(LOG_DEBUG, "ent.name: \"%s\"", ent->name);
239
240 rv = MOD_FILERECOVERD(params, ent->name, ENOENT);
241 if (rv < 0)
242 break;
243 }
244 }
245
246 return (rv);
247 }
248
249
250 /*
251 * backup_release_structs
252 *
253 * Deallocated the NDMP/LBR specific parameters
254 *
255 * Parameters:
256 * session (input) - session handle
257 *
258 * Returns:
259 * void
260 */
261 /*ARGSUSED*/
262 static void
263 backup_release_structs(ndmpd_session_t *session)
264 {
265 ndmp_lbr_params_t *nlp;
266 tlm_commands_t *cmds;
267
268 if ((nlp = ndmp_get_nlp(session)) == NULL) {
269 return;
270 }
271 cmds = &nlp->nlp_cmds;
272 if (cmds == NULL) {
273 return;
274 }
275
276 if (nlp->nlp_logcallbacks != NULL) {
277 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
278 nlp->nlp_logcallbacks = NULL;
279 }
280
281 if (cmds->tcs_command != NULL) {
282 if (cmds->tcs_command->tc_buffers != NULL)
283 tlm_release_reader_writer_ipc(cmds->tcs_command);
284 cmds->tcs_command = NULL;
285 }
286
287 if (nlp->nlp_bkmap >= 0) {
288 (void) dbm_free(nlp->nlp_bkmap);
289 nlp->nlp_bkmap = -1;
290 }
291
292 if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER &&
293 nlp->nlp_restored != NULL) {
294 free(nlp->nlp_restored);
295 nlp->nlp_restored = NULL;
296 }
297 }
298
299 /*
300 * ndmp_write_utf8magic
301 *
302 * Write a magic pattern to the tar header. This is used
303 * as a crest to indicate that tape belongs to us.
304 */
305 int
306 ndmp_write_utf8magic(tlm_cmd_t *cmd)
307 {
308 char *cp;
309 long actual_size;
310
311 if (cmd->tc_buffers == NULL) {
312 return (-1);
313 }
314
315 cp = tlm_get_write_buffer(RECORDSIZE, &actual_size,
316 cmd->tc_buffers, TRUE);
317 if (actual_size < RECORDSIZE) {
318 return (-1);
319 }
320
321 (void) strlcpy(cp, NDMPUTF8MAGIC, RECORDSIZE);
322 return (0);
323 }
324
325
326 /*
327 * timecmp
328 *
329 * This callback function is used during backup. It checks
330 * if the object specified by the 'attr' should be backed
331 * up or not.
332 *
333 * Directories are backed up anyways for dump format.
334 * If this function is called, then the directory is
335 * marked in the bitmap vector, it shows that either the
336 * directory itself is modified or there is something below
337 * it that will be backed up.
342 * By setting ndmp_force_bk_dirs global variable to a non-zero
343 * value, directories are backed up anyways.
344 *
345 * Backing up the directories unconditionally, helps
346 * restoring the metadata of directories as well, when one
347 * of the objects below them are being restored.
348 *
349 * For non-directory objects, if the modification or change
350 * time of the object is after the date specified by the
351 * bk_selector_t, the the object must be backed up.
352 *
353 */
354 static boolean_t
355 timecmp(bk_selector_t *bksp,
356 struct stat64 *attr)
357 {
358 ndmp_lbr_params_t *nlp;
359
360 nlp = (ndmp_lbr_params_t *)bksp->bs_cookie;
361 if (S_ISDIR(attr->st_mode) && ndmp_force_bk_dirs) {
362 return (TRUE);
363 }
364 if (S_ISDIR(attr->st_mode) &&
365 dbm_getone(nlp->nlp_bkmap, (u_longlong_t)attr->st_ino) &&
366 ((NLP_ISDUMP(nlp) && ndmp_dump_path_node) ||
367 (NLP_ISTAR(nlp) && ndmp_tar_path_node))) {
368 /*
369 * If the object is a directory and it leads to a modified
370 * object (that should be backed up) and for that type of
371 * backup the path nodes should be backed up, then return
372 * TRUE.
373 *
374 * This is required by some DMAs like Backup Express, which
375 * needs to receive ADD_NODE (for dump) or ADD_PATH (for tar)
376 * for the intermediate directories of a modified object.
377 * Other DMAs, like net_backup and net_worker, do not have such
378 * requirement. This requirement makes sense for dump format
379 * but for 'tar' format, it does not. In provision to the
380 * NDMP-v4 spec, for 'tar' format the intermediate directories
381 * need not to be reported.
382 */
383 syslog(LOG_DEBUG, "p(%lu)", (u_longlong_t)attr->st_ino);
384 return (TRUE);
385 }
386 if (attr->st_mtime > bksp->bs_ldate) {
387 syslog(LOG_DEBUG, "m(%lu): %lu > %lu",
388 (uint_t)attr->st_ino, (uint_t)attr->st_mtime,
389 (uint_t)bksp->bs_ldate);
390 return (TRUE);
391 }
392 if (attr->st_ctime > bksp->bs_ldate) {
393 if (NLP_IGNCTIME(nlp)) {
394 syslog(LOG_DEBUG, "ign c(%lu): %lu > %lu",
395 (uint_t)attr->st_ino, (uint_t)attr->st_ctime,
396 (uint_t)bksp->bs_ldate);
397 return (FALSE);
398 }
399 syslog(LOG_DEBUG, "c(%lu): %lu > %lu",
400 (uint_t)attr->st_ino, (uint_t)attr->st_ctime,
401 (uint_t)bksp->bs_ldate);
402 return (TRUE);
403 }
404 syslog(LOG_DEBUG, "mc(%lu): (%lu,%lu) < %lu",
405 (uint_t)attr->st_ino, (uint_t)attr->st_mtime,
406 (uint_t)attr->st_ctime, (uint_t)bksp->bs_ldate);
407 return (FALSE);
408 }
409
410
411 /*
412 * get_acl_info
413 *
414 * load up all the access and attribute info
415 */
416 static int
417 get_acl_info(char *name, tlm_acls_t *tlm_acls)
418 {
419 int erc;
420 acl_t *aclp = NULL;
421 char *acltp;
422
423 erc = lstat64(name, &tlm_acls->acl_attr);
424 if (erc != 0) {
425 syslog(LOG_ERR, "Could not find file %s.", name);
426 erc = TLM_NO_SOURCE_FILE;
427 return (erc);
428 }
429 erc = acl_get(name, ACL_NO_TRIVIAL, &aclp);
430 if (erc != 0) {
431 syslog(LOG_DEBUG,
432 "Could not read ACL for file [%s]", name);
433 erc = TLM_NO_SOURCE_FILE;
434 return (erc);
435 }
436 if (aclp && (acltp = acl_totext(aclp,
437 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
438 (void) strlcpy(tlm_acls->acl_info.attr_info, acltp,
439 TLM_MAX_ACL_TXT);
440 acl_free(aclp);
441 free(acltp);
442 }
443 return (erc);
444 }
445 /*
446 * get_dir_acl_info
447 *
448 * load up all ACL and attr info about a directory
449 */
450 static int
451 get_dir_acl_info(char *dir, tlm_acls_t *tlm_acls, tlm_job_stats_t *js)
452 {
453 int erc;
454 char *checkpointed_dir;
455 char root_dir[TLM_VOLNAME_MAX_LENGTH];
456 char *spot;
457 char *fil;
458 acl_t *aclp = NULL;
459 char *acltp;
460
461 checkpointed_dir = ndmp_malloc(TLM_MAX_PATH_NAME);
462 if (checkpointed_dir == NULL)
463 return (-1);
464
465 if (tlm_acls->acl_checkpointed)
466 fil = tlm_build_snapshot_name(dir, checkpointed_dir,
467 js->js_job_name);
468 else
469 fil = dir;
470 erc = lstat64(fil, &tlm_acls->acl_attr);
471 if (erc != 0) {
472 syslog(LOG_ERR, "Could not find directory %s.", dir);
473 free(checkpointed_dir);
474 return (-1);
475 }
476
477 spot = strchr(&fil[1], '/');
478 if (spot == NULL) {
479 (void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH);
480 } else {
481 *spot = 0;
482 (void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH);
483 *spot = '/';
484 }
485 if (strcmp(root_dir, tlm_acls->acl_root_dir) != 0) {
486 struct stat64 attr;
487
488 erc = lstat64(root_dir, &attr);
489 if (erc != 0) {
490 syslog(LOG_ERR, "Cannot find root directory %s.",
491 root_dir);
492 free(checkpointed_dir);
493 return (-1);
494 }
495 (void) strlcpy(tlm_acls->acl_root_dir, root_dir,
496 TLM_VOLNAME_MAX_LENGTH);
497 }
498 erc = acl_get(fil, ACL_NO_TRIVIAL, &aclp);
499 if (erc != 0) {
500 syslog(LOG_DEBUG,
501 "Could not read metadata for directory [%s]", dir);
502 free(checkpointed_dir);
503 return (-1);
504 }
505 if (aclp && (acltp = acl_totext(aclp,
506 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
507 (void) strlcpy(tlm_acls->acl_info.attr_info, acltp,
508 TLM_MAX_ACL_TXT);
509 acl_free(aclp);
510 free(acltp);
511 }
512
513 free(checkpointed_dir);
514 return (0);
515 }
516
517 /*
518 * backup_dir
519 *
520 * Create a TAR entry record for a directory
521 */
522 static int
523 backup_dir(char *dir, tlm_acls_t *tlm_acls,
524 tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats,
525 bk_selector_t *bksp)
526 {
527 int erc;
528
529 erc = get_dir_acl_info(dir, tlm_acls, job_stats);
530 if (erc != 0) {
531 syslog(LOG_ERR,
532 "Could not read directory info for %s", dir);
533 job_stats->js_errors++;
534 } else {
535 /*
536 * See if the directory must be backed up.
537 */
538 if (bksp && !(*bksp->bs_fn)(bksp, &tlm_acls->acl_attr)) {
539 syslog(LOG_DEBUG, "[%s] dir skipped", dir);
540 return (erc);
541 }
542
543 if (tm_tar_ops.tm_putdir != NULL)
544 (void) (tm_tar_ops.tm_putdir)(dir, tlm_acls,
545 local_commands, job_stats);
546 }
547
548 return (erc);
549 }
550
551
552 /*
553 * backup_file
554 *
555 * Create a TAR record entry for a file
556 */
557 static longlong_t
558 backup_file(char *dir, char *name, tlm_acls_t *tlm_acls,
559 tlm_commands_t *commands, tlm_cmd_t *local_commands,
560 tlm_job_stats_t *job_stats, bk_selector_t *bksp)
561 {
562
563 int erc;
564 char buf[TLM_MAX_PATH_NAME];
565 longlong_t rv = -1;
566
567 (void) strlcpy(buf, dir, sizeof (buf));
568 (void) strlcat(buf, "/", sizeof (buf));
569 (void) strlcat(buf, name, sizeof (buf));
570
571 /*
572 * get_acl_info extracts file handle, attributes and ACLs of the file.
573 * This is not efficient when the attributes and file handle of
574 * the file is already known.
575 */
576 erc = get_acl_info(buf, tlm_acls);
577 if (erc != TLM_NO_ERRORS) {
578 syslog(LOG_ERR, "Could not open file %s/%s.", dir, name);
579 return (-ENOENT);
580 }
581
582 /* Should the file be backed up? */
583 if (!bksp) {
584 syslog(LOG_DEBUG,
585 "[%s/%s] has no selection criteria", dir, name);
586
587 } else if (!((*bksp->bs_fn)(bksp, &tlm_acls->acl_attr))) {
588 syslog(LOG_DEBUG, "[%s/%s] file skipped", dir, name);
589 return (0);
590 }
591
592 /* Only the regular files and symbolic links can be backed up. */
593 if (!S_ISLNK(tlm_acls->acl_attr.st_mode) &&
594 !S_ISREG(tlm_acls->acl_attr.st_mode)) {
595 syslog(LOG_DEBUG,
596 "Warning: skip backing up [%s][%s]", dir, name);
597 return (-EINVAL);
598 }
599
600
601 if (tm_tar_ops.tm_putfile != NULL)
602 rv = (tm_tar_ops.tm_putfile)(dir, name, tlm_acls, commands,
603 local_commands, job_stats);
604
605 return (rv);
606 }
607
608
609
610 /*
611 * backup_work
612 *
613 * Start the NDMP backup (V2 only).
614 */
615 int
617 ndmp_run_args_t *np, tlm_commands_t *commands,
618 ndmp_lbr_params_t *nlp)
619 {
620 struct full_dir_info dir_info; /* the blob to push/pop with cstack_t */
621 struct full_dir_info *t_dir_info, *p_dir_info;
622 struct stat64 ret_attr; /* attributes of current file name */
623 fs_fhandle_t ret_fh;
624 char *first_name; /* where the first name is located */
625 char *dname;
626 int erc;
627 int retval;
628 cstack_t *stk;
629 unsigned long fileid;
630 tlm_acls_t tlm_acls;
631 int dname_size;
632 longlong_t fsize;
633 bk_selector_t bks;
634 tlm_cmd_t *local_commands;
635 long dpos;
636
637 syslog(LOG_DEBUG, "nr_chkpnted %d nr_ldate: %u bk_path: \"%s\"",
638 NLP_ISCHKPNTED(nlp), nlp->nlp_ldate, bk_path);
639
640 /* Get every name in this directory */
641 dname = ndmp_malloc(TLM_MAX_PATH_NAME);
642 if (dname == NULL)
643 return (-ENOMEM);
644
645 local_commands = commands->tcs_command;
646 retval = 0;
647 (void) memset(&bks, 0, sizeof (bks));
648 bks.bs_cookie = (void *)nlp;
649 bks.bs_level = nlp->nlp_clevel;
650 bks.bs_ldate = nlp->nlp_ldate;
651 bks.bs_fn = timecmp;
652
653 /*
654 * should we skip the whole thing?
655 */
656 if (tlm_is_excluded("", bk_path, np->nr_excls)) {
657 syslog(LOG_DEBUG, "%s excluded", bk_path);
658 free(dname);
659 return (0);
660 }
661
662 /*
663 * Search for the top-level file-directory
664 */
665 if (NLP_ISCHKPNTED(nlp)) {
666 first_name = np->nr_chkp_nm;
667 (void) strlcpy(first_name, bk_path, TLM_MAX_PATH_NAME);
668 } else {
669 first_name = tlm_build_snapshot_name(bk_path, np->nr_chkp_nm,
670 nlp->nlp_jstat->js_job_name);
671 }
672
673 (void) memset(&ret_fh, 0, sizeof (ret_fh));
674 erc = fs_getstat(first_name, &ret_fh, &ret_attr);
675 if (erc != 0) {
676 syslog(LOG_ERR, "Path %s not found.", first_name);
677 free(dname);
678 return (-EINVAL);
679 }
680
681 if ((stk = cstack_new()) == NULL) {
682 free(dname);
683 syslog(LOG_DEBUG, "cstack_new failed");
684 return (-ENOMEM);
685 }
686 (void) strlcpy(dir_info.fd_dir_name, first_name, TLM_MAX_PATH_NAME);
687 (void) memcpy(&dir_info.fd_dir_fh, &ret_fh, sizeof (fs_fhandle_t));
688 p_dir_info = dup_dir_info(&dir_info);
689
690 /*
691 * Push the first name onto the stack so that we can pop it back
692 * off as part of the normal cycle
693 */
694 if (cstack_push(stk, p_dir_info, 0)) {
695 free(dname);
696 free(p_dir_info);
697 cstack_delete(stk);
698 syslog(LOG_DEBUG, "cstack_push failed");
699 return (-ENOMEM);
700 }
701
702 (void) memset(&tlm_acls, 0, sizeof (tlm_acls));
703 /*
704 * Did NDMP create a checkpoint?
705 */
706 if (NLP_ISCHKPNTED(nlp) || fs_is_rdonly(bk_path)) {
707 tlm_acls.acl_checkpointed = FALSE;
708 } else {
709 /* Use the checkpoint created by NDMP */
710 tlm_acls.acl_checkpointed = TRUE;
711 }
712
713 /*
714 * This is level-backup. It never resets the archive bit.
715 */
716 tlm_acls.acl_clear_archive = FALSE;
717
718 syslog(LOG_DEBUG, "acls.chkpnt: %c acls.clear_arcbit: %c",
719 NDMP_YORN(tlm_acls.acl_checkpointed),
720 NDMP_YORN(tlm_acls.acl_clear_archive));
721
722 while (commands->tcs_reader == TLM_BACKUP_RUN &&
723 local_commands->tc_reader == TLM_BACKUP_RUN &&
724 cstack_pop(stk, (void **)&p_dir_info, 0) == 0) {
725
726 if (NLP_ISCHKPNTED(nlp))
727 (void) strlcpy(np->nr_unchkp_nm,
728 p_dir_info->fd_dir_name, TLM_MAX_PATH_NAME);
729 else
730 (void) tlm_remove_checkpoint(p_dir_info->fd_dir_name,
731 np->nr_unchkp_nm);
732
733 (void) backup_dir(np->nr_unchkp_nm, &tlm_acls, local_commands,
734 job_stats, &bks);
735
736
737 while (commands->tcs_reader == TLM_BACKUP_RUN &&
738 local_commands->tc_reader == TLM_BACKUP_RUN) {
739
740 dname_size = TLM_MAX_PATH_NAME - 1;
741
742 syslog(LOG_DEBUG,
743 "dir_name: %s", p_dir_info->fd_dir_name);
744
745 (void) memset(&ret_fh, 0, sizeof (ret_fh));
746 erc = fs_readdir(&p_dir_info->fd_dir_fh,
747 p_dir_info->fd_dir_name, &dpos,
748 dname, &dname_size, &ret_fh, &ret_attr);
749 if (erc == 0) {
750 fileid = ret_fh.fh_fid;
751 } else {
752 syslog(LOG_DEBUG,
753 "Filesystem readdir in [%s]",
754 p_dir_info->fd_dir_name);
755 retval = -ENOENT;
756 break;
757 }
758
759 /* an empty name size marks the end of the list */
760 if (dname_size == 0)
761 break;
762 dname[dname_size] = '\0';
763
764 /*
765 * If name refers to a directory, push its file
766 * handle onto the stack (skip "." and "..").
767 */
768 if (rootfs_dot_or_dotdot(dname)) {
769 fileid = 0;
770 continue;
771 }
772
773 /*
774 * Skip the:
775 * non-dir entries which should not be backed up
776 * Or
777 * dir-type entries which have have nothing under
778 * their hierarchy to be backed up.
779 */
780 if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)fileid)) {
781 syslog(LOG_DEBUG, "Skipping %s/%s",
782 p_dir_info->fd_dir_name, dname);
783 fileid = 0;
784 continue;
785 }
786
787 if (tlm_is_excluded(np->nr_unchkp_nm, dname,
788 np->nr_excls)) {
789 fileid = 0;
790 continue;
791 }
792 if (S_ISDIR(ret_attr.st_mode)) {
793 /*
794 * only directories get pushed onto this stack,
795 * so we do not have to test for regular files.
796 */
797 t_dir_info = tlm_new_dir_info(&ret_fh,
798 p_dir_info->fd_dir_name, dname);
799 if (t_dir_info == NULL) {
800 syslog(LOG_DEBUG,
801 "While backing up [%s][%s]",
802 p_dir_info->fd_dir_name, dname);
803 } else if (cstack_push(stk, t_dir_info,
804 0) != 0) {
805 syslog(LOG_DEBUG,
806 "No enough memory stack_push");
807 retval = -ENOMEM;
808 break;
809 }
810 } else if (S_ISREG(ret_attr.st_mode) ||
811 S_ISLNK(ret_attr.st_mode)) {
812
813 fsize = backup_file(np->nr_unchkp_nm, dname,
814 &tlm_acls, commands, local_commands,
815 job_stats, &bks);
816
817 if (fsize >= 0) {
818 job_stats->js_files_so_far++;
819 job_stats->js_bytes_total += fsize;
820 } else
821 job_stats->js_errors++;
822 fileid = 0;
823 }
824 }
825 fileid = 0;
875 }
876 return (rv);
877 }
878
879
880 /*
881 * ndmp_backup_reader
882 *
883 * Backup reader thread which uses backup_work to read and TAR
884 * the files/dirs to be backed up (V2 only)
885 */
886 static int
887 ndmp_backup_reader(tlm_commands_t *commands, ndmp_lbr_params_t *nlp,
888 char *job_name)
889 {
890 int retval;
891 ndmp_run_args_t np;
892 tlm_job_stats_t *job_stats;
893 tlm_cmd_t *local_commands;
894
895 syslog(LOG_DEBUG, "bk_path: \"%s\"", nlp->nlp_backup_path);
896
897 local_commands = commands->tcs_command;
898 (void) memset(&np, 0, sizeof (np));
899 if (!malloc_paths(&np))
900 return (-1);
901 local_commands->tc_ref++;
902 commands->tcs_reader_count++;
903
904 job_stats = tlm_ref_job_stats(job_name);
905
906 retval = backup_work(nlp->nlp_backup_path, job_stats, &np,
907 commands, nlp);
908 write_tar_eof(local_commands);
909
910 commands->tcs_reader_count--;
911 local_commands->tc_writer = TLM_STOP;
912 tlm_release_reader_writer_ipc(local_commands);
913 tlm_un_ref_job_stats(job_name);
914
915 free_paths(&np);
919
920
921 /*
922 * ndmp_tar_writer
923 *
924 * The backup writer thread that writes the TAR records to the
925 * tape media (V2 only)
926 */
927 int
928 ndmp_tar_writer(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
929 tlm_commands_t *cmds)
930 {
931 int bidx, nw;
932 int err;
933 tlm_buffer_t *buf;
934 tlm_buffers_t *bufs;
935 tlm_cmd_t *lcmd; /* Local command */
936
937 err = 0;
938 if (session == NULL) {
939 err = -1;
940 } else if (mod_params == NULL) {
941 err = -1;
942 } else if (cmds == NULL) {
943 err = -1;
944 }
945
946 if (err != 0)
947 return (err);
948
949 lcmd = cmds->tcs_command;
950 bufs = lcmd->tc_buffers;
951
952 lcmd->tc_ref++;
953 cmds->tcs_writer_count++;
954
955 nw = 0;
956 buf = tlm_buffer_out_buf(bufs, &bidx);
957 while (cmds->tcs_writer != (int)TLM_ABORT &&
958 lcmd->tc_writer != (int)TLM_ABORT) {
959 if (buf->tb_full) {
960 if (MOD_WRITE(mod_params, buf->tb_buffer_data,
961 buf->tb_buffer_size) != 0) {
962 syslog(LOG_DEBUG,
963 "Writing buffer %d, pos: %lld",
964 bidx, session->ns_mover.md_position);
965 err = -1;
966 break;
967 }
968
969 tlm_buffer_mark_empty(buf);
970 (void) tlm_buffer_advance_out_idx(bufs);
971 buf = tlm_buffer_out_buf(bufs, &bidx);
972 tlm_buffer_release_out_buf(bufs);
973 nw++;
974 } else {
975 if (lcmd->tc_writer != TLM_BACKUP_RUN) {
976 /* No more data is comming; time to exit. */
977 break;
978 } else {
979 tlm_buffer_in_buf_timed_wait(bufs, 100);
980 }
981 }
982 }
983
984 cmds->tcs_writer_count--;
985 lcmd->tc_reader = TLM_STOP;
986 lcmd->tc_ref--;
987
988 return (err);
989 }
990
991
992 /*
993 * read_one_buf
994 *
995 * Read one buffer from the tape
996 */
997 static int
998 read_one_buf(ndmpd_module_params_t *mod_params, tlm_buffers_t *bufs,
999 tlm_buffer_t *buf)
1000 {
1001 int rv;
1002
1003 if ((rv = MOD_READ(mod_params, buf->tb_buffer_data,
1025 ndmp_tar_reader(ndmp_tar_reader_arg_t *argp)
1026 {
1027 int bidx;
1028 int err;
1029 tlm_buffer_t *buf;
1030 tlm_buffers_t *bufs;
1031 tlm_cmd_t *lcmd; /* Local command */
1032 ndmpd_session_t *session;
1033 ndmpd_module_params_t *mod_params;
1034 tlm_commands_t *cmds;
1035
1036 if (!argp)
1037 return (-1);
1038
1039 session = argp->tr_session;
1040 mod_params = argp->tr_mod_params;
1041 cmds = argp->tr_cmds;
1042
1043 err = 0;
1044 if (session == NULL) {
1045 err = -1;
1046 } else if (cmds == NULL) {
1047 err = -1;
1048 }
1049
1050 if (err != 0) {
1051 tlm_cmd_signal(cmds->tcs_command, TLM_TAR_READER);
1052 return (err);
1053 }
1054
1055 lcmd = cmds->tcs_command;
1056 bufs = lcmd->tc_buffers;
1057
1058 lcmd->tc_ref++;
1059 cmds->tcs_reader_count++;
1060
1061 /*
1062 * Synchronize with our parent thread.
1063 */
1064 tlm_cmd_signal(cmds->tcs_command, TLM_TAR_READER);
1065
1066 buf = tlm_buffer_in_buf(bufs, &bidx);
1067 while (cmds->tcs_reader == TLM_RESTORE_RUN &&
1068 lcmd->tc_reader == TLM_RESTORE_RUN) {
1069
1070 if (buf->tb_full) {
1071 /*
1072 * The buffer is still full, wait for the consumer
1073 * thread to use it.
1074 */
1075 tlm_buffer_out_buf_timed_wait(bufs, 100);
1076 buf = tlm_buffer_in_buf(bufs, NULL);
1077 } else {
1078 err = read_one_buf(mod_params, bufs, buf);
1079 if (err < 0) {
1080 syslog(LOG_DEBUG,
1081 "Reading buffer %d, pos: %lld",
1082 bidx, session->ns_mover.md_position);
1083
1084 /* Force the writer to stop. */
1085 buf->tb_eot = buf->tb_eof = TRUE;
1086 break;
1087 } else if (err == 1) {
1088 syslog(LOG_DEBUG,
1089 "operation aborted or session terminated");
1090 err = 0;
1091 break;
1092 }
1093
1094 buf = tlm_buffer_in_buf(bufs, &bidx);
1095 tlm_buffer_release_in_buf(bufs);
1096 }
1097 }
1098
1099 /*
1100 * If the consumer is waiting for us, wake it up so that it detects
1101 * we're quiting.
1102 */
1103 lcmd->tc_writer = TLM_STOP;
1104 tlm_buffer_release_in_buf(bufs);
1105 (void) usleep(1000);
1106
1107 /*
1108 * Clean up.
1111 lcmd->tc_ref--;
1112 return (err);
1113 }
1114
1115
1116 /*
1117 * ndmpd_tar_backup
1118 *
1119 * Check must have been done that backup work directory exists, before
1120 * calling this function.
1121 */
1122 static int
1123 ndmpd_tar_backup(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
1124 ndmp_lbr_params_t *nlp)
1125 {
1126 char jname[TLM_MAX_BACKUP_JOB_NAME];
1127 int err;
1128 tlm_commands_t *cmds;
1129
1130 if (mod_params->mp_operation != NDMP_DATA_OP_BACKUP) {
1131 syslog(LOG_DEBUG,
1132 "mod_params->mp_operation != NDMP_DATA_OP_BACKUP");
1133 err = -1;
1134 } else {
1135 if (ndmpd_mark_inodes_v2(session, nlp) != 0)
1136 err = -1;
1137 else if (ndmp_get_bk_dir_ino(nlp))
1138 err = -1;
1139 else
1140 err = 0;
1141 }
1142
1143 if (err != 0)
1144 return (err);
1145
1146 if (ndmp_new_job_name(jname, sizeof (jname)) <= 0) {
1147 return (-1);
1148 }
1149 if (backup_create_structs(session, jname) < 0) {
1150 return (-1);
1151 }
1152 nlp->nlp_jstat->js_start_ltime = time(NULL);
1153 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
1154 nlp->nlp_jstat->js_chkpnt_time = nlp->nlp_cdate;
1155
1156 if (!session->ns_data.dd_abort) {
1157
1158 cmds = &nlp->nlp_cmds;
1159 cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
1160 cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
1161 cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
1162
1163 if (ndmp_write_utf8magic(cmds->tcs_command) < 0) {
1164 backup_release_structs(session);
1165 return (-1);
1166 }
1167
1168 syslog(LOG_DEBUG, "Backing up \"%s\" started.",
1169 nlp->nlp_backup_path);
1170
1171 err = ndmp_backup_reader(cmds, nlp, jname);
1172 if (err != 0) {
1173 backup_release_structs(session);
1174 syslog(LOG_DEBUG, "Launch ndmp_backup_reader: %s",
1175 strerror(err));
1176 return (-1);
1177 }
1178
1179 /* Act as the writer thread. */
1180 err = ndmp_tar_writer(session, mod_params, cmds);
1181
1182 nlp->nlp_jstat->js_stop_time = time(NULL);
1183
1184 syslog(LOG_DEBUG,
1185 "Runtime [%s] %lu bytes (%llu): %d seconds",
1186 nlp->nlp_backup_path, session->ns_mover.md_data_written,
1187 session->ns_mover.md_data_written,
1188 nlp->nlp_jstat->js_stop_time -
1189 nlp->nlp_jstat->js_start_ltime);
1190 MOD_LOG(mod_params,
1191 "Runtime [%s] %lu bytes (%lu): %d seconds",
1192 nlp->nlp_backup_path, session->ns_mover.md_data_written,
1193 session->ns_mover.md_data_written,
1194 nlp->nlp_jstat->js_stop_time -
1195 nlp->nlp_jstat->js_start_ltime);
1196
1197 if (session->ns_data.dd_abort)
1198 err = -1;
1199
1200 syslog(LOG_DEBUG, "Backing up \"%s\" finished. (%d)",
1201 nlp->nlp_backup_path, err);
1202 } else {
1203 nlp->nlp_jstat->js_stop_time = time(NULL);
1204 syslog(LOG_DEBUG, "Backing up \"%s\" aborted.",
1205 nlp->nlp_backup_path);
1206 err = 0;
1207 }
1208
1209 backup_release_structs(session);
1210 return (err);
1211 }
1212
1213
1214 /*
1215 * ndmpd_tar_restore
1216 *
1217 * Restore function that launches TAR reader thread to read from the
1218 * tape and writes the extracted files/dirs to the filesystem
1219 */
1220 static int
1221 ndmpd_tar_restore(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
1222 ndmp_lbr_params_t *nlp)
1223 {
1224 char jname[TLM_MAX_BACKUP_JOB_NAME];
1225 char *rspath;
1226 int err;
1227 tlm_commands_t *cmds;
1228 ndmp_tar_reader_arg_t arg;
1229 tlm_backup_restore_arg_t tlm_arg;
1230 ndmp_name *ent;
1231 pthread_t rdtp, wrtp;
1232 int i;
1233
1234 if (mod_params->mp_operation != NDMP_DATA_OP_RECOVER) {
1235 return (-1);
1236 }
1237
1238 if (nlp->nlp_restore_path[0] != '\0')
1239 rspath = nlp->nlp_restore_path;
1240 else if (nlp->nlp_restore_bk_path[0] != '\0')
1241 rspath = nlp->nlp_restore_bk_path;
1242 else
1243 rspath = "";
1244
1245 if (ndmp_new_job_name(jname, sizeof (jname)) <= 0) {
1246 return (-1);
1247 }
1248 if (restore_create_structs(session, jname) < 0) {
1249 return (-1);
1250 }
1251
1252 nlp->nlp_jstat->js_start_ltime = time(NULL);
1253 nlp->nlp_jstat->js_start_time = time(NULL);
1254
1255 if (!session->ns_data.dd_abort) {
1256 cmds = &nlp->nlp_cmds;
1257 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
1258 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
1259 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
1260
1261 syslog(LOG_DEBUG, "Restoring to \"%s\" started.", rspath);
1262 syslog(LOG_DEBUG, "Restoring from %s tape(s).",
1263 ndmp_data_get_mover_mode(session));
1264
1265 arg.tr_session = session;
1266 arg.tr_mod_params = mod_params;
1267 arg.tr_cmds = cmds;
1268
1269 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
1270 (void *)&arg);
1271 if (err == 0) {
1272 tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
1273 } else {
1274 syslog(LOG_DEBUG, "Launch ndmp_tar_reader: %m");
1275 return (-1);
1276 }
1277
1278 if (!ndmp_check_utf8magic(cmds->tcs_command)) {
1279 syslog(LOG_DEBUG, "UTF8Magic not found!");
1280 } else {
1281 syslog(LOG_DEBUG, "UTF8Magic found");
1282 }
1283
1284 (void) memset(&tlm_arg, 0, sizeof (tlm_backup_restore_arg_t));
1285 (void) pthread_barrier_init(&tlm_arg.ba_barrier, 0, 2);
1286
1287 /*
1288 * Set up restore parameters
1289 */
1290 tlm_arg.ba_commands = cmds;
1291 tlm_arg.ba_cmd = cmds->tcs_command;
1292 tlm_arg.ba_job = nlp->nlp_jstat->js_job_name;
1293 tlm_arg.ba_dir = nlp->nlp_restore_path;
1294 for (i = 0; i < nlp->nlp_nfiles; i++) {
1295 ent = (ndmp_name *)MOD_GETNAME(mod_params, i);
1296 tlm_arg.ba_sels[i] = strdup(ent->name);
1297 }
1298 tlm_arg.ba_count = i;
1299
1300 if (tm_tar_ops.tm_getfile != NULL) {
1301 err = pthread_create(&wrtp, NULL,
1302 (funct_t)tm_tar_ops.tm_getfile, (void *)&tlm_arg);
1303 } else {
1304 (void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1305 syslog(LOG_DEBUG,
1306 "Thread create tm_getfile: ops NULL");
1307 return (-1);
1308 }
1309 if (err == 0) {
1310 (void) pthread_barrier_wait(&tlm_arg.ba_barrier);
1311 } else {
1312 (void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1313 syslog(LOG_DEBUG, "thread create tm_getfile: %m");
1314 return (-1);
1315 }
1316
1317 (void) pthread_join(rdtp, NULL);
1318 (void) pthread_join(wrtp, NULL);
1319 (void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1320
1321 nlp->nlp_jstat->js_stop_time = time(NULL);
1322
1323 /* Send the list of un-recovered files/dirs to the client. */
1324 (void) send_unrecovered_list(mod_params, nlp);
1325
1326 ndmp_stop_local_reader(session, cmds);
1327 ndmp_wait_for_reader(cmds);
1328 ndmp_stop_remote_reader(session);
1329 syslog(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
1330 rspath, err);
1331 } else {
1332 nlp->nlp_jstat->js_stop_time = time(NULL);
1333
1334 /* nothing restored. */
1335 (void) send_unrecovered_list(mod_params, nlp);
1336 syslog(LOG_DEBUG, "Restoring to \"%s\" aborted.",
1337 rspath);
1338 err = -1;
1339 }
1340
1341 NDMP_FREE(nlp->nlp_restore_path);
1342 backup_release_structs(session);
1343
1344 return (err);
1345 }
1346
1347
1348 /*
1349 * prefixdir
1350 *
1351 * Extract the path for a given full path entry
1352 */
1353 static char *
1354 prefixdir(char *dir, char *suffix)
1355 {
1356 static char tmp[TLM_MAX_PATH_NAME];
1441 * Correct the entries in the restore list by appending the appropriate
1442 * path to them
1443 */
1444 static int
1445 correct_ents(ndmpd_module_params_t *params, int n, char *bkpath)
1446 {
1447 char *cp, *pathname;
1448 int i, len, rv;
1449 ndmp_name *ent;
1450
1451 if ((pathname = ndmp_malloc(TLM_MAX_PATH_NAME)) == NULL) {
1452 MOD_LOG(params, "Error: insufficient memory.\n");
1453 return (-1);
1454 }
1455
1456 rv = 0;
1457 /* Append the backup path to all the "ent[].name"s. */
1458 for (i = 0; i < n; i++) {
1459 ent = (ndmp_name *)MOD_GETNAME(params, i);
1460
1461 syslog(LOG_DEBUG,
1462 "Old: ent[%d].name: \"%s\"", i, ent->name);
1463 syslog(LOG_DEBUG,
1464 "Old: ent[%d].dest: \"%s\"", i, ent->dest);
1465
1466 /* remove trailing slash */
1467 len = strlen(ent->name);
1468 if (ent->name[len - 1] == '/')
1469 ent->name[len - 1] = '\0';
1470
1471 if (!tlm_cat_path(pathname, bkpath, ent->name)) {
1472 MOD_LOG(params, "Error: path too long.\n");
1473 rv = -1;
1474 break;
1475 }
1476
1477 /* Make a copy of the new string and save it in ent->name. */
1478 cp = strdup(pathname);
1479 if (cp == NULL) {
1480 MOD_LOG(params, "Error: insufficient memory.\n");
1481 rv = -1;
1482 break;
1483 }
1484 free(ent->name);
1485 ent->name = cp;
1486
1487 syslog(LOG_DEBUG,
1488 "New: ent[%d].name: \"%s\"", i, ent->name);
1489 }
1490
1491 free(pathname);
1492 return (rv);
1493 }
1494
1495
1496 /*
1497 * check_restore_paths
1498 *
1499 * Go through the restore list and check the validity of the
1500 * restore path.
1501 */
1502 static int
1503 check_restore_paths(ndmpd_module_params_t *params, int n, char *rspath)
1504 {
1505 int i, rv;
1506 ndmp_name *ent;
1507
1508 rv = 0;
1509 if (rspath != NULL && *rspath != '\0') {
1510 syslog(LOG_DEBUG, "rspath: \"%s\"", rspath);
1511 if (!fs_volexist(rspath)) {
1512 MOD_LOG(params,
1513 "Error: Invalid volume name for restore.");
1514 rv = -1;
1515 }
1516 } else {
1517 for (i = 0; i < n; i++) {
1518 ent = (ndmp_name *)MOD_GETNAME(params, i);
1519 syslog(LOG_DEBUG,
1520 "ent[%d].name: \"%s\"", i, ent->name);
1521
1522 if (!fs_volexist(ent->name)) {
1523 MOD_LOG(params,
1524 "Error: Invalid volume name for restore.",
1525 ent->name);
1526 rv = -1;
1527 break;
1528 }
1529 }
1530 }
1531
1532 return (rv);
1533 }
1534
1535
1536 /*
1537 * check_backup_dir_validity
1538 *
1539 * Check if the backup directory is valid. Make sure it exists and
1576 ndmpd_module_params_t *params)
1577 {
1578 char *cp;
1579 int rv;
1580 ndmp_lbr_params_t *nlp;
1581
1582 /* Extract directory to be backed up from env variables */
1583 if ((nlp = ndmp_get_nlp(session)) == NULL) {
1584 MOD_LOG(params, "Error: Internal error: nlp == NULL.\n");
1585 return (NDMP_ILLEGAL_ARGS_ERR);
1586 }
1587 if ((nlp->nlp_backup_path = get_backup_path_v2(params)) == NULL)
1588 return (NDMP_FILE_NOT_FOUND_ERR);
1589
1590 if ((rv = check_backup_dir_validity(params,
1591 nlp->nlp_backup_path)) != NDMP_NO_ERR)
1592 return (rv);
1593
1594 /* Should the st_ctime be ignored when backing up? */
1595 if (ndmp_ignore_ctime) {
1596 syslog(LOG_DEBUG, "ignoring st_ctime");
1597 NLP_SET(nlp, NLPF_IGNCTIME);
1598 } else
1599 NLP_UNSET(nlp, NLPF_IGNCTIME);
1600
1601 /* Should the st_lmtime be ignored when backing up? */
1602 if (ndmp_include_lmtime) {
1603 syslog(LOG_DEBUG, "including st_lmtime");
1604 NLP_SET(nlp, NLPF_INCLMTIME);
1605 } else
1606 NLP_UNSET(nlp, NLPF_INCLMTIME);
1607
1608 syslog(LOG_DEBUG, "flags %x", nlp->nlp_flags);
1609
1610 /* Is backup history requested? */
1611 cp = MOD_GETENV(params, "HIST");
1612 if (cp == NULL) {
1613 syslog(LOG_DEBUG, "env(HIST) not specified");
1614 NLP_UNSET(nlp, NLPF_FH);
1615 } else {
1616 syslog(LOG_DEBUG, "env(HIST): \"%s\"", cp);
1617
1618 if (strchr("t_ty_y", *cp))
1619 NLP_SET(nlp, NLPF_FH);
1620 else
1621 NLP_UNSET(nlp, NLPF_FH);
1622 }
1623
1624 nlp->nlp_clevel = 0;
1625 /* Is it an incremental backup? */
1626 cp = MOD_GETENV(params, "LEVEL");
1627 if (cp == NULL) {
1628 syslog(LOG_DEBUG,
1629 "env(LEVEL) not specified, default to 0");
1630 } else if (*cp < '0' || *cp > '9' || *(cp+1) != '\0') {
1631 syslog(LOG_DEBUG, "Invalid backup level '%s'", cp);
1632 return (NDMP_ILLEGAL_ARGS_ERR);
1633 } else
1634 nlp->nlp_clevel = *cp - '0';
1635
1636 /* Extract last backup time from the dumpdates file */
1637 nlp->nlp_llevel = nlp->nlp_clevel;
1638 nlp->nlp_ldate = 0;
1639 if (ndmpd_get_dumptime(nlp->nlp_backup_path, &nlp->nlp_llevel,
1640 &nlp->nlp_ldate) < 0) {
1641 MOD_LOG(params, "Error: getting dumpdate for %s level %d\n",
1642 nlp->nlp_backup_path, nlp->nlp_clevel);
1643 return (NDMP_NO_MEM_ERR);
1644 }
1645
1646 syslog(LOG_DEBUG,
1647 "Date of this level %d on \"%s\": %s",
1648 nlp->nlp_clevel, nlp->nlp_backup_path, cctime(&nlp->nlp_cdate));
1649 syslog(LOG_DEBUG,
1650 "Date of last level %d on \"%s\": %s",
1651 nlp->nlp_llevel, nlp->nlp_backup_path, cctime(&nlp->nlp_ldate));
1652
1653 /* Should the dumpdate file be updated? */
1654 cp = MOD_GETENV(params, "UPDATE");
1655 if (cp == NULL) {
1656 syslog(LOG_DEBUG,
1657 "env(UPDATE) not specified, default to TRUE");
1658 NLP_SET(nlp, NLPF_UPDATE);
1659 } else {
1660 syslog(LOG_DEBUG, "env(UPDATE): \"%s\"", cp);
1661 if (strchr("t_ty_y", *cp) != NULL)
1662 NLP_SET(nlp, NLPF_UPDATE);
1663 else
1664 NLP_UNSET(nlp, NLPF_UPDATE);
1665 }
1666
1667 return (NDMP_NO_ERR);
1668 }
1669
1670
1671
1672 /*
1673 * log_bk_params_v2
1674 *
1675 * Dump the value of the parameters in the log file for debugging.
1676 */
1677 void
1678 log_bk_params_v2(ndmpd_session_t *session, ndmpd_module_params_t *params,
1679 ndmp_lbr_params_t *nlp)
1680 {
1707 same_path(char *s, char *t)
1708 {
1709 boolean_t rv;
1710 int slen, tlen;
1711
1712 rv = FALSE;
1713 slen = strlen(s);
1714 tlen = strlen(t);
1715 if (slen == tlen && strcmp(s, t) == 0) {
1716 rv = TRUE;
1717 } else {
1718 if (slen == tlen - 1) {
1719 if (strncmp(s, t, slen) == 0 && t[tlen - 1] == '/')
1720 rv = TRUE;
1721 } else if (tlen == slen -1) {
1722 if (strncmp(s, t, tlen) == 0 && s[slen - 1] == '/')
1723 rv = TRUE;
1724 }
1725 }
1726
1727 syslog(LOG_DEBUG, "rv: %d", rv);
1728 return (rv);
1729 }
1730
1731
1732 /*
1733 * ndmp_restore_extract_params
1734 *
1735 * Go through the restore parameters and check them and extract them
1736 * by setting NLP flags and other values.
1737 *
1738 * Parameters:
1739 *
1740 * Returns:
1741 * 0: on success
1742 * -1: otherwise
1743 */
1744 int
1745 ndmp_restore_extract_params(ndmpd_session_t *session,
1746 ndmpd_module_params_t *params)
1747 {
1748 char *bkpath, *rspath;
1749 ndmp_lbr_params_t *nlp;
1750
1751 if ((nlp = ndmp_get_nlp(session)) == NULL) {
1752 return (-1);
1753 }
1754
1755 /* Extract directory from where the backup was made. */
1756 if ((bkpath = get_backup_path_v2(params)) == NULL)
1757 return (NDMP_ILLEGAL_ARGS_ERR);
1758
1759 nlp->nlp_restore_bk_path = bkpath;
1760
1761 /* The number of the selections. */
1762 if ((nlp->nlp_nfiles = get_nfiles(session, params)) == 0)
1763 return (NDMP_ILLEGAL_ARGS_ERR);
1764
1765 syslog(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
1766
1767 if ((rspath = get_restore_dest(params)) == NULL)
1768 return (NDMP_ILLEGAL_ARGS_ERR);
1769
1770 if (fs_is_rdonly(rspath)) {
1771 MOD_LOG(params,
1772 "Error: Can't restore to a read-only volume: \"%s\"\n",
1773 rspath);
1774 return (NDMP_ILLEGAL_ARGS_ERR);
1775 }
1776 if (fs_is_chkpntvol(rspath)) {
1777 MOD_LOG(params,
1778 "Error: Can't restore to a checkpoint: \"%s\"\n", rspath);
1779 return (NDMP_ILLEGAL_ARGS_ERR);
1780 }
1781
1782 if (same_path(bkpath, rspath))
1783 rspath = "";
1784
1785 if ((nlp->nlp_restore_path = strdup(rspath)) == NULL)
1812 */
1813 int
1814 ndmpd_tar_backup_starter(void *arg)
1815 {
1816 ndmpd_module_params_t *mod_params = arg;
1817 int err;
1818 ndmpd_session_t *session;
1819 ndmp_lbr_params_t *nlp;
1820
1821 session = (ndmpd_session_t *)(mod_params->mp_daemon_cookie);
1822 *(mod_params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
1823 ndmp_session_ref(session);
1824
1825 err = 0;
1826 if (fs_is_chkpntvol(nlp->nlp_backup_path) ||
1827 fs_is_rdonly(nlp->nlp_backup_path) ||
1828 !fs_is_chkpnt_enabled(nlp->nlp_backup_path))
1829 NLP_SET(nlp, NLPF_CHKPNTED_PATH);
1830 else {
1831 NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
1832 if (backup_dataset_create(nlp) < 0) {
1833 MOD_LOG(mod_params,
1834 "Error: creating checkpoint on %s\n",
1835 nlp->nlp_backup_path);
1836 /* -1 causes halt reason to become internal error. */
1837 err = -1;
1838 }
1839 }
1840
1841 syslog(LOG_DEBUG, "NLPF_CHKPNTED_PATH: %c",
1842 NDMP_YORN(NLP_ISCHKPNTED(nlp)));
1843 syslog(LOG_DEBUG, "err: %d, update %c",
1844 err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
1845
1846 if (err == 0) {
1847 err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate);
1848 if (err != 0) {
1849 syslog(LOG_DEBUG, "err %d", err);
1850 } else {
1851 log_bk_params_v2(session, mod_params, nlp);
1852 err = ndmpd_tar_backup(session, mod_params, nlp);
1853 }
1854 }
1855
1856 if (nlp->nlp_bkmap >= 0) {
1857 (void) dbm_free(nlp->nlp_bkmap);
1858 nlp->nlp_bkmap = -1;
1859 }
1860
1861 if (!NLP_ISCHKPNTED(nlp))
1862 (void) backup_dataset_destroy(nlp);
1863
1864 syslog(LOG_DEBUG, "err %d, update %c",
1865 err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
1866
1867 if (err == 0 && NLP_SHOULD_UPDATE(nlp)) {
1868 if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel,
1869 nlp->nlp_cdate) < 0) {
1870 err = EPERM;
1871 MOD_LOG(mod_params,
1872 "Error: updating the dumpdates file on %s\n",
1873 nlp->nlp_backup_path);
1874 }
1875 }
1876
1877 MOD_DONE(mod_params, err);
1878
1879 /* nlp_params is allocated in start_backup() */
1880 NDMP_FREE(nlp->nlp_params);
1881
1882 NS_DEC(nbk);
1883 ndmp_session_unref(session);
1884 return (err);
|