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