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
65 /*
66 * backup_create_structs
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
backup_create_structs(ndmpd_session_t * session,char * jname)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 /*
135 * restore_create_structs
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
restore_create_structs(ndmpd_session_t * session,char * jname)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 }
191 for (i = 0; i < (int)nlp->nlp_nfiles; i++)
192 nlp->nlp_restored[i] = FALSE;
193
194 return (0);
195 }
196
197
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
send_unrecovered_list(ndmpd_module_params_t * params,ndmp_lbr_params_t * nlp)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
backup_release_structs(ndmpd_session_t * session)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
ndmp_write_utf8magic(tlm_cmd_t * cmd)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.
356 *
357 * Directories for tar format are backed up if and only if
358 * they are modified.
359 *
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
timecmp(bk_selector_t * bksp,struct stat64 * attr)373 timecmp(bk_selector_t *bksp, struct stat64 *attr)
374 {
375 ndmp_lbr_params_t *nlp;
376
377 nlp = (ndmp_lbr_params_t *)bksp->bs_cookie;
378 if (S_ISDIR(attr->st_mode) && ndmp_force_bk_dirs) {
379 NDMP_LOG(LOG_DEBUG, "d(%lu)",
380 (uint_t)attr->st_ino);
381 return (TRUE);
382 }
383 if (S_ISDIR(attr->st_mode) &&
384 dbm_getone(nlp->nlp_bkmap, (u_longlong_t)attr->st_ino) &&
385 ((NLP_ISDUMP(nlp) && ndmp_dump_path_node) ||
386 (NLP_ISTAR(nlp) && ndmp_tar_path_node))) {
387 /*
388 * If the object is a directory and it leads to a modified
389 * object (that should be backed up) and for that type of
390 * backup the path nodes should be backed up, then return
391 * TRUE.
392 *
393 * This is required by some DMAs like Backup Express, which
394 * needs to receive ADD_NODE (for dump) or ADD_PATH (for tar)
395 * for the intermediate directories of a modified object.
396 * Other DMAs, like net_backup and net_worker, do not have such
397 * requirement. This requirement makes sense for dump format
398 * but for 'tar' format, it does not. In provision to the
399 * NDMP-v4 spec, for 'tar' format the intermediate directories
400 * need not to be reported.
401 */
402 NDMP_LOG(LOG_DEBUG, "p(%lu)", (u_longlong_t)attr->st_ino);
403 return (TRUE);
404 }
405 if (attr->st_mtime > bksp->bs_ldate) {
406 NDMP_LOG(LOG_DEBUG, "m(%lu): %lu > %lu",
407 (uint_t)attr->st_ino, (uint_t)attr->st_mtime,
408 (uint_t)bksp->bs_ldate);
409 return (TRUE);
410 }
411 if (attr->st_ctime > bksp->bs_ldate) {
412 if (NLP_IGNCTIME(nlp)) {
413 NDMP_LOG(LOG_DEBUG, "ign c(%lu): %lu > %lu",
414 (uint_t)attr->st_ino, (uint_t)attr->st_ctime,
415 (uint_t)bksp->bs_ldate);
416 return (FALSE);
417 }
418 NDMP_LOG(LOG_DEBUG, "c(%lu): %lu > %lu",
419 (uint_t)attr->st_ino, (uint_t)attr->st_ctime,
420 (uint_t)bksp->bs_ldate);
421 return (TRUE);
422 }
423 NDMP_LOG(LOG_DEBUG, "mc(%lu): (%lu,%lu) < %lu",
424 (uint_t)attr->st_ino, (uint_t)attr->st_mtime,
425 (uint_t)attr->st_ctime, (uint_t)bksp->bs_ldate);
426 return (FALSE);
427 }
428
429
430 /*
431 * get_acl_info
432 *
433 * load up all the access and attribute info
434 */
435 static int
get_acl_info(char * name,tlm_acls_t * tlm_acls)436 get_acl_info(char *name, tlm_acls_t *tlm_acls)
437 {
438 int erc;
439 acl_t *aclp = NULL;
440 char *acltp;
441
442 erc = lstat64(name, &tlm_acls->acl_attr);
443 if (erc != 0) {
444 NDMP_LOG(LOG_ERR, "Could not find file %s.", name);
445 erc = TLM_NO_SOURCE_FILE;
446 return (erc);
447 }
448 erc = acl_get(name, ACL_NO_TRIVIAL, &aclp);
449 if (erc != 0) {
450 NDMP_LOG(LOG_DEBUG,
451 "Could not read ACL for file [%s]", name);
452 erc = TLM_NO_SOURCE_FILE;
453 return (erc);
454 }
455 if (aclp && (acltp = acl_totext(aclp,
456 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
457 (void) strlcpy(tlm_acls->acl_info.attr_info, acltp,
458 TLM_MAX_ACL_TXT);
459 acl_free(aclp);
460 free(acltp);
461 }
462 return (erc);
463 }
464 /*
465 * get_dir_acl_info
466 *
467 * load up all ACL and attr info about a directory
468 */
469 static int
get_dir_acl_info(char * dir,tlm_acls_t * tlm_acls,tlm_job_stats_t * js)470 get_dir_acl_info(char *dir, tlm_acls_t *tlm_acls, tlm_job_stats_t *js)
471 {
472 int erc;
473 char *checkpointed_dir;
474 char root_dir[TLM_VOLNAME_MAX_LENGTH];
475 char *spot;
476 char *fil;
477 acl_t *aclp = NULL;
478 char *acltp;
479
480 checkpointed_dir = ndmp_malloc(TLM_MAX_PATH_NAME);
481 if (checkpointed_dir == NULL)
482 return (-1);
483
484 if (tlm_acls->acl_checkpointed)
485 fil = tlm_build_snapshot_name(dir, checkpointed_dir,
486 js->js_job_name);
487 else
488 fil = dir;
489 erc = lstat64(fil, &tlm_acls->acl_attr);
490 if (erc != 0) {
491 NDMP_LOG(LOG_ERR, "Could not find directory %s.", dir);
492 free(checkpointed_dir);
493 return (-1);
494 }
495
496 spot = strchr(&fil[1], '/');
497 if (spot == NULL) {
498 (void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH);
499 } else {
500 *spot = 0;
501 (void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH);
502 *spot = '/';
503 }
504 if (strcmp(root_dir, tlm_acls->acl_root_dir) != 0) {
505 struct stat64 attr;
506
507 erc = lstat64(root_dir, &attr);
508 if (erc != 0) {
509 NDMP_LOG(LOG_ERR, "Cannot find root directory %s.",
510 root_dir);
511 free(checkpointed_dir);
512 return (-1);
513 }
514 (void) strlcpy(tlm_acls->acl_root_dir, root_dir,
515 TLM_VOLNAME_MAX_LENGTH);
516 }
517 erc = acl_get(fil, ACL_NO_TRIVIAL, &aclp);
518 if (erc != 0) {
519 NDMP_LOG(LOG_DEBUG,
520 "Could not read metadata for directory [%s]", dir);
521 free(checkpointed_dir);
522 return (-1);
523 }
524 if (aclp && (acltp = acl_totext(aclp,
525 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
526 (void) strlcpy(tlm_acls->acl_info.attr_info, acltp,
527 TLM_MAX_ACL_TXT);
528 acl_free(aclp);
529 free(acltp);
530 }
531
532 free(checkpointed_dir);
533 return (0);
534 }
535
536 /*
537 * backup_dir
538 *
539 * Create a TAR entry record for a directory
540 */
541 static int
backup_dir(char * dir,tlm_acls_t * tlm_acls,tlm_cmd_t * local_commands,tlm_job_stats_t * job_stats,bk_selector_t * bksp)542 backup_dir(char *dir, tlm_acls_t *tlm_acls,
543 tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats,
544 bk_selector_t *bksp)
545 {
546 int erc;
547
548 NDMP_LOG(LOG_DEBUG, "\"%s\"", dir);
549
550 erc = get_dir_acl_info(dir, tlm_acls, job_stats);
551 if (erc != 0) {
552 NDMP_LOG(LOG_DEBUG,
553 "Could not read directory info for %s", dir);
554 job_stats->js_errors++;
555 } else {
556 /*
557 * See if the directory must be backed up.
558 */
559 if (bksp && !(*bksp->bs_fn)(bksp, &tlm_acls->acl_attr)) {
560 NDMP_LOG(LOG_DEBUG, "[%s] dir skipped", dir);
561 return (erc);
562 }
563
564 if (tm_tar_ops.tm_putdir != NULL)
565 (void) (tm_tar_ops.tm_putdir)(dir, tlm_acls,
566 local_commands, job_stats);
567 }
568
569 return (erc);
570 }
571
572
573 /*
574 * backup_file
575 *
576 * Create a TAR record entry for a file
577 */
578 static longlong_t
backup_file(char * dir,char * name,tlm_acls_t * tlm_acls,tlm_commands_t * commands,tlm_cmd_t * local_commands,tlm_job_stats_t * job_stats,bk_selector_t * bksp)579 backup_file(char *dir, char *name, tlm_acls_t *tlm_acls,
580 tlm_commands_t *commands, tlm_cmd_t *local_commands,
581 tlm_job_stats_t *job_stats, bk_selector_t *bksp)
582 {
583
584 int erc;
585 char buf[TLM_MAX_PATH_NAME];
586 longlong_t rv;
587
588 NDMP_LOG(LOG_DEBUG, "\"%s/%s\"", dir, name);
589
590 (void) strlcpy(buf, dir, sizeof (buf));
591 (void) strlcat(buf, "/", sizeof (buf));
592 (void) strlcat(buf, name, sizeof (buf));
593
594 /*
595 * get_acl_info extracts file handle, attributes and ACLs of the file.
596 * This is not efficient when the attributes and file handle of
597 * the file is already known.
598 */
599 erc = get_acl_info(buf, tlm_acls);
600 if (erc != TLM_NO_ERRORS) {
601 NDMP_LOG(LOG_ERR, "Could not open file %s/%s.", dir, name);
602 return (-ENOENT);
603 }
604
605 /* Should the file be backed up? */
606 if (!bksp) {
607 NDMP_LOG(LOG_DEBUG,
608 "[%s/%s] has no selection criteria", dir, name);
609
610 } else if (!((*bksp->bs_fn)(bksp, &tlm_acls->acl_attr))) {
611 NDMP_LOG(LOG_DEBUG, "[%s/%s] file skipped", dir, name);
612 return (0);
613 }
614
615 /* Only the regular files and symbolic links can be backed up. */
616 if (!S_ISLNK(tlm_acls->acl_attr.st_mode) &&
617 !S_ISREG(tlm_acls->acl_attr.st_mode)) {
618 NDMP_LOG(LOG_DEBUG,
619 "Warning: skip backing up [%s][%s]", dir, name);
620 return (-EINVAL);
621 }
622
623
624 if (tm_tar_ops.tm_putfile != NULL)
625 rv = (tm_tar_ops.tm_putfile)(dir, name, tlm_acls, commands,
626 local_commands, job_stats);
627
628 return (rv);
629 }
630
631
632
633 /*
634 * backup_work
635 *
636 * Start the NDMP backup (V2 only).
637 */
638 int
backup_work(char * bk_path,tlm_job_stats_t * job_stats,ndmp_run_args_t * np,tlm_commands_t * commands,ndmp_lbr_params_t * nlp)639 backup_work(char *bk_path, tlm_job_stats_t *job_stats,
640 ndmp_run_args_t *np, tlm_commands_t *commands,
641 ndmp_lbr_params_t *nlp)
642 {
643 struct full_dir_info dir_info; /* the blob to push/pop with cstack_t */
644 struct full_dir_info *t_dir_info, *p_dir_info;
645 struct stat64 ret_attr; /* attributes of current file name */
646 fs_fhandle_t ret_fh;
647 char *first_name; /* where the first name is located */
648 char *dname;
649 int erc;
650 int retval;
651 cstack_t *stk;
652 unsigned long fileid;
653 tlm_acls_t tlm_acls;
654 int dname_size;
655 longlong_t fsize;
656 bk_selector_t bks;
657 tlm_cmd_t *local_commands;
658 long dpos;
659
660 NDMP_LOG(LOG_DEBUG, "nr_chkpnted %d nr_ldate: %u bk_path: \"%s\"",
661 NLP_ISCHKPNTED(nlp), nlp->nlp_ldate, bk_path);
662
663 /* Get every name in this directory */
664 dname = ndmp_malloc(TLM_MAX_PATH_NAME);
665 if (dname == NULL)
666 return (-ENOMEM);
667
668 local_commands = commands->tcs_command;
669 retval = 0;
670 (void) memset(&bks, 0, sizeof (bks));
671 bks.bs_cookie = (void *)nlp;
672 bks.bs_level = nlp->nlp_clevel;
673 bks.bs_ldate = nlp->nlp_ldate;
674 bks.bs_fn = timecmp;
675
676 /*
677 * should we skip the whole thing?
678 */
679 if (tlm_is_excluded("", bk_path, np->nr_excls)) {
680 NDMP_LOG(LOG_DEBUG, "%s excluded", bk_path);
681 free(dname);
682 return (0);
683 }
684
685 /*
686 * Search for the top-level file-directory
687 */
688 if (NLP_ISCHKPNTED(nlp)) {
689 first_name = np->nr_chkp_nm;
690 (void) strlcpy(first_name, bk_path, TLM_MAX_PATH_NAME);
691 } else {
692 first_name = tlm_build_snapshot_name(bk_path, np->nr_chkp_nm,
693 nlp->nlp_jstat->js_job_name);
694 }
695
696 (void) memset(&ret_fh, 0, sizeof (ret_fh));
697 erc = fs_getstat(first_name, &ret_fh, &ret_attr);
698 if (erc != 0) {
699 NDMP_LOG(LOG_ERR, "Path %s not found.", first_name);
700 free(dname);
701 return (-EINVAL);
702 }
703
704 if ((stk = cstack_new()) == NULL) {
705 free(dname);
706 NDMP_LOG(LOG_DEBUG, "cstack_new failed");
707 return (-ENOMEM);
708 }
709 (void) strlcpy(dir_info.fd_dir_name, first_name, TLM_MAX_PATH_NAME);
710 (void) memcpy(&dir_info.fd_dir_fh, &ret_fh, sizeof (fs_fhandle_t));
711 p_dir_info = dup_dir_info(&dir_info);
712
713 /*
714 * Push the first name onto the stack so that we can pop it back
715 * off as part of the normal cycle
716 */
717 if (cstack_push(stk, p_dir_info, 0)) {
718 free(dname);
719 free(p_dir_info);
720 cstack_delete(stk);
721 NDMP_LOG(LOG_DEBUG, "cstack_push failed");
722 return (-ENOMEM);
723 }
724
725 (void) memset(&tlm_acls, 0, sizeof (tlm_acls));
726 /*
727 * Did NDMP create a checkpoint?
728 */
729 if (NLP_ISCHKPNTED(nlp) || fs_is_rdonly(bk_path)) {
730 tlm_acls.acl_checkpointed = FALSE;
731 } else {
732 /* Use the checkpoint created by NDMP */
733 tlm_acls.acl_checkpointed = TRUE;
734 }
735
736 /*
737 * This is level-backup. It never resets the archive bit.
738 */
739 tlm_acls.acl_clear_archive = FALSE;
740
741 NDMP_LOG(LOG_DEBUG, "acls.chkpnt: %c acls.clear_arcbit: %c",
742 NDMP_YORN(tlm_acls.acl_checkpointed),
743 NDMP_YORN(tlm_acls.acl_clear_archive));
744
745 while (commands->tcs_reader == TLM_BACKUP_RUN &&
746 local_commands->tc_reader == TLM_BACKUP_RUN &&
747 cstack_pop(stk, (void **)&p_dir_info, 0) == 0) {
748
749 if (NLP_ISCHKPNTED(nlp))
750 (void) strlcpy(np->nr_unchkp_nm,
751 p_dir_info->fd_dir_name, TLM_MAX_PATH_NAME);
752 else
753 (void) tlm_remove_checkpoint(p_dir_info->fd_dir_name,
754 np->nr_unchkp_nm);
755
756 (void) backup_dir(np->nr_unchkp_nm, &tlm_acls, local_commands,
757 job_stats, &bks);
758
759
760 while (commands->tcs_reader == TLM_BACKUP_RUN &&
761 local_commands->tc_reader == TLM_BACKUP_RUN) {
762
763 dname_size = TLM_MAX_PATH_NAME - 1;
764
765 NDMP_LOG(LOG_DEBUG,
766 "dir_name: %s", p_dir_info->fd_dir_name);
767
768 (void) memset(&ret_fh, 0, sizeof (ret_fh));
769 erc = fs_readdir(&p_dir_info->fd_dir_fh,
770 p_dir_info->fd_dir_name, &dpos,
771 dname, &dname_size, &ret_fh, &ret_attr);
772 if (erc == 0) {
773 fileid = ret_fh.fh_fid;
774 } else {
775 NDMP_LOG(LOG_DEBUG,
776 "Filesystem readdir in [%s]",
777 p_dir_info->fd_dir_name);
778 retval = -ENOENT;
779 break;
780 }
781
782 /* an empty name size marks the end of the list */
783 if (dname_size == 0)
784 break;
785 dname[dname_size] = '\0';
786
787 NDMP_LOG(LOG_DEBUG, "dname: \"%s\"", dname);
788
789 /*
790 * If name refers to a directory, push its file
791 * handle onto the stack (skip "." and "..").
792 */
793 if (rootfs_dot_or_dotdot(dname)) {
794 fileid = 0;
795 continue;
796 }
797
798 /*
799 * Skip the:
800 * non-dir entries which should not be backed up
801 * Or
802 * dir-type entries which have have nothing under
803 * their hierarchy to be backed up.
804 */
805 if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)fileid)) {
806 NDMP_LOG(LOG_DEBUG, "Skipping %s/%s",
807 p_dir_info->fd_dir_name, dname);
808 fileid = 0;
809 continue;
810 }
811
812 if (tlm_is_excluded(np->nr_unchkp_nm, dname,
813 np->nr_excls)) {
814 fileid = 0;
815 continue;
816 }
817 if (S_ISDIR(ret_attr.st_mode)) {
818 /*
819 * only directories get pushed onto this stack,
820 * so we do not have to test for regular files.
821 */
822 t_dir_info = tlm_new_dir_info(&ret_fh,
823 p_dir_info->fd_dir_name, dname);
824 if (t_dir_info == NULL) {
825 NDMP_LOG(LOG_DEBUG,
826 "While backing up [%s][%s]",
827 p_dir_info->fd_dir_name, dname);
828 } else if (cstack_push(stk, t_dir_info,
829 0) != 0) {
830 NDMP_LOG(LOG_DEBUG,
831 "No enough memory stack_push");
832 retval = -ENOMEM;
833 break;
834 }
835 } else if (S_ISREG(ret_attr.st_mode) ||
836 S_ISLNK(ret_attr.st_mode)) {
837
838 fsize = backup_file(np->nr_unchkp_nm, dname,
839 &tlm_acls, commands, local_commands,
840 job_stats, &bks);
841
842 if (fsize >= 0) {
843 job_stats->js_files_so_far++;
844 job_stats->js_bytes_total += fsize;
845 } else
846 job_stats->js_errors++;
847 fileid = 0;
848 }
849 }
850 fileid = 0;
851 free(p_dir_info);
852 if (retval != 0)
853 break;
854 }
855
856 free(dname);
857
858 while (cstack_pop(stk, (void **)&p_dir_info, 0) == 0) {
859 free(p_dir_info);
860 }
861
862 cstack_delete(stk);
863 return (retval);
864 }
865
866
867 /*
868 * free_paths
869 *
870 * Free the path names
871 */
872 static void
free_paths(ndmp_run_args_t * np)873 free_paths(ndmp_run_args_t *np)
874 {
875 free(np->nr_chkp_nm);
876 free(np->nr_unchkp_nm);
877 free(np->nr_excls);
878 }
879
880
881 /*
882 * malloc_paths
883 *
884 * Allocate the path names (direct and checkpointed paths)
885 */
886 static boolean_t
malloc_paths(ndmp_run_args_t * np)887 malloc_paths(ndmp_run_args_t *np)
888 {
889 boolean_t rv;
890
891 rv = TRUE;
892 np->nr_chkp_nm = ndmp_malloc(TLM_MAX_PATH_NAME);
893 np->nr_unchkp_nm = ndmp_malloc(TLM_MAX_PATH_NAME);
894 if (!np->nr_chkp_nm || !np->nr_unchkp_nm) {
895 free_paths(np);
896 rv = FALSE;
897 } else if ((np->nr_excls = ndmpd_make_exc_list()) == NULL) {
898 free_paths(np);
899 rv = FALSE;
900 }
901 return (rv);
902 }
903
904
905 /*
906 * ndmp_backup_reader
907 *
908 * Backup reader thread which uses backup_work to read and TAR
909 * the files/dirs to be backed up (V2 only)
910 */
911 static int
ndmp_backup_reader(tlm_commands_t * commands,ndmp_lbr_params_t * nlp,char * job_name)912 ndmp_backup_reader(tlm_commands_t *commands, ndmp_lbr_params_t *nlp,
913 char *job_name)
914 {
915 int retval;
916 ndmp_run_args_t np;
917 tlm_job_stats_t *job_stats;
918 tlm_cmd_t *local_commands;
919
920 NDMP_LOG(LOG_DEBUG, "bk_path: \"%s\"", nlp->nlp_backup_path);
921
922 local_commands = commands->tcs_command;
923 (void) memset(&np, 0, sizeof (np));
924 if (!malloc_paths(&np))
925 return (-1);
926 local_commands->tc_ref++;
927 commands->tcs_reader_count++;
928
929 job_stats = tlm_ref_job_stats(job_name);
930
931 retval = backup_work(nlp->nlp_backup_path, job_stats, &np,
932 commands, nlp);
933 write_tar_eof(local_commands);
934
935 commands->tcs_reader_count--;
936 local_commands->tc_writer = TLM_STOP;
937 tlm_release_reader_writer_ipc(local_commands);
938 tlm_un_ref_job_stats(job_name);
939
940 free_paths(&np);
941 return (retval);
942
943 }
944
945
946 /*
947 * ndmp_tar_writer
948 *
949 * The backup writer thread that writes the TAR records to the
950 * tape media (V2 only)
951 */
952 int
ndmp_tar_writer(ndmpd_session_t * session,ndmpd_module_params_t * mod_params,tlm_commands_t * cmds)953 ndmp_tar_writer(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
954 tlm_commands_t *cmds)
955 {
956 int bidx, nw;
957 int err;
958 tlm_buffer_t *buf;
959 tlm_buffers_t *bufs;
960 tlm_cmd_t *lcmd; /* Local command */
961
962 err = 0;
963 if (session == NULL) {
964 NDMP_LOG(LOG_DEBUG, "session == NULL");
965 err = -1;
966 } else if (mod_params == NULL) {
967 NDMP_LOG(LOG_DEBUG, "mod_params == NULL");
968 err = -1;
969 } else if (cmds == NULL) {
970 NDMP_LOG(LOG_DEBUG, "cmds == NULL");
971 err = -1;
972 }
973
974 if (err != 0)
975 return (err);
976
977 lcmd = cmds->tcs_command;
978 bufs = lcmd->tc_buffers;
979
980 lcmd->tc_ref++;
981 cmds->tcs_writer_count++;
982
983 nw = 0;
984 buf = tlm_buffer_out_buf(bufs, &bidx);
985 while (cmds->tcs_writer != (int)TLM_ABORT &&
986 lcmd->tc_writer != (int)TLM_ABORT) {
987 if (buf->tb_full) {
988 NDMP_LOG(LOG_DEBUG, "w%d", bidx);
989
990 if (MOD_WRITE(mod_params, buf->tb_buffer_data,
991 buf->tb_buffer_size) != 0) {
992 NDMP_LOG(LOG_DEBUG,
993 "Writing buffer %d, pos: %lld",
994 bidx, session->ns_mover.md_position);
995 err = -1;
996 break;
997 }
998
999 tlm_buffer_mark_empty(buf);
1000 (void) tlm_buffer_advance_out_idx(bufs);
1001 buf = tlm_buffer_out_buf(bufs, &bidx);
1002 tlm_buffer_release_out_buf(bufs);
1003 nw++;
1004 } else {
1005 if (lcmd->tc_writer != TLM_BACKUP_RUN) {
1006 /* No more data is comming; time to exit. */
1007 NDMP_LOG(LOG_DEBUG,
1008 "tc_writer!=TLM_BACKUP_RUN; time to exit");
1009 break;
1010 } else {
1011 NDMP_LOG(LOG_DEBUG, "W%d", bidx);
1012 tlm_buffer_in_buf_timed_wait(bufs, 100);
1013 }
1014 }
1015 }
1016
1017 NDMP_LOG(LOG_DEBUG, "nw: %d", nw);
1018 if (cmds->tcs_writer != (int)TLM_ABORT) {
1019 NDMP_LOG(LOG_DEBUG, "tcs_writer != TLM_ABORT");
1020 } else {
1021 NDMP_LOG(LOG_DEBUG, "tcs_writer == TLM_ABORT");
1022 }
1023
1024 if (lcmd->tc_writer != (int)TLM_ABORT) {
1025 NDMP_LOG(LOG_DEBUG, "tc_writer != TLM_ABORT");
1026 } else {
1027 NDMP_LOG(LOG_DEBUG, "tc_writer == TLM_ABORT");
1028 }
1029 cmds->tcs_writer_count--;
1030 lcmd->tc_reader = TLM_STOP;
1031 lcmd->tc_ref--;
1032
1033 return (err);
1034 }
1035
1036
1037 /*
1038 * read_one_buf
1039 *
1040 * Read one buffer from the tape
1041 */
1042 static int
read_one_buf(ndmpd_module_params_t * mod_params,tlm_buffers_t * bufs,tlm_buffer_t * buf)1043 read_one_buf(ndmpd_module_params_t *mod_params, tlm_buffers_t *bufs,
1044 tlm_buffer_t *buf)
1045 {
1046 int rv;
1047
1048 if ((rv = MOD_READ(mod_params, buf->tb_buffer_data,
1049 bufs->tbs_data_transfer_size)) == 0) {
1050 buf->tb_eof = buf->tb_eot = FALSE;
1051 buf->tb_errno = 0;
1052 buf->tb_buffer_size = bufs->tbs_data_transfer_size;
1053 buf->tb_buffer_spot = 0;
1054 buf->tb_full = TRUE;
1055 (void) tlm_buffer_advance_in_idx(bufs);
1056 }
1057
1058 return (rv);
1059 }
1060
1061
1062 /*
1063 * ndmp_tar_reader
1064 *
1065 * NDMP Tar reader thread. This threads keep reading the tar
1066 * file from the tape and wakes up the consumer thread to extract
1067 * it on the disk
1068 */
1069 void *
ndmp_tar_reader(void * ptr)1070 ndmp_tar_reader(void *ptr)
1071 {
1072 int bidx;
1073 int err;
1074 tlm_buffer_t *buf;
1075 tlm_buffers_t *bufs;
1076 tlm_cmd_t *lcmd; /* Local command */
1077 ndmpd_session_t *session;
1078 ndmpd_module_params_t *mod_params;
1079 tlm_commands_t *cmds;
1080 ndmp_tar_reader_arg_t *argp = ptr;
1081
1082 if (!argp)
1083 return ((void *)(uintptr_t)-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 ((void *)(uintptr_t)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.
1160 */
1161 cmds->tcs_reader_count--;
1162 lcmd->tc_ref--;
1163 return ((void *)(uintptr_t)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
ndmpd_tar_backup(ndmpd_session_t * session,ndmpd_module_params_t * mod_params,ndmp_lbr_params_t * nlp)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
ndmpd_tar_restore(ndmpd_session_t * session,ndmpd_module_params_t * mod_params,ndmp_lbr_params_t * nlp)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, ndmp_tar_reader, &arg);
1318 if (err == 0) {
1319 tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
1320 } else {
1321 NDMP_LOG(LOG_DEBUG, "Launch ndmp_tar_reader: %m");
1322 return (-1);
1323 }
1324
1325 if (!ndmp_check_utf8magic(cmds->tcs_command)) {
1326 NDMP_LOG(LOG_DEBUG, "UTF8Magic not found!");
1327 } else {
1328 NDMP_LOG(LOG_DEBUG, "UTF8Magic found");
1329 }
1330
1331 (void) memset(&tlm_arg, 0, sizeof (tlm_backup_restore_arg_t));
1332 (void) pthread_barrier_init(&tlm_arg.ba_barrier, 0, 2);
1333
1334 /*
1335 * Set up restore parameters
1336 */
1337 tlm_arg.ba_commands = cmds;
1338 tlm_arg.ba_cmd = cmds->tcs_command;
1339 tlm_arg.ba_job = nlp->nlp_jstat->js_job_name;
1340 tlm_arg.ba_dir = nlp->nlp_restore_path;
1341 for (i = 0; i < nlp->nlp_nfiles; i++) {
1342 ent = (ndmp_name *)MOD_GETNAME(mod_params, i);
1343 tlm_arg.ba_sels[i] = ent->name;
1344 }
1345
1346
1347 if (tm_tar_ops.tm_getfile != NULL) {
1348 err = pthread_create(&wrtp, NULL, tm_tar_ops.tm_getfile,
1349 &tlm_arg);
1350 } else {
1351 (void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1352 NDMP_LOG(LOG_DEBUG,
1353 "Thread create tm_getfile: ops NULL");
1354 return (-1);
1355 }
1356 if (err == 0) {
1357 (void) pthread_barrier_wait(&tlm_arg.ba_barrier);
1358 } else {
1359 (void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1360 NDMP_LOG(LOG_DEBUG, "thread create tm_getfile: %m");
1361 return (-1);
1362 }
1363
1364 (void) pthread_join(rdtp, NULL);
1365 (void) pthread_join(wrtp, NULL);
1366 (void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1367
1368 nlp->nlp_jstat->js_stop_time = time(NULL);
1369
1370 /* Send the list of un-recovered files/dirs to the client. */
1371 (void) send_unrecovered_list(mod_params, nlp);
1372
1373 ndmp_stop_local_reader(session, cmds);
1374 ndmp_wait_for_reader(cmds);
1375 ndmp_stop_remote_reader(session);
1376 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
1377 rspath, err);
1378 } else {
1379 nlp->nlp_jstat->js_stop_time = time(NULL);
1380
1381 /* nothing restored. */
1382 (void) send_unrecovered_list(mod_params, nlp);
1383 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
1384 rspath);
1385 err = -1;
1386 }
1387
1388 NDMP_FREE(nlp->nlp_restore_path);
1389 backup_release_structs(session);
1390
1391 return (err);
1392 }
1393
1394
1395 /*
1396 * prefixdir
1397 *
1398 * Extract the path for a given full path entry
1399 */
1400 static char *
prefixdir(char * dir,char * suffix)1401 prefixdir(char *dir, char *suffix)
1402 {
1403 static char tmp[TLM_MAX_PATH_NAME];
1404 char *tend, *send; /* tmp and suffix end */
1405
1406 if (dir == NULL || suffix == NULL)
1407 return (NULL);
1408
1409 if (*suffix == '\0')
1410 return (dir);
1411
1412 if (*dir == '\0')
1413 return (NULL);
1414
1415 (void) strlcpy(tmp, dir, TLM_MAX_PATH_NAME);
1416 tend = &tmp[strlen(tmp)];
1417 send = &suffix[strlen(suffix)];
1418
1419 /*
1420 * Move backward as far as the last part of the dir and
1421 * the suffix match.
1422 */
1423 while (tend >= tmp && send >= suffix)
1424 if (*tend == *send)
1425 tend--, send--;
1426 else
1427 break;
1428
1429 *++tend = '\0';
1430 return (tmp);
1431 }
1432
1433
1434 /*
1435 * get_nfiles
1436 *
1437 * Get the count of files to be restored
1438 */
1439 static int
get_nfiles(ndmpd_session_t * session,ndmpd_module_params_t * params)1440 get_nfiles(ndmpd_session_t *session, ndmpd_module_params_t *params)
1441 {
1442 if (session->ns_data.dd_nlist_len == 0) {
1443 MOD_LOG(params, "Error: nothing specified to be restored.\n");
1444 return (-1);
1445 }
1446
1447 return (session->ns_data.dd_nlist_len);
1448 }
1449
1450
1451 /*
1452 * get_restore_dest
1453 *
1454 * Get the full pathname of where the entries should be restored to.
1455 */
1456 static char *
get_restore_dest(ndmpd_module_params_t * params)1457 get_restore_dest(ndmpd_module_params_t *params)
1458 {
1459 ndmp_name *ent;
1460 char *cp;
1461
1462 /*
1463 * Destination of restore:
1464 * NetBackup of Veritas(C) sends the entries like this:
1465 *
1466 * ent[i].name: is the relative pathname of what is selected in
1467 * the GUI.
1468 * ent[i].dest: is the full pathname of where the dir/file must
1469 * be restored to.
1470 * ent[i].ssi: 0
1471 * ent[i].fh_info: 0
1472 *
1473 */
1474 ent = (ndmp_name *)MOD_GETNAME(params, 0);
1475 cp = prefixdir(ent->dest, ent->name);
1476 if (cp == NULL) {
1477 MOD_LOG(params, "Error: empty restore path.\n");
1478 return (NULL);
1479 }
1480
1481 return (cp);
1482 }
1483
1484
1485 /*
1486 * correct_ents
1487 *
1488 * Correct the entries in the restore list by appending the appropriate
1489 * path to them
1490 */
1491 static int
correct_ents(ndmpd_module_params_t * params,int n,char * bkpath)1492 correct_ents(ndmpd_module_params_t *params, int n, char *bkpath)
1493 {
1494 char *cp, *pathname;
1495 int i, len, rv;
1496 ndmp_name *ent;
1497
1498 if ((pathname = ndmp_malloc(TLM_MAX_PATH_NAME)) == NULL) {
1499 MOD_LOG(params, "Error: insufficient memory.\n");
1500 return (-1);
1501 }
1502
1503 rv = 0;
1504 /* Append the backup path to all the "ent[].name"s. */
1505 for (i = 0; i < n; i++) {
1506 ent = (ndmp_name *)MOD_GETNAME(params, i);
1507
1508 NDMP_LOG(LOG_DEBUG,
1509 "Old: ent[%d].name: \"%s\"", i, ent->name);
1510 NDMP_LOG(LOG_DEBUG,
1511 "Old: ent[%d].dest: \"%s\"", i, ent->dest);
1512
1513 /* remove trailing slash */
1514 len = strlen(ent->name);
1515 if (ent->name[len - 1] == '/')
1516 ent->name[len - 1] = '\0';
1517
1518 if (!tlm_cat_path(pathname, bkpath, ent->name)) {
1519 MOD_LOG(params, "Error: path too long.\n");
1520 rv = -1;
1521 break;
1522 }
1523
1524 /* Make a copy of the new string and save it in ent->name. */
1525 cp = strdup(pathname);
1526 if (cp == NULL) {
1527 MOD_LOG(params, "Error: insufficient memory.\n");
1528 rv = -1;
1529 break;
1530 }
1531 free(ent->name);
1532 ent->name = cp;
1533
1534 NDMP_LOG(LOG_DEBUG,
1535 "New: ent[%d].name: \"%s\"", i, ent->name);
1536 }
1537
1538 free(pathname);
1539 return (rv);
1540 }
1541
1542
1543 /*
1544 * check_restore_paths
1545 *
1546 * Go through the restore list and check the validity of the
1547 * restore path.
1548 */
1549 static int
check_restore_paths(ndmpd_module_params_t * params,int n,char * rspath)1550 check_restore_paths(ndmpd_module_params_t *params, int n, char *rspath)
1551 {
1552 int i, rv;
1553 ndmp_name *ent;
1554
1555 rv = 0;
1556 if (rspath != NULL && *rspath != '\0') {
1557 NDMP_LOG(LOG_DEBUG, "rspath: \"%s\"", rspath);
1558 if (!fs_volexist(rspath)) {
1559 MOD_LOG(params,
1560 "Error: Invalid volume name for restore.");
1561 rv = -1;
1562 }
1563 } else {
1564 for (i = 0; i < n; i++) {
1565 ent = (ndmp_name *)MOD_GETNAME(params, i);
1566 NDMP_LOG(LOG_DEBUG,
1567 "ent[%d].name: \"%s\"", i, ent->name);
1568
1569 if (!fs_volexist(ent->name)) {
1570 MOD_LOG(params,
1571 "Error: Invalid volume name for restore.",
1572 ent->name);
1573 rv = -1;
1574 break;
1575 }
1576 }
1577 }
1578
1579 return (rv);
1580 }
1581
1582
1583 /*
1584 * check_backup_dir_validity
1585 *
1586 * Check if the backup directory is valid. Make sure it exists and
1587 * is writable. Check for snapshot and readonly cases.
1588 */
1589 static int
check_backup_dir_validity(ndmpd_module_params_t * params,char * bkpath)1590 check_backup_dir_validity(ndmpd_module_params_t *params, char *bkpath)
1591 {
1592 char *msg;
1593 int rv;
1594 struct stat64 st;
1595
1596 rv = NDMP_NO_ERR;
1597 if (stat64(bkpath, &st) < 0) {
1598 msg = strerror(errno);
1599 MOD_LOG(params, "Error: stat(%s): %s.\n", bkpath, msg);
1600 rv = NDMP_ILLEGAL_ARGS_ERR;
1601 } else if (!S_ISDIR(st.st_mode)) {
1602 MOD_LOG(params, "Error: %s is not a directory.\n", bkpath);
1603 rv = NDMP_ILLEGAL_ARGS_ERR;
1604 } else if (fs_is_rdonly(bkpath) && !fs_is_chkpntvol(bkpath) &&
1605 fs_is_chkpnt_enabled(bkpath)) {
1606 MOD_LOG(params, "Error: %s is not a checkpointed path.\n",
1607 bkpath);
1608 rv = NDMP_BAD_FILE_ERR;
1609 }
1610
1611 return (rv);
1612 }
1613
1614
1615 /*
1616 * ndmp_backup_extract_params
1617 *
1618 * Go through the backup parameters and check the validity
1619 * for each one. Then set the NLP flags according to the parameters.
1620 */
1621 int
ndmp_backup_extract_params(ndmpd_session_t * session,ndmpd_module_params_t * params)1622 ndmp_backup_extract_params(ndmpd_session_t *session,
1623 ndmpd_module_params_t *params)
1624 {
1625 char *cp;
1626 int rv;
1627 ndmp_lbr_params_t *nlp;
1628
1629 /* Extract directory to be backed up from env variables */
1630 if ((nlp = ndmp_get_nlp(session)) == NULL) {
1631 MOD_LOG(params, "Error: Internal error: nlp == NULL.\n");
1632 return (NDMP_ILLEGAL_ARGS_ERR);
1633 }
1634 if ((nlp->nlp_backup_path = get_backup_path_v2(params)) == NULL)
1635 return (NDMP_FILE_NOT_FOUND_ERR);
1636
1637 if ((rv = check_backup_dir_validity(params,
1638 nlp->nlp_backup_path)) != NDMP_NO_ERR)
1639 return (rv);
1640
1641 /* Should the st_ctime be ignored when backing up? */
1642 if (ndmp_ignore_ctime) {
1643 NDMP_LOG(LOG_DEBUG, "ignoring st_ctime");
1644 NLP_SET(nlp, NLPF_IGNCTIME);
1645 } else
1646 NLP_UNSET(nlp, NLPF_IGNCTIME);
1647
1648 /* Should the st_lmtime be ignored when backing up? */
1649 if (ndmp_include_lmtime) {
1650 NDMP_LOG(LOG_DEBUG, "including st_lmtime");
1651 NLP_SET(nlp, NLPF_INCLMTIME);
1652 } else
1653 NLP_UNSET(nlp, NLPF_INCLMTIME);
1654
1655 NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
1656
1657 /* Is backup history requested? */
1658 cp = MOD_GETENV(params, "HIST");
1659 if (cp == NULL) {
1660 NDMP_LOG(LOG_DEBUG, "env(HIST) not specified");
1661 NLP_UNSET(nlp, NLPF_FH);
1662 } else {
1663 NDMP_LOG(LOG_DEBUG, "env(HIST): \"%s\"", cp);
1664
1665 if (strchr("t_ty_y", *cp))
1666 NLP_SET(nlp, NLPF_FH);
1667 else
1668 NLP_UNSET(nlp, NLPF_FH);
1669 }
1670
1671 nlp->nlp_clevel = 0;
1672 /* Is it an incremental backup? */
1673 cp = MOD_GETENV(params, "LEVEL");
1674 if (cp == NULL) {
1675 NDMP_LOG(LOG_DEBUG,
1676 "env(LEVEL) not specified, default to 0");
1677 } else if (*cp < '0' || *cp > '9' || *(cp+1) != '\0') {
1678 NDMP_LOG(LOG_DEBUG, "Invalid backup level '%s'", cp);
1679 return (NDMP_ILLEGAL_ARGS_ERR);
1680 } else
1681 nlp->nlp_clevel = *cp - '0';
1682
1683 /* Extract last backup time from the dumpdates file */
1684 nlp->nlp_llevel = nlp->nlp_clevel;
1685 nlp->nlp_ldate = 0;
1686 if (ndmpd_get_dumptime(nlp->nlp_backup_path, &nlp->nlp_llevel,
1687 &nlp->nlp_ldate) < 0) {
1688 MOD_LOG(params, "Error: getting dumpdate for %s level %d\n",
1689 nlp->nlp_backup_path, nlp->nlp_clevel);
1690 return (NDMP_NO_MEM_ERR);
1691 }
1692
1693 NDMP_LOG(LOG_DEBUG,
1694 "Date of this level %d on \"%s\": %s",
1695 nlp->nlp_clevel, nlp->nlp_backup_path, cctime(&nlp->nlp_cdate));
1696 NDMP_LOG(LOG_DEBUG,
1697 "Date of last level %d on \"%s\": %s",
1698 nlp->nlp_llevel, nlp->nlp_backup_path, cctime(&nlp->nlp_ldate));
1699
1700 /* Should the dumpdate file be updated? */
1701 cp = MOD_GETENV(params, "UPDATE");
1702 if (cp == NULL) {
1703 NDMP_LOG(LOG_DEBUG,
1704 "env(UPDATE) not specified, default to TRUE");
1705 NLP_SET(nlp, NLPF_UPDATE);
1706 } else {
1707 NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", cp);
1708 if (strchr("t_ty_y", *cp) != NULL)
1709 NLP_SET(nlp, NLPF_UPDATE);
1710 else
1711 NLP_UNSET(nlp, NLPF_UPDATE);
1712 }
1713
1714 return (NDMP_NO_ERR);
1715 }
1716
1717
1718
1719 /*
1720 * log_bk_params_v2
1721 *
1722 * Dump the value of the parameters in the log file for debugging.
1723 */
1724 void
log_bk_params_v2(ndmpd_session_t * session,ndmpd_module_params_t * params,ndmp_lbr_params_t * nlp)1725 log_bk_params_v2(ndmpd_session_t *session, ndmpd_module_params_t *params,
1726 ndmp_lbr_params_t *nlp)
1727 {
1728 MOD_LOG(params, "Date of this level %d on \"%s\": %s\n",
1729 nlp->nlp_clevel, nlp->nlp_backup_path, cctime(&nlp->nlp_cdate));
1730 MOD_LOG(params, "Date of last level %d on \"%s\": %s\n",
1731 nlp->nlp_llevel, nlp->nlp_backup_path, cctime(&nlp->nlp_ldate));
1732
1733 MOD_LOG(params, "Backing up: \"%s\".\n", nlp->nlp_backup_path);
1734 MOD_LOG(params, "Record size: %d\n", session->ns_mover.md_record_size);
1735 MOD_LOG(params, "File history: %c.\n",
1736 NDMP_YORN(NLP_ISSET(nlp, NLPF_FH)));
1737 MOD_LOG(params, "Update: %s\n",
1738 NLP_ISSET(nlp, NLPF_UPDATE) ? "TRUE" : "FALSE");
1739
1740 }
1741
1742
1743 /*
1744 * same_path
1745 *
1746 * Find out if the paths are the same regardless of the ending slash
1747 *
1748 * Examples :
1749 * /a/b/c == /a/b/c
1750 * /a/b/c/ == /a/b/c
1751 * /a/b/c == /a/b/c/
1752 */
1753 static boolean_t
same_path(char * s,char * t)1754 same_path(char *s, char *t)
1755 {
1756 boolean_t rv;
1757 int slen, tlen;
1758
1759 rv = FALSE;
1760 slen = strlen(s);
1761 tlen = strlen(t);
1762 if (slen == tlen && strcmp(s, t) == 0) {
1763 rv = TRUE;
1764 } else {
1765 if (slen == tlen - 1) {
1766 if (strncmp(s, t, slen) == 0 && t[tlen - 1] == '/')
1767 rv = TRUE;
1768 } else if (tlen == slen -1) {
1769 if (strncmp(s, t, tlen) == 0 && s[slen - 1] == '/')
1770 rv = TRUE;
1771 }
1772 }
1773
1774 NDMP_LOG(LOG_DEBUG, "rv: %d", rv);
1775 return (rv);
1776 }
1777
1778
1779 /*
1780 * ndmp_restore_extract_params
1781 *
1782 * Go through the restore parameters and check them and extract them
1783 * by setting NLP flags and other values.
1784 *
1785 * Parameters:
1786 *
1787 * Returns:
1788 * 0: on success
1789 * -1: otherwise
1790 */
1791 int
ndmp_restore_extract_params(ndmpd_session_t * session,ndmpd_module_params_t * params)1792 ndmp_restore_extract_params(ndmpd_session_t *session,
1793 ndmpd_module_params_t *params)
1794 {
1795 char *bkpath, *rspath;
1796 ndmp_lbr_params_t *nlp;
1797
1798 if ((nlp = ndmp_get_nlp(session)) == NULL) {
1799 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1800 return (-1);
1801 }
1802
1803 /* Extract directory from where the backup was made. */
1804 if ((bkpath = get_backup_path_v2(params)) == NULL)
1805 return (NDMP_ILLEGAL_ARGS_ERR);
1806
1807 nlp->nlp_restore_bk_path = bkpath;
1808
1809 /* The number of the selections. */
1810 if ((nlp->nlp_nfiles = get_nfiles(session, params)) == 0)
1811 return (NDMP_ILLEGAL_ARGS_ERR);
1812
1813 NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
1814
1815 if ((rspath = get_restore_dest(params)) == NULL)
1816 return (NDMP_ILLEGAL_ARGS_ERR);
1817
1818 if (fs_is_rdonly(rspath)) {
1819 MOD_LOG(params,
1820 "Error: Can't restore to a read-only volume: \"%s\"\n",
1821 rspath);
1822 return (NDMP_ILLEGAL_ARGS_ERR);
1823 }
1824 if (fs_is_chkpntvol(rspath)) {
1825 MOD_LOG(params,
1826 "Error: Can't restore to a checkpoint: \"%s\"\n", rspath);
1827 return (NDMP_ILLEGAL_ARGS_ERR);
1828 }
1829
1830 if (same_path(bkpath, rspath))
1831 rspath = "";
1832
1833 if ((nlp->nlp_restore_path = strdup(rspath)) == NULL)
1834 return (NDMP_NO_MEM_ERR);
1835
1836 bkpath = trim_name(bkpath);
1837 if (correct_ents(params, nlp->nlp_nfiles, bkpath) < 0) {
1838 free(nlp->nlp_restore_path);
1839 return (NDMP_ILLEGAL_ARGS_ERR);
1840 }
1841
1842 if (check_restore_paths(params, nlp->nlp_nfiles, rspath) < 0) {
1843 free(nlp->nlp_restore_path);
1844 return (NDMP_ILLEGAL_ARGS_ERR);
1845 }
1846
1847 MOD_LOG(params, "Restoring %d files.\n", nlp->nlp_nfiles);
1848 MOD_LOG(params, "Restoring to: \"%s\".\n", nlp->nlp_restore_path);
1849 MOD_LOG(params, "Record size: %d\n", session->ns_mover.md_record_size);
1850
1851 return (NDMP_NO_ERR);
1852 }
1853
1854 /*
1855 * ndmpd_tar_backup_starter (V2 only)
1856 *
1857 * The main backup starter function. It creates a snapshot if necessary
1858 * and calls ndmp_tar_backup to perform the actual backup. It does the cleanup
1859 * and release the snapshot at the end.
1860 */
1861 void *
ndmpd_tar_backup_starter(void * arg)1862 ndmpd_tar_backup_starter(void *arg)
1863 {
1864 ndmpd_module_params_t *mod_params = arg;
1865 int err;
1866 ndmpd_session_t *session;
1867 ndmp_lbr_params_t *nlp;
1868
1869 session = (ndmpd_session_t *)(mod_params->mp_daemon_cookie);
1870 *(mod_params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
1871 ndmp_session_ref(session);
1872
1873 err = 0;
1874 if (fs_is_chkpntvol(nlp->nlp_backup_path) ||
1875 fs_is_rdonly(nlp->nlp_backup_path) ||
1876 !fs_is_chkpnt_enabled(nlp->nlp_backup_path))
1877 NLP_SET(nlp, NLPF_CHKPNTED_PATH);
1878 else {
1879 NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
1880 if (ndmp_create_snapshot(nlp->nlp_backup_path,
1881 nlp->nlp_jstat->js_job_name) < 0) {
1882 MOD_LOG(mod_params,
1883 "Error: creating checkpoint on %s\n",
1884 nlp->nlp_backup_path);
1885 /* -1 causes halt reason to become internal error. */
1886 err = -1;
1887 }
1888 }
1889
1890 NDMP_LOG(LOG_DEBUG, "NLPF_CHKPNTED_PATH: %c",
1891 NDMP_YORN(NLP_ISCHKPNTED(nlp)));
1892 NDMP_LOG(LOG_DEBUG, "err: %d, update %c",
1893 err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
1894
1895 if (err == 0) {
1896 err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate,
1897 nlp->nlp_jstat->js_job_name);
1898 if (err != 0) {
1899 NDMP_LOG(LOG_DEBUG, "err %d", err);
1900 } else {
1901 log_bk_params_v2(session, mod_params, nlp);
1902 err = ndmpd_tar_backup(session, mod_params, nlp);
1903 }
1904 }
1905
1906 if (nlp->nlp_bkmap >= 0) {
1907 (void) dbm_free(nlp->nlp_bkmap);
1908 nlp->nlp_bkmap = -1;
1909 }
1910
1911 if (!NLP_ISCHKPNTED(nlp))
1912 (void) ndmp_remove_snapshot(nlp->nlp_backup_path,
1913 nlp->nlp_jstat->js_job_name);
1914
1915 NDMP_LOG(LOG_DEBUG, "err %d, update %c",
1916 err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
1917
1918 if (err == 0 && NLP_SHOULD_UPDATE(nlp)) {
1919 if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel,
1920 nlp->nlp_cdate) < 0) {
1921 err = EPERM;
1922 MOD_LOG(mod_params,
1923 "Error: updating the dumpdates file on %s\n",
1924 nlp->nlp_backup_path);
1925 }
1926 }
1927
1928 MOD_DONE(mod_params, err);
1929
1930 /* nlp_params is allocated in start_backup() */
1931 NDMP_FREE(nlp->nlp_params);
1932
1933 NS_DEC(nbk);
1934 ndmp_session_unref(session);
1935 return ((void *)(uintptr_t)err);
1936 }
1937
1938
1939 /*
1940 * ndmpd_tar_backup_abort
1941 *
1942 * Abort the running backup by stopping the reader thread (V2 only)
1943 */
1944 int
ndmpd_tar_backup_abort(void * module_cookie)1945 ndmpd_tar_backup_abort(void *module_cookie)
1946 {
1947 ndmp_lbr_params_t *nlp;
1948
1949 nlp = (ndmp_lbr_params_t *)module_cookie;
1950 if (nlp != NULL && nlp->nlp_session != NULL) {
1951 if (nlp->nlp_session->ns_data.dd_mover.addr_type ==
1952 NDMP_ADDR_TCP && nlp->nlp_session->ns_data.dd_sock != -1) {
1953 (void) close(nlp->nlp_session->ns_data.dd_sock);
1954 nlp->nlp_session->ns_data.dd_sock = -1;
1955 }
1956 ndmp_stop_reader_thread(nlp->nlp_session);
1957 }
1958
1959 return (0);
1960 }
1961
1962 /*
1963 * ndmpd_tar_restore_starter
1964 *
1965 * Starts the restore by running ndmpd_tar_restore function (V2 only)
1966 */
1967
1968 void *
ndmpd_tar_restore_starter(void * arg)1969 ndmpd_tar_restore_starter(void *arg)
1970 {
1971 ndmpd_module_params_t *mod_params = arg;
1972 int err;
1973 ndmpd_session_t *session;
1974 ndmp_lbr_params_t *nlp;
1975
1976 session = (ndmpd_session_t *)(mod_params->mp_daemon_cookie);
1977 *(mod_params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
1978 ndmp_session_ref(session);
1979
1980 err = ndmpd_tar_restore(session, mod_params, nlp);
1981 MOD_DONE(mod_params, err);
1982
1983 /* nlp_params is allocated in start_recover() */
1984 NDMP_FREE(nlp->nlp_params);
1985
1986 NS_DEC(nrs);
1987 ndmp_session_unref(session);
1988 return ((void *)(uintptr_t)err);
1989 }
1990
1991
1992 /*
1993 * ndmpd_tar_restore_abort
1994 *
1995 * Aborts the restore operation by stopping the writer thread (V2 only)
1996 */
1997 int
ndmpd_tar_restore_abort(void * module_cookie)1998 ndmpd_tar_restore_abort(void *module_cookie)
1999 {
2000 ndmp_lbr_params_t *nlp;
2001
2002 nlp = (ndmp_lbr_params_t *)module_cookie;
2003 if (nlp != NULL && nlp->nlp_session != NULL) {
2004 (void) mutex_lock(&nlp->nlp_mtx);
2005 if (nlp->nlp_session->ns_data.dd_mover.addr_type ==
2006 NDMP_ADDR_TCP && nlp->nlp_session->ns_data.dd_sock != -1) {
2007 (void) close(nlp->nlp_session->ns_data.dd_sock);
2008 nlp->nlp_session->ns_data.dd_sock = -1;
2009 }
2010 (void) cond_broadcast(&nlp->nlp_cv);
2011 (void) mutex_unlock(&nlp->nlp_mtx);
2012 ndmp_stop_writer_thread(nlp->nlp_session);
2013 }
2014
2015 return (0);
2016 }
2017