1 /*
2 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
4 */
5
6 /*
7 * BSD 3 Clause License
8 *
9 * Copyright (c) 2007, The Storage Networking Industry Association.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * - Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
21 *
22 * - Neither the name of The Storage Networking Industry Association (SNIA)
23 * nor the names of its contributors may be used to endorse or promote
24 * products derived from this software without specific prior written
25 * permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
41
42 #include <sys/types.h>
43 #include <sys/param.h>
44 #include <sys/lwp.h>
45 #include <sys/fs/zfs.h>
46 #include <sys/mtio.h>
47 #include <sys/time.h>
48 #include <unistd.h>
49 #include <errno.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <ctype.h>
53 #include <libzfs.h>
54 #include <stdio.h>
55 #include "ndmpd_common.h"
56 #include "ndmpd.h"
57
58 typedef struct {
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;
66
67 mutex_t ndmpd_zfs_fd_lock;
68
69 static int ndmpd_zfs_open_fds(ndmpd_zfs_args_t *);
70 static void ndmpd_zfs_close_fds(ndmpd_zfs_args_t *);
71
72 static void ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *, int);
73
74 static int ndmpd_zfs_header_write(ndmpd_session_t *);
75 static int ndmpd_zfs_header_read(ndmpd_zfs_args_t *);
76
77 static void *ndmpd_zfs_backup_send_read(void *);
78 static void *ndmpd_zfs_backup_tape_write(void *);
79
80 static int ndmpd_zfs_restore(ndmpd_zfs_args_t *);
81 static void *ndmpd_zfs_restore_tape_read(void *);
82 static void *ndmpd_zfs_restore_recv_write(void *);
83
84 static int ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *, int **, int **);
85
86 static int ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t *, u_longlong_t);
87
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 *);
91
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 *);
95
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 *);
103
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 *);
107
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 *);
115
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 *,
120 boolean_t *);
121 static int ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *, char *, int,
122 boolean_t);
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 *);
126
127 static int ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *, char *, int);
128
129 static void ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *);
130
131 static int ndmpd_zfs_backup(ndmpd_zfs_args_t *);
132
133 /*
134 * Syntax for com.sun.ndmp:incr property value:
135 * #.#.n|u/$LEVEL.$DMP_NAME.$ZFS_MODE(/ ...)
136 *
137 * where
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]
143 *
144 * Examples:
145 *
146 * 0.0.n/0.bob.p
147 * 0.0.u/1.bob.p/0.jane.d
148 *
149 * Note: NDMPD_ZFS_SUBPROP_MAX is calculated based on ZFS_MAXPROPLEN
150 */
151
152 #define NDMPD_ZFS_PROP_INCR "com.sun.ndmp:incr"
153 #define NDMPD_ZFS_SUBPROP_MAX 28
154
155 /*
156 * NDMPD_ZFS_LOG_ZERR
157 *
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.
162 */
163
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)); \
170 }
171
172 int
ndmpd_zfs_init(ndmpd_session_t * session)173 ndmpd_zfs_init(ndmpd_session_t *session)
174 {
175 ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
176 int version = session->ns_protocol_version;
177
178 bzero(ndmpd_zfs_args, sizeof (*ndmpd_zfs_args));
179
180 if ((version < NDMPV3) || (version > NDMPV4)) {
181 NDMP_LOG(LOG_ERR, "Unknown or unsupported version %d", version);
182 return (-1);
183 }
184
185 if ((ndmpd_zfs_args->nz_zlibh = libzfs_init()) == NULL) {
186 NDMP_LOG(LOG_ERR, "libzfs init error [%d]", errno);
187 return (-1);
188 }
189
190 if (ndmpd_zfs_open_fds(ndmpd_zfs_args) < 0) {
191 NDMP_LOG(LOG_ERR, "open_fds() failure(): %d\n", errno);
192 return (-1);
193 }
194
195 ndmpd_zfs_args->nz_bufsize = ndmp_buffer_get_size(session);
196 ndmpd_zfs_args->nz_window_len = session->ns_mover.md_window_length;
197
198 ndmpd_zfs_args->nz_nlp = ndmp_get_nlp(session);
199
200 assert(ndmpd_zfs_args->nz_nlp != NULL);
201
202 ndmpd_zfs_args->nz_nlp->nlp_bytes_total = 0;
203
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;
208
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;
214
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;
227
228 switch (version) {
229 case NDMPV3:
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;
237 break;
238 case NDMPV4:
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;
246 break;
247 default:
248 /* error already returned above for this case */
249 break;
250 }
251
252 return (0);
253 }
254
255 void
ndmpd_zfs_fini(ndmpd_zfs_args_t * ndmpd_zfs_args)256 ndmpd_zfs_fini(ndmpd_zfs_args_t *ndmpd_zfs_args)
257 {
258 libzfs_fini(ndmpd_zfs_args->nz_zlibh);
259
260 ndmpd_zfs_close_fds(ndmpd_zfs_args);
261 }
262
263 static int
ndmpd_zfs_open_fds(ndmpd_zfs_args_t * ndmpd_zfs_args)264 ndmpd_zfs_open_fds(ndmpd_zfs_args_t *ndmpd_zfs_args)
265 {
266 int err;
267
268 err = pipe(ndmpd_zfs_args->nz_pipe_fd);
269 if (err)
270 NDMP_LOG(LOG_ERR, "pipe(2) failed: %s:\n", strerror(errno));
271
272 return (err);
273 }
274
275 /*
276 * ndmpd_zfs_close_fds()
277 *
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.
283 */
284
285 static void
ndmpd_zfs_close_fds(ndmpd_zfs_args_t * ndmpd_zfs_args)286 ndmpd_zfs_close_fds(ndmpd_zfs_args_t *ndmpd_zfs_args)
287 {
288 ndmpd_session_t *session = (ndmpd_session_t *)
289 (ndmpd_zfs_params->mp_daemon_cookie);
290 int pipe_end;
291 int fds[2];
292
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);
296 return;
297 }
298
299 (void) mutex_lock(&ndmpd_zfs_fd_lock);
300
301 if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP) {
302 pipe_end = PIPE_ZFS;
303 } else {
304 pipe_end = PIPE_TAPE;
305 }
306
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",
311 strerror(errno));
312 return;
313 }
314
315 (void) dup2(fds[0], ndmpd_zfs_args->nz_pipe_fd[pipe_end]);
316 (void) close(fds[0]);
317 (void) close(fds[1]);
318
319 ndmpd_zfs_args->nz_pipe_fd[pipe_end] = -1;
320 }
321
322 (void) mutex_unlock(&ndmpd_zfs_fd_lock);
323 }
324
325 static void
ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t * ndmpd_zfs_args,int pipe_end)326 ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *ndmpd_zfs_args, int pipe_end)
327 {
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);
332 }
333
334 static int
ndmpd_zfs_header_write(ndmpd_session_t * session)335 ndmpd_zfs_header_write(ndmpd_session_t *session)
336 {
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;
340 char *buf;
341
342 buf = ndmp_malloc(bufsize);
343 if (buf == NULL) {
344 NDMP_LOG(LOG_DEBUG, "buf NULL");
345 return (-1);
346 }
347
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);
353
354 bzero(buf, bufsize);
355 (void) memcpy(buf, tape_header, sizeof (ndmpd_zfs_header_t));
356
357 NDMP_LOG(LOG_DEBUG, "header (major, minor, length): %u %u %u",
358 NDMPD_ZFS_MAJOR_VERSION,
359 NDMPD_ZFS_MINOR_VERSION,
360 bufsize);
361
362 if (MOD_WRITE(ndmpd_zfs_params, buf, bufsize) != 0) {
363 free(buf);
364 NDMP_LOG(LOG_ERR, "MOD_WRITE error");
365 return (-1);
366 }
367
368 free(buf);
369
370 session->ns_data.dd_module.dm_stats.ms_bytes_processed = bufsize;
371
372 return (0);
373 }
374
375 static int
ndmpd_zfs_header_read(ndmpd_zfs_args_t * ndmpd_zfs_args)376 ndmpd_zfs_header_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
377 {
378 int32_t bufsize = ndmpd_zfs_args->nz_bufsize;
379 ndmpd_zfs_header_t *tape_header = &ndmpd_zfs_args->nz_tape_header;
380 uint32_t hdrlen;
381 int32_t header_left;
382 int err;
383 char *buf;
384
385 buf = ndmp_malloc(bufsize);
386 if (buf == NULL) {
387 NDMP_LOG(LOG_DEBUG, "buf NULL");
388 return (-1);
389 }
390
391 bzero(buf, bufsize);
392
393 /*
394 * Read nz_bufsize worth of bytes first (the size of a mover record).
395 */
396
397 err = MOD_READ(ndmpd_zfs_params, buf, bufsize);
398
399 if (err != 0) {
400 NDMP_LOG(LOG_ERR, "MOD_READ error: %d", err);
401 free(buf);
402 return (-1);
403 }
404
405 (void) memcpy(tape_header, buf, sizeof (ndmpd_zfs_header_t));
406
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");
410 goto _err;
411 }
412
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);
417 goto _err;
418 }
419
420 /*
421 * Major version 0 (regardless of minor version):
422 * Header must be a multiple of the mover record size.
423 */
424
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);
430 if (err == -1) {
431 ndmpd_zfs_dma_log(ndmpd_zfs_args,
432 NDMP_LOG_ERROR, "bad header\n");
433 goto _err;
434 }
435 header_left -= bufsize;
436 }
437 }
438
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));
444
445 ndmpd_zfs_args->nz_nlp->nlp_bytes_total = hdrlen;
446
447 free(buf);
448 return (0);
449
450 _err:
451
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));
457
458 free(buf);
459 return (-1);
460 }
461
462 void *
ndmpd_zfs_backup_starter(void * arg)463 ndmpd_zfs_backup_starter(void *arg)
464 {
465 ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
466 ndmpd_session_t *session = (ndmpd_session_t *)
467 (ndmpd_zfs_params->mp_daemon_cookie);
468 int cleanup_err = 0;
469 int err = 0;
470
471 ndmp_session_ref(session);
472
473 if (ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args) != 0) {
474 err = -1;
475 goto _done;
476 }
477
478 err = ndmpd_zfs_backup(ndmpd_zfs_args);
479
480 cleanup_err = ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args, err);
481
482 NDMP_LOG(LOG_DEBUG,
483 "data bytes_total(including header):%llu",
484 session->ns_data.dd_module.dm_stats.ms_bytes_processed);
485
486 if (err == 0)
487 err = ndmpd_zfs_send_fhist(ndmpd_zfs_args);
488
489 _done:
490 NS_DEC(nbk);
491 MOD_DONE(ndmpd_zfs_params, err ? err : cleanup_err);
492 ndmp_session_unref(session);
493 ndmpd_zfs_fini(ndmpd_zfs_args);
494
495 return ((void *)(uintptr_t)err);
496 }
497
498 static int
ndmpd_zfs_send_fhist(ndmpd_zfs_args_t * ndmpd_zfs_args)499 ndmpd_zfs_send_fhist(ndmpd_zfs_args_t *ndmpd_zfs_args)
500 {
501 ndmpd_session_t *session = (ndmpd_session_t *)
502 (ndmpd_zfs_params->mp_daemon_cookie);
503 struct stat64 st;
504 char *envp;
505
506 envp = MOD_GETENV(ndmpd_zfs_params, "HIST");
507 if (!envp)
508 return (0);
509
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 "
513 "generated.\n");
514 return (0);
515 }
516
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;
522 st.st_size = 1;
523 st.st_nlink = 1;
524
525 if (ndmpd_api_file_history_dir_v3(session, ".", ROOT_INODE,
526 ROOT_INODE) != 0)
527 return (-1);
528 if (ndmpd_api_file_history_dir_v3(session, "..", ROOT_INODE,
529 ROOT_INODE) != 0)
530 return (-1);
531 if (ndmpd_api_file_history_node_v3(session, ROOT_INODE, &st, 0) != 0)
532 return (-1);
533
534 ndmpd_file_history_cleanup(session, TRUE);
535 return (0);
536 }
537
538 static int
ndmpd_zfs_backup(ndmpd_zfs_args_t * ndmpd_zfs_args)539 ndmpd_zfs_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
540 {
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;
545 int result = 0;
546 int err;
547
548 if (session->ns_eof)
549 return (-1);
550
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");
555 return (-1);
556 }
557
558 err = ndmpd_zfs_reader_writer(ndmpd_zfs_args,
559 &read_err, &write_err);
560
561 if (err || read_err || write_err || session->ns_eof)
562 result = EPIPE;
563 }
564
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);
572
573 (void) ndmpd_zfs_post_backup(ndmpd_zfs_args);
574 err = -1;
575 } else {
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);
580
581 err = ndmpd_zfs_post_backup(ndmpd_zfs_args);
582 if (err || result)
583 err = -1;
584
585 if (err == 0) {
586 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" finished.",
587 ndmpd_zfs_args->nz_dataset);
588 } else {
589 NDMP_LOG(LOG_DEBUG, "An error occurred while backing up"
590 " \"%s\"", ndmpd_zfs_args->nz_dataset);
591 }
592 }
593
594 return (err);
595 }
596
597 /*
598 * ndmpd_zfs_backup_send_read()
599 *
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
605 * backed up
606 *
607 * Volumes do not have descednants, so 'd' and 'r' produce equivalent results.
608 */
609
610 static void *
ndmpd_zfs_backup_send_read(void * ptr)611 ndmpd_zfs_backup_send_read(void *ptr)
612 {
613 ndmpd_zfs_args_t *ndmpd_zfs_args = ptr;
614 ndmpd_session_t *session = (ndmpd_session_t *)
615 (ndmpd_zfs_params->mp_daemon_cookie);
616 sendflags_t flags = { 0 };
617 char *fromsnap = NULL;
618 zfs_handle_t *zhp;
619 int err;
620
621 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
622 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
623
624 if (!zhp) {
625 if (!session->ns_data.dd_abort)
626 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
627 return ((void *)(uintptr_t)-1);
628 }
629
630 switch (ndmpd_zfs_args->nz_zfs_mode) {
631 case ('d'):
632 flags.props = B_TRUE;
633 break;
634 case ('r'):
635 flags.replicate = B_TRUE;
636 break;
637 case ('p'):
638 flags.doall = B_TRUE;
639 flags.replicate = B_TRUE;
640 break;
641 default:
642 NDMP_LOG(LOG_ERR, "unknown zfs_mode: %c",
643 ndmpd_zfs_args->nz_zfs_mode);
644 zfs_close(zhp);
645 return ((void *)(uintptr_t)-1);
646 }
647
648 if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
649 if (ndmpd_zfs_args->nz_fromsnap[0] == '\0') {
650 NDMP_LOG(LOG_ERR, "no fromsnap");
651 zfs_close(zhp);
652 return ((void *)(uintptr_t)-1);
653 }
654 fromsnap = ndmpd_zfs_args->nz_fromsnap;
655 }
656
657 err = zfs_send(zhp, fromsnap, ndmpd_zfs_args->nz_snapname, &flags,
658 ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL, NULL, NULL);
659
660 if (err && !session->ns_data.dd_abort)
661 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_send: %d", err);
662
663 zfs_close(zhp);
664
665 return ((void *)(uintptr_t)err);
666 }
667
668 /*
669 * ndmpd_zfs_backup_tape_write()
670 *
671 * The data begins on a mover record boundary (because
672 * the header is the size of a mover record--i.e.
673 * ndmpd_zfs_args->nz_bufsize).
674 */
675
676 static void *
ndmpd_zfs_backup_tape_write(void * ptr)677 ndmpd_zfs_backup_tape_write(void *ptr)
678 {
679 ndmpd_zfs_args_t *ndmpd_zfs_args = ptr;
680 ndmpd_session_t *session = (ndmpd_session_t *)
681 (ndmpd_zfs_params->mp_daemon_cookie);
682 int bufsize = ndmpd_zfs_args->nz_bufsize;
683 u_longlong_t *bytes_totalp;
684 int count;
685 char *buf;
686
687 buf = ndmp_malloc(bufsize);
688 if (buf == NULL) {
689 NDMP_LOG(LOG_DEBUG, "buf NULL");
690 return ((void *)(uintptr_t)-1);
691 }
692
693 bytes_totalp =
694 &(session->ns_data.dd_module.dm_stats.ms_bytes_processed);
695
696 for (;;) {
697 bzero(buf, bufsize);
698
699 count = read(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
700 bufsize);
701
702 if (count == 0) /* EOF */ {
703 NDMP_LOG(LOG_DEBUG,
704 "zfs_send stream size: %llu bytes; "
705 "full backup size (including header): %llu",
706 *bytes_totalp - bufsize, *bytes_totalp);
707 free(buf);
708
709 return ((void *)(uintptr_t)
710 ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args,
711 *bytes_totalp));
712 }
713
714 if (count == -1) {
715 NDMP_LOG(LOG_DEBUG, "pipe read error (errno %d)",
716 errno);
717 free(buf);
718 return ((void *)(uintptr_t)-1);
719 }
720 NS_ADD(rdisk, count);
721
722 if (MOD_WRITE(ndmpd_zfs_params, buf, count) != 0) {
723 (void) ndmpd_zfs_abort((void *) ndmpd_zfs_args);
724 NDMP_LOG(LOG_ERR, "MOD_WRITE error");
725 free(buf);
726 return ((void *)(uintptr_t)-1);
727 }
728
729 *bytes_totalp += count;
730 }
731 /* NOTREACHED */
732 }
733
734 static int
ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t * ndmpd_zfs_args,u_longlong_t bytes_total)735 ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args,
736 u_longlong_t bytes_total)
737 {
738 char zfs_backup_size[32];
739 int err;
740
741 (void) snprintf(zfs_backup_size, sizeof (zfs_backup_size), "%llu",
742 bytes_total);
743
744 err = MOD_ADDENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE", zfs_backup_size);
745
746 if (err) {
747 NDMP_LOG(LOG_ERR, "Failed to add ZFS_BACKUP_SIZE env");
748 return (-1);
749 }
750
751 NDMP_LOG(LOG_DEBUG, "Added ZFS_BACKUP_SIZE env: %s", zfs_backup_size);
752
753 return (0);
754 }
755
756 void *
ndmpd_zfs_restore_starter(void * arg)757 ndmpd_zfs_restore_starter(void *arg)
758 {
759 ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
760 ndmpd_session_t *session = (ndmpd_session_t *)
761 (ndmpd_zfs_params->mp_daemon_cookie);
762 int err;
763
764 ndmp_session_ref(session);
765
766 err = ndmpd_zfs_restore(ndmpd_zfs_args);
767
768 MOD_DONE(ndmpd_zfs_params, err);
769
770 NS_DEC(nrs);
771
772 ndmp_session_unref(session);
773
774 ndmpd_zfs_fini(ndmpd_zfs_args);
775
776 return ((void *)(uintptr_t)err);
777 }
778
779 static int
ndmpd_zfs_restore(ndmpd_zfs_args_t * ndmpd_zfs_args)780 ndmpd_zfs_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
781 {
782 ndmpd_session_t *session = (ndmpd_session_t *)
783 (ndmpd_zfs_params->mp_daemon_cookie);
784 int *read_err = NULL;
785 int *write_err = NULL;
786 int result = 0;
787 int err;
788
789 if (!session->ns_data.dd_abort) {
790 if (ndmpd_zfs_header_read(ndmpd_zfs_args)) {
791 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
792 "ndmpd_zfs header read error\n");
793 return (-1);
794 }
795
796 err = ndmpd_zfs_reader_writer(ndmpd_zfs_args,
797 &write_err, &read_err);
798
799 if (err || read_err || write_err || session->ns_eof)
800 result = EIO;
801 }
802
803 if (session->ns_data.dd_abort) {
804 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
805 ndmpd_zfs_args->nz_dataset);
806 ndmpd_audit_restore(session->ns_connection,
807 ndmpd_zfs_args->nz_dataset,
808 session->ns_data.dd_data_addr.addr_type,
809 ndmpd_zfs_args->nz_dataset, EINTR);
810 (void) ndmpd_zfs_post_restore(ndmpd_zfs_args);
811 err = -1;
812 } else {
813 ndmpd_audit_restore(session->ns_connection,
814 ndmpd_zfs_args->nz_dataset,
815 session->ns_data.dd_data_addr.addr_type,
816 ndmpd_zfs_args->nz_dataset, result);
817 err = ndmpd_zfs_post_restore(ndmpd_zfs_args);
818 if (err || result)
819 err = -1;
820
821 if (err == 0) {
822 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished",
823 ndmpd_zfs_args->nz_dataset);
824 } else {
825 NDMP_LOG(LOG_DEBUG, "An error occurred while restoring"
826 " to \"%s\"", ndmpd_zfs_args->nz_dataset);
827 }
828 }
829
830 return (err);
831 }
832
833 static void *
ndmpd_zfs_restore_tape_read(void * ptr)834 ndmpd_zfs_restore_tape_read(void *ptr)
835 {
836 ndmpd_zfs_args_t *ndmpd_zfs_args = ptr;
837 ndmpd_session_t *session = (ndmpd_session_t *)
838 (ndmpd_zfs_params->mp_daemon_cookie);
839 int bufsize = ndmpd_zfs_args->nz_bufsize;
840 u_longlong_t backup_size = ndmpd_zfs_args->nz_zfs_backup_size;
841 u_longlong_t *bytes_totalp;
842 u_longlong_t bytes;
843 char *buf;
844 int count;
845 int err;
846
847 buf = ndmp_malloc(bufsize);
848 if (buf == NULL) {
849 NDMP_LOG(LOG_DEBUG, "buf NULL");
850 return ((void *)(uintptr_t)-1);
851 }
852
853 bytes_totalp = &ndmpd_zfs_args->nz_nlp->nlp_bytes_total;
854
855 while (*bytes_totalp < backup_size) {
856
857 bytes = backup_size - *bytes_totalp;
858
859 if (bytes >= bufsize)
860 bytes = bufsize;
861
862 err = MOD_READ(ndmpd_zfs_params, buf, bytes);
863
864 if (err != 0) {
865 NDMP_LOG(LOG_ERR, "MOD_READ error: %d; returning -1",
866 err);
867 free(buf);
868 return ((void *)(uintptr_t)-1);
869 }
870
871 count = write(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
872 bytes);
873
874 if (count != bytes) {
875 NDMP_LOG(LOG_ERR, "count (%d) != bytes (%d)",
876 count, bytes);
877
878 if (count == -1) {
879 NDMP_LOG(LOG_ERR, "pipe write error: errno: %d",
880 errno);
881
882 if (session->ns_data.dd_abort)
883 NDMP_LOG(LOG_DEBUG, "abort set");
884 }
885
886 free(buf);
887 return ((void *)(uintptr_t)-1);
888 }
889
890 NS_ADD(wdisk, count);
891
892 *bytes_totalp += count;
893 }
894
895 free(buf);
896 return (NULL);
897 }
898
899 /*
900 * ndmpd_zfs_restore_recv_write()
901 *
902 * This routine executes zfs_receive() to restore the backup.
903 */
904
905 static void *
ndmpd_zfs_restore_recv_write(void * ptr)906 ndmpd_zfs_restore_recv_write(void *ptr)
907 {
908 ndmpd_zfs_args_t *ndmpd_zfs_args = ptr;
909 ndmpd_session_t *session = (ndmpd_session_t *)
910 (ndmpd_zfs_params->mp_daemon_cookie);
911 recvflags_t flags;
912 int err;
913
914 bzero(&flags, sizeof (recvflags_t));
915
916 flags.nomount = B_TRUE;
917
918 NDMP_LOG(LOG_DEBUG, "nz_zfs_force: %d\n", ndmpd_zfs_args->nz_zfs_force);
919
920 if (ndmpd_zfs_args->nz_zfs_force)
921 flags.force = B_TRUE;
922
923 err = zfs_receive(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
924 NULL, &flags, ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL);
925
926 if (err && !session->ns_data.dd_abort)
927 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_receive: %d", err);
928
929 return ((void *)(uintptr_t)err);
930 }
931
932 /*
933 * ndmpd_zfs_reader_writer()
934 *
935 * Two separate threads are used for actual backup or restore.
936 */
937
938 static int
ndmpd_zfs_reader_writer(ndmpd_zfs_args_t * ndmpd_zfs_args,int ** sendrecv_errp,int ** tape_errp)939 ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *ndmpd_zfs_args,
940 int **sendrecv_errp, int **tape_errp)
941 {
942 funct_t sendrecv_func;
943 funct_t tape_func;
944 int sendrecv_err;
945 int tape_err;
946
947 switch (ndmpd_zfs_params->mp_operation) {
948 case NDMP_DATA_OP_BACKUP:
949 sendrecv_func = ndmpd_zfs_backup_send_read;
950 tape_func = ndmpd_zfs_backup_tape_write;
951 break;
952 case NDMP_DATA_OP_RECOVER:
953 sendrecv_func = ndmpd_zfs_restore_recv_write;
954 tape_func = ndmpd_zfs_restore_tape_read;
955 break;
956 }
957
958 sendrecv_err = pthread_create(&ndmpd_zfs_args->nz_sendrecv_thread,
959 NULL, sendrecv_func, ndmpd_zfs_args);
960
961 if (sendrecv_err == 0) {
962 tape_err = pthread_create(&ndmpd_zfs_args->nz_tape_thread,
963 NULL, tape_func, ndmpd_zfs_args);
964
965 if (tape_err) {
966 /*
967 * The close of the tape side of the pipe will cause
968 * nz_sendrecv_thread to error in the zfs_send/recv()
969 * call and to return. Hence we do not need
970 * to explicitly cancel the sendrecv_thread here
971 * (the pthread_join() below is sufficient).
972 */
973
974 (void) close(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE]);
975 NDMP_LOG(LOG_ERR, "Could not start tape thread; "
976 "aborting z-op");
977 }
978
979 (void) pthread_join(ndmpd_zfs_args->nz_sendrecv_thread,
980 (void **) sendrecv_errp);
981 }
982
983 if ((tape_err == 0) &&
984 (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_RECOVER))
985 ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
986
987 ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS);
988
989 if ((sendrecv_err == 0) && (tape_err == 0)) {
990 (void) pthread_join(ndmpd_zfs_args->nz_tape_thread,
991 (void **) tape_errp);
992 }
993
994 if ((tape_err == 0) &&
995 (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP))
996 ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
997
998 return (sendrecv_err ? sendrecv_err : tape_err);
999 }
1000
1001 int
ndmpd_zfs_abort(void * arg)1002 ndmpd_zfs_abort(void *arg)
1003 {
1004 ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
1005 char str[8];
1006
1007 if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP)
1008 (void) strlcpy(str, "backup", 8);
1009 else
1010 (void) strlcpy(str, "recover", 8);
1011
1012 NDMP_LOG(LOG_ERR, "ndmpd_zfs_abort() called...aborting %s operation",
1013 str);
1014
1015 ndmpd_zfs_close_fds(ndmpd_zfs_args);
1016
1017 return (0);
1018 }
1019
1020 /*
1021 * ndmpd_zfs_pre_backup()
1022 *
1023 * Note: The memset to 0 of nctxp ensures that nctx->nc_cmds == NULL.
1024 * This ensures that ndmp_include_zfs() will fail, which is
1025 * a requirement for "zfs"-type backup.
1026 */
1027
1028 int
ndmpd_zfs_pre_backup(ndmpd_zfs_args_t * ndmpd_zfs_args)1029 ndmpd_zfs_pre_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
1030 {
1031 ndmpd_session_t *session = (ndmpd_session_t *)
1032 (ndmpd_zfs_params->mp_daemon_cookie);
1033 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
1034 int err;
1035
1036 if (ndmp_pl == NULL || ndmp_pl->np_pre_backup == NULL)
1037 return (0);
1038
1039 (void) memset(nctxp, 0, sizeof (ndmp_context_t));
1040 nctxp->nc_plversion = ndmp_pl->np_plversion;
1041 nctxp->nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
1042 nctxp->nc_ddata = (void *) session;
1043 nctxp->nc_params = ndmpd_zfs_params;
1044
1045 err = ndmp_pl->np_pre_backup(ndmp_pl, nctxp,
1046 ndmpd_zfs_args->nz_dataset);
1047
1048 if (err != 0) {
1049 NDMP_LOG(LOG_DEBUG, "Pre-backup plug-in: %m");
1050 (void) ndmpd_zfs_post_backup(ndmpd_zfs_args);
1051 }
1052
1053 return (err);
1054 }
1055
1056 int
ndmpd_zfs_post_backup(ndmpd_zfs_args_t * ndmpd_zfs_args)1057 ndmpd_zfs_post_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
1058 {
1059 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
1060 int err = 0;
1061
1062 if (ndmp_pl == NULL || ndmp_pl->np_post_backup == NULL)
1063 return (0);
1064
1065 err = ndmp_pl->np_post_backup(ndmp_pl, nctxp, err);
1066
1067 if (err == -1)
1068 NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m");
1069
1070 return (err);
1071 }
1072
1073 int
ndmpd_zfs_pre_restore(ndmpd_zfs_args_t * ndmpd_zfs_args)1074 ndmpd_zfs_pre_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
1075 {
1076 ndmpd_session_t *session = (ndmpd_session_t *)
1077 (ndmpd_zfs_params->mp_daemon_cookie);
1078 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
1079 char bkpath[ZFS_MAX_DATASET_NAME_LEN];
1080 int err;
1081
1082 if (ndmp_pl == NULL || ndmp_pl->np_pre_restore == NULL)
1083 return (0);
1084
1085 err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, bkpath,
1086 ZFS_MAX_DATASET_NAME_LEN);
1087
1088 if (err != 0) {
1089 NDMP_LOG(LOG_DEBUG, "error getting bkup path: %d", err);
1090 return (-1);
1091 }
1092
1093 err = ndmpd_zfs_restore_getpath(ndmpd_zfs_args);
1094
1095 if (err != 0) {
1096 NDMP_LOG(LOG_DEBUG, "error getting restore path: %d", err);
1097 return (-1);
1098 }
1099
1100 (void) memset(nctxp, 0, sizeof (ndmp_context_t));
1101 nctxp->nc_ddata = (void *) session;
1102 nctxp->nc_params = ndmpd_zfs_params;
1103
1104 err = ndmp_pl->np_pre_restore(ndmp_pl, nctxp, bkpath,
1105 ndmpd_zfs_args->nz_dataset);
1106
1107 if (err != 0) {
1108 NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m");
1109 return (-1);
1110 }
1111
1112 return (0);
1113 }
1114
1115 int
ndmpd_zfs_post_restore(ndmpd_zfs_args_t * ndmpd_zfs_args)1116 ndmpd_zfs_post_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
1117 {
1118 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
1119 int err = 0;
1120
1121 if (ndmp_pl == NULL || ndmp_pl->np_post_restore == NULL)
1122 return (0);
1123
1124 err = ndmp_pl->np_post_restore(ndmp_pl, nctxp, err);
1125
1126 if (err == -1)
1127 NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
1128
1129 return (err);
1130 }
1131
1132 boolean_t
ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t * ndmpd_zfs_args)1133 ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1134 {
1135 ndmpd_zfs_snapfind_t snapdata;
1136
1137 if (ndmpd_zfs_backup_getenv(ndmpd_zfs_args) != 0)
1138 return (B_FALSE);
1139
1140 if (!ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args))
1141 return (B_FALSE);
1142
1143 if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
1144 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
1145 snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_TRUE);
1146
1147 snapdata.nzs_snapname[0] = '\0';
1148 snapdata.nzs_snapprop[0] = '\0';
1149
1150 if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata))
1151 return (B_FALSE);
1152
1153 if (snapdata.nzs_snapname[0] == '\0') { /* not found */
1154 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1155 "Snapshot for level %d does not exist\n",
1156 ndmpd_zfs_args->nz_level-1);
1157 return (B_FALSE);
1158 }
1159
1160 (void) strlcpy(ndmpd_zfs_args->nz_fromsnap,
1161 snapdata.nzs_snapname, ZFS_MAX_DATASET_NAME_LEN);
1162 }
1163
1164 return (B_TRUE);
1165 }
1166
1167 /*
1168 * ndmpd_zfs_backup_pathvalid()
1169 *
1170 * Make sure the path is of an existing dataset
1171 */
1172
1173 static boolean_t
ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t * ndmpd_zfs_args)1174 ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1175 {
1176 char zpath[ZFS_MAX_DATASET_NAME_LEN];
1177 char propstr[ZFS_MAXPROPLEN];
1178 zfs_handle_t *zhp;
1179 zfs_type_t ztype = 0;
1180 int err;
1181
1182 if (ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath,
1183 ZFS_MAX_DATASET_NAME_LEN) != 0)
1184 return (B_FALSE);
1185
1186 if (ndmpd_zfs_args->nz_snapname[0] != '\0') {
1187 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, zpath,
1188 ZFS_TYPE_SNAPSHOT);
1189
1190 if (!zhp) {
1191 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args,
1192 "zfs_open (snap)");
1193 ndmpd_zfs_args->nz_snapname[0] = '\0';
1194 ndmpd_zfs_args->nz_dataset[0] = '\0';
1195 return (B_FALSE);
1196 }
1197
1198 err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
1199
1200 zfs_close(zhp);
1201
1202 if (err) {
1203 NDMP_LOG(LOG_DEBUG,
1204 "ndmpd_zfs_snapshot_prop_get failed");
1205 return (-1);
1206 }
1207
1208 if (propstr && ndmpd_zfs_snapshot_ndmpd_generated(propstr)) {
1209 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1210 "cannot use an ndmpd-generated snapshot\n");
1211 return (B_FALSE);
1212 }
1213 }
1214
1215 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
1216 ndmpd_zfs_args->nz_dataset, ZFS_TYPE_DATASET);
1217
1218 if (zhp) {
1219 ztype = zfs_get_type(zhp);
1220 zfs_close(zhp);
1221 }
1222
1223 if ((ztype == ZFS_TYPE_VOLUME) ||
1224 (ztype == ZFS_TYPE_FILESYSTEM)) {
1225 ndmpd_zfs_args->nz_type = ztype;
1226 return (B_TRUE);
1227 }
1228
1229 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1230 "Invalid file system or volume.\n");
1231
1232 return (B_FALSE);
1233 }
1234
1235 /*
1236 * ndmpd_zfs_backup_getpath()
1237 *
1238 * Retrieve the backup path from the environment, which should
1239 * be of the form "/dataset[@snap]". The leading slash is required
1240 * by certain DMA's but can otherwise be ignored.
1241 *
1242 * (Note: "dataset" can consist of more than one component,
1243 * e.g. "pool", "pool/volume", "pool/fs/fs2".)
1244 *
1245 * The dataset name and the snapshot name (if any) will be
1246 * stored in ndmpd_zfs_args.
1247 */
1248
1249 static int
ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t * ndmpd_zfs_args,char * zpath,int zlen)1250 ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args, char *zpath,
1251 int zlen)
1252 {
1253 char *env_path;
1254 char *at;
1255
1256 env_path = get_backup_path_v3(ndmpd_zfs_params);
1257 if (env_path == NULL)
1258 return (-1);
1259
1260 if (env_path[0] != '/') {
1261 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1262 "Invalid path: %s (leading slash required)\n", env_path);
1263 return (-1);
1264 }
1265
1266 (void) strlcpy(zpath, &env_path[1], zlen);
1267 (void) strlcpy(ndmpd_zfs_args->nz_dataset, &env_path[1],
1268 ZFS_MAX_DATASET_NAME_LEN);
1269
1270 at = strchr(ndmpd_zfs_args->nz_dataset, '@');
1271 if (at) {
1272 *at = '\0';
1273 (void) strlcpy(ndmpd_zfs_args->nz_snapname, ++at,
1274 ZFS_MAX_DATASET_NAME_LEN);
1275 } else {
1276 ndmpd_zfs_args->nz_snapname[0] = '\0';
1277 }
1278
1279 (void) trim_whitespace(ndmpd_zfs_args->nz_dataset);
1280
1281 return (0);
1282 }
1283
1284 static int
ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t * ndmpd_zfs_args)1285 ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
1286 {
1287 return (ndmpd_zfs_getenv(ndmpd_zfs_args));
1288 }
1289
1290 boolean_t
ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t * ndmpd_zfs_args)1291 ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1292 {
1293 if (ndmpd_zfs_restore_getenv(ndmpd_zfs_args) != 0)
1294 return (B_FALSE);
1295
1296 if (!ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args))
1297 return (B_FALSE);
1298
1299 return (B_TRUE);
1300 }
1301
1302 static boolean_t
ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t * ndmpd_zfs_args)1303 ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1304 {
1305 zfs_handle_t *zhp;
1306 char *at;
1307
1308 if (ndmpd_zfs_restore_getpath(ndmpd_zfs_args) != 0)
1309 return (B_FALSE);
1310
1311 at = strchr(ndmpd_zfs_args->nz_dataset, '@');
1312
1313 if (at) {
1314 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING,
1315 "%s ignored in restore path\n", at);
1316 *at = '\0';
1317 }
1318
1319 ndmpd_zfs_args->nz_type = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM;
1320
1321 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
1322 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
1323
1324 if (zhp) {
1325 zfs_close(zhp);
1326
1327 if (!ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
1328 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1329 "Restore dataset exists.\n"
1330 "A nonexistent dataset must be specified "
1331 "for 'zfs' non-incremental restore.\n");
1332 return (B_FALSE);
1333 }
1334 }
1335
1336 NDMP_LOG(LOG_DEBUG, "restore path: %s\n", ndmpd_zfs_args->nz_dataset);
1337
1338 return (B_TRUE);
1339 }
1340
1341 /*
1342 * ndmpd_zfs_restore_getpath()
1343 *
1344 * Be sure to not include the leading slash, which is required for
1345 * compatibility with backup applications (NBU) but which is not part
1346 * of the ZFS syntax. (Note that this done explicitly in all paths
1347 * below except those calling ndmpd_zfs_backup_getpath(), because it is
1348 * already stripped in that function.)
1349 *
1350 * In addition, the DMA might add a trailing slash to the path.
1351 * Strip all such slashes.
1352 */
1353
1354 static int
ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t * ndmpd_zfs_args)1355 ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args)
1356 {
1357 int version = ndmpd_zfs_params->mp_protocol_version;
1358 char zpath[ZFS_MAX_DATASET_NAME_LEN];
1359 mem_ndmp_name_v3_t *namep_v3;
1360 char *dataset = ndmpd_zfs_args->nz_dataset;
1361 char *nm;
1362 char *p;
1363 int len;
1364 int err;
1365
1366 namep_v3 = (mem_ndmp_name_v3_t *)MOD_GETNAME(ndmpd_zfs_params, 0);
1367
1368 if (namep_v3 == NULL) {
1369 NDMP_LOG(LOG_DEBUG, "Can't get Nlist[0]");
1370 return (-1);
1371 }
1372
1373 if (namep_v3->nm3_dpath) {
1374 if (namep_v3->nm3_dpath[0] != '/') {
1375 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1376 "Invalid path: %s (leading slash required)\n",
1377 namep_v3->nm3_dpath);
1378 return (-1);
1379 }
1380
1381 (void) strlcpy(dataset, &(namep_v3->nm3_dpath[1]),
1382 ZFS_MAX_DATASET_NAME_LEN);
1383
1384 if (namep_v3->nm3_newnm) {
1385 (void) strlcat(dataset, "/", ZFS_MAX_DATASET_NAME_LEN);
1386 (void) strlcat(dataset, namep_v3->nm3_newnm,
1387 ZFS_MAX_DATASET_NAME_LEN);
1388
1389 } else {
1390 if (version == NDMPV3) {
1391 /*
1392 * The following does not apply for V4.
1393 *
1394 * Find the last component of nm3_opath.
1395 * nm3_opath has no trailing '/'.
1396 */
1397 p = strrchr(namep_v3->nm3_opath, '/');
1398 nm = p? p : namep_v3->nm3_opath;
1399 (void) strlcat(dataset, "/",
1400 ZFS_MAX_DATASET_NAME_LEN);
1401 (void) strlcat(dataset, nm,
1402 ZFS_MAX_DATASET_NAME_LEN);
1403 }
1404 }
1405 } else {
1406 err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath,
1407 ZFS_MAX_DATASET_NAME_LEN);
1408 if (err)
1409 return (err);
1410 }
1411
1412 len = strlen(dataset);
1413 while (dataset[len-1] == '/') {
1414 dataset[len-1] = '\0';
1415 len--;
1416 }
1417
1418 return (0);
1419 }
1420
1421 static int
ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t * ndmpd_zfs_args)1422 ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
1423 {
1424 if (ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args) != 0)
1425 return (-1);
1426
1427 return (ndmpd_zfs_getenv(ndmpd_zfs_args));
1428 }
1429
1430 static int
ndmpd_zfs_getenv(ndmpd_zfs_args_t * ndmpd_zfs_args)1431 ndmpd_zfs_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
1432 {
1433
1434 if (ndmpd_zfs_getenv_level(ndmpd_zfs_args) != 0)
1435 return (-1);
1436
1437 if (ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args) != 0)
1438 return (-1);
1439
1440 if (ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args) != 0)
1441 return (-1);
1442
1443 if (ndmpd_zfs_getenv_update(ndmpd_zfs_args) != 0)
1444 return (-1);
1445
1446 if (ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args) != 0)
1447 return (-1);
1448
1449 return (0);
1450 }
1451
1452 static int
ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t * ndmpd_zfs_args)1453 ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *ndmpd_zfs_args)
1454 {
1455 char *envp;
1456
1457 envp = MOD_GETENV(ndmpd_zfs_params, "ZFS_MODE");
1458
1459 if (envp == NULL) {
1460 NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE) not specified, "
1461 "defaulting to recursive");
1462 ndmpd_zfs_args->nz_zfs_mode = 'r';
1463 return (0);
1464 }
1465
1466 if ((strcmp(envp, "dataset") == 0) || (strcmp(envp, "d") == 0)) {
1467 ndmpd_zfs_args->nz_zfs_mode = 'd';
1468 } else if ((strcmp(envp, "recursive") == 0) ||
1469 (strcmp(envp, "r") == 0)) {
1470 ndmpd_zfs_args->nz_zfs_mode = 'r';
1471 } else if ((strcmp(envp, "package") == 0) || (strcmp(envp, "p") == 0)) {
1472 ndmpd_zfs_args->nz_zfs_mode = 'p';
1473 } else {
1474 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1475 "Invalid ZFS_MODE value \"%s\".\n", envp);
1476 return (-1);
1477 }
1478
1479 NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE): \"%c\"",
1480 ndmpd_zfs_args->nz_zfs_mode);
1481
1482 return (0);
1483 }
1484
1485 /*
1486 * ndmpd_zfs_getenv_zfs_force()
1487 *
1488 * If SMF property zfs-force-override is set to "yes" or "no", this
1489 * value will override any value of NDMP environment variable ZFS_FORCE
1490 * as set by the DMA admin (or override the default of 'n', if ZFS_FORCE
1491 * is not set). By default, zfs-force-override is "off", which means it
1492 * will not override ZFS_FORCE.
1493 */
1494
1495 static int
ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t * ndmpd_zfs_args)1496 ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *ndmpd_zfs_args)
1497 {
1498 char *envp_force;
1499 char *override;
1500
1501 override = ndmpd_get_prop(NDMP_ZFS_FORCE_OVERRIDE);
1502
1503 if (strcasecmp(override, "yes") == 0) {
1504 ndmpd_zfs_args->nz_zfs_force = B_TRUE;
1505 NDMP_LOG(LOG_NOTICE,
1506 "SMF property zfs-force-override set to 'yes', "
1507 "overriding ZFS_FORCE");
1508 return (0);
1509 }
1510
1511 if (strcasecmp(override, "no") == 0) {
1512 ndmpd_zfs_args->nz_zfs_force = B_FALSE;
1513 NDMP_LOG(LOG_NOTICE,
1514 "SMF property zfs-force-override set to 'no', "
1515 "overriding ZFS_FORCE");
1516 return (0);
1517 }
1518
1519 if (strcasecmp(override, "off") != 0) {
1520 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1521 "SMF property zfs-force-override set to invalid value of "
1522 "'%s'; treating it as 'off'.", override);
1523 }
1524
1525 envp_force = MOD_GETENV(ndmpd_zfs_params, "ZFS_FORCE");
1526
1527 if (envp_force == NULL) {
1528 NDMP_LOG(LOG_DEBUG,
1529 "env(ZFS_FORCE) not specified, defaulting to FALSE");
1530 ndmpd_zfs_args->nz_zfs_force = B_FALSE;
1531 return (0);
1532 }
1533
1534 /*
1535 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
1536 */
1537
1538 if (strchr("tTyY", *envp_force))
1539 ndmpd_zfs_args->nz_zfs_force = B_TRUE;
1540
1541 NDMP_LOG(LOG_DEBUG, "env(ZFS_FORCE): \"%s\"", envp_force);
1542
1543 return (0);
1544 }
1545
1546 static int
ndmpd_zfs_getenv_level(ndmpd_zfs_args_t * ndmpd_zfs_args)1547 ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *ndmpd_zfs_args)
1548 {
1549 char *envp;
1550
1551 envp = MOD_GETENV(ndmpd_zfs_params, "LEVEL");
1552
1553 if (envp == NULL) {
1554 NDMP_LOG(LOG_DEBUG, "env(LEVEL) not specified, "
1555 "defaulting to 0");
1556 ndmpd_zfs_args->nz_level = 0;
1557 return (0);
1558 }
1559
1560 if (envp[1] != '\0') {
1561 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1562 "Invalid backup level \"%s\".\n", envp);
1563 return (-1);
1564 }
1565
1566 if (!isdigit(*envp)) {
1567 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1568 "Invalid backup level \"%s\".\n", envp);
1569 return (-1);
1570 }
1571
1572 ndmpd_zfs_args->nz_level = atoi(envp);
1573
1574 NDMP_LOG(LOG_DEBUG, "env(LEVEL): \"%d\"",
1575 ndmpd_zfs_args->nz_level);
1576
1577 return (0);
1578 }
1579
1580 static int
ndmpd_zfs_getenv_update(ndmpd_zfs_args_t * ndmpd_zfs_args)1581 ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *ndmpd_zfs_args)
1582 {
1583 char *envp_update;
1584
1585 envp_update = MOD_GETENV(ndmpd_zfs_params, "UPDATE");
1586
1587 if (envp_update == NULL) {
1588 NDMP_LOG(LOG_DEBUG,
1589 "env(UPDATE) not specified, defaulting to TRUE");
1590 ndmpd_zfs_args->nz_update = B_TRUE;
1591 return (0);
1592 }
1593
1594 /*
1595 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
1596 */
1597
1598 if (strchr("tTyY", *envp_update))
1599 ndmpd_zfs_args->nz_update = B_TRUE;
1600
1601 NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp_update);
1602
1603 return (0);
1604 }
1605
1606 static int
ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t * ndmpd_zfs_args)1607 ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *ndmpd_zfs_args)
1608 {
1609 char *envp;
1610
1611 envp = MOD_GETENV(ndmpd_zfs_params, "DMP_NAME");
1612
1613 if (envp == NULL) {
1614 NDMP_LOG(LOG_DEBUG,
1615 "env(DMP_NAME) not specified, defaulting to 'level'");
1616 (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, "level",
1617 NDMPD_ZFS_DMP_NAME_MAX);
1618 return (0);
1619 }
1620
1621 if (!ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args, envp))
1622 return (-1);
1623
1624 (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, envp,
1625 NDMPD_ZFS_DMP_NAME_MAX);
1626
1627 NDMP_LOG(LOG_DEBUG, "env(DMP_NAME): \"%s\"", envp);
1628
1629 return (0);
1630 }
1631
1632 static int
ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t * ndmpd_zfs_args)1633 ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args)
1634 {
1635 char *zfs_backup_size;
1636
1637 zfs_backup_size = MOD_GETENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE");
1638
1639 if (zfs_backup_size == NULL) {
1640 NDMP_LOG(LOG_ERR, "ZFS_BACKUP_SIZE env is NULL");
1641 return (-1);
1642 }
1643
1644 NDMP_LOG(LOG_DEBUG, "ZFS_BACKUP_SIZE: %s\n", zfs_backup_size);
1645
1646 (void) sscanf(zfs_backup_size, "%llu",
1647 &ndmpd_zfs_args->nz_zfs_backup_size);
1648
1649 return (0);
1650 }
1651
1652 /*
1653 * ndmpd_zfs_dmp_name_valid()
1654 *
1655 * This function verifies that the dmp_name is valid.
1656 *
1657 * The dmp_name is restricted to alphanumeric characters plus
1658 * the underscore and hyphen, and must be 31 characters or less.
1659 * This is due to its use in the NDMPD_ZFS_PROP_INCR property
1660 * and in the ZFS snapshot name (if an ndmpd-generated snapshot
1661 * is required).
1662 */
1663
1664 static boolean_t
ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t * ndmpd_zfs_args,char * dmp_name)1665 ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *ndmpd_zfs_args, char *dmp_name)
1666 {
1667 char *c;
1668
1669 if (strlen(dmp_name) >= NDMPD_ZFS_DMP_NAME_MAX) {
1670 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1671 "DMP_NAME %s is longer than %d\n",
1672 dmp_name, NDMPD_ZFS_DMP_NAME_MAX-1);
1673 return (B_FALSE);
1674 }
1675
1676 for (c = dmp_name; *c != '\0'; c++) {
1677 if (!isalpha(*c) && !isdigit(*c) &&
1678 (*c != '_') && (*c != '-')) {
1679 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1680 "DMP_NAME %s contains illegal character %c\n",
1681 dmp_name, *c);
1682 return (B_FALSE);
1683 }
1684 }
1685
1686 NDMP_LOG(LOG_DEBUG, "DMP_NAME is valid: %s\n", dmp_name);
1687 return (B_TRUE);
1688 }
1689
1690 /*
1691 * ndmpd_zfs_is_incremental()
1692 *
1693 * This can only be called after ndmpd_zfs_getenv_level()
1694 * has been called.
1695 */
1696
1697 static boolean_t
ndmpd_zfs_is_incremental(ndmpd_zfs_args_t * ndmpd_zfs_args)1698 ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *ndmpd_zfs_args)
1699 {
1700 return (ndmpd_zfs_args->nz_level != 0);
1701 }
1702
1703 /*
1704 * ndmpd_zfs_snapshot_prepare()
1705 *
1706 * If no snapshot was supplied by the user, create a snapshot
1707 * for use by ndmpd.
1708 */
1709
1710 static int
ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t * ndmpd_zfs_args)1711 ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *ndmpd_zfs_args)
1712 {
1713 ndmpd_session_t *session = (ndmpd_session_t *)
1714 (ndmpd_zfs_params->mp_daemon_cookie);
1715 boolean_t recursive = B_FALSE;
1716 int zfs_err = 0;
1717
1718 if (session->ns_data.dd_abort) {
1719 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
1720 ndmpd_zfs_args->nz_dataset);
1721 return (-1);
1722 }
1723
1724 if (ndmpd_zfs_args->nz_snapname[0] == '\0') {
1725 ndmpd_zfs_args->nz_ndmpd_snap = B_TRUE;
1726
1727 if (ndmpd_zfs_snapshot_create(ndmpd_zfs_args) != 0) {
1728 ndmpd_zfs_args->nz_snapname[0] = '\0';
1729
1730 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1731 "Error creating snapshot for %s\n",
1732 ndmpd_zfs_args->nz_dataset);
1733
1734 return (-1);
1735 }
1736 }
1737
1738 if (ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args)) {
1739 NDMP_LOG(LOG_DEBUG,
1740 "ndmpd_zfs_snapshot_prop_add error\n");
1741
1742 if (ndmpd_zfs_args->nz_ndmpd_snap) {
1743
1744 if (ndmpd_zfs_args->nz_zfs_mode != 'd')
1745 recursive = B_TRUE;
1746
1747 (void) snapshot_destroy(ndmpd_zfs_args->nz_dataset,
1748 ndmpd_zfs_args->nz_snapname, recursive, B_FALSE,
1749 &zfs_err);
1750 }
1751
1752 return (-1);
1753 }
1754
1755 return (0);
1756 }
1757
1758 /*
1759 * ndmpd_zfs_snapshot_cleanup()
1760 *
1761 * If UPDATE = y, find the old snapshot (if any) corresponding to
1762 * {LEVEL, DMP_NAME, ZFS_MODE}. If it was ndmpd-generated,
1763 * remove the snapshot. Otherwise, update its NDMPD_ZFS_PROP_INCR
1764 * property to remove {L, D, Z}.
1765 *
1766 * If UPDATE = n, if an ndmpd-generated snapshot was used for backup,
1767 * remove the snapshot. Otherwise, update its NDMPD_ZFS_PROP_INCR
1768 * property to remove {L, D, Z}.
1769 */
1770
1771 static int
ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t * ndmpd_zfs_args,int err)1772 ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *ndmpd_zfs_args, int err)
1773 {
1774 ndmpd_session_t *session = (ndmpd_session_t *)
1775 (ndmpd_zfs_params->mp_daemon_cookie);
1776 ndmpd_zfs_snapfind_t snapdata;
1777 boolean_t ndmpd_generated = B_FALSE;
1778
1779 bzero(&snapdata, sizeof (ndmpd_zfs_snapfind_t));
1780
1781 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
1782 snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_FALSE);
1783
1784 if (ndmpd_zfs_args->nz_update && !session->ns_data.dd_abort && !err) {
1785 /*
1786 * Find the existing snapshot, if any, to "unuse."
1787 * Indicate that the current snapshot used for backup
1788 * should be skipped in the search. (The search is
1789 * sorted by creation time but this cannot be relied
1790 * upon for user-supplied snapshots.)
1791 */
1792
1793 (void) snprintf(snapdata.nzs_snapskip, ZFS_MAX_DATASET_NAME_LEN,
1794 "%s", ndmpd_zfs_args->nz_snapname);
1795
1796 if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata)) {
1797 NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_find error\n");
1798 goto _remove_tmp_snap;
1799 }
1800
1801 if (snapdata.nzs_snapname[0] != '\0') { /* snapshot found */
1802 ndmpd_generated = ndmpd_zfs_snapshot_ndmpd_generated
1803 (snapdata.nzs_snapprop);
1804
1805 if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args,
1806 ndmpd_generated, &snapdata) != 0) {
1807 NDMP_LOG(LOG_DEBUG,
1808 "ndmpd_zfs_snapshot_unuse error\n");
1809 goto _remove_tmp_snap;
1810 }
1811 }
1812
1813 if (session->ns_data.dd_abort)
1814 goto _remove_tmp_snap;
1815
1816 return (0);
1817 }
1818
1819 _remove_tmp_snap:
1820
1821 (void) snprintf(snapdata.nzs_snapname, ZFS_MAX_DATASET_NAME_LEN, "%s",
1822 ndmpd_zfs_args->nz_snapname);
1823
1824 (void) strlcpy(snapdata.nzs_snapprop, ndmpd_zfs_args->nz_snapprop,
1825 ZFS_MAXPROPLEN);
1826
1827 snapdata.nzs_snapskip[0] = '\0';
1828
1829 if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args,
1830 ndmpd_zfs_args->nz_ndmpd_snap, &snapdata) != 0) {
1831 NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_unuse error\n");
1832 return (-1);
1833 }
1834
1835 if (!ndmpd_zfs_args->nz_update)
1836 return (0);
1837
1838 return (-1);
1839 }
1840
1841 static int
ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t * ndmpd_zfs_args)1842 ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *ndmpd_zfs_args)
1843 {
1844 boolean_t recursive = B_FALSE;
1845
1846 if (ndmpd_zfs_snapname_create(ndmpd_zfs_args,
1847 ndmpd_zfs_args->nz_snapname, ZFS_MAX_DATASET_NAME_LEN - 1) < 0) {
1848 NDMP_LOG(LOG_ERR, "Error (%d) creating snapshot name for %s",
1849 errno, ndmpd_zfs_args->nz_dataset);
1850 return (-1);
1851 }
1852
1853 if (ndmpd_zfs_args->nz_zfs_mode != 'd')
1854 recursive = B_TRUE;
1855
1856 if (snapshot_create(ndmpd_zfs_args->nz_dataset,
1857 ndmpd_zfs_args->nz_snapname, recursive, B_FALSE) != 0) {
1858 NDMP_LOG(LOG_ERR, "could not create snapshot %s@%s",
1859 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname);
1860 return (-1);
1861 }
1862
1863 NDMP_LOG(LOG_DEBUG, "created snapshot %s@%s",
1864 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname);
1865
1866 return (0);
1867 }
1868
1869 /*
1870 * ndmpd_zfs_snapshot_unuse()
1871 *
1872 * Given a pre-existing snapshot of the given {L, D, Z}:
1873 * If snapshot is ndmpd-generated, remove snapshot.
1874 * If not ndmpd-generated, or if the ndmpd-generated snapshot
1875 * cannot be destroyed, remove the {L, D, Z} substring from the
1876 * snapshot's NDMPD_ZFS_PROP_INCR property.
1877 *
1878 * In the event of a failure, it may be that two snapshots will
1879 * have the {L, D, Z} property set on them. This is not desirable,
1880 * so return an error and log the failure.
1881 */
1882
1883 static int
ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t * ndmpd_zfs_args,boolean_t ndmpd_generated,ndmpd_zfs_snapfind_t * snapdata_p)1884 ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *ndmpd_zfs_args,
1885 boolean_t ndmpd_generated, ndmpd_zfs_snapfind_t *snapdata_p)
1886 {
1887 boolean_t recursive = B_FALSE;
1888 int zfs_err = 0;
1889 int err = 0;
1890
1891 if (ndmpd_generated) {
1892 if (ndmpd_zfs_args->nz_zfs_mode != 'd')
1893 recursive = B_TRUE;
1894
1895 err = snapshot_destroy(ndmpd_zfs_args->nz_dataset,
1896 snapdata_p->nzs_snapname, recursive, B_FALSE, &zfs_err);
1897
1898 if (err) {
1899 NDMP_LOG(LOG_ERR, "snapshot_destroy: %s@%s;"
1900 " err: %d; zfs_err: %d",
1901 ndmpd_zfs_args->nz_dataset,
1902 snapdata_p->nzs_snapname, err, zfs_err);
1903 return (-1);
1904 }
1905 }
1906
1907 if (!ndmpd_generated || zfs_err) {
1908 if (ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args, snapdata_p))
1909 return (-1);
1910 }
1911
1912 return (0);
1913 }
1914
1915 static boolean_t
ndmpd_zfs_snapshot_ndmpd_generated(char * snapprop)1916 ndmpd_zfs_snapshot_ndmpd_generated(char *snapprop)
1917 {
1918 char origin;
1919
1920 (void) sscanf(snapprop, "%*u.%*u.%c%*s", &origin);
1921
1922 return (origin == 'n');
1923 }
1924
1925 /*
1926 * ndmpd_zfs_snapshot_find()
1927 *
1928 * Find a snapshot with a particular value for
1929 * the NDMPD_ZFS_PROP_INCR property.
1930 */
1931
1932 static int
ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t * ndmpd_zfs_args,ndmpd_zfs_snapfind_t * snapdata)1933 ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *ndmpd_zfs_args,
1934 ndmpd_zfs_snapfind_t *snapdata)
1935 {
1936 zfs_handle_t *zhp;
1937 int err;
1938
1939 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
1940 ndmpd_zfs_args->nz_type);
1941
1942 if (!zhp) {
1943 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
1944 return (-1);
1945 }
1946
1947 err = zfs_iter_snapshots_sorted(zhp, ndmpd_zfs_snapshot_prop_find,
1948 snapdata);
1949
1950 zfs_close(zhp);
1951
1952 if (err) {
1953 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_iter_snapshots: %d",
1954 err);
1955 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1956 "Error iterating snapshots\n");
1957 return (-1);
1958 }
1959
1960 return (0);
1961 }
1962
1963 /*
1964 * ndmpd_zfs_snapshot_prop_find()
1965 *
1966 * Find a snapshot with a particular value for
1967 * NDMPD_ZFS_PROP_INCR. Fill in data for the first one
1968 * found (sorted by creation time). However, skip the
1969 * the snapshot indicated in nzs_snapskip, if any.
1970 */
1971
1972 static int
ndmpd_zfs_snapshot_prop_find(zfs_handle_t * zhp,void * arg)1973 ndmpd_zfs_snapshot_prop_find(zfs_handle_t *zhp, void *arg)
1974 {
1975 ndmpd_zfs_snapfind_t *snapdata_p = (ndmpd_zfs_snapfind_t *)arg;
1976 char propstr[ZFS_MAXPROPLEN];
1977 char findprop_plus_slash[ZFS_MAXPROPLEN];
1978 char *justsnap;
1979 int err = 0;
1980
1981 if (snapdata_p->nzs_snapname[0] != '\0') {
1982 NDMP_LOG(LOG_DEBUG, "no need to get prop for snapshot %s",
1983 (char *)zfs_get_name(zhp));
1984 goto _done;
1985 }
1986
1987 err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
1988
1989 if (err) {
1990 NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_prop_get failed");
1991 goto _done;
1992 }
1993
1994 if (propstr[0] == '\0') {
1995 NDMP_LOG(LOG_DEBUG, "snapshot %s: propr not set",
1996 (char *)zfs_get_name(zhp));
1997 goto _done;
1998 }
1999
2000 (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
2001 snapdata_p->nzs_findprop);
2002
2003 if (!strstr((const char *)propstr,
2004 (const char *)findprop_plus_slash)) {
2005 NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s not found)",
2006 (char *)zfs_get_name(zhp), propstr,
2007 snapdata_p->nzs_findprop);
2008 goto _done;
2009 }
2010
2011 if (!ndmpd_zfs_prop_version_check(propstr,
2012 &snapdata_p->nzs_prop_major, &snapdata_p->nzs_prop_minor)) {
2013 NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s found)",
2014 (char *)zfs_get_name(zhp), propstr,
2015 snapdata_p->nzs_findprop);
2016 NDMP_LOG(LOG_DEBUG, "did not pass version check");
2017 goto _done;
2018 }
2019
2020 justsnap = strchr(zfs_get_name(zhp), '@') + 1;
2021
2022 if (strcmp(justsnap, snapdata_p->nzs_snapskip) != 0) {
2023 (void) strlcpy(snapdata_p->nzs_snapname, justsnap,
2024 ZFS_MAX_DATASET_NAME_LEN);
2025
2026 (void) strlcpy(snapdata_p->nzs_snapprop, propstr,
2027 ZFS_MAXPROPLEN);
2028
2029 NDMP_LOG(LOG_DEBUG, "found match: %s [%s]\n",
2030 snapdata_p->nzs_snapname, snapdata_p->nzs_snapprop);
2031 }
2032
2033 _done:
2034 zfs_close(zhp);
2035 return (err);
2036 }
2037
2038 /*
2039 * ndmpd_zfs_snapshot_prop_get()
2040 *
2041 * Retrieve NDMPD_ZFS_PROP_INCR property from snapshot
2042 */
2043
2044 static int
ndmpd_zfs_snapshot_prop_get(zfs_handle_t * zhp,char * propstr)2045 ndmpd_zfs_snapshot_prop_get(zfs_handle_t *zhp, char *propstr)
2046 {
2047 nvlist_t *userprop;
2048 nvlist_t *propval;
2049 char *strval;
2050 int err;
2051
2052 propstr[0] = '\0';
2053
2054 userprop = zfs_get_user_props(zhp);
2055
2056 if (userprop == NULL)
2057 return (0);
2058
2059 err = nvlist_lookup_nvlist(userprop, NDMPD_ZFS_PROP_INCR, &propval);
2060
2061 if (err != 0) {
2062 if (err == ENOENT)
2063 return (0);
2064
2065 NDMP_LOG(LOG_DEBUG, "nvlist_lookup_nvlist error: %d\n", err);
2066
2067 return (-1);
2068 }
2069
2070 err = nvlist_lookup_string(propval, ZPROP_VALUE, &strval);
2071
2072 if (err != 0) {
2073 if (err == ENOENT)
2074 return (0);
2075
2076 NDMP_LOG(LOG_DEBUG, "nvlist_lookup_string error: %d\n", err);
2077
2078 return (-1);
2079 }
2080
2081 (void) strlcpy(propstr, strval, ZFS_MAXPROPLEN);
2082
2083 return (0);
2084 }
2085
2086 /*
2087 * ndmpd_zfs_snapshot_prop_add()
2088 *
2089 * Update snapshot's NDMPD_ZFS_PROP_INCR property with
2090 * the current LEVEL, DMP_NAME, and ZFS_MODE values
2091 * (add property if it doesn't exist)
2092 */
2093
2094 static int
ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t * ndmpd_zfs_args)2095 ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *ndmpd_zfs_args)
2096 {
2097 char fullname[ZFS_MAX_DATASET_NAME_LEN];
2098 char propstr[ZFS_MAXPROPLEN];
2099 zfs_handle_t *zhp;
2100 boolean_t set;
2101 int err;
2102
2103 (void) snprintf(fullname, ZFS_MAX_DATASET_NAME_LEN, "%s@%s",
2104 ndmpd_zfs_args->nz_dataset,
2105 ndmpd_zfs_args->nz_snapname);
2106
2107 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
2108
2109 if (!zhp) {
2110 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open (snap)");
2111 return (-1);
2112 }
2113
2114 bzero(propstr, ZFS_MAXPROPLEN);
2115
2116 if (ndmpd_zfs_snapshot_prop_get(zhp, propstr)) {
2117 NDMP_LOG(LOG_DEBUG, "error getting property");
2118 zfs_close(zhp);
2119 return (-1);
2120 }
2121
2122 if (ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args, propstr, &set)) {
2123 zfs_close(zhp);
2124 return (-1);
2125 }
2126
2127 if (set) {
2128 err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, propstr);
2129 if (err) {
2130 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
2131 err);
2132 NDMP_LOG(LOG_ERR, "error setting property %s",
2133 propstr);
2134 zfs_close(zhp);
2135 return (-1);
2136 }
2137 }
2138
2139 zfs_close(zhp);
2140
2141 (void) strlcpy(ndmpd_zfs_args->nz_snapprop, propstr, ZFS_MAXPROPLEN);
2142
2143 return (0);
2144 }
2145
2146 static int
ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t * ndmpd_zfs_args,char * propstr,boolean_t * set)2147 ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
2148 char *propstr, boolean_t *set)
2149 {
2150 char subprop[ZFS_MAXPROPLEN];
2151 char *p = propstr;
2152 int slash_count = 0;
2153
2154 *set = B_TRUE;
2155
2156 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
2157 subprop, ZFS_MAXPROPLEN, B_FALSE);
2158
2159 if (propstr[0] == '\0') {
2160 (void) snprintf(propstr, ZFS_MAXPROPLEN, "%u.%u.%c/%s",
2161 NDMPD_ZFS_PROP_MAJOR_VERSION,
2162 NDMPD_ZFS_PROP_MINOR_VERSION,
2163 (ndmpd_zfs_args->nz_ndmpd_snap) ? 'n' : 'u',
2164 subprop);
2165 return (0);
2166 }
2167
2168 if (strstr((const char *)propstr, (const char *)subprop)) {
2169 NDMP_LOG(LOG_DEBUG, "Did not add entry %s as it already exists",
2170 subprop);
2171 *set = B_FALSE;
2172 return (0);
2173 }
2174
2175 while (*p) {
2176 if (*(p++) == '/')
2177 slash_count++;
2178 }
2179
2180 if (slash_count >= NDMPD_ZFS_SUBPROP_MAX) {
2181 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2182 "snapshot %s: user property %s limit of %d subprops "
2183 "reached; cannot complete operation",
2184 ndmpd_zfs_args->nz_snapname,
2185 NDMPD_ZFS_PROP_INCR,
2186 NDMPD_ZFS_SUBPROP_MAX);
2187 return (-1);
2188 }
2189
2190 assert((strlen(propstr) + strlen(subprop) + 2) < ZFS_MAXPROPLEN);
2191
2192 (void) strlcat(propstr, "/", ZFS_MAXPROPLEN);
2193 (void) strlcat(propstr, subprop, ZFS_MAXPROPLEN);
2194
2195 return (0);
2196 }
2197
2198 static int
ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t * ndmpd_zfs_args,char * subprop,int len,boolean_t prev_level)2199 ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *ndmpd_zfs_args,
2200 char *subprop, int len, boolean_t prev_level)
2201 {
2202 return (snprintf(subprop, len, "%d.%s.%c",
2203 prev_level ? ndmpd_zfs_args->nz_level-1 : ndmpd_zfs_args->nz_level,
2204 ndmpd_zfs_args->nz_dmp_name,
2205 ndmpd_zfs_args->nz_zfs_mode));
2206 }
2207
2208 /*
2209 * ndmpd_zfs_snapshot_prop_remove()
2210 *
2211 * Remove specified substring from the snapshot's
2212 * NDMPD_ZFS_PROP_INCR property
2213 */
2214
2215 static int
ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t * ndmpd_zfs_args,ndmpd_zfs_snapfind_t * snapdata_p)2216 ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *ndmpd_zfs_args,
2217 ndmpd_zfs_snapfind_t *snapdata_p)
2218 {
2219 char findprop_plus_slash[ZFS_MAXPROPLEN];
2220 char fullname[ZFS_MAX_DATASET_NAME_LEN];
2221 char newprop[ZFS_MAXPROPLEN];
2222 char tmpstr[ZFS_MAXPROPLEN];
2223 zfs_handle_t *zhp;
2224 char *ptr;
2225 int err;
2226
2227 (void) snprintf(fullname, ZFS_MAX_DATASET_NAME_LEN, "%s@%s",
2228 ndmpd_zfs_args->nz_dataset,
2229 snapdata_p->nzs_snapname);
2230
2231 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
2232
2233 if (!zhp) {
2234 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
2235 return (-1);
2236 }
2237
2238 bzero(newprop, ZFS_MAXPROPLEN);
2239
2240 /*
2241 * If the substring to be removed is the only {L, D, Z}
2242 * in the property, remove the entire property
2243 */
2244
2245 tmpstr[0] = '\0';
2246
2247 (void) sscanf(snapdata_p->nzs_snapprop, "%*u.%*u.%*c/%1023s", tmpstr);
2248
2249 if (strcmp(tmpstr, snapdata_p->nzs_findprop) == 0) {
2250
2251 err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
2252
2253 zfs_close(zhp);
2254
2255 if (err) {
2256 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
2257 err);
2258 NDMP_LOG(LOG_ERR, "error setting property %s", newprop);
2259 return (-1);
2260 }
2261
2262 return (0);
2263 }
2264
2265 (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
2266 snapdata_p->nzs_findprop);
2267
2268 ptr = strstr((const char *)snapdata_p->nzs_snapprop,
2269 (const char *)findprop_plus_slash);
2270
2271 if (ptr == NULL) {
2272 /*
2273 * This shouldn't happen. Just return success.
2274 */
2275 zfs_close(zhp);
2276
2277 return (0);
2278 }
2279
2280 /*
2281 * Remove "nzs_findprop" substring from property
2282 *
2283 * Example property:
2284 * 0.0.u/1.bob.p/0.jane.d
2285 *
2286 * Note that there will always be a prefix to the
2287 * strstr() result. Hence the below code works for
2288 * all cases.
2289 */
2290
2291 ptr--;
2292 (void) strncpy(newprop, snapdata_p->nzs_snapprop,
2293 (char *)ptr - snapdata_p->nzs_snapprop);
2294 ptr += strlen(snapdata_p->nzs_findprop) + 1;
2295 (void) strlcat(newprop, ptr, ZFS_MAXPROPLEN);
2296
2297 err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
2298
2299 zfs_close(zhp);
2300
2301 if (err) {
2302 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", err);
2303 NDMP_LOG(LOG_ERR, "error modifying property %s", newprop);
2304 return (-1);
2305 }
2306
2307 return (0);
2308 }
2309
2310 static boolean_t
ndmpd_zfs_prop_version_check(char * propstr,uint32_t * major,uint32_t * minor)2311 ndmpd_zfs_prop_version_check(char *propstr, uint32_t *major, uint32_t *minor)
2312 {
2313 (void) sscanf(propstr, "%u.%u.%*c%*s", major, minor);
2314
2315 if (*major > NDMPD_ZFS_PROP_MAJOR_VERSION) {
2316 NDMP_LOG(LOG_ERR, "unsupported prop major (%u > %u)",
2317 *major, NDMPD_ZFS_PROP_MAJOR_VERSION);
2318 return (B_FALSE);
2319 }
2320
2321 if (*minor > NDMPD_ZFS_PROP_MINOR_VERSION) {
2322 NDMP_LOG(LOG_ERR, "later prop minor (%u > %u)",
2323 *minor, NDMPD_ZFS_PROP_MINOR_VERSION);
2324 }
2325
2326 NDMP_LOG(LOG_DEBUG, "passed version check: "
2327 "supported prop major (%u <= %u); (snapprop minor: %u [%u])",
2328 *major, NDMPD_ZFS_PROP_MAJOR_VERSION,
2329 *minor, NDMPD_ZFS_PROP_MINOR_VERSION);
2330
2331 return (B_TRUE);
2332 }
2333
2334 static int
ndmpd_zfs_snapname_create(ndmpd_zfs_args_t * ndmpd_zfs_args,char * snapname,int namelen)2335 ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
2336 char *snapname, int namelen)
2337 {
2338 char subprop[ZFS_MAXPROPLEN];
2339 struct timeval tp;
2340 int err = 0;
2341
2342 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
2343 subprop, ZFS_MAXPROPLEN, B_FALSE);
2344
2345 (void) gettimeofday(&tp, NULL);
2346
2347 err = snprintf(snapname, namelen,
2348 "ndmp.%s.%ld.%ld",
2349 subprop,
2350 tp.tv_sec,
2351 tp.tv_usec);
2352
2353 if (err > namelen) {
2354 NDMP_LOG(LOG_ERR, "name of snapshot [%s...] would exceed %d",
2355 snapname, namelen);
2356 return (-1);
2357 }
2358
2359 return (0);
2360 }
2361
2362 static void
ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t * ndmpd_zfs_args)2363 ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args)
2364 {
2365 switch (libzfs_errno(ndmpd_zfs_args->nz_zlibh)) {
2366 case EZFS_EXISTS:
2367 case EZFS_BUSY:
2368 case EZFS_NOENT:
2369 case EZFS_INVALIDNAME:
2370 case EZFS_MOUNTFAILED:
2371 case EZFS_UMOUNTFAILED:
2372 case EZFS_NAMETOOLONG:
2373 case EZFS_BADRESTORE:
2374
2375 /* use existing error text */
2376
2377 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2378 "%s: %s: %s\n",
2379 ndmpd_zfs_args->nz_dataset,
2380 libzfs_error_action(ndmpd_zfs_args->nz_zlibh),
2381 libzfs_error_description(ndmpd_zfs_args->nz_zlibh));
2382
2383 break;
2384
2385 case EZFS_NOMEM:
2386 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2387 "Unable to obtain memory for operation\n");
2388 break;
2389
2390 case EZFS_PROPSPACE:
2391 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2392 "A bad ZFS quota or reservation was encountered.\n");
2393 break;
2394
2395 case EZFS_BADSTREAM:
2396 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2397 "The backup stream is invalid.\n");
2398 break;
2399
2400 case EZFS_ZONED:
2401 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2402 "An error related to the local zone occurred.\n");
2403 break;
2404
2405 case EZFS_NOSPC:
2406 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2407 "No more space is available\n");
2408 break;
2409
2410 case EZFS_IO:
2411 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2412 "An I/O error occurred.\n");
2413 break;
2414
2415 default:
2416 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2417 "An internal ndmpd error occurred. "
2418 "Please contact support\n");
2419 break;
2420 }
2421 }
2422
2423 void
ndmpd_zfs_dma_log(ndmpd_zfs_args_t * ndmpd_zfs_args,ndmp_log_type log_type,char * format,...)2424 ndmpd_zfs_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args, ndmp_log_type log_type,
2425 char *format, ...)
2426 {
2427 static char buf[1024];
2428 va_list ap;
2429
2430 va_start(ap, format);
2431
2432 /*LINTED variable format specifier */
2433 (void) vsnprintf(buf, sizeof (buf), format, ap);
2434 va_end(ap);
2435
2436 MOD_LOGV3(ndmpd_zfs_params, log_type, buf);
2437
2438 if ((log_type) == NDMP_LOG_ERROR) {
2439 NDMP_LOG(LOG_ERR, buf);
2440 } else {
2441 NDMP_LOG(LOG_NOTICE, buf);
2442 }
2443 }
2444