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 int ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *);
78 static int ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t *);
79
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 *);
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 int
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 (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 int
ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t * ndmpd_zfs_args)611 ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
612 {
613 ndmpd_session_t *session = (ndmpd_session_t *)
614 (ndmpd_zfs_params->mp_daemon_cookie);
615 sendflags_t flags = { 0 };
616 char *fromsnap = NULL;
617 zfs_handle_t *zhp;
618 int err;
619
620 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
621 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
622
623 if (!zhp) {
624 if (!session->ns_data.dd_abort)
625 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
626 return (-1);
627 }
628
629 switch (ndmpd_zfs_args->nz_zfs_mode) {
630 case ('d'):
631 flags.props = B_TRUE;
632 break;
633 case ('r'):
634 flags.replicate = B_TRUE;
635 break;
636 case ('p'):
637 flags.doall = B_TRUE;
638 flags.replicate = B_TRUE;
639 break;
640 default:
641 NDMP_LOG(LOG_ERR, "unknown zfs_mode: %c",
642 ndmpd_zfs_args->nz_zfs_mode);
643 zfs_close(zhp);
644 return (-1);
645 }
646
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");
650 zfs_close(zhp);
651 return (-1);
652 }
653 fromsnap = ndmpd_zfs_args->nz_fromsnap;
654 }
655
656 err = zfs_send(zhp, fromsnap, ndmpd_zfs_args->nz_snapname, &flags,
657 ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL, NULL, NULL);
658
659 if (err && !session->ns_data.dd_abort)
660 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_send: %d", err);
661
662 zfs_close(zhp);
663
664 return (err);
665 }
666
667 /*
668 * ndmpd_zfs_backup_tape_write()
669 *
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).
673 */
674
675 static int
ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t * ndmpd_zfs_args)676 ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t *ndmpd_zfs_args)
677 {
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;
682 int count;
683 char *buf;
684
685 buf = ndmp_malloc(bufsize);
686 if (buf == NULL) {
687 NDMP_LOG(LOG_DEBUG, "buf NULL");
688 return (-1);
689 }
690
691 bytes_totalp =
692 &(session->ns_data.dd_module.dm_stats.ms_bytes_processed);
693
694 for (;;) {
695 bzero(buf, bufsize);
696
697 count = read(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
698 bufsize);
699
700 if (count == 0) /* EOF */ {
701 NDMP_LOG(LOG_DEBUG,
702 "zfs_send stream size: %llu bytes; "
703 "full backup size (including header): %llu",
704 *bytes_totalp - bufsize, *bytes_totalp);
705 free(buf);
706
707 return (ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args,
708 *bytes_totalp));
709 }
710
711 if (count == -1) {
712 NDMP_LOG(LOG_DEBUG, "pipe read error (errno %d)",
713 errno);
714 free(buf);
715 return (-1);
716 }
717 NS_ADD(rdisk, count);
718
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");
722 free(buf);
723 return (-1);
724 }
725
726 *bytes_totalp += count;
727 }
728 /* NOTREACHED */
729 }
730
731 static int
ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t * ndmpd_zfs_args,u_longlong_t bytes_total)732 ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args,
733 u_longlong_t bytes_total)
734 {
735 char zfs_backup_size[32];
736 int err;
737
738 (void) snprintf(zfs_backup_size, sizeof (zfs_backup_size), "%llu",
739 bytes_total);
740
741 err = MOD_ADDENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE", zfs_backup_size);
742
743 if (err) {
744 NDMP_LOG(LOG_ERR, "Failed to add ZFS_BACKUP_SIZE env");
745 return (-1);
746 }
747
748 NDMP_LOG(LOG_DEBUG, "Added ZFS_BACKUP_SIZE env: %s", zfs_backup_size);
749
750 return (0);
751 }
752
753 int
ndmpd_zfs_restore_starter(void * arg)754 ndmpd_zfs_restore_starter(void *arg)
755 {
756 ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
757 ndmpd_session_t *session = (ndmpd_session_t *)
758 (ndmpd_zfs_params->mp_daemon_cookie);
759 int err;
760
761 ndmp_session_ref(session);
762
763 err = ndmpd_zfs_restore(ndmpd_zfs_args);
764
765 MOD_DONE(ndmpd_zfs_params, err);
766
767 NS_DEC(nrs);
768
769 ndmp_session_unref(session);
770
771 ndmpd_zfs_fini(ndmpd_zfs_args);
772
773 return (err);
774 }
775
776 static int
ndmpd_zfs_restore(ndmpd_zfs_args_t * ndmpd_zfs_args)777 ndmpd_zfs_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
778 {
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;
783 int result = 0;
784 int err;
785
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");
790 return (-1);
791 }
792
793 err = ndmpd_zfs_reader_writer(ndmpd_zfs_args,
794 &write_err, &read_err);
795
796 if (err || read_err || write_err || session->ns_eof)
797 result = EIO;
798 }
799
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);
808 err = -1;
809 } else {
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);
815 if (err || result)
816 err = -1;
817
818 if (err == 0) {
819 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished",
820 ndmpd_zfs_args->nz_dataset);
821 } else {
822 NDMP_LOG(LOG_DEBUG, "An error occurred while restoring"
823 " to \"%s\"", ndmpd_zfs_args->nz_dataset);
824 }
825 }
826
827 return (err);
828 }
829
830 static int
ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t * ndmpd_zfs_args)831 ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
832 {
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;
838 u_longlong_t bytes;
839 char *buf;
840 int count;
841 int err;
842
843 buf = ndmp_malloc(bufsize);
844 if (buf == NULL) {
845 NDMP_LOG(LOG_DEBUG, "buf NULL");
846 return (-1);
847 }
848
849 bytes_totalp = &ndmpd_zfs_args->nz_nlp->nlp_bytes_total;
850
851 while (*bytes_totalp < backup_size) {
852
853 bytes = backup_size - *bytes_totalp;
854
855 if (bytes >= bufsize)
856 bytes = bufsize;
857
858 err = MOD_READ(ndmpd_zfs_params, buf, bytes);
859
860 if (err != 0) {
861 NDMP_LOG(LOG_ERR, "MOD_READ error: %d; returning -1",
862 err);
863 free(buf);
864 return (-1);
865 }
866
867 count = write(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
868 bytes);
869
870 if (count != bytes) {
871 NDMP_LOG(LOG_ERR, "count (%d) != bytes (%d)",
872 count, bytes);
873
874 if (count == -1) {
875 NDMP_LOG(LOG_ERR, "pipe write error: errno: %d",
876 errno);
877
878 if (session->ns_data.dd_abort)
879 NDMP_LOG(LOG_DEBUG, "abort set");
880 }
881
882 free(buf);
883 return (-1);
884 }
885
886 NS_ADD(wdisk, count);
887
888 *bytes_totalp += count;
889 }
890
891 free(buf);
892 return (0);
893 }
894
895 /*
896 * ndmpd_zfs_restore_recv_write()
897 *
898 * This routine executes zfs_receive() to restore the backup.
899 */
900
901 static int
ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t * ndmpd_zfs_args)902 ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t *ndmpd_zfs_args)
903 {
904 ndmpd_session_t *session = (ndmpd_session_t *)
905 (ndmpd_zfs_params->mp_daemon_cookie);
906 recvflags_t flags;
907 int err;
908
909 bzero(&flags, sizeof (recvflags_t));
910
911 flags.nomount = B_TRUE;
912
913 NDMP_LOG(LOG_DEBUG, "nz_zfs_force: %d\n", ndmpd_zfs_args->nz_zfs_force);
914
915 if (ndmpd_zfs_args->nz_zfs_force)
916 flags.force = B_TRUE;
917
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);
920
921 if (err && !session->ns_data.dd_abort)
922 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_receive: %d", err);
923
924 return (err);
925 }
926
927 /*
928 * ndmpd_zfs_reader_writer()
929 *
930 * Two separate threads are used for actual backup or restore.
931 */
932
933 static int
ndmpd_zfs_reader_writer(ndmpd_zfs_args_t * ndmpd_zfs_args,int ** sendrecv_errp,int ** tape_errp)934 ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *ndmpd_zfs_args,
935 int **sendrecv_errp, int **tape_errp)
936 {
937 funct_t sendrecv_func;
938 funct_t tape_func;
939 int sendrecv_err;
940 int tape_err;
941
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;
946 break;
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;
950 break;
951 }
952
953 sendrecv_err = pthread_create(&ndmpd_zfs_args->nz_sendrecv_thread,
954 NULL, sendrecv_func, ndmpd_zfs_args);
955
956 if (sendrecv_err == 0) {
957 tape_err = pthread_create(&ndmpd_zfs_args->nz_tape_thread,
958 NULL, tape_func, ndmpd_zfs_args);
959
960 if (tape_err) {
961 /*
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).
967 */
968
969 (void) close(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE]);
970 NDMP_LOG(LOG_ERR, "Could not start tape thread; "
971 "aborting z-op");
972 }
973
974 (void) pthread_join(ndmpd_zfs_args->nz_sendrecv_thread,
975 (void **) sendrecv_errp);
976 }
977
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);
981
982 ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS);
983
984 if ((sendrecv_err == 0) && (tape_err == 0)) {
985 (void) pthread_join(ndmpd_zfs_args->nz_tape_thread,
986 (void **) tape_errp);
987 }
988
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);
992
993 return (sendrecv_err ? sendrecv_err : tape_err);
994 }
995
996 int
ndmpd_zfs_abort(void * arg)997 ndmpd_zfs_abort(void *arg)
998 {
999 ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
1000 char str[8];
1001
1002 if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP)
1003 (void) strlcpy(str, "backup", 8);
1004 else
1005 (void) strlcpy(str, "recover", 8);
1006
1007 NDMP_LOG(LOG_ERR, "ndmpd_zfs_abort() called...aborting %s operation",
1008 str);
1009
1010 ndmpd_zfs_close_fds(ndmpd_zfs_args);
1011
1012 return (0);
1013 }
1014
1015 /*
1016 * ndmpd_zfs_pre_backup()
1017 *
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.
1021 */
1022
1023 int
ndmpd_zfs_pre_backup(ndmpd_zfs_args_t * ndmpd_zfs_args)1024 ndmpd_zfs_pre_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
1025 {
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;
1029 int err;
1030
1031 if (ndmp_pl == NULL || ndmp_pl->np_pre_backup == NULL)
1032 return (0);
1033
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;
1039
1040 err = ndmp_pl->np_pre_backup(ndmp_pl, nctxp,
1041 ndmpd_zfs_args->nz_dataset);
1042
1043 if (err != 0) {
1044 NDMP_LOG(LOG_DEBUG, "Pre-backup plug-in: %m");
1045 (void) ndmpd_zfs_post_backup(ndmpd_zfs_args);
1046 }
1047
1048 return (err);
1049 }
1050
1051 int
ndmpd_zfs_post_backup(ndmpd_zfs_args_t * ndmpd_zfs_args)1052 ndmpd_zfs_post_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
1053 {
1054 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
1055 int err = 0;
1056
1057 if (ndmp_pl == NULL || ndmp_pl->np_post_backup == NULL)
1058 return (0);
1059
1060 err = ndmp_pl->np_post_backup(ndmp_pl, nctxp, err);
1061
1062 if (err == -1)
1063 NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m");
1064
1065 return (err);
1066 }
1067
1068 int
ndmpd_zfs_pre_restore(ndmpd_zfs_args_t * ndmpd_zfs_args)1069 ndmpd_zfs_pre_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
1070 {
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];
1075 int err;
1076
1077 if (ndmp_pl == NULL || ndmp_pl->np_pre_restore == NULL)
1078 return (0);
1079
1080 err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, bkpath,
1081 ZFS_MAX_DATASET_NAME_LEN);
1082
1083 if (err != 0) {
1084 NDMP_LOG(LOG_DEBUG, "error getting bkup path: %d", err);
1085 return (-1);
1086 }
1087
1088 err = ndmpd_zfs_restore_getpath(ndmpd_zfs_args);
1089
1090 if (err != 0) {
1091 NDMP_LOG(LOG_DEBUG, "error getting restore path: %d", err);
1092 return (-1);
1093 }
1094
1095 (void) memset(nctxp, 0, sizeof (ndmp_context_t));
1096 nctxp->nc_ddata = (void *) session;
1097 nctxp->nc_params = ndmpd_zfs_params;
1098
1099 err = ndmp_pl->np_pre_restore(ndmp_pl, nctxp, bkpath,
1100 ndmpd_zfs_args->nz_dataset);
1101
1102 if (err != 0) {
1103 NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m");
1104 return (-1);
1105 }
1106
1107 return (0);
1108 }
1109
1110 int
ndmpd_zfs_post_restore(ndmpd_zfs_args_t * ndmpd_zfs_args)1111 ndmpd_zfs_post_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
1112 {
1113 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
1114 int err = 0;
1115
1116 if (ndmp_pl == NULL || ndmp_pl->np_post_restore == NULL)
1117 return (0);
1118
1119 err = ndmp_pl->np_post_restore(ndmp_pl, nctxp, err);
1120
1121 if (err == -1)
1122 NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
1123
1124 return (err);
1125 }
1126
1127 boolean_t
ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t * ndmpd_zfs_args)1128 ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1129 {
1130 ndmpd_zfs_snapfind_t snapdata;
1131
1132 if (ndmpd_zfs_backup_getenv(ndmpd_zfs_args) != 0)
1133 return (B_FALSE);
1134
1135 if (!ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args))
1136 return (B_FALSE);
1137
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);
1141
1142 snapdata.nzs_snapname[0] = '\0';
1143 snapdata.nzs_snapprop[0] = '\0';
1144
1145 if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata))
1146 return (B_FALSE);
1147
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);
1152 return (B_FALSE);
1153 }
1154
1155 (void) strlcpy(ndmpd_zfs_args->nz_fromsnap,
1156 snapdata.nzs_snapname, ZFS_MAX_DATASET_NAME_LEN);
1157 }
1158
1159 return (B_TRUE);
1160 }
1161
1162 /*
1163 * ndmpd_zfs_backup_pathvalid()
1164 *
1165 * Make sure the path is of an existing dataset
1166 */
1167
1168 static boolean_t
ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t * ndmpd_zfs_args)1169 ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1170 {
1171 char zpath[ZFS_MAX_DATASET_NAME_LEN];
1172 char propstr[ZFS_MAXPROPLEN];
1173 zfs_handle_t *zhp;
1174 zfs_type_t ztype = 0;
1175 int err;
1176
1177 if (ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath,
1178 ZFS_MAX_DATASET_NAME_LEN) != 0)
1179 return (B_FALSE);
1180
1181 if (ndmpd_zfs_args->nz_snapname[0] != '\0') {
1182 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, zpath,
1183 ZFS_TYPE_SNAPSHOT);
1184
1185 if (!zhp) {
1186 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args,
1187 "zfs_open (snap)");
1188 ndmpd_zfs_args->nz_snapname[0] = '\0';
1189 ndmpd_zfs_args->nz_dataset[0] = '\0';
1190 return (B_FALSE);
1191 }
1192
1193 err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
1194
1195 zfs_close(zhp);
1196
1197 if (err) {
1198 NDMP_LOG(LOG_DEBUG,
1199 "ndmpd_zfs_snapshot_prop_get failed");
1200 return (-1);
1201 }
1202
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");
1206 return (B_FALSE);
1207 }
1208 }
1209
1210 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
1211 ndmpd_zfs_args->nz_dataset, ZFS_TYPE_DATASET);
1212
1213 if (zhp) {
1214 ztype = zfs_get_type(zhp);
1215 zfs_close(zhp);
1216 }
1217
1218 if ((ztype == ZFS_TYPE_VOLUME) ||
1219 (ztype == ZFS_TYPE_FILESYSTEM)) {
1220 ndmpd_zfs_args->nz_type = ztype;
1221 return (B_TRUE);
1222 }
1223
1224 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1225 "Invalid file system or volume.\n");
1226
1227 return (B_FALSE);
1228 }
1229
1230 /*
1231 * ndmpd_zfs_backup_getpath()
1232 *
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.
1236 *
1237 * (Note: "dataset" can consist of more than one component,
1238 * e.g. "pool", "pool/volume", "pool/fs/fs2".)
1239 *
1240 * The dataset name and the snapshot name (if any) will be
1241 * stored in ndmpd_zfs_args.
1242 */
1243
1244 static int
ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t * ndmpd_zfs_args,char * zpath,int zlen)1245 ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args, char *zpath,
1246 int zlen)
1247 {
1248 char *env_path;
1249 char *at;
1250
1251 env_path = get_backup_path_v3(ndmpd_zfs_params);
1252 if (env_path == NULL)
1253 return (-1);
1254
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);
1258 return (-1);
1259 }
1260
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);
1264
1265 at = strchr(ndmpd_zfs_args->nz_dataset, '@');
1266 if (at) {
1267 *at = '\0';
1268 (void) strlcpy(ndmpd_zfs_args->nz_snapname, ++at,
1269 ZFS_MAX_DATASET_NAME_LEN);
1270 } else {
1271 ndmpd_zfs_args->nz_snapname[0] = '\0';
1272 }
1273
1274 (void) trim_whitespace(ndmpd_zfs_args->nz_dataset);
1275
1276 return (0);
1277 }
1278
1279 static int
ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t * ndmpd_zfs_args)1280 ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
1281 {
1282 return (ndmpd_zfs_getenv(ndmpd_zfs_args));
1283 }
1284
1285 boolean_t
ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t * ndmpd_zfs_args)1286 ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1287 {
1288 if (ndmpd_zfs_restore_getenv(ndmpd_zfs_args) != 0)
1289 return (B_FALSE);
1290
1291 if (!ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args))
1292 return (B_FALSE);
1293
1294 return (B_TRUE);
1295 }
1296
1297 static boolean_t
ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t * ndmpd_zfs_args)1298 ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1299 {
1300 zfs_handle_t *zhp;
1301 char *at;
1302
1303 if (ndmpd_zfs_restore_getpath(ndmpd_zfs_args) != 0)
1304 return (B_FALSE);
1305
1306 at = strchr(ndmpd_zfs_args->nz_dataset, '@');
1307
1308 if (at) {
1309 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING,
1310 "%s ignored in restore path\n", at);
1311 *at = '\0';
1312 }
1313
1314 ndmpd_zfs_args->nz_type = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM;
1315
1316 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
1317 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
1318
1319 if (zhp) {
1320 zfs_close(zhp);
1321
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");
1327 return (B_FALSE);
1328 }
1329 }
1330
1331 NDMP_LOG(LOG_DEBUG, "restore path: %s\n", ndmpd_zfs_args->nz_dataset);
1332
1333 return (B_TRUE);
1334 }
1335
1336 /*
1337 * ndmpd_zfs_restore_getpath()
1338 *
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.)
1344 *
1345 * In addition, the DMA might add a trailing slash to the path.
1346 * Strip all such slashes.
1347 */
1348
1349 static int
ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t * ndmpd_zfs_args)1350 ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args)
1351 {
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;
1356 char *nm;
1357 char *p;
1358 int len;
1359 int err;
1360
1361 namep_v3 = (mem_ndmp_name_v3_t *)MOD_GETNAME(ndmpd_zfs_params, 0);
1362
1363 if (namep_v3 == NULL) {
1364 NDMP_LOG(LOG_DEBUG, "Can't get Nlist[0]");
1365 return (-1);
1366 }
1367
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);
1373 return (-1);
1374 }
1375
1376 (void) strlcpy(dataset, &(namep_v3->nm3_dpath[1]),
1377 ZFS_MAX_DATASET_NAME_LEN);
1378
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);
1383
1384 } else {
1385 if (version == NDMPV3) {
1386 /*
1387 * The following does not apply for V4.
1388 *
1389 * Find the last component of nm3_opath.
1390 * nm3_opath has no trailing '/'.
1391 */
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);
1398 }
1399 }
1400 } else {
1401 err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath,
1402 ZFS_MAX_DATASET_NAME_LEN);
1403 if (err)
1404 return (err);
1405 }
1406
1407 len = strlen(dataset);
1408 while (dataset[len-1] == '/') {
1409 dataset[len-1] = '\0';
1410 len--;
1411 }
1412
1413 return (0);
1414 }
1415
1416 static int
ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t * ndmpd_zfs_args)1417 ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
1418 {
1419 if (ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args) != 0)
1420 return (-1);
1421
1422 return (ndmpd_zfs_getenv(ndmpd_zfs_args));
1423 }
1424
1425 static int
ndmpd_zfs_getenv(ndmpd_zfs_args_t * ndmpd_zfs_args)1426 ndmpd_zfs_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
1427 {
1428
1429 if (ndmpd_zfs_getenv_level(ndmpd_zfs_args) != 0)
1430 return (-1);
1431
1432 if (ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args) != 0)
1433 return (-1);
1434
1435 if (ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args) != 0)
1436 return (-1);
1437
1438 if (ndmpd_zfs_getenv_update(ndmpd_zfs_args) != 0)
1439 return (-1);
1440
1441 if (ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args) != 0)
1442 return (-1);
1443
1444 return (0);
1445 }
1446
1447 static int
ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t * ndmpd_zfs_args)1448 ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *ndmpd_zfs_args)
1449 {
1450 char *envp;
1451
1452 envp = MOD_GETENV(ndmpd_zfs_params, "ZFS_MODE");
1453
1454 if (envp == NULL) {
1455 NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE) not specified, "
1456 "defaulting to recursive");
1457 ndmpd_zfs_args->nz_zfs_mode = 'r';
1458 return (0);
1459 }
1460
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';
1468 } else {
1469 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1470 "Invalid ZFS_MODE value \"%s\".\n", envp);
1471 return (-1);
1472 }
1473
1474 NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE): \"%c\"",
1475 ndmpd_zfs_args->nz_zfs_mode);
1476
1477 return (0);
1478 }
1479
1480 /*
1481 * ndmpd_zfs_getenv_zfs_force()
1482 *
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.
1488 */
1489
1490 static int
ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t * ndmpd_zfs_args)1491 ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *ndmpd_zfs_args)
1492 {
1493 char *envp_force;
1494 char *override;
1495
1496 override = ndmpd_get_prop(NDMP_ZFS_FORCE_OVERRIDE);
1497
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");
1503 return (0);
1504 }
1505
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");
1511 return (0);
1512 }
1513
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);
1518 }
1519
1520 envp_force = MOD_GETENV(ndmpd_zfs_params, "ZFS_FORCE");
1521
1522 if (envp_force == NULL) {
1523 NDMP_LOG(LOG_DEBUG,
1524 "env(ZFS_FORCE) not specified, defaulting to FALSE");
1525 ndmpd_zfs_args->nz_zfs_force = B_FALSE;
1526 return (0);
1527 }
1528
1529 /*
1530 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
1531 */
1532
1533 if (strchr("tTyY", *envp_force))
1534 ndmpd_zfs_args->nz_zfs_force = B_TRUE;
1535
1536 NDMP_LOG(LOG_DEBUG, "env(ZFS_FORCE): \"%s\"", envp_force);
1537
1538 return (0);
1539 }
1540
1541 static int
ndmpd_zfs_getenv_level(ndmpd_zfs_args_t * ndmpd_zfs_args)1542 ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *ndmpd_zfs_args)
1543 {
1544 char *envp;
1545
1546 envp = MOD_GETENV(ndmpd_zfs_params, "LEVEL");
1547
1548 if (envp == NULL) {
1549 NDMP_LOG(LOG_DEBUG, "env(LEVEL) not specified, "
1550 "defaulting to 0");
1551 ndmpd_zfs_args->nz_level = 0;
1552 return (0);
1553 }
1554
1555 if (envp[1] != '\0') {
1556 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1557 "Invalid backup level \"%s\".\n", envp);
1558 return (-1);
1559 }
1560
1561 if (!isdigit(*envp)) {
1562 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1563 "Invalid backup level \"%s\".\n", envp);
1564 return (-1);
1565 }
1566
1567 ndmpd_zfs_args->nz_level = atoi(envp);
1568
1569 NDMP_LOG(LOG_DEBUG, "env(LEVEL): \"%d\"",
1570 ndmpd_zfs_args->nz_level);
1571
1572 return (0);
1573 }
1574
1575 static int
ndmpd_zfs_getenv_update(ndmpd_zfs_args_t * ndmpd_zfs_args)1576 ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *ndmpd_zfs_args)
1577 {
1578 char *envp_update;
1579
1580 envp_update = MOD_GETENV(ndmpd_zfs_params, "UPDATE");
1581
1582 if (envp_update == NULL) {
1583 NDMP_LOG(LOG_DEBUG,
1584 "env(UPDATE) not specified, defaulting to TRUE");
1585 ndmpd_zfs_args->nz_update = B_TRUE;
1586 return (0);
1587 }
1588
1589 /*
1590 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
1591 */
1592
1593 if (strchr("tTyY", *envp_update))
1594 ndmpd_zfs_args->nz_update = B_TRUE;
1595
1596 NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp_update);
1597
1598 return (0);
1599 }
1600
1601 static int
ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t * ndmpd_zfs_args)1602 ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *ndmpd_zfs_args)
1603 {
1604 char *envp;
1605
1606 envp = MOD_GETENV(ndmpd_zfs_params, "DMP_NAME");
1607
1608 if (envp == NULL) {
1609 NDMP_LOG(LOG_DEBUG,
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);
1613 return (0);
1614 }
1615
1616 if (!ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args, envp))
1617 return (-1);
1618
1619 (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, envp,
1620 NDMPD_ZFS_DMP_NAME_MAX);
1621
1622 NDMP_LOG(LOG_DEBUG, "env(DMP_NAME): \"%s\"", envp);
1623
1624 return (0);
1625 }
1626
1627 static int
ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t * ndmpd_zfs_args)1628 ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args)
1629 {
1630 char *zfs_backup_size;
1631
1632 zfs_backup_size = MOD_GETENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE");
1633
1634 if (zfs_backup_size == NULL) {
1635 NDMP_LOG(LOG_ERR, "ZFS_BACKUP_SIZE env is NULL");
1636 return (-1);
1637 }
1638
1639 NDMP_LOG(LOG_DEBUG, "ZFS_BACKUP_SIZE: %s\n", zfs_backup_size);
1640
1641 (void) sscanf(zfs_backup_size, "%llu",
1642 &ndmpd_zfs_args->nz_zfs_backup_size);
1643
1644 return (0);
1645 }
1646
1647 /*
1648 * ndmpd_zfs_dmp_name_valid()
1649 *
1650 * This function verifies that the dmp_name is valid.
1651 *
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
1656 * is required).
1657 */
1658
1659 static boolean_t
ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t * ndmpd_zfs_args,char * dmp_name)1660 ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *ndmpd_zfs_args, char *dmp_name)
1661 {
1662 char *c;
1663
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);
1668 return (B_FALSE);
1669 }
1670
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",
1676 dmp_name, *c);
1677 return (B_FALSE);
1678 }
1679 }
1680
1681 NDMP_LOG(LOG_DEBUG, "DMP_NAME is valid: %s\n", dmp_name);
1682 return (B_TRUE);
1683 }
1684
1685 /*
1686 * ndmpd_zfs_is_incremental()
1687 *
1688 * This can only be called after ndmpd_zfs_getenv_level()
1689 * has been called.
1690 */
1691
1692 static boolean_t
ndmpd_zfs_is_incremental(ndmpd_zfs_args_t * ndmpd_zfs_args)1693 ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *ndmpd_zfs_args)
1694 {
1695 return (ndmpd_zfs_args->nz_level != 0);
1696 }
1697
1698 /*
1699 * ndmpd_zfs_snapshot_prepare()
1700 *
1701 * If no snapshot was supplied by the user, create a snapshot
1702 * for use by ndmpd.
1703 */
1704
1705 static int
ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t * ndmpd_zfs_args)1706 ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *ndmpd_zfs_args)
1707 {
1708 ndmpd_session_t *session = (ndmpd_session_t *)
1709 (ndmpd_zfs_params->mp_daemon_cookie);
1710 boolean_t recursive = B_FALSE;
1711 int zfs_err = 0;
1712
1713 if (session->ns_data.dd_abort) {
1714 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
1715 ndmpd_zfs_args->nz_dataset);
1716 return (-1);
1717 }
1718
1719 if (ndmpd_zfs_args->nz_snapname[0] == '\0') {
1720 ndmpd_zfs_args->nz_ndmpd_snap = B_TRUE;
1721
1722 if (ndmpd_zfs_snapshot_create(ndmpd_zfs_args) != 0) {
1723 ndmpd_zfs_args->nz_snapname[0] = '\0';
1724
1725 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1726 "Error creating snapshot for %s\n",
1727 ndmpd_zfs_args->nz_dataset);
1728
1729 return (-1);
1730 }
1731 }
1732
1733 if (ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args)) {
1734 NDMP_LOG(LOG_DEBUG,
1735 "ndmpd_zfs_snapshot_prop_add error\n");
1736
1737 if (ndmpd_zfs_args->nz_ndmpd_snap) {
1738
1739 if (ndmpd_zfs_args->nz_zfs_mode != 'd')
1740 recursive = B_TRUE;
1741
1742 (void) snapshot_destroy(ndmpd_zfs_args->nz_dataset,
1743 ndmpd_zfs_args->nz_snapname, recursive, B_FALSE,
1744 &zfs_err);
1745 }
1746
1747 return (-1);
1748 }
1749
1750 return (0);
1751 }
1752
1753 /*
1754 * ndmpd_zfs_snapshot_cleanup()
1755 *
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}.
1760 *
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}.
1764 */
1765
1766 static int
ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t * ndmpd_zfs_args,int err)1767 ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *ndmpd_zfs_args, int err)
1768 {
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;
1773
1774 bzero(&snapdata, sizeof (ndmpd_zfs_snapfind_t));
1775
1776 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
1777 snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_FALSE);
1778
1779 if (ndmpd_zfs_args->nz_update && !session->ns_data.dd_abort && !err) {
1780 /*
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.)
1786 */
1787
1788 (void) snprintf(snapdata.nzs_snapskip, ZFS_MAX_DATASET_NAME_LEN,
1789 "%s", ndmpd_zfs_args->nz_snapname);
1790
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;
1794 }
1795
1796 if (snapdata.nzs_snapname[0] != '\0') { /* snapshot found */
1797 ndmpd_generated = ndmpd_zfs_snapshot_ndmpd_generated
1798 (snapdata.nzs_snapprop);
1799
1800 if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args,
1801 ndmpd_generated, &snapdata) != 0) {
1802 NDMP_LOG(LOG_DEBUG,
1803 "ndmpd_zfs_snapshot_unuse error\n");
1804 goto _remove_tmp_snap;
1805 }
1806 }
1807
1808 if (session->ns_data.dd_abort)
1809 goto _remove_tmp_snap;
1810
1811 return (0);
1812 }
1813
1814 _remove_tmp_snap:
1815
1816 (void) snprintf(snapdata.nzs_snapname, ZFS_MAX_DATASET_NAME_LEN, "%s",
1817 ndmpd_zfs_args->nz_snapname);
1818
1819 (void) strlcpy(snapdata.nzs_snapprop, ndmpd_zfs_args->nz_snapprop,
1820 ZFS_MAXPROPLEN);
1821
1822 snapdata.nzs_snapskip[0] = '\0';
1823
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");
1827 return (-1);
1828 }
1829
1830 if (!ndmpd_zfs_args->nz_update)
1831 return (0);
1832
1833 return (-1);
1834 }
1835
1836 static int
ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t * ndmpd_zfs_args)1837 ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *ndmpd_zfs_args)
1838 {
1839 boolean_t recursive = B_FALSE;
1840
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);
1845 return (-1);
1846 }
1847
1848 if (ndmpd_zfs_args->nz_zfs_mode != 'd')
1849 recursive = B_TRUE;
1850
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);
1855 return (-1);
1856 }
1857
1858 NDMP_LOG(LOG_DEBUG, "created snapshot %s@%s",
1859 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname);
1860
1861 return (0);
1862 }
1863
1864 /*
1865 * ndmpd_zfs_snapshot_unuse()
1866 *
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.
1872 *
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.
1876 */
1877
1878 static int
ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t * ndmpd_zfs_args,boolean_t ndmpd_generated,ndmpd_zfs_snapfind_t * snapdata_p)1879 ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *ndmpd_zfs_args,
1880 boolean_t ndmpd_generated, ndmpd_zfs_snapfind_t *snapdata_p)
1881 {
1882 boolean_t recursive = B_FALSE;
1883 int zfs_err = 0;
1884 int err = 0;
1885
1886 if (ndmpd_generated) {
1887 if (ndmpd_zfs_args->nz_zfs_mode != 'd')
1888 recursive = B_TRUE;
1889
1890 err = snapshot_destroy(ndmpd_zfs_args->nz_dataset,
1891 snapdata_p->nzs_snapname, recursive, B_FALSE, &zfs_err);
1892
1893 if (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);
1898 return (-1);
1899 }
1900 }
1901
1902 if (!ndmpd_generated || zfs_err) {
1903 if (ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args, snapdata_p))
1904 return (-1);
1905 }
1906
1907 return (0);
1908 }
1909
1910 static boolean_t
ndmpd_zfs_snapshot_ndmpd_generated(char * snapprop)1911 ndmpd_zfs_snapshot_ndmpd_generated(char *snapprop)
1912 {
1913 char origin;
1914
1915 (void) sscanf(snapprop, "%*u.%*u.%c%*s", &origin);
1916
1917 return (origin == 'n');
1918 }
1919
1920 /*
1921 * ndmpd_zfs_snapshot_find()
1922 *
1923 * Find a snapshot with a particular value for
1924 * the NDMPD_ZFS_PROP_INCR property.
1925 */
1926
1927 static int
ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t * ndmpd_zfs_args,ndmpd_zfs_snapfind_t * snapdata)1928 ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *ndmpd_zfs_args,
1929 ndmpd_zfs_snapfind_t *snapdata)
1930 {
1931 zfs_handle_t *zhp;
1932 int err;
1933
1934 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
1935 ndmpd_zfs_args->nz_type);
1936
1937 if (!zhp) {
1938 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
1939 return (-1);
1940 }
1941
1942 err = zfs_iter_snapshots_sorted(zhp, ndmpd_zfs_snapshot_prop_find,
1943 snapdata);
1944
1945 zfs_close(zhp);
1946
1947 if (err) {
1948 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_iter_snapshots: %d",
1949 err);
1950 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1951 "Error iterating snapshots\n");
1952 return (-1);
1953 }
1954
1955 return (0);
1956 }
1957
1958 /*
1959 * ndmpd_zfs_snapshot_prop_find()
1960 *
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.
1965 */
1966
1967 static int
ndmpd_zfs_snapshot_prop_find(zfs_handle_t * zhp,void * arg)1968 ndmpd_zfs_snapshot_prop_find(zfs_handle_t *zhp, void *arg)
1969 {
1970 ndmpd_zfs_snapfind_t *snapdata_p = (ndmpd_zfs_snapfind_t *)arg;
1971 char propstr[ZFS_MAXPROPLEN];
1972 char findprop_plus_slash[ZFS_MAXPROPLEN];
1973 char *justsnap;
1974 int err = 0;
1975
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));
1979 goto _done;
1980 }
1981
1982 err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
1983
1984 if (err) {
1985 NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_prop_get failed");
1986 goto _done;
1987 }
1988
1989 if (propstr[0] == '\0') {
1990 NDMP_LOG(LOG_DEBUG, "snapshot %s: propr not set",
1991 (char *)zfs_get_name(zhp));
1992 goto _done;
1993 }
1994
1995 (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
1996 snapdata_p->nzs_findprop);
1997
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);
2003 goto _done;
2004 }
2005
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");
2012 goto _done;
2013 }
2014
2015 justsnap = strchr(zfs_get_name(zhp), '@') + 1;
2016
2017 if (strcmp(justsnap, snapdata_p->nzs_snapskip) != 0) {
2018 (void) strlcpy(snapdata_p->nzs_snapname, justsnap,
2019 ZFS_MAX_DATASET_NAME_LEN);
2020
2021 (void) strlcpy(snapdata_p->nzs_snapprop, propstr,
2022 ZFS_MAXPROPLEN);
2023
2024 NDMP_LOG(LOG_DEBUG, "found match: %s [%s]\n",
2025 snapdata_p->nzs_snapname, snapdata_p->nzs_snapprop);
2026 }
2027
2028 _done:
2029 zfs_close(zhp);
2030 return (err);
2031 }
2032
2033 /*
2034 * ndmpd_zfs_snapshot_prop_get()
2035 *
2036 * Retrieve NDMPD_ZFS_PROP_INCR property from snapshot
2037 */
2038
2039 static int
ndmpd_zfs_snapshot_prop_get(zfs_handle_t * zhp,char * propstr)2040 ndmpd_zfs_snapshot_prop_get(zfs_handle_t *zhp, char *propstr)
2041 {
2042 nvlist_t *userprop;
2043 nvlist_t *propval;
2044 char *strval;
2045 int err;
2046
2047 propstr[0] = '\0';
2048
2049 userprop = zfs_get_user_props(zhp);
2050
2051 if (userprop == NULL)
2052 return (0);
2053
2054 err = nvlist_lookup_nvlist(userprop, NDMPD_ZFS_PROP_INCR, &propval);
2055
2056 if (err != 0) {
2057 if (err == ENOENT)
2058 return (0);
2059
2060 NDMP_LOG(LOG_DEBUG, "nvlist_lookup_nvlist error: %d\n", err);
2061
2062 return (-1);
2063 }
2064
2065 err = nvlist_lookup_string(propval, ZPROP_VALUE, &strval);
2066
2067 if (err != 0) {
2068 if (err == ENOENT)
2069 return (0);
2070
2071 NDMP_LOG(LOG_DEBUG, "nvlist_lookup_string error: %d\n", err);
2072
2073 return (-1);
2074 }
2075
2076 (void) strlcpy(propstr, strval, ZFS_MAXPROPLEN);
2077
2078 return (0);
2079 }
2080
2081 /*
2082 * ndmpd_zfs_snapshot_prop_add()
2083 *
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)
2087 */
2088
2089 static int
ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t * ndmpd_zfs_args)2090 ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *ndmpd_zfs_args)
2091 {
2092 char fullname[ZFS_MAX_DATASET_NAME_LEN];
2093 char propstr[ZFS_MAXPROPLEN];
2094 zfs_handle_t *zhp;
2095 boolean_t set;
2096 int err;
2097
2098 (void) snprintf(fullname, ZFS_MAX_DATASET_NAME_LEN, "%s@%s",
2099 ndmpd_zfs_args->nz_dataset,
2100 ndmpd_zfs_args->nz_snapname);
2101
2102 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
2103
2104 if (!zhp) {
2105 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open (snap)");
2106 return (-1);
2107 }
2108
2109 bzero(propstr, ZFS_MAXPROPLEN);
2110
2111 if (ndmpd_zfs_snapshot_prop_get(zhp, propstr)) {
2112 NDMP_LOG(LOG_DEBUG, "error getting property");
2113 zfs_close(zhp);
2114 return (-1);
2115 }
2116
2117 if (ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args, propstr, &set)) {
2118 zfs_close(zhp);
2119 return (-1);
2120 }
2121
2122 if (set) {
2123 err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, propstr);
2124 if (err) {
2125 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
2126 err);
2127 NDMP_LOG(LOG_ERR, "error setting property %s",
2128 propstr);
2129 zfs_close(zhp);
2130 return (-1);
2131 }
2132 }
2133
2134 zfs_close(zhp);
2135
2136 (void) strlcpy(ndmpd_zfs_args->nz_snapprop, propstr, ZFS_MAXPROPLEN);
2137
2138 return (0);
2139 }
2140
2141 static int
ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t * ndmpd_zfs_args,char * propstr,boolean_t * set)2142 ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
2143 char *propstr, boolean_t *set)
2144 {
2145 char subprop[ZFS_MAXPROPLEN];
2146 char *p = propstr;
2147 int slash_count = 0;
2148
2149 *set = B_TRUE;
2150
2151 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
2152 subprop, ZFS_MAXPROPLEN, B_FALSE);
2153
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',
2159 subprop);
2160 return (0);
2161 }
2162
2163 if (strstr((const char *)propstr, (const char *)subprop)) {
2164 NDMP_LOG(LOG_DEBUG, "Did not add entry %s as it already exists",
2165 subprop);
2166 *set = B_FALSE;
2167 return (0);
2168 }
2169
2170 while (*p) {
2171 if (*(p++) == '/')
2172 slash_count++;
2173 }
2174
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);
2182 return (-1);
2183 }
2184
2185 assert((strlen(propstr) + strlen(subprop) + 2) < ZFS_MAXPROPLEN);
2186
2187 (void) strlcat(propstr, "/", ZFS_MAXPROPLEN);
2188 (void) strlcat(propstr, subprop, ZFS_MAXPROPLEN);
2189
2190 return (0);
2191 }
2192
2193 static int
ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t * ndmpd_zfs_args,char * subprop,int len,boolean_t prev_level)2194 ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *ndmpd_zfs_args,
2195 char *subprop, int len, boolean_t prev_level)
2196 {
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));
2201 }
2202
2203 /*
2204 * ndmpd_zfs_snapshot_prop_remove()
2205 *
2206 * Remove specified substring from the snapshot's
2207 * NDMPD_ZFS_PROP_INCR property
2208 */
2209
2210 static int
ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t * ndmpd_zfs_args,ndmpd_zfs_snapfind_t * snapdata_p)2211 ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *ndmpd_zfs_args,
2212 ndmpd_zfs_snapfind_t *snapdata_p)
2213 {
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];
2218 zfs_handle_t *zhp;
2219 char *ptr;
2220 int err;
2221
2222 (void) snprintf(fullname, ZFS_MAX_DATASET_NAME_LEN, "%s@%s",
2223 ndmpd_zfs_args->nz_dataset,
2224 snapdata_p->nzs_snapname);
2225
2226 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
2227
2228 if (!zhp) {
2229 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
2230 return (-1);
2231 }
2232
2233 bzero(newprop, ZFS_MAXPROPLEN);
2234
2235 /*
2236 * If the substring to be removed is the only {L, D, Z}
2237 * in the property, remove the entire property
2238 */
2239
2240 tmpstr[0] = '\0';
2241
2242 (void) sscanf(snapdata_p->nzs_snapprop, "%*u.%*u.%*c/%1023s", tmpstr);
2243
2244 if (strcmp(tmpstr, snapdata_p->nzs_findprop) == 0) {
2245
2246 err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
2247
2248 zfs_close(zhp);
2249
2250 if (err) {
2251 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
2252 err);
2253 NDMP_LOG(LOG_ERR, "error setting property %s", newprop);
2254 return (-1);
2255 }
2256
2257 return (0);
2258 }
2259
2260 (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
2261 snapdata_p->nzs_findprop);
2262
2263 ptr = strstr((const char *)snapdata_p->nzs_snapprop,
2264 (const char *)findprop_plus_slash);
2265
2266 if (ptr == NULL) {
2267 /*
2268 * This shouldn't happen. Just return success.
2269 */
2270 zfs_close(zhp);
2271
2272 return (0);
2273 }
2274
2275 /*
2276 * Remove "nzs_findprop" substring from property
2277 *
2278 * Example property:
2279 * 0.0.u/1.bob.p/0.jane.d
2280 *
2281 * Note that there will always be a prefix to the
2282 * strstr() result. Hence the below code works for
2283 * all cases.
2284 */
2285
2286 ptr--;
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);
2291
2292 err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
2293
2294 zfs_close(zhp);
2295
2296 if (err) {
2297 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", err);
2298 NDMP_LOG(LOG_ERR, "error modifying property %s", newprop);
2299 return (-1);
2300 }
2301
2302 return (0);
2303 }
2304
2305 static boolean_t
ndmpd_zfs_prop_version_check(char * propstr,uint32_t * major,uint32_t * minor)2306 ndmpd_zfs_prop_version_check(char *propstr, uint32_t *major, uint32_t *minor)
2307 {
2308 (void) sscanf(propstr, "%u.%u.%*c%*s", major, minor);
2309
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);
2313 return (B_FALSE);
2314 }
2315
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);
2319 }
2320
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);
2325
2326 return (B_TRUE);
2327 }
2328
2329 static int
ndmpd_zfs_snapname_create(ndmpd_zfs_args_t * ndmpd_zfs_args,char * snapname,int namelen)2330 ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
2331 char *snapname, int namelen)
2332 {
2333 char subprop[ZFS_MAXPROPLEN];
2334 struct timeval tp;
2335 int err = 0;
2336
2337 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
2338 subprop, ZFS_MAXPROPLEN, B_FALSE);
2339
2340 (void) gettimeofday(&tp, NULL);
2341
2342 err = snprintf(snapname, namelen,
2343 "ndmp.%s.%ld.%ld",
2344 subprop,
2345 tp.tv_sec,
2346 tp.tv_usec);
2347
2348 if (err > namelen) {
2349 NDMP_LOG(LOG_ERR, "name of snapshot [%s...] would exceed %d",
2350 snapname, namelen);
2351 return (-1);
2352 }
2353
2354 return (0);
2355 }
2356
2357 static void
ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t * ndmpd_zfs_args)2358 ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args)
2359 {
2360 switch (libzfs_errno(ndmpd_zfs_args->nz_zlibh)) {
2361 case EZFS_EXISTS:
2362 case EZFS_BUSY:
2363 case EZFS_NOENT:
2364 case EZFS_INVALIDNAME:
2365 case EZFS_MOUNTFAILED:
2366 case EZFS_UMOUNTFAILED:
2367 case EZFS_NAMETOOLONG:
2368 case EZFS_BADRESTORE:
2369
2370 /* use existing error text */
2371
2372 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2373 "%s: %s: %s\n",
2374 ndmpd_zfs_args->nz_dataset,
2375 libzfs_error_action(ndmpd_zfs_args->nz_zlibh),
2376 libzfs_error_description(ndmpd_zfs_args->nz_zlibh));
2377
2378 break;
2379
2380 case EZFS_NOMEM:
2381 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2382 "Unable to obtain memory for operation\n");
2383 break;
2384
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");
2388 break;
2389
2390 case EZFS_BADSTREAM:
2391 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2392 "The backup stream is invalid.\n");
2393 break;
2394
2395 case EZFS_ZONED:
2396 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2397 "An error related to the local zone occurred.\n");
2398 break;
2399
2400 case EZFS_NOSPC:
2401 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2402 "No more space is available\n");
2403 break;
2404
2405 case EZFS_IO:
2406 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2407 "An I/O error occurred.\n");
2408 break;
2409
2410 default:
2411 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2412 "An internal ndmpd error occurred. "
2413 "Please contact support\n");
2414 break;
2415 }
2416 }
2417
2418 void
ndmpd_zfs_dma_log(ndmpd_zfs_args_t * ndmpd_zfs_args,ndmp_log_type log_type,char * format,...)2419 ndmpd_zfs_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args, ndmp_log_type log_type,
2420 char *format, ...)
2421 {
2422 static char buf[1024];
2423 va_list ap;
2424
2425 va_start(ap, format);
2426
2427 /*LINTED variable format specifier */
2428 (void) vsnprintf(buf, sizeof (buf), format, ap);
2429 va_end(ap);
2430
2431 MOD_LOGV3(ndmpd_zfs_params, log_type, buf);
2432
2433 if ((log_type) == NDMP_LOG_ERROR) {
2434 NDMP_LOG(LOG_ERR, buf);
2435 } else {
2436 NDMP_LOG(LOG_NOTICE, buf);
2437 }
2438 }
2439