2 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
9 * Copyright (c) 2007, The Storage Networking Industry Association.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
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
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
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.
39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
42 #include <sys/types.h>
43 #include <sys/param.h>
45 #include <sys/fs/zfs.h>
55 #include "ndmpd_common.h"
59 char nzs_findprop
[ZFS_MAXPROPLEN
]; /* prop substring to find */
60 char nzs_snapname
[ZFS_MAX_DATASET_NAME_LEN
]; /* snap's name */
61 char nzs_snapprop
[ZFS_MAXPROPLEN
]; /* snap's prop value */
62 char nzs_snapskip
[ZFS_MAXPROPLEN
]; /* snap to skip */
63 uint32_t nzs_prop_major
; /* property major version */
64 uint32_t nzs_prop_minor
; /* property minor version */
65 } ndmpd_zfs_snapfind_t
;
67 mutex_t ndmpd_zfs_fd_lock
;
69 static int ndmpd_zfs_open_fds(ndmpd_zfs_args_t
*);
70 static void ndmpd_zfs_close_fds(ndmpd_zfs_args_t
*);
72 static void ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t
*, int);
74 static int ndmpd_zfs_header_write(ndmpd_session_t
*);
75 static int ndmpd_zfs_header_read(ndmpd_zfs_args_t
*);
77 static int ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t
*);
78 static int ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t
*);
80 static int ndmpd_zfs_restore(ndmpd_zfs_args_t
*);
81 static int ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t
*);
82 static int ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t
*);
84 static int ndmpd_zfs_reader_writer(ndmpd_zfs_args_t
*, int **, int **);
86 static int ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t
*, u_longlong_t
);
88 static boolean_t
ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t
*);
89 static int ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t
*, char *, int);
90 static int ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t
*);
92 static boolean_t
ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t
*);
93 static int ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t
*);
94 static int ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t
*);
96 static int ndmpd_zfs_getenv(ndmpd_zfs_args_t
*);
97 static int ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t
*);
98 static int ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t
*);
99 static int ndmpd_zfs_getenv_level(ndmpd_zfs_args_t
*);
100 static int ndmpd_zfs_getenv_update(ndmpd_zfs_args_t
*);
101 static int ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t
*);
102 static int ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t
*);
104 static boolean_t
ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t
*, char *);
105 static boolean_t
ndmpd_zfs_is_incremental(ndmpd_zfs_args_t
*);
106 static int ndmpd_zfs_send_fhist(ndmpd_zfs_args_t
*);
108 static int ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t
*);
109 static int ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t
*, int);
110 static int ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t
*);
111 static int ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t
*,
112 boolean_t
, ndmpd_zfs_snapfind_t
*);
113 static boolean_t
ndmpd_zfs_snapshot_ndmpd_generated(char *);
114 static int ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t
*, ndmpd_zfs_snapfind_t
*);
116 static int ndmpd_zfs_snapshot_prop_find(zfs_handle_t
*, void *);
117 static int ndmpd_zfs_snapshot_prop_get(zfs_handle_t
*, char *);
118 static int ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t
*);
119 static int ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t
*, char *,
121 static int ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t
*, char *, int,
123 static int ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t
*,
124 ndmpd_zfs_snapfind_t
*);
125 static boolean_t
ndmpd_zfs_prop_version_check(char *, uint32_t *, uint32_t *);
127 static int ndmpd_zfs_snapname_create(ndmpd_zfs_args_t
*, char *, int);
129 static void ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t
*);
131 static int ndmpd_zfs_backup(ndmpd_zfs_args_t
*);
134 * Syntax for com.sun.ndmp:incr property value:
135 * #.#.n|u/$LEVEL.$DMP_NAME.$ZFS_MODE(/ ...)
138 * #.# is the version number
139 * 'n' means ndmp-generated; 'u' means user-supplied
140 * $LEVEL: backup (incremental) level [0-9]
141 * $DMP_NAME: set name [default: "level"]
142 * $ZFS_MODE: d | r | p [for dataset, recursive, or package]
147 * 0.0.u/1.bob.p/0.jane.d
149 * Note: NDMPD_ZFS_SUBPROP_MAX is calculated based on ZFS_MAXPROPLEN
152 #define NDMPD_ZFS_PROP_INCR "com.sun.ndmp:incr"
153 #define NDMPD_ZFS_SUBPROP_MAX 28
158 * As coded, there should be no races in the retrieval of the ZFS errno
159 * from the ndmpd_zfs_args->nz_zlibh. I.e., for a given ndmpd_zfs backup
160 * or restore, there should only ever be one ZFS library call taking place
161 * at any one moment in time.
164 #define NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, ...) { \
165 NDMP_LOG(LOG_ERR, __VA_ARGS__); \
166 NDMP_LOG(LOG_ERR, "%s--%s", \
167 libzfs_error_action((ndmpd_zfs_args)->nz_zlibh), \
168 libzfs_error_description((ndmpd_zfs_args)->nz_zlibh)); \
169 ndmpd_zfs_zerr_dma_log((ndmpd_zfs_args)); \
173 ndmpd_zfs_init(ndmpd_session_t
*session
)
175 ndmpd_zfs_args_t
*ndmpd_zfs_args
= &session
->ns_ndmpd_zfs_args
;
176 int version
= session
->ns_protocol_version
;
178 bzero(ndmpd_zfs_args
, sizeof (*ndmpd_zfs_args
));
180 if ((version
< NDMPV3
) || (version
> NDMPV4
)) {
181 NDMP_LOG(LOG_ERR
, "Unknown or unsupported version %d", version
);
185 if ((ndmpd_zfs_args
->nz_zlibh
= libzfs_init()) == NULL
) {
186 NDMP_LOG(LOG_ERR
, "libzfs init error [%d]", errno
);
190 if (ndmpd_zfs_open_fds(ndmpd_zfs_args
) < 0) {
191 NDMP_LOG(LOG_ERR
, "open_fds() failure(): %d\n", errno
);
195 ndmpd_zfs_args
->nz_bufsize
= ndmp_buffer_get_size(session
);
196 ndmpd_zfs_args
->nz_window_len
= session
->ns_mover
.md_window_length
;
198 ndmpd_zfs_args
->nz_nlp
= ndmp_get_nlp(session
);
200 assert(ndmpd_zfs_args
->nz_nlp
!= NULL
);
202 ndmpd_zfs_args
->nz_nlp
->nlp_bytes_total
= 0;
204 session
->ns_data
.dd_module
.dm_module_cookie
= ndmpd_zfs_args
;
205 session
->ns_data
.dd_data_size
= 0;
206 session
->ns_data
.dd_module
.dm_stats
.ms_est_bytes_remaining
= 0;
207 session
->ns_data
.dd_module
.dm_stats
.ms_est_time_remaining
= 0;
209 session
->ns_data
.dd_bytes_left_to_read
= 0;
210 session
->ns_data
.dd_position
= 0;
211 session
->ns_data
.dd_discard_length
= 0;
212 session
->ns_data
.dd_read_offset
= 0;
213 session
->ns_data
.dd_read_length
= 0;
215 ndmpd_zfs_params
->mp_get_env_func
= ndmpd_api_get_env
;
216 ndmpd_zfs_params
->mp_add_env_func
= ndmpd_api_add_env
;
217 ndmpd_zfs_params
->mp_set_env_func
= ndmpd_api_set_env
;
218 ndmpd_zfs_params
->mp_dispatch_func
= ndmpd_api_dispatch
;
219 ndmpd_zfs_params
->mp_daemon_cookie
= (void *)session
;
220 ndmpd_zfs_params
->mp_protocol_version
= session
->ns_protocol_version
;
221 ndmpd_zfs_params
->mp_stats
= &session
->ns_data
.dd_module
.dm_stats
;
222 ndmpd_zfs_params
->mp_add_file_handler_func
=
223 ndmpd_api_add_file_handler
;
224 ndmpd_zfs_params
->mp_remove_file_handler_func
=
225 ndmpd_api_remove_file_handler
;
226 ndmpd_zfs_params
->mp_seek_func
= 0;
230 ndmpd_zfs_params
->mp_write_func
= ndmpd_api_write_v3
;
231 ndmpd_zfs_params
->mp_read_func
= ndmpd_api_read_v3
;
232 ndmpd_zfs_params
->mp_get_name_func
= ndmpd_api_get_name_v3
;
233 ndmpd_zfs_params
->mp_done_func
= ndmpd_api_done_v3
;
234 ndmpd_zfs_params
->mp_log_func_v3
= ndmpd_api_log_v3
;
235 ndmpd_zfs_params
->mp_file_recovered_func
=
236 ndmpd_api_file_recovered_v3
;
239 ndmpd_zfs_params
->mp_write_func
= ndmpd_api_write_v3
;
240 ndmpd_zfs_params
->mp_read_func
= ndmpd_api_read_v3
;
241 ndmpd_zfs_params
->mp_get_name_func
= ndmpd_api_get_name_v3
;
242 ndmpd_zfs_params
->mp_done_func
= ndmpd_api_done_v3
;
243 ndmpd_zfs_params
->mp_log_func_v3
= ndmpd_api_log_v4
;
244 ndmpd_zfs_params
->mp_file_recovered_func
=
245 ndmpd_api_file_recovered_v4
;
248 /* error already returned above for this case */
256 ndmpd_zfs_fini(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
258 libzfs_fini(ndmpd_zfs_args
->nz_zlibh
);
260 ndmpd_zfs_close_fds(ndmpd_zfs_args
);
264 ndmpd_zfs_open_fds(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
268 err
= pipe(ndmpd_zfs_args
->nz_pipe_fd
);
270 NDMP_LOG(LOG_ERR
, "pipe(2) failed: %s:\n", strerror(errno
));
276 * ndmpd_zfs_close_fds()
278 * In the abort case, use dup2() to redirect the end of the pipe that is
279 * being written to (to a new pipe). Close the ends of the new pipe to cause
280 * EPIPE to be returned to the writing thread. This will cause the writer
281 * and reader to terminate without having any of the writer's data erroneously
282 * go to any reopened descriptor.
286 ndmpd_zfs_close_fds(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
288 ndmpd_session_t
*session
= (ndmpd_session_t
*)
289 (ndmpd_zfs_params
->mp_daemon_cookie
);
293 if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_ACTIVE
) {
294 ndmpd_zfs_close_one_fd(ndmpd_zfs_args
, PIPE_ZFS
);
295 ndmpd_zfs_close_one_fd(ndmpd_zfs_args
, PIPE_TAPE
);
299 (void) mutex_lock(&ndmpd_zfs_fd_lock
);
301 if (ndmpd_zfs_params
->mp_operation
== NDMP_DATA_OP_BACKUP
) {
304 pipe_end
= PIPE_TAPE
;
307 if (ndmpd_zfs_args
->nz_pipe_fd
[pipe_end
] != -1) {
308 if (pipe(fds
) != 0) {
309 (void) mutex_unlock(&ndmpd_zfs_fd_lock
);
310 NDMP_LOG(LOG_ERR
, "pipe(2) failed: %s:\n",
315 (void) dup2(fds
[0], ndmpd_zfs_args
->nz_pipe_fd
[pipe_end
]);
316 (void) close(fds
[0]);
317 (void) close(fds
[1]);
319 ndmpd_zfs_args
->nz_pipe_fd
[pipe_end
] = -1;
322 (void) mutex_unlock(&ndmpd_zfs_fd_lock
);
326 ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t
*ndmpd_zfs_args
, int pipe_end
)
328 (void) mutex_lock(&ndmpd_zfs_fd_lock
);
329 (void) close(ndmpd_zfs_args
->nz_pipe_fd
[pipe_end
]);
330 ndmpd_zfs_args
->nz_pipe_fd
[pipe_end
] = -1;
331 (void) mutex_unlock(&ndmpd_zfs_fd_lock
);
335 ndmpd_zfs_header_write(ndmpd_session_t
*session
)
337 ndmpd_zfs_args_t
*ndmpd_zfs_args
= &session
->ns_ndmpd_zfs_args
;
338 int32_t bufsize
= ndmpd_zfs_args
->nz_bufsize
;
339 ndmpd_zfs_header_t
*tape_header
= &ndmpd_zfs_args
->nz_tape_header
;
342 buf
= ndmp_malloc(bufsize
);
344 NDMP_LOG(LOG_DEBUG
, "buf NULL");
348 (void) strlcpy(tape_header
->nzh_magic
, NDMPUTF8MAGIC
,
349 sizeof (NDMPUTF8MAGIC
));
350 tape_header
->nzh_major
= LE_32(NDMPD_ZFS_MAJOR_VERSION
);
351 tape_header
->nzh_minor
= LE_32(NDMPD_ZFS_MINOR_VERSION
);
352 tape_header
->nzh_hdrlen
= LE_32(bufsize
);
355 (void) memcpy(buf
, tape_header
, sizeof (ndmpd_zfs_header_t
));
357 NDMP_LOG(LOG_DEBUG
, "header (major, minor, length): %u %u %u",
358 NDMPD_ZFS_MAJOR_VERSION
,
359 NDMPD_ZFS_MINOR_VERSION
,
362 if (MOD_WRITE(ndmpd_zfs_params
, buf
, bufsize
) != 0) {
364 NDMP_LOG(LOG_ERR
, "MOD_WRITE error");
370 session
->ns_data
.dd_module
.dm_stats
.ms_bytes_processed
= bufsize
;
376 ndmpd_zfs_header_read(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
378 int32_t bufsize
= ndmpd_zfs_args
->nz_bufsize
;
379 ndmpd_zfs_header_t
*tape_header
= &ndmpd_zfs_args
->nz_tape_header
;
385 buf
= ndmp_malloc(bufsize
);
387 NDMP_LOG(LOG_DEBUG
, "buf NULL");
394 * Read nz_bufsize worth of bytes first (the size of a mover record).
397 err
= MOD_READ(ndmpd_zfs_params
, buf
, bufsize
);
400 NDMP_LOG(LOG_ERR
, "MOD_READ error: %d", err
);
405 (void) memcpy(tape_header
, buf
, sizeof (ndmpd_zfs_header_t
));
407 if (strcmp(tape_header
->nzh_magic
, NDMPUTF8MAGIC
) != 0) {
408 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
409 "bad magic string\n");
413 if (tape_header
->nzh_major
> LE_32(NDMPD_ZFS_MAJOR_VERSION
)) {
414 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
415 "major number larger than supported: (%d %d)\n",
416 LE_32(tape_header
->nzh_major
), NDMPD_ZFS_MAJOR_VERSION
);
421 * Major version 0 (regardless of minor version):
422 * Header must be a multiple of the mover record size.
425 hdrlen
= LE_32(tape_header
->nzh_hdrlen
);
426 if (hdrlen
> bufsize
) {
427 header_left
= hdrlen
- bufsize
;
428 while (header_left
> 0) {
429 err
= MOD_READ(ndmpd_zfs_params
, buf
, bufsize
);
431 ndmpd_zfs_dma_log(ndmpd_zfs_args
,
432 NDMP_LOG_ERROR
, "bad header\n");
435 header_left
-= bufsize
;
439 NDMP_LOG(LOG_DEBUG
, "tape header: %s; %u %u; %u ",
440 tape_header
->nzh_magic
,
441 LE_32(tape_header
->nzh_major
),
442 LE_32(tape_header
->nzh_minor
),
443 LE_32(tape_header
->nzh_hdrlen
));
445 ndmpd_zfs_args
->nz_nlp
->nlp_bytes_total
= hdrlen
;
452 NDMP_LOG(LOG_ERR
, "tape header: %s; %u %u; %u ",
453 tape_header
->nzh_magic
,
454 LE_32(tape_header
->nzh_major
),
455 LE_32(tape_header
->nzh_minor
),
456 LE_32(tape_header
->nzh_hdrlen
));
463 ndmpd_zfs_backup_starter(void *arg
)
465 ndmpd_zfs_args_t
*ndmpd_zfs_args
= arg
;
466 ndmpd_session_t
*session
= (ndmpd_session_t
*)
467 (ndmpd_zfs_params
->mp_daemon_cookie
);
471 ndmp_session_ref(session
);
473 if (ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args
) != 0) {
478 err
= ndmpd_zfs_backup(ndmpd_zfs_args
);
480 cleanup_err
= ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args
, err
);
483 "data bytes_total(including header):%llu",
484 session
->ns_data
.dd_module
.dm_stats
.ms_bytes_processed
);
487 err
= ndmpd_zfs_send_fhist(ndmpd_zfs_args
);
491 MOD_DONE(ndmpd_zfs_params
, err
? err
: cleanup_err
);
492 ndmp_session_unref(session
);
493 ndmpd_zfs_fini(ndmpd_zfs_args
);
499 ndmpd_zfs_send_fhist(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
501 ndmpd_session_t
*session
= (ndmpd_session_t
*)
502 (ndmpd_zfs_params
->mp_daemon_cookie
);
506 envp
= MOD_GETENV(ndmpd_zfs_params
, "HIST");
510 if (!(strchr("YT", toupper(*envp
)))) {
511 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_WARNING
,
512 "HIST is not set. No file history will be "
517 /* Build up a sample root dir stat */
518 (void) memset(&st
, 0, sizeof (struct stat64
));
519 st
.st_mode
= S_IFDIR
| 0777;
520 st
.st_mtime
= st
.st_atime
= st
.st_ctime
= time(NULL
);
521 st
.st_uid
= st
.st_gid
= 0;
525 if (ndmpd_api_file_history_dir_v3(session
, ".", ROOT_INODE
,
528 if (ndmpd_api_file_history_dir_v3(session
, "..", ROOT_INODE
,
531 if (ndmpd_api_file_history_node_v3(session
, ROOT_INODE
, &st
, 0) != 0)
534 ndmpd_file_history_cleanup(session
, TRUE
);
539 ndmpd_zfs_backup(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
541 ndmpd_session_t
*session
= (ndmpd_session_t
*)
542 (ndmpd_zfs_params
->mp_daemon_cookie
);
543 int *read_err
= NULL
;
544 int *write_err
= NULL
;
551 if (!session
->ns_data
.dd_abort
) {
552 if (ndmpd_zfs_header_write(session
)) {
553 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
554 "ndmpd_zfs header write error\n");
558 err
= ndmpd_zfs_reader_writer(ndmpd_zfs_args
,
559 &read_err
, &write_err
);
561 if (err
|| read_err
|| write_err
|| session
->ns_eof
)
565 if (session
->ns_data
.dd_abort
) {
566 ndmpd_audit_backup(session
->ns_connection
,
567 ndmpd_zfs_args
->nz_dataset
,
568 session
->ns_data
.dd_data_addr
.addr_type
,
569 ndmpd_zfs_args
->nz_dataset
, EINTR
);
570 NDMP_LOG(LOG_DEBUG
, "Backing up \"%s\" aborted.",
571 ndmpd_zfs_args
->nz_dataset
);
573 (void) ndmpd_zfs_post_backup(ndmpd_zfs_args
);
576 ndmpd_audit_backup(session
->ns_connection
,
577 ndmpd_zfs_args
->nz_dataset
,
578 session
->ns_data
.dd_data_addr
.addr_type
,
579 ndmpd_zfs_args
->nz_dataset
, result
);
581 err
= ndmpd_zfs_post_backup(ndmpd_zfs_args
);
586 NDMP_LOG(LOG_DEBUG
, "Backing up \"%s\" finished.",
587 ndmpd_zfs_args
->nz_dataset
);
589 NDMP_LOG(LOG_DEBUG
, "An error occurred while backing up"
590 " \"%s\"", ndmpd_zfs_args
->nz_dataset
);
598 * ndmpd_zfs_backup_send_read()
600 * This routine executes zfs_send() to create the backup data stream.
601 * The value of ZFS_MODE determines the type of zfs_send():
602 * dataset ('d'): Only the dataset specified (i.e., top level) is backed up
603 * recursive ('r'): The dataset and its child file systems are backed up
604 * package ('p'): Same as 'r', except all intermediate snapshots are also
607 * Volumes do not have descednants, so 'd' and 'r' produce equivalent results.
611 ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
613 ndmpd_session_t
*session
= (ndmpd_session_t
*)
614 (ndmpd_zfs_params
->mp_daemon_cookie
);
615 sendflags_t flags
= { 0 };
616 char *fromsnap
= NULL
;
620 zhp
= zfs_open(ndmpd_zfs_args
->nz_zlibh
,
621 ndmpd_zfs_args
->nz_dataset
, ndmpd_zfs_args
->nz_type
);
624 if (!session
->ns_data
.dd_abort
)
625 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args
, "zfs_open");
629 switch (ndmpd_zfs_args
->nz_zfs_mode
) {
631 flags
.props
= B_TRUE
;
634 flags
.replicate
= B_TRUE
;
637 flags
.doall
= B_TRUE
;
638 flags
.replicate
= B_TRUE
;
641 NDMP_LOG(LOG_ERR
, "unknown zfs_mode: %c",
642 ndmpd_zfs_args
->nz_zfs_mode
);
647 if (ndmpd_zfs_is_incremental(ndmpd_zfs_args
)) {
648 if (ndmpd_zfs_args
->nz_fromsnap
[0] == '\0') {
649 NDMP_LOG(LOG_ERR
, "no fromsnap");
653 fromsnap
= ndmpd_zfs_args
->nz_fromsnap
;
656 err
= zfs_send(zhp
, fromsnap
, ndmpd_zfs_args
->nz_snapname
, &flags
,
657 ndmpd_zfs_args
->nz_pipe_fd
[PIPE_ZFS
], NULL
, NULL
, NULL
);
659 if (err
&& !session
->ns_data
.dd_abort
)
660 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args
, "zfs_send: %d", err
);
668 * ndmpd_zfs_backup_tape_write()
670 * The data begins on a mover record boundary (because
671 * the header is the size of a mover record--i.e.
672 * ndmpd_zfs_args->nz_bufsize).
676 ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
678 ndmpd_session_t
*session
= (ndmpd_session_t
*)
679 (ndmpd_zfs_params
->mp_daemon_cookie
);
680 int bufsize
= ndmpd_zfs_args
->nz_bufsize
;
681 u_longlong_t
*bytes_totalp
;
685 buf
= ndmp_malloc(bufsize
);
687 NDMP_LOG(LOG_DEBUG
, "buf NULL");
692 &(session
->ns_data
.dd_module
.dm_stats
.ms_bytes_processed
);
697 count
= read(ndmpd_zfs_args
->nz_pipe_fd
[PIPE_TAPE
], buf
,
700 if (count
== 0) /* EOF */ {
702 "zfs_send stream size: %llu bytes; "
703 "full backup size (including header): %llu",
704 *bytes_totalp
- bufsize
, *bytes_totalp
);
707 return (ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args
,
712 NDMP_LOG(LOG_DEBUG
, "pipe read error (errno %d)",
717 NS_ADD(rdisk
, count
);
719 if (MOD_WRITE(ndmpd_zfs_params
, buf
, count
) != 0) {
720 (void) ndmpd_zfs_abort((void *) ndmpd_zfs_args
);
721 NDMP_LOG(LOG_ERR
, "MOD_WRITE error");
726 *bytes_totalp
+= count
;
732 ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t
*ndmpd_zfs_args
,
733 u_longlong_t bytes_total
)
735 char zfs_backup_size
[32];
738 (void) snprintf(zfs_backup_size
, sizeof (zfs_backup_size
), "%llu",
741 err
= MOD_ADDENV(ndmpd_zfs_params
, "ZFS_BACKUP_SIZE", zfs_backup_size
);
744 NDMP_LOG(LOG_ERR
, "Failed to add ZFS_BACKUP_SIZE env");
748 NDMP_LOG(LOG_DEBUG
, "Added ZFS_BACKUP_SIZE env: %s", zfs_backup_size
);
754 ndmpd_zfs_restore_starter(void *arg
)
756 ndmpd_zfs_args_t
*ndmpd_zfs_args
= arg
;
757 ndmpd_session_t
*session
= (ndmpd_session_t
*)
758 (ndmpd_zfs_params
->mp_daemon_cookie
);
761 ndmp_session_ref(session
);
763 err
= ndmpd_zfs_restore(ndmpd_zfs_args
);
765 MOD_DONE(ndmpd_zfs_params
, err
);
769 ndmp_session_unref(session
);
771 ndmpd_zfs_fini(ndmpd_zfs_args
);
777 ndmpd_zfs_restore(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
779 ndmpd_session_t
*session
= (ndmpd_session_t
*)
780 (ndmpd_zfs_params
->mp_daemon_cookie
);
781 int *read_err
= NULL
;
782 int *write_err
= NULL
;
786 if (!session
->ns_data
.dd_abort
) {
787 if (ndmpd_zfs_header_read(ndmpd_zfs_args
)) {
788 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
789 "ndmpd_zfs header read error\n");
793 err
= ndmpd_zfs_reader_writer(ndmpd_zfs_args
,
794 &write_err
, &read_err
);
796 if (err
|| read_err
|| write_err
|| session
->ns_eof
)
800 if (session
->ns_data
.dd_abort
) {
801 NDMP_LOG(LOG_DEBUG
, "Restoring to \"%s\" aborted.",
802 ndmpd_zfs_args
->nz_dataset
);
803 ndmpd_audit_restore(session
->ns_connection
,
804 ndmpd_zfs_args
->nz_dataset
,
805 session
->ns_data
.dd_data_addr
.addr_type
,
806 ndmpd_zfs_args
->nz_dataset
, EINTR
);
807 (void) ndmpd_zfs_post_restore(ndmpd_zfs_args
);
810 ndmpd_audit_restore(session
->ns_connection
,
811 ndmpd_zfs_args
->nz_dataset
,
812 session
->ns_data
.dd_data_addr
.addr_type
,
813 ndmpd_zfs_args
->nz_dataset
, result
);
814 err
= ndmpd_zfs_post_restore(ndmpd_zfs_args
);
819 NDMP_LOG(LOG_DEBUG
, "Restoring to \"%s\" finished",
820 ndmpd_zfs_args
->nz_dataset
);
822 NDMP_LOG(LOG_DEBUG
, "An error occurred while restoring"
823 " to \"%s\"", ndmpd_zfs_args
->nz_dataset
);
831 ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
833 ndmpd_session_t
*session
= (ndmpd_session_t
*)
834 (ndmpd_zfs_params
->mp_daemon_cookie
);
835 int bufsize
= ndmpd_zfs_args
->nz_bufsize
;
836 u_longlong_t backup_size
= ndmpd_zfs_args
->nz_zfs_backup_size
;
837 u_longlong_t
*bytes_totalp
;
843 buf
= ndmp_malloc(bufsize
);
845 NDMP_LOG(LOG_DEBUG
, "buf NULL");
849 bytes_totalp
= &ndmpd_zfs_args
->nz_nlp
->nlp_bytes_total
;
851 while (*bytes_totalp
< backup_size
) {
853 bytes
= backup_size
- *bytes_totalp
;
855 if (bytes
>= bufsize
)
858 err
= MOD_READ(ndmpd_zfs_params
, buf
, bytes
);
861 NDMP_LOG(LOG_ERR
, "MOD_READ error: %d; returning -1",
867 count
= write(ndmpd_zfs_args
->nz_pipe_fd
[PIPE_TAPE
], buf
,
870 if (count
!= bytes
) {
871 NDMP_LOG(LOG_ERR
, "count (%d) != bytes (%d)",
875 NDMP_LOG(LOG_ERR
, "pipe write error: errno: %d",
878 if (session
->ns_data
.dd_abort
)
879 NDMP_LOG(LOG_DEBUG
, "abort set");
886 NS_ADD(wdisk
, count
);
888 *bytes_totalp
+= count
;
896 * ndmpd_zfs_restore_recv_write()
898 * This routine executes zfs_receive() to restore the backup.
902 ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
904 ndmpd_session_t
*session
= (ndmpd_session_t
*)
905 (ndmpd_zfs_params
->mp_daemon_cookie
);
909 bzero(&flags
, sizeof (recvflags_t
));
911 flags
.nomount
= B_TRUE
;
913 NDMP_LOG(LOG_DEBUG
, "nz_zfs_force: %d\n", ndmpd_zfs_args
->nz_zfs_force
);
915 if (ndmpd_zfs_args
->nz_zfs_force
)
916 flags
.force
= B_TRUE
;
918 err
= zfs_receive(ndmpd_zfs_args
->nz_zlibh
, ndmpd_zfs_args
->nz_dataset
,
919 NULL
, &flags
, ndmpd_zfs_args
->nz_pipe_fd
[PIPE_ZFS
], NULL
);
921 if (err
&& !session
->ns_data
.dd_abort
)
922 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args
, "zfs_receive: %d", err
);
928 * ndmpd_zfs_reader_writer()
930 * Two separate threads are used for actual backup or restore.
934 ndmpd_zfs_reader_writer(ndmpd_zfs_args_t
*ndmpd_zfs_args
,
935 int **sendrecv_errp
, int **tape_errp
)
937 funct_t sendrecv_func
;
942 switch (ndmpd_zfs_params
->mp_operation
) {
943 case NDMP_DATA_OP_BACKUP
:
944 sendrecv_func
= (funct_t
)ndmpd_zfs_backup_send_read
;
945 tape_func
= (funct_t
)ndmpd_zfs_backup_tape_write
;
947 case NDMP_DATA_OP_RECOVER
:
948 sendrecv_func
= (funct_t
)ndmpd_zfs_restore_recv_write
;
949 tape_func
= (funct_t
)ndmpd_zfs_restore_tape_read
;
953 sendrecv_err
= pthread_create(&ndmpd_zfs_args
->nz_sendrecv_thread
,
954 NULL
, sendrecv_func
, ndmpd_zfs_args
);
956 if (sendrecv_err
== 0) {
957 tape_err
= pthread_create(&ndmpd_zfs_args
->nz_tape_thread
,
958 NULL
, tape_func
, ndmpd_zfs_args
);
962 * The close of the tape side of the pipe will cause
963 * nz_sendrecv_thread to error in the zfs_send/recv()
964 * call and to return. Hence we do not need
965 * to explicitly cancel the sendrecv_thread here
966 * (the pthread_join() below is sufficient).
969 (void) close(ndmpd_zfs_args
->nz_pipe_fd
[PIPE_TAPE
]);
970 NDMP_LOG(LOG_ERR
, "Could not start tape thread; "
974 (void) pthread_join(ndmpd_zfs_args
->nz_sendrecv_thread
,
975 (void **) sendrecv_errp
);
978 if ((tape_err
== 0) &&
979 (ndmpd_zfs_params
->mp_operation
== NDMP_DATA_OP_RECOVER
))
980 ndmpd_zfs_close_one_fd(ndmpd_zfs_args
, PIPE_TAPE
);
982 ndmpd_zfs_close_one_fd(ndmpd_zfs_args
, PIPE_ZFS
);
984 if ((sendrecv_err
== 0) && (tape_err
== 0)) {
985 (void) pthread_join(ndmpd_zfs_args
->nz_tape_thread
,
986 (void **) tape_errp
);
989 if ((tape_err
== 0) &&
990 (ndmpd_zfs_params
->mp_operation
== NDMP_DATA_OP_BACKUP
))
991 ndmpd_zfs_close_one_fd(ndmpd_zfs_args
, PIPE_TAPE
);
993 return (sendrecv_err
? sendrecv_err
: tape_err
);
997 ndmpd_zfs_abort(void *arg
)
999 ndmpd_zfs_args_t
*ndmpd_zfs_args
= arg
;
1002 if (ndmpd_zfs_params
->mp_operation
== NDMP_DATA_OP_BACKUP
)
1003 (void) strlcpy(str
, "backup", 8);
1005 (void) strlcpy(str
, "recover", 8);
1007 NDMP_LOG(LOG_ERR
, "ndmpd_zfs_abort() called...aborting %s operation",
1010 ndmpd_zfs_close_fds(ndmpd_zfs_args
);
1016 * ndmpd_zfs_pre_backup()
1018 * Note: The memset to 0 of nctxp ensures that nctx->nc_cmds == NULL.
1019 * This ensures that ndmp_include_zfs() will fail, which is
1020 * a requirement for "zfs"-type backup.
1024 ndmpd_zfs_pre_backup(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1026 ndmpd_session_t
*session
= (ndmpd_session_t
*)
1027 (ndmpd_zfs_params
->mp_daemon_cookie
);
1028 ndmp_context_t
*nctxp
= &ndmpd_zfs_args
->nz_nctx
;
1031 if (ndmp_pl
== NULL
|| ndmp_pl
->np_pre_backup
== NULL
)
1034 (void) memset(nctxp
, 0, sizeof (ndmp_context_t
));
1035 nctxp
->nc_plversion
= ndmp_pl
->np_plversion
;
1036 nctxp
->nc_plname
= ndmpd_get_prop(NDMP_PLUGIN_PATH
);
1037 nctxp
->nc_ddata
= (void *) session
;
1038 nctxp
->nc_params
= ndmpd_zfs_params
;
1040 err
= ndmp_pl
->np_pre_backup(ndmp_pl
, nctxp
,
1041 ndmpd_zfs_args
->nz_dataset
);
1044 NDMP_LOG(LOG_DEBUG
, "Pre-backup plug-in: %m");
1045 (void) ndmpd_zfs_post_backup(ndmpd_zfs_args
);
1052 ndmpd_zfs_post_backup(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1054 ndmp_context_t
*nctxp
= &ndmpd_zfs_args
->nz_nctx
;
1057 if (ndmp_pl
== NULL
|| ndmp_pl
->np_post_backup
== NULL
)
1060 err
= ndmp_pl
->np_post_backup(ndmp_pl
, nctxp
, err
);
1063 NDMP_LOG(LOG_DEBUG
, "Post-backup plug-in: %m");
1069 ndmpd_zfs_pre_restore(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1071 ndmpd_session_t
*session
= (ndmpd_session_t
*)
1072 (ndmpd_zfs_params
->mp_daemon_cookie
);
1073 ndmp_context_t
*nctxp
= &ndmpd_zfs_args
->nz_nctx
;
1074 char bkpath
[ZFS_MAX_DATASET_NAME_LEN
];
1077 if (ndmp_pl
== NULL
|| ndmp_pl
->np_pre_restore
== NULL
)
1080 err
= ndmpd_zfs_backup_getpath(ndmpd_zfs_args
, bkpath
,
1081 ZFS_MAX_DATASET_NAME_LEN
);
1084 NDMP_LOG(LOG_DEBUG
, "error getting bkup path: %d", err
);
1088 err
= ndmpd_zfs_restore_getpath(ndmpd_zfs_args
);
1091 NDMP_LOG(LOG_DEBUG
, "error getting restore path: %d", err
);
1095 (void) memset(nctxp
, 0, sizeof (ndmp_context_t
));
1096 nctxp
->nc_ddata
= (void *) session
;
1097 nctxp
->nc_params
= ndmpd_zfs_params
;
1099 err
= ndmp_pl
->np_pre_restore(ndmp_pl
, nctxp
, bkpath
,
1100 ndmpd_zfs_args
->nz_dataset
);
1103 NDMP_LOG(LOG_DEBUG
, "Pre-restore plug-in: %m");
1111 ndmpd_zfs_post_restore(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1113 ndmp_context_t
*nctxp
= &ndmpd_zfs_args
->nz_nctx
;
1116 if (ndmp_pl
== NULL
|| ndmp_pl
->np_post_restore
== NULL
)
1119 err
= ndmp_pl
->np_post_restore(ndmp_pl
, nctxp
, err
);
1122 NDMP_LOG(LOG_DEBUG
, "Post-restore plug-in: %m");
1128 ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1130 ndmpd_zfs_snapfind_t snapdata
;
1132 if (ndmpd_zfs_backup_getenv(ndmpd_zfs_args
) != 0)
1135 if (!ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args
))
1138 if (ndmpd_zfs_is_incremental(ndmpd_zfs_args
)) {
1139 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args
,
1140 snapdata
.nzs_findprop
, ZFS_MAXPROPLEN
, B_TRUE
);
1142 snapdata
.nzs_snapname
[0] = '\0';
1143 snapdata
.nzs_snapprop
[0] = '\0';
1145 if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args
, &snapdata
))
1148 if (snapdata
.nzs_snapname
[0] == '\0') { /* not found */
1149 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
1150 "Snapshot for level %d does not exist\n",
1151 ndmpd_zfs_args
->nz_level
-1);
1155 (void) strlcpy(ndmpd_zfs_args
->nz_fromsnap
,
1156 snapdata
.nzs_snapname
, ZFS_MAX_DATASET_NAME_LEN
);
1163 * ndmpd_zfs_backup_pathvalid()
1165 * Make sure the path is of an existing dataset
1169 ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1171 char zpath
[ZFS_MAX_DATASET_NAME_LEN
];
1172 char propstr
[ZFS_MAXPROPLEN
];
1174 zfs_type_t ztype
= 0;
1177 if (ndmpd_zfs_backup_getpath(ndmpd_zfs_args
, zpath
,
1178 ZFS_MAX_DATASET_NAME_LEN
) != 0)
1181 if (ndmpd_zfs_args
->nz_snapname
[0] != '\0') {
1182 zhp
= zfs_open(ndmpd_zfs_args
->nz_zlibh
, zpath
,
1186 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args
,
1188 ndmpd_zfs_args
->nz_snapname
[0] = '\0';
1189 ndmpd_zfs_args
->nz_dataset
[0] = '\0';
1193 err
= ndmpd_zfs_snapshot_prop_get(zhp
, propstr
);
1199 "ndmpd_zfs_snapshot_prop_get failed");
1203 if (propstr
&& ndmpd_zfs_snapshot_ndmpd_generated(propstr
)) {
1204 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
1205 "cannot use an ndmpd-generated snapshot\n");
1210 zhp
= zfs_open(ndmpd_zfs_args
->nz_zlibh
,
1211 ndmpd_zfs_args
->nz_dataset
, ZFS_TYPE_DATASET
);
1214 ztype
= zfs_get_type(zhp
);
1218 if ((ztype
== ZFS_TYPE_VOLUME
) ||
1219 (ztype
== ZFS_TYPE_FILESYSTEM
)) {
1220 ndmpd_zfs_args
->nz_type
= ztype
;
1224 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
1225 "Invalid file system or volume.\n");
1231 * ndmpd_zfs_backup_getpath()
1233 * Retrieve the backup path from the environment, which should
1234 * be of the form "/dataset[@snap]". The leading slash is required
1235 * by certain DMA's but can otherwise be ignored.
1237 * (Note: "dataset" can consist of more than one component,
1238 * e.g. "pool", "pool/volume", "pool/fs/fs2".)
1240 * The dataset name and the snapshot name (if any) will be
1241 * stored in ndmpd_zfs_args.
1245 ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t
*ndmpd_zfs_args
, char *zpath
,
1251 env_path
= get_backup_path_v3(ndmpd_zfs_params
);
1252 if (env_path
== NULL
)
1255 if (env_path
[0] != '/') {
1256 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
1257 "Invalid path: %s (leading slash required)\n", env_path
);
1261 (void) strlcpy(zpath
, &env_path
[1], zlen
);
1262 (void) strlcpy(ndmpd_zfs_args
->nz_dataset
, &env_path
[1],
1263 ZFS_MAX_DATASET_NAME_LEN
);
1265 at
= strchr(ndmpd_zfs_args
->nz_dataset
, '@');
1268 (void) strlcpy(ndmpd_zfs_args
->nz_snapname
, ++at
,
1269 ZFS_MAX_DATASET_NAME_LEN
);
1271 ndmpd_zfs_args
->nz_snapname
[0] = '\0';
1274 (void) trim_whitespace(ndmpd_zfs_args
->nz_dataset
);
1280 ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1282 return (ndmpd_zfs_getenv(ndmpd_zfs_args
));
1286 ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1288 if (ndmpd_zfs_restore_getenv(ndmpd_zfs_args
) != 0)
1291 if (!ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args
))
1298 ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1303 if (ndmpd_zfs_restore_getpath(ndmpd_zfs_args
) != 0)
1306 at
= strchr(ndmpd_zfs_args
->nz_dataset
, '@');
1309 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_WARNING
,
1310 "%s ignored in restore path\n", at
);
1314 ndmpd_zfs_args
->nz_type
= ZFS_TYPE_VOLUME
| ZFS_TYPE_FILESYSTEM
;
1316 zhp
= zfs_open(ndmpd_zfs_args
->nz_zlibh
,
1317 ndmpd_zfs_args
->nz_dataset
, ndmpd_zfs_args
->nz_type
);
1322 if (!ndmpd_zfs_is_incremental(ndmpd_zfs_args
)) {
1323 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
1324 "Restore dataset exists.\n"
1325 "A nonexistent dataset must be specified "
1326 "for 'zfs' non-incremental restore.\n");
1331 NDMP_LOG(LOG_DEBUG
, "restore path: %s\n", ndmpd_zfs_args
->nz_dataset
);
1337 * ndmpd_zfs_restore_getpath()
1339 * Be sure to not include the leading slash, which is required for
1340 * compatibility with backup applications (NBU) but which is not part
1341 * of the ZFS syntax. (Note that this done explicitly in all paths
1342 * below except those calling ndmpd_zfs_backup_getpath(), because it is
1343 * already stripped in that function.)
1345 * In addition, the DMA might add a trailing slash to the path.
1346 * Strip all such slashes.
1350 ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1352 int version
= ndmpd_zfs_params
->mp_protocol_version
;
1353 char zpath
[ZFS_MAX_DATASET_NAME_LEN
];
1354 mem_ndmp_name_v3_t
*namep_v3
;
1355 char *dataset
= ndmpd_zfs_args
->nz_dataset
;
1361 namep_v3
= (mem_ndmp_name_v3_t
*)MOD_GETNAME(ndmpd_zfs_params
, 0);
1363 if (namep_v3
== NULL
) {
1364 NDMP_LOG(LOG_DEBUG
, "Can't get Nlist[0]");
1368 if (namep_v3
->nm3_dpath
) {
1369 if (namep_v3
->nm3_dpath
[0] != '/') {
1370 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
1371 "Invalid path: %s (leading slash required)\n",
1372 namep_v3
->nm3_dpath
);
1376 (void) strlcpy(dataset
, &(namep_v3
->nm3_dpath
[1]),
1377 ZFS_MAX_DATASET_NAME_LEN
);
1379 if (namep_v3
->nm3_newnm
) {
1380 (void) strlcat(dataset
, "/", ZFS_MAX_DATASET_NAME_LEN
);
1381 (void) strlcat(dataset
, namep_v3
->nm3_newnm
,
1382 ZFS_MAX_DATASET_NAME_LEN
);
1385 if (version
== NDMPV3
) {
1387 * The following does not apply for V4.
1389 * Find the last component of nm3_opath.
1390 * nm3_opath has no trailing '/'.
1392 p
= strrchr(namep_v3
->nm3_opath
, '/');
1393 nm
= p
? p
: namep_v3
->nm3_opath
;
1394 (void) strlcat(dataset
, "/",
1395 ZFS_MAX_DATASET_NAME_LEN
);
1396 (void) strlcat(dataset
, nm
,
1397 ZFS_MAX_DATASET_NAME_LEN
);
1401 err
= ndmpd_zfs_backup_getpath(ndmpd_zfs_args
, zpath
,
1402 ZFS_MAX_DATASET_NAME_LEN
);
1407 len
= strlen(dataset
);
1408 while (dataset
[len
-1] == '/') {
1409 dataset
[len
-1] = '\0';
1417 ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1419 if (ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args
) != 0)
1422 return (ndmpd_zfs_getenv(ndmpd_zfs_args
));
1426 ndmpd_zfs_getenv(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1429 if (ndmpd_zfs_getenv_level(ndmpd_zfs_args
) != 0)
1432 if (ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args
) != 0)
1435 if (ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args
) != 0)
1438 if (ndmpd_zfs_getenv_update(ndmpd_zfs_args
) != 0)
1441 if (ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args
) != 0)
1448 ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1452 envp
= MOD_GETENV(ndmpd_zfs_params
, "ZFS_MODE");
1455 NDMP_LOG(LOG_DEBUG
, "env(ZFS_MODE) not specified, "
1456 "defaulting to recursive");
1457 ndmpd_zfs_args
->nz_zfs_mode
= 'r';
1461 if ((strcmp(envp
, "dataset") == 0) || (strcmp(envp
, "d") == 0)) {
1462 ndmpd_zfs_args
->nz_zfs_mode
= 'd';
1463 } else if ((strcmp(envp
, "recursive") == 0) ||
1464 (strcmp(envp
, "r") == 0)) {
1465 ndmpd_zfs_args
->nz_zfs_mode
= 'r';
1466 } else if ((strcmp(envp
, "package") == 0) || (strcmp(envp
, "p") == 0)) {
1467 ndmpd_zfs_args
->nz_zfs_mode
= 'p';
1469 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
1470 "Invalid ZFS_MODE value \"%s\".\n", envp
);
1474 NDMP_LOG(LOG_DEBUG
, "env(ZFS_MODE): \"%c\"",
1475 ndmpd_zfs_args
->nz_zfs_mode
);
1481 * ndmpd_zfs_getenv_zfs_force()
1483 * If SMF property zfs-force-override is set to "yes" or "no", this
1484 * value will override any value of NDMP environment variable ZFS_FORCE
1485 * as set by the DMA admin (or override the default of 'n', if ZFS_FORCE
1486 * is not set). By default, zfs-force-override is "off", which means it
1487 * will not override ZFS_FORCE.
1491 ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1496 override
= ndmpd_get_prop(NDMP_ZFS_FORCE_OVERRIDE
);
1498 if (strcasecmp(override
, "yes") == 0) {
1499 ndmpd_zfs_args
->nz_zfs_force
= B_TRUE
;
1500 NDMP_LOG(LOG_NOTICE
,
1501 "SMF property zfs-force-override set to 'yes', "
1502 "overriding ZFS_FORCE");
1506 if (strcasecmp(override
, "no") == 0) {
1507 ndmpd_zfs_args
->nz_zfs_force
= B_FALSE
;
1508 NDMP_LOG(LOG_NOTICE
,
1509 "SMF property zfs-force-override set to 'no', "
1510 "overriding ZFS_FORCE");
1514 if (strcasecmp(override
, "off") != 0) {
1515 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
1516 "SMF property zfs-force-override set to invalid value of "
1517 "'%s'; treating it as 'off'.", override
);
1520 envp_force
= MOD_GETENV(ndmpd_zfs_params
, "ZFS_FORCE");
1522 if (envp_force
== NULL
) {
1524 "env(ZFS_FORCE) not specified, defaulting to FALSE");
1525 ndmpd_zfs_args
->nz_zfs_force
= B_FALSE
;
1530 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
1533 if (strchr("tTyY", *envp_force
))
1534 ndmpd_zfs_args
->nz_zfs_force
= B_TRUE
;
1536 NDMP_LOG(LOG_DEBUG
, "env(ZFS_FORCE): \"%s\"", envp_force
);
1542 ndmpd_zfs_getenv_level(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1546 envp
= MOD_GETENV(ndmpd_zfs_params
, "LEVEL");
1549 NDMP_LOG(LOG_DEBUG
, "env(LEVEL) not specified, "
1551 ndmpd_zfs_args
->nz_level
= 0;
1555 if (envp
[1] != '\0') {
1556 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
1557 "Invalid backup level \"%s\".\n", envp
);
1561 if (!isdigit(*envp
)) {
1562 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
1563 "Invalid backup level \"%s\".\n", envp
);
1567 ndmpd_zfs_args
->nz_level
= atoi(envp
);
1569 NDMP_LOG(LOG_DEBUG
, "env(LEVEL): \"%d\"",
1570 ndmpd_zfs_args
->nz_level
);
1576 ndmpd_zfs_getenv_update(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1580 envp_update
= MOD_GETENV(ndmpd_zfs_params
, "UPDATE");
1582 if (envp_update
== NULL
) {
1584 "env(UPDATE) not specified, defaulting to TRUE");
1585 ndmpd_zfs_args
->nz_update
= B_TRUE
;
1590 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
1593 if (strchr("tTyY", *envp_update
))
1594 ndmpd_zfs_args
->nz_update
= B_TRUE
;
1596 NDMP_LOG(LOG_DEBUG
, "env(UPDATE): \"%s\"", envp_update
);
1602 ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1606 envp
= MOD_GETENV(ndmpd_zfs_params
, "DMP_NAME");
1610 "env(DMP_NAME) not specified, defaulting to 'level'");
1611 (void) strlcpy(ndmpd_zfs_args
->nz_dmp_name
, "level",
1612 NDMPD_ZFS_DMP_NAME_MAX
);
1616 if (!ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args
, envp
))
1619 (void) strlcpy(ndmpd_zfs_args
->nz_dmp_name
, envp
,
1620 NDMPD_ZFS_DMP_NAME_MAX
);
1622 NDMP_LOG(LOG_DEBUG
, "env(DMP_NAME): \"%s\"", envp
);
1628 ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1630 char *zfs_backup_size
;
1632 zfs_backup_size
= MOD_GETENV(ndmpd_zfs_params
, "ZFS_BACKUP_SIZE");
1634 if (zfs_backup_size
== NULL
) {
1635 NDMP_LOG(LOG_ERR
, "ZFS_BACKUP_SIZE env is NULL");
1639 NDMP_LOG(LOG_DEBUG
, "ZFS_BACKUP_SIZE: %s\n", zfs_backup_size
);
1641 (void) sscanf(zfs_backup_size
, "%llu",
1642 &ndmpd_zfs_args
->nz_zfs_backup_size
);
1648 * ndmpd_zfs_dmp_name_valid()
1650 * This function verifies that the dmp_name is valid.
1652 * The dmp_name is restricted to alphanumeric characters plus
1653 * the underscore and hyphen, and must be 31 characters or less.
1654 * This is due to its use in the NDMPD_ZFS_PROP_INCR property
1655 * and in the ZFS snapshot name (if an ndmpd-generated snapshot
1660 ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t
*ndmpd_zfs_args
, char *dmp_name
)
1664 if (strlen(dmp_name
) >= NDMPD_ZFS_DMP_NAME_MAX
) {
1665 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
1666 "DMP_NAME %s is longer than %d\n",
1667 dmp_name
, NDMPD_ZFS_DMP_NAME_MAX
-1);
1671 for (c
= dmp_name
; *c
!= '\0'; c
++) {
1672 if (!isalpha(*c
) && !isdigit(*c
) &&
1673 (*c
!= '_') && (*c
!= '-')) {
1674 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
1675 "DMP_NAME %s contains illegal character %c\n",
1681 NDMP_LOG(LOG_DEBUG
, "DMP_NAME is valid: %s\n", dmp_name
);
1686 * ndmpd_zfs_is_incremental()
1688 * This can only be called after ndmpd_zfs_getenv_level()
1693 ndmpd_zfs_is_incremental(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1695 return (ndmpd_zfs_args
->nz_level
!= 0);
1699 * ndmpd_zfs_snapshot_prepare()
1701 * If no snapshot was supplied by the user, create a snapshot
1706 ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1708 ndmpd_session_t
*session
= (ndmpd_session_t
*)
1709 (ndmpd_zfs_params
->mp_daemon_cookie
);
1710 boolean_t recursive
= B_FALSE
;
1713 if (session
->ns_data
.dd_abort
) {
1714 NDMP_LOG(LOG_DEBUG
, "Backing up \"%s\" aborted.",
1715 ndmpd_zfs_args
->nz_dataset
);
1719 if (ndmpd_zfs_args
->nz_snapname
[0] == '\0') {
1720 ndmpd_zfs_args
->nz_ndmpd_snap
= B_TRUE
;
1722 if (ndmpd_zfs_snapshot_create(ndmpd_zfs_args
) != 0) {
1723 ndmpd_zfs_args
->nz_snapname
[0] = '\0';
1725 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
1726 "Error creating snapshot for %s\n",
1727 ndmpd_zfs_args
->nz_dataset
);
1733 if (ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args
)) {
1735 "ndmpd_zfs_snapshot_prop_add error\n");
1737 if (ndmpd_zfs_args
->nz_ndmpd_snap
) {
1739 if (ndmpd_zfs_args
->nz_zfs_mode
!= 'd')
1742 (void) snapshot_destroy(ndmpd_zfs_args
->nz_dataset
,
1743 ndmpd_zfs_args
->nz_snapname
, recursive
, B_FALSE
,
1754 * ndmpd_zfs_snapshot_cleanup()
1756 * If UPDATE = y, find the old snapshot (if any) corresponding to
1757 * {LEVEL, DMP_NAME, ZFS_MODE}. If it was ndmpd-generated,
1758 * remove the snapshot. Otherwise, update its NDMPD_ZFS_PROP_INCR
1759 * property to remove {L, D, Z}.
1761 * If UPDATE = n, if an ndmpd-generated snapshot was used for backup,
1762 * remove the snapshot. Otherwise, update its NDMPD_ZFS_PROP_INCR
1763 * property to remove {L, D, Z}.
1767 ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t
*ndmpd_zfs_args
, int err
)
1769 ndmpd_session_t
*session
= (ndmpd_session_t
*)
1770 (ndmpd_zfs_params
->mp_daemon_cookie
);
1771 ndmpd_zfs_snapfind_t snapdata
;
1772 boolean_t ndmpd_generated
= B_FALSE
;
1774 bzero(&snapdata
, sizeof (ndmpd_zfs_snapfind_t
));
1776 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args
,
1777 snapdata
.nzs_findprop
, ZFS_MAXPROPLEN
, B_FALSE
);
1779 if (ndmpd_zfs_args
->nz_update
&& !session
->ns_data
.dd_abort
&& !err
) {
1781 * Find the existing snapshot, if any, to "unuse."
1782 * Indicate that the current snapshot used for backup
1783 * should be skipped in the search. (The search is
1784 * sorted by creation time but this cannot be relied
1785 * upon for user-supplied snapshots.)
1788 (void) snprintf(snapdata
.nzs_snapskip
, ZFS_MAX_DATASET_NAME_LEN
,
1789 "%s", ndmpd_zfs_args
->nz_snapname
);
1791 if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args
, &snapdata
)) {
1792 NDMP_LOG(LOG_DEBUG
, "ndmpd_zfs_snapshot_find error\n");
1793 goto _remove_tmp_snap
;
1796 if (snapdata
.nzs_snapname
[0] != '\0') { /* snapshot found */
1797 ndmpd_generated
= ndmpd_zfs_snapshot_ndmpd_generated
1798 (snapdata
.nzs_snapprop
);
1800 if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args
,
1801 ndmpd_generated
, &snapdata
) != 0) {
1803 "ndmpd_zfs_snapshot_unuse error\n");
1804 goto _remove_tmp_snap
;
1808 if (session
->ns_data
.dd_abort
)
1809 goto _remove_tmp_snap
;
1816 (void) snprintf(snapdata
.nzs_snapname
, ZFS_MAX_DATASET_NAME_LEN
, "%s",
1817 ndmpd_zfs_args
->nz_snapname
);
1819 (void) strlcpy(snapdata
.nzs_snapprop
, ndmpd_zfs_args
->nz_snapprop
,
1822 snapdata
.nzs_snapskip
[0] = '\0';
1824 if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args
,
1825 ndmpd_zfs_args
->nz_ndmpd_snap
, &snapdata
) != 0) {
1826 NDMP_LOG(LOG_DEBUG
, "ndmpd_zfs_snapshot_unuse error\n");
1830 if (!ndmpd_zfs_args
->nz_update
)
1837 ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
1839 boolean_t recursive
= B_FALSE
;
1841 if (ndmpd_zfs_snapname_create(ndmpd_zfs_args
,
1842 ndmpd_zfs_args
->nz_snapname
, ZFS_MAX_DATASET_NAME_LEN
- 1) < 0) {
1843 NDMP_LOG(LOG_ERR
, "Error (%d) creating snapshot name for %s",
1844 errno
, ndmpd_zfs_args
->nz_dataset
);
1848 if (ndmpd_zfs_args
->nz_zfs_mode
!= 'd')
1851 if (snapshot_create(ndmpd_zfs_args
->nz_dataset
,
1852 ndmpd_zfs_args
->nz_snapname
, recursive
, B_FALSE
) != 0) {
1853 NDMP_LOG(LOG_ERR
, "could not create snapshot %s@%s",
1854 ndmpd_zfs_args
->nz_dataset
, ndmpd_zfs_args
->nz_snapname
);
1858 NDMP_LOG(LOG_DEBUG
, "created snapshot %s@%s",
1859 ndmpd_zfs_args
->nz_dataset
, ndmpd_zfs_args
->nz_snapname
);
1865 * ndmpd_zfs_snapshot_unuse()
1867 * Given a pre-existing snapshot of the given {L, D, Z}:
1868 * If snapshot is ndmpd-generated, remove snapshot.
1869 * If not ndmpd-generated, or if the ndmpd-generated snapshot
1870 * cannot be destroyed, remove the {L, D, Z} substring from the
1871 * snapshot's NDMPD_ZFS_PROP_INCR property.
1873 * In the event of a failure, it may be that two snapshots will
1874 * have the {L, D, Z} property set on them. This is not desirable,
1875 * so return an error and log the failure.
1879 ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t
*ndmpd_zfs_args
,
1880 boolean_t ndmpd_generated
, ndmpd_zfs_snapfind_t
*snapdata_p
)
1882 boolean_t recursive
= B_FALSE
;
1886 if (ndmpd_generated
) {
1887 if (ndmpd_zfs_args
->nz_zfs_mode
!= 'd')
1890 err
= snapshot_destroy(ndmpd_zfs_args
->nz_dataset
,
1891 snapdata_p
->nzs_snapname
, recursive
, B_FALSE
, &zfs_err
);
1894 NDMP_LOG(LOG_ERR
, "snapshot_destroy: %s@%s;"
1895 " err: %d; zfs_err: %d",
1896 ndmpd_zfs_args
->nz_dataset
,
1897 snapdata_p
->nzs_snapname
, err
, zfs_err
);
1902 if (!ndmpd_generated
|| zfs_err
) {
1903 if (ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args
, snapdata_p
))
1911 ndmpd_zfs_snapshot_ndmpd_generated(char *snapprop
)
1915 (void) sscanf(snapprop
, "%*u.%*u.%c%*s", &origin
);
1917 return (origin
== 'n');
1921 * ndmpd_zfs_snapshot_find()
1923 * Find a snapshot with a particular value for
1924 * the NDMPD_ZFS_PROP_INCR property.
1928 ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t
*ndmpd_zfs_args
,
1929 ndmpd_zfs_snapfind_t
*snapdata
)
1934 zhp
= zfs_open(ndmpd_zfs_args
->nz_zlibh
, ndmpd_zfs_args
->nz_dataset
,
1935 ndmpd_zfs_args
->nz_type
);
1938 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args
, "zfs_open");
1942 err
= zfs_iter_snapshots_sorted(zhp
, ndmpd_zfs_snapshot_prop_find
,
1948 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args
, "zfs_iter_snapshots: %d",
1950 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
1951 "Error iterating snapshots\n");
1959 * ndmpd_zfs_snapshot_prop_find()
1961 * Find a snapshot with a particular value for
1962 * NDMPD_ZFS_PROP_INCR. Fill in data for the first one
1963 * found (sorted by creation time). However, skip the
1964 * the snapshot indicated in nzs_snapskip, if any.
1968 ndmpd_zfs_snapshot_prop_find(zfs_handle_t
*zhp
, void *arg
)
1970 ndmpd_zfs_snapfind_t
*snapdata_p
= (ndmpd_zfs_snapfind_t
*)arg
;
1971 char propstr
[ZFS_MAXPROPLEN
];
1972 char findprop_plus_slash
[ZFS_MAXPROPLEN
];
1976 if (snapdata_p
->nzs_snapname
[0] != '\0') {
1977 NDMP_LOG(LOG_DEBUG
, "no need to get prop for snapshot %s",
1978 (char *)zfs_get_name(zhp
));
1982 err
= ndmpd_zfs_snapshot_prop_get(zhp
, propstr
);
1985 NDMP_LOG(LOG_DEBUG
, "ndmpd_zfs_snapshot_prop_get failed");
1989 if (propstr
[0] == '\0') {
1990 NDMP_LOG(LOG_DEBUG
, "snapshot %s: propr not set",
1991 (char *)zfs_get_name(zhp
));
1995 (void) snprintf(findprop_plus_slash
, ZFS_MAXPROPLEN
, "/%s",
1996 snapdata_p
->nzs_findprop
);
1998 if (!strstr((const char *)propstr
,
1999 (const char *)findprop_plus_slash
)) {
2000 NDMP_LOG(LOG_DEBUG
, "snapshot %s: property %s (%s not found)",
2001 (char *)zfs_get_name(zhp
), propstr
,
2002 snapdata_p
->nzs_findprop
);
2006 if (!ndmpd_zfs_prop_version_check(propstr
,
2007 &snapdata_p
->nzs_prop_major
, &snapdata_p
->nzs_prop_minor
)) {
2008 NDMP_LOG(LOG_DEBUG
, "snapshot %s: property %s (%s found)",
2009 (char *)zfs_get_name(zhp
), propstr
,
2010 snapdata_p
->nzs_findprop
);
2011 NDMP_LOG(LOG_DEBUG
, "did not pass version check");
2015 justsnap
= strchr(zfs_get_name(zhp
), '@') + 1;
2017 if (strcmp(justsnap
, snapdata_p
->nzs_snapskip
) != 0) {
2018 (void) strlcpy(snapdata_p
->nzs_snapname
, justsnap
,
2019 ZFS_MAX_DATASET_NAME_LEN
);
2021 (void) strlcpy(snapdata_p
->nzs_snapprop
, propstr
,
2024 NDMP_LOG(LOG_DEBUG
, "found match: %s [%s]\n",
2025 snapdata_p
->nzs_snapname
, snapdata_p
->nzs_snapprop
);
2034 * ndmpd_zfs_snapshot_prop_get()
2036 * Retrieve NDMPD_ZFS_PROP_INCR property from snapshot
2040 ndmpd_zfs_snapshot_prop_get(zfs_handle_t
*zhp
, char *propstr
)
2049 userprop
= zfs_get_user_props(zhp
);
2051 if (userprop
== NULL
)
2054 err
= nvlist_lookup_nvlist(userprop
, NDMPD_ZFS_PROP_INCR
, &propval
);
2060 NDMP_LOG(LOG_DEBUG
, "nvlist_lookup_nvlist error: %d\n", err
);
2065 err
= nvlist_lookup_string(propval
, ZPROP_VALUE
, &strval
);
2071 NDMP_LOG(LOG_DEBUG
, "nvlist_lookup_string error: %d\n", err
);
2076 (void) strlcpy(propstr
, strval
, ZFS_MAXPROPLEN
);
2082 * ndmpd_zfs_snapshot_prop_add()
2084 * Update snapshot's NDMPD_ZFS_PROP_INCR property with
2085 * the current LEVEL, DMP_NAME, and ZFS_MODE values
2086 * (add property if it doesn't exist)
2090 ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
2092 char fullname
[ZFS_MAX_DATASET_NAME_LEN
];
2093 char propstr
[ZFS_MAXPROPLEN
];
2098 (void) snprintf(fullname
, ZFS_MAX_DATASET_NAME_LEN
, "%s@%s",
2099 ndmpd_zfs_args
->nz_dataset
,
2100 ndmpd_zfs_args
->nz_snapname
);
2102 zhp
= zfs_open(ndmpd_zfs_args
->nz_zlibh
, fullname
, ZFS_TYPE_SNAPSHOT
);
2105 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args
, "zfs_open (snap)");
2109 bzero(propstr
, ZFS_MAXPROPLEN
);
2111 if (ndmpd_zfs_snapshot_prop_get(zhp
, propstr
)) {
2112 NDMP_LOG(LOG_DEBUG
, "error getting property");
2117 if (ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args
, propstr
, &set
)) {
2123 err
= zfs_prop_set(zhp
, NDMPD_ZFS_PROP_INCR
, propstr
);
2125 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args
, "zfs_prop_set: %d",
2127 NDMP_LOG(LOG_ERR
, "error setting property %s",
2136 (void) strlcpy(ndmpd_zfs_args
->nz_snapprop
, propstr
, ZFS_MAXPROPLEN
);
2142 ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t
*ndmpd_zfs_args
,
2143 char *propstr
, boolean_t
*set
)
2145 char subprop
[ZFS_MAXPROPLEN
];
2147 int slash_count
= 0;
2151 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args
,
2152 subprop
, ZFS_MAXPROPLEN
, B_FALSE
);
2154 if (propstr
[0] == '\0') {
2155 (void) snprintf(propstr
, ZFS_MAXPROPLEN
, "%u.%u.%c/%s",
2156 NDMPD_ZFS_PROP_MAJOR_VERSION
,
2157 NDMPD_ZFS_PROP_MINOR_VERSION
,
2158 (ndmpd_zfs_args
->nz_ndmpd_snap
) ? 'n' : 'u',
2163 if (strstr((const char *)propstr
, (const char *)subprop
)) {
2164 NDMP_LOG(LOG_DEBUG
, "Did not add entry %s as it already exists",
2175 if (slash_count
>= NDMPD_ZFS_SUBPROP_MAX
) {
2176 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
2177 "snapshot %s: user property %s limit of %d subprops "
2178 "reached; cannot complete operation",
2179 ndmpd_zfs_args
->nz_snapname
,
2180 NDMPD_ZFS_PROP_INCR
,
2181 NDMPD_ZFS_SUBPROP_MAX
);
2185 assert((strlen(propstr
) + strlen(subprop
) + 2) < ZFS_MAXPROPLEN
);
2187 (void) strlcat(propstr
, "/", ZFS_MAXPROPLEN
);
2188 (void) strlcat(propstr
, subprop
, ZFS_MAXPROPLEN
);
2194 ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t
*ndmpd_zfs_args
,
2195 char *subprop
, int len
, boolean_t prev_level
)
2197 return (snprintf(subprop
, len
, "%d.%s.%c",
2198 prev_level
? ndmpd_zfs_args
->nz_level
-1 : ndmpd_zfs_args
->nz_level
,
2199 ndmpd_zfs_args
->nz_dmp_name
,
2200 ndmpd_zfs_args
->nz_zfs_mode
));
2204 * ndmpd_zfs_snapshot_prop_remove()
2206 * Remove specified substring from the snapshot's
2207 * NDMPD_ZFS_PROP_INCR property
2211 ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t
*ndmpd_zfs_args
,
2212 ndmpd_zfs_snapfind_t
*snapdata_p
)
2214 char findprop_plus_slash
[ZFS_MAXPROPLEN
];
2215 char fullname
[ZFS_MAX_DATASET_NAME_LEN
];
2216 char newprop
[ZFS_MAXPROPLEN
];
2217 char tmpstr
[ZFS_MAXPROPLEN
];
2222 (void) snprintf(fullname
, ZFS_MAX_DATASET_NAME_LEN
, "%s@%s",
2223 ndmpd_zfs_args
->nz_dataset
,
2224 snapdata_p
->nzs_snapname
);
2226 zhp
= zfs_open(ndmpd_zfs_args
->nz_zlibh
, fullname
, ZFS_TYPE_SNAPSHOT
);
2229 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args
, "zfs_open");
2233 bzero(newprop
, ZFS_MAXPROPLEN
);
2236 * If the substring to be removed is the only {L, D, Z}
2237 * in the property, remove the entire property
2242 (void) sscanf(snapdata_p
->nzs_snapprop
, "%*u.%*u.%*c/%1023s", tmpstr
);
2244 if (strcmp(tmpstr
, snapdata_p
->nzs_findprop
) == 0) {
2246 err
= zfs_prop_set(zhp
, NDMPD_ZFS_PROP_INCR
, newprop
);
2251 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args
, "zfs_prop_set: %d",
2253 NDMP_LOG(LOG_ERR
, "error setting property %s", newprop
);
2260 (void) snprintf(findprop_plus_slash
, ZFS_MAXPROPLEN
, "/%s",
2261 snapdata_p
->nzs_findprop
);
2263 ptr
= strstr((const char *)snapdata_p
->nzs_snapprop
,
2264 (const char *)findprop_plus_slash
);
2268 * This shouldn't happen. Just return success.
2276 * Remove "nzs_findprop" substring from property
2279 * 0.0.u/1.bob.p/0.jane.d
2281 * Note that there will always be a prefix to the
2282 * strstr() result. Hence the below code works for
2287 (void) strncpy(newprop
, snapdata_p
->nzs_snapprop
,
2288 (char *)ptr
- snapdata_p
->nzs_snapprop
);
2289 ptr
+= strlen(snapdata_p
->nzs_findprop
) + 1;
2290 (void) strlcat(newprop
, ptr
, ZFS_MAXPROPLEN
);
2292 err
= zfs_prop_set(zhp
, NDMPD_ZFS_PROP_INCR
, newprop
);
2297 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args
, "zfs_prop_set: %d", err
);
2298 NDMP_LOG(LOG_ERR
, "error modifying property %s", newprop
);
2306 ndmpd_zfs_prop_version_check(char *propstr
, uint32_t *major
, uint32_t *minor
)
2308 (void) sscanf(propstr
, "%u.%u.%*c%*s", major
, minor
);
2310 if (*major
> NDMPD_ZFS_PROP_MAJOR_VERSION
) {
2311 NDMP_LOG(LOG_ERR
, "unsupported prop major (%u > %u)",
2312 *major
, NDMPD_ZFS_PROP_MAJOR_VERSION
);
2316 if (*minor
> NDMPD_ZFS_PROP_MINOR_VERSION
) {
2317 NDMP_LOG(LOG_ERR
, "later prop minor (%u > %u)",
2318 *minor
, NDMPD_ZFS_PROP_MINOR_VERSION
);
2321 NDMP_LOG(LOG_DEBUG
, "passed version check: "
2322 "supported prop major (%u <= %u); (snapprop minor: %u [%u])",
2323 *major
, NDMPD_ZFS_PROP_MAJOR_VERSION
,
2324 *minor
, NDMPD_ZFS_PROP_MINOR_VERSION
);
2330 ndmpd_zfs_snapname_create(ndmpd_zfs_args_t
*ndmpd_zfs_args
,
2331 char *snapname
, int namelen
)
2333 char subprop
[ZFS_MAXPROPLEN
];
2337 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args
,
2338 subprop
, ZFS_MAXPROPLEN
, B_FALSE
);
2340 (void) gettimeofday(&tp
, NULL
);
2342 err
= snprintf(snapname
, namelen
,
2348 if (err
> namelen
) {
2349 NDMP_LOG(LOG_ERR
, "name of snapshot [%s...] would exceed %d",
2358 ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t
*ndmpd_zfs_args
)
2360 switch (libzfs_errno(ndmpd_zfs_args
->nz_zlibh
)) {
2364 case EZFS_INVALIDNAME
:
2365 case EZFS_MOUNTFAILED
:
2366 case EZFS_UMOUNTFAILED
:
2367 case EZFS_NAMETOOLONG
:
2368 case EZFS_BADRESTORE
:
2370 /* use existing error text */
2372 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
2374 ndmpd_zfs_args
->nz_dataset
,
2375 libzfs_error_action(ndmpd_zfs_args
->nz_zlibh
),
2376 libzfs_error_description(ndmpd_zfs_args
->nz_zlibh
));
2381 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
2382 "Unable to obtain memory for operation\n");
2385 case EZFS_PROPSPACE
:
2386 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
2387 "A bad ZFS quota or reservation was encountered.\n");
2390 case EZFS_BADSTREAM
:
2391 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
2392 "The backup stream is invalid.\n");
2396 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
2397 "An error related to the local zone occurred.\n");
2401 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
2402 "No more space is available\n");
2406 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
2407 "An I/O error occurred.\n");
2411 ndmpd_zfs_dma_log(ndmpd_zfs_args
, NDMP_LOG_ERROR
,
2412 "An internal ndmpd error occurred. "
2413 "Please contact support\n");
2419 ndmpd_zfs_dma_log(ndmpd_zfs_args_t
*ndmpd_zfs_args
, ndmp_log_type log_type
,
2422 static char buf
[1024];
2425 va_start(ap
, format
);
2427 /*LINTED variable format specifier */
2428 (void) vsnprintf(buf
, sizeof (buf
), format
, ap
);
2431 MOD_LOGV3(ndmpd_zfs_params
, log_type
, buf
);
2433 if ((log_type
) == NDMP_LOG_ERROR
) {
2434 NDMP_LOG(LOG_ERR
, buf
);
2436 NDMP_LOG(LOG_NOTICE
, buf
);