112186SJanice.Chang@Sun.COM /*
212186SJanice.Chang@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
312186SJanice.Chang@Sun.COM */
412186SJanice.Chang@Sun.COM
512186SJanice.Chang@Sun.COM /*
612186SJanice.Chang@Sun.COM * BSD 3 Clause License
712186SJanice.Chang@Sun.COM *
812186SJanice.Chang@Sun.COM * Copyright (c) 2007, The Storage Networking Industry Association.
912186SJanice.Chang@Sun.COM *
1012186SJanice.Chang@Sun.COM * Redistribution and use in source and binary forms, with or without
1112186SJanice.Chang@Sun.COM * modification, are permitted provided that the following conditions
1212186SJanice.Chang@Sun.COM * are met:
1312186SJanice.Chang@Sun.COM * - Redistributions of source code must retain the above copyright
1412186SJanice.Chang@Sun.COM * notice, this list of conditions and the following disclaimer.
1512186SJanice.Chang@Sun.COM *
1612186SJanice.Chang@Sun.COM * - Redistributions in binary form must reproduce the above copyright
1712186SJanice.Chang@Sun.COM * notice, this list of conditions and the following disclaimer in
1812186SJanice.Chang@Sun.COM * the documentation and/or other materials provided with the
1912186SJanice.Chang@Sun.COM * distribution.
2012186SJanice.Chang@Sun.COM *
2112186SJanice.Chang@Sun.COM * - Neither the name of The Storage Networking Industry Association (SNIA)
2212186SJanice.Chang@Sun.COM * nor the names of its contributors may be used to endorse or promote
2312186SJanice.Chang@Sun.COM * products derived from this software without specific prior written
2412186SJanice.Chang@Sun.COM * permission.
2512186SJanice.Chang@Sun.COM *
2612186SJanice.Chang@Sun.COM * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2712186SJanice.Chang@Sun.COM * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2812186SJanice.Chang@Sun.COM * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2912186SJanice.Chang@Sun.COM * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
3012186SJanice.Chang@Sun.COM * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3112186SJanice.Chang@Sun.COM * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3212186SJanice.Chang@Sun.COM * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3312186SJanice.Chang@Sun.COM * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3412186SJanice.Chang@Sun.COM * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3512186SJanice.Chang@Sun.COM * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3612186SJanice.Chang@Sun.COM * POSSIBILITY OF SUCH DAMAGE.
3712186SJanice.Chang@Sun.COM */
3812186SJanice.Chang@Sun.COM /* Copyright (c) 2007, The Storage Networking Industry Association. */
3912186SJanice.Chang@Sun.COM /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
4012186SJanice.Chang@Sun.COM
4112186SJanice.Chang@Sun.COM #include <sys/types.h>
4212186SJanice.Chang@Sun.COM #include <sys/param.h>
4312186SJanice.Chang@Sun.COM #include <sys/lwp.h>
4412186SJanice.Chang@Sun.COM #include <sys/fs/zfs.h>
4512186SJanice.Chang@Sun.COM #include <sys/mtio.h>
4612186SJanice.Chang@Sun.COM #include <sys/time.h>
4712186SJanice.Chang@Sun.COM #include <unistd.h>
4812186SJanice.Chang@Sun.COM #include <errno.h>
4912186SJanice.Chang@Sun.COM #include <stdlib.h>
5012186SJanice.Chang@Sun.COM #include <string.h>
5112186SJanice.Chang@Sun.COM #include <ctype.h>
5212186SJanice.Chang@Sun.COM #include <libzfs.h>
5312186SJanice.Chang@Sun.COM #include <stdio.h>
5412186SJanice.Chang@Sun.COM #include "ndmpd_common.h"
5512186SJanice.Chang@Sun.COM #include "ndmpd.h"
5612186SJanice.Chang@Sun.COM
5712186SJanice.Chang@Sun.COM typedef struct {
5812186SJanice.Chang@Sun.COM char nzs_findprop[ZFS_MAXPROPLEN]; /* prop substring to find */
5912186SJanice.Chang@Sun.COM char nzs_snapname[ZFS_MAXNAMELEN]; /* snap's name */
6012186SJanice.Chang@Sun.COM char nzs_snapprop[ZFS_MAXPROPLEN]; /* snap's prop value */
6112186SJanice.Chang@Sun.COM char nzs_snapskip[ZFS_MAXPROPLEN]; /* snap to skip */
6212186SJanice.Chang@Sun.COM uint32_t nzs_prop_major; /* property major version */
6312186SJanice.Chang@Sun.COM uint32_t nzs_prop_minor; /* property minor version */
6412186SJanice.Chang@Sun.COM } ndmpd_zfs_snapfind_t;
6512186SJanice.Chang@Sun.COM
6612186SJanice.Chang@Sun.COM mutex_t ndmpd_zfs_fd_lock;
6712186SJanice.Chang@Sun.COM
6812186SJanice.Chang@Sun.COM static int ndmpd_zfs_open_fds(ndmpd_zfs_args_t *);
6912186SJanice.Chang@Sun.COM static void ndmpd_zfs_close_fds(ndmpd_zfs_args_t *);
7012186SJanice.Chang@Sun.COM
7112186SJanice.Chang@Sun.COM static void ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *, int);
7212186SJanice.Chang@Sun.COM
7312186SJanice.Chang@Sun.COM static int ndmpd_zfs_header_write(ndmpd_session_t *);
7412186SJanice.Chang@Sun.COM static int ndmpd_zfs_header_read(ndmpd_zfs_args_t *);
7512186SJanice.Chang@Sun.COM
7612186SJanice.Chang@Sun.COM static int ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *);
7712186SJanice.Chang@Sun.COM static int ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t *);
7812186SJanice.Chang@Sun.COM
7912186SJanice.Chang@Sun.COM static int ndmpd_zfs_restore(ndmpd_zfs_args_t *);
8012186SJanice.Chang@Sun.COM static int ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t *);
8112186SJanice.Chang@Sun.COM static int ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t *);
8212186SJanice.Chang@Sun.COM
8312186SJanice.Chang@Sun.COM static int ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *, int **, int **);
8412186SJanice.Chang@Sun.COM
8512740SJanice.Chang@Sun.COM static int ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t *, u_longlong_t);
8612186SJanice.Chang@Sun.COM
8712186SJanice.Chang@Sun.COM static boolean_t ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *);
8812186SJanice.Chang@Sun.COM static int ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *, char *, int);
8912186SJanice.Chang@Sun.COM static int ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *);
9012186SJanice.Chang@Sun.COM
9112186SJanice.Chang@Sun.COM static boolean_t ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *);
9212186SJanice.Chang@Sun.COM static int ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *);
9312186SJanice.Chang@Sun.COM static int ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *);
9412186SJanice.Chang@Sun.COM
9512186SJanice.Chang@Sun.COM static int ndmpd_zfs_getenv(ndmpd_zfs_args_t *);
9612186SJanice.Chang@Sun.COM static int ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *);
9712186SJanice.Chang@Sun.COM static int ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *);
9812186SJanice.Chang@Sun.COM static int ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *);
9912186SJanice.Chang@Sun.COM static int ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *);
10012186SJanice.Chang@Sun.COM static int ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *);
10112740SJanice.Chang@Sun.COM static int ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t *);
10212740SJanice.Chang@Sun.COM
10312186SJanice.Chang@Sun.COM static boolean_t ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *, char *);
10412186SJanice.Chang@Sun.COM static boolean_t ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *);
10512669SReza.Sabdar@Sun.COM static int ndmpd_zfs_send_fhist(ndmpd_zfs_args_t *);
10612186SJanice.Chang@Sun.COM
10712186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *);
10812186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *, int);
10912186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *);
11012186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *,
11112186SJanice.Chang@Sun.COM boolean_t, ndmpd_zfs_snapfind_t *);
11212186SJanice.Chang@Sun.COM static boolean_t ndmpd_zfs_snapshot_ndmpd_generated(char *);
11312186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *, ndmpd_zfs_snapfind_t *);
11412186SJanice.Chang@Sun.COM
11512186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_prop_find(zfs_handle_t *, void *);
11612186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_prop_get(zfs_handle_t *, char *);
11712186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *);
11812186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *, char *,
11912186SJanice.Chang@Sun.COM boolean_t *);
12012186SJanice.Chang@Sun.COM static int ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *, char *, int,
12112186SJanice.Chang@Sun.COM boolean_t);
12212186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *,
12312186SJanice.Chang@Sun.COM ndmpd_zfs_snapfind_t *);
12412186SJanice.Chang@Sun.COM static boolean_t ndmpd_zfs_prop_version_check(char *, uint32_t *, uint32_t *);
12512186SJanice.Chang@Sun.COM
12612186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *, char *, int);
12712186SJanice.Chang@Sun.COM
12812186SJanice.Chang@Sun.COM static void ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *);
12912186SJanice.Chang@Sun.COM
13012186SJanice.Chang@Sun.COM static int ndmpd_zfs_backup(ndmpd_zfs_args_t *);
13112186SJanice.Chang@Sun.COM
13212186SJanice.Chang@Sun.COM /*
13312186SJanice.Chang@Sun.COM * Syntax for com.sun.ndmp:incr property value:
13412186SJanice.Chang@Sun.COM * #.#.n|u/$LEVEL.$DMP_NAME.$ZFS_MODE(/ ...)
13512186SJanice.Chang@Sun.COM *
13612186SJanice.Chang@Sun.COM * where
13712186SJanice.Chang@Sun.COM * #.# is the version number
13812186SJanice.Chang@Sun.COM * 'n' means ndmp-generated; 'u' means user-supplied
13912186SJanice.Chang@Sun.COM * $LEVEL: backup (incremental) level [0-9]
14012186SJanice.Chang@Sun.COM * $DMP_NAME: set name [default: "level"]
14112186SJanice.Chang@Sun.COM * $ZFS_MODE: d | r | p [for dataset, recursive, or package]
14212186SJanice.Chang@Sun.COM *
14312186SJanice.Chang@Sun.COM * Examples:
14412186SJanice.Chang@Sun.COM *
14512186SJanice.Chang@Sun.COM * 0.0.n/0.bob.p
14612186SJanice.Chang@Sun.COM * 0.0.u/1.bob.p/0.jane.d
14712514SJanice.Chang@Sun.COM *
14812514SJanice.Chang@Sun.COM * Note: NDMPD_ZFS_SUBPROP_MAX is calculated based on ZFS_MAXPROPLEN
14912186SJanice.Chang@Sun.COM */
15012186SJanice.Chang@Sun.COM
15112186SJanice.Chang@Sun.COM #define NDMPD_ZFS_PROP_INCR "com.sun.ndmp:incr"
15212514SJanice.Chang@Sun.COM #define NDMPD_ZFS_SUBPROP_MAX 28
15312186SJanice.Chang@Sun.COM
15412186SJanice.Chang@Sun.COM /*
15512186SJanice.Chang@Sun.COM * NDMPD_ZFS_LOG_ZERR
15612186SJanice.Chang@Sun.COM *
15712186SJanice.Chang@Sun.COM * As coded, there should be no races in the retrieval of the ZFS errno
15812186SJanice.Chang@Sun.COM * from the ndmpd_zfs_args->nz_zlibh. I.e., for a given ndmpd_zfs backup
15912186SJanice.Chang@Sun.COM * or restore, there should only ever be one ZFS library call taking place
16012186SJanice.Chang@Sun.COM * at any one moment in time.
16112186SJanice.Chang@Sun.COM */
16212186SJanice.Chang@Sun.COM
16312186SJanice.Chang@Sun.COM #define NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, ...) { \
16412186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, __VA_ARGS__); \
16512186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "%s--%s", \
16612186SJanice.Chang@Sun.COM libzfs_error_action((ndmpd_zfs_args)->nz_zlibh), \
16712186SJanice.Chang@Sun.COM libzfs_error_description((ndmpd_zfs_args)->nz_zlibh)); \
16812186SJanice.Chang@Sun.COM ndmpd_zfs_zerr_dma_log((ndmpd_zfs_args)); \
16912186SJanice.Chang@Sun.COM }
17012186SJanice.Chang@Sun.COM
17112186SJanice.Chang@Sun.COM int
ndmpd_zfs_init(ndmpd_session_t * session)17212186SJanice.Chang@Sun.COM ndmpd_zfs_init(ndmpd_session_t *session)
17312186SJanice.Chang@Sun.COM {
17412186SJanice.Chang@Sun.COM ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
17512186SJanice.Chang@Sun.COM int version = session->ns_protocol_version;
17612186SJanice.Chang@Sun.COM
17712186SJanice.Chang@Sun.COM bzero(ndmpd_zfs_args, sizeof (*ndmpd_zfs_args));
17812186SJanice.Chang@Sun.COM
17912186SJanice.Chang@Sun.COM if ((version < NDMPV3) || (version > NDMPV4)) {
18012186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "Unknown or unsupported version %d", version);
18112186SJanice.Chang@Sun.COM return (-1);
18212186SJanice.Chang@Sun.COM }
18312186SJanice.Chang@Sun.COM
18412186SJanice.Chang@Sun.COM if ((ndmpd_zfs_args->nz_zlibh = libzfs_init()) == NULL) {
18512186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "libzfs init error [%d]", errno);
18612186SJanice.Chang@Sun.COM return (-1);
18712186SJanice.Chang@Sun.COM }
18812186SJanice.Chang@Sun.COM
18912186SJanice.Chang@Sun.COM if (ndmpd_zfs_open_fds(ndmpd_zfs_args) < 0) {
19012186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "open_fds() failure(): %d\n", errno);
19112186SJanice.Chang@Sun.COM return (-1);
19212186SJanice.Chang@Sun.COM }
19312186SJanice.Chang@Sun.COM
19412186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_bufsize = ndmp_buffer_get_size(session);
19512186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_window_len = session->ns_mover.md_window_length;
19612186SJanice.Chang@Sun.COM
19712186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_nlp = ndmp_get_nlp(session);
19812186SJanice.Chang@Sun.COM
19912186SJanice.Chang@Sun.COM assert(ndmpd_zfs_args->nz_nlp != NULL);
20012186SJanice.Chang@Sun.COM
20112186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_nlp->nlp_bytes_total = 0;
20212186SJanice.Chang@Sun.COM
20312186SJanice.Chang@Sun.COM session->ns_data.dd_module.dm_module_cookie = ndmpd_zfs_args;
20412186SJanice.Chang@Sun.COM session->ns_data.dd_data_size = 0;
20512186SJanice.Chang@Sun.COM session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
20612186SJanice.Chang@Sun.COM session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
20712186SJanice.Chang@Sun.COM
20812186SJanice.Chang@Sun.COM session->ns_data.dd_bytes_left_to_read = 0;
20912186SJanice.Chang@Sun.COM session->ns_data.dd_position = 0;
21012186SJanice.Chang@Sun.COM session->ns_data.dd_discard_length = 0;
21112186SJanice.Chang@Sun.COM session->ns_data.dd_read_offset = 0;
21212186SJanice.Chang@Sun.COM session->ns_data.dd_read_length = 0;
21312186SJanice.Chang@Sun.COM
21412186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_get_env_func = ndmpd_api_get_env;
21512186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_add_env_func = ndmpd_api_add_env;
21612186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_set_env_func = ndmpd_api_set_env;
21712186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_dispatch_func = ndmpd_api_dispatch;
21812186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_daemon_cookie = (void *)session;
21912186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_protocol_version = session->ns_protocol_version;
22012186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_stats = &session->ns_data.dd_module.dm_stats;
22112186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_add_file_handler_func =
22212186SJanice.Chang@Sun.COM ndmpd_api_add_file_handler;
22312186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_remove_file_handler_func =
22412186SJanice.Chang@Sun.COM ndmpd_api_remove_file_handler;
22512186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_seek_func = 0;
22612186SJanice.Chang@Sun.COM
22712186SJanice.Chang@Sun.COM switch (version) {
22812186SJanice.Chang@Sun.COM case NDMPV3:
22912186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_write_func = ndmpd_api_write_v3;
23012186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_read_func = ndmpd_api_read_v3;
23112186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_get_name_func = ndmpd_api_get_name_v3;
23212186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_done_func = ndmpd_api_done_v3;
23312186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_log_func_v3 = ndmpd_api_log_v3;
23412186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_file_recovered_func =
23512186SJanice.Chang@Sun.COM ndmpd_api_file_recovered_v3;
23612186SJanice.Chang@Sun.COM break;
23712186SJanice.Chang@Sun.COM case NDMPV4:
23812186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_write_func = ndmpd_api_write_v3;
23912186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_read_func = ndmpd_api_read_v3;
24012186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_get_name_func = ndmpd_api_get_name_v3;
24112186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_done_func = ndmpd_api_done_v3;
24212186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_log_func_v3 = ndmpd_api_log_v4;
24312186SJanice.Chang@Sun.COM ndmpd_zfs_params->mp_file_recovered_func =
24412186SJanice.Chang@Sun.COM ndmpd_api_file_recovered_v4;
24512186SJanice.Chang@Sun.COM break;
24612186SJanice.Chang@Sun.COM default:
24712186SJanice.Chang@Sun.COM /* error already returned above for this case */
24812186SJanice.Chang@Sun.COM break;
24912186SJanice.Chang@Sun.COM }
25012186SJanice.Chang@Sun.COM
25112186SJanice.Chang@Sun.COM return (0);
25212186SJanice.Chang@Sun.COM }
25312186SJanice.Chang@Sun.COM
25412186SJanice.Chang@Sun.COM void
ndmpd_zfs_fini(ndmpd_zfs_args_t * ndmpd_zfs_args)25512186SJanice.Chang@Sun.COM ndmpd_zfs_fini(ndmpd_zfs_args_t *ndmpd_zfs_args)
25612186SJanice.Chang@Sun.COM {
25712186SJanice.Chang@Sun.COM libzfs_fini(ndmpd_zfs_args->nz_zlibh);
25812186SJanice.Chang@Sun.COM
25912186SJanice.Chang@Sun.COM ndmpd_zfs_close_fds(ndmpd_zfs_args);
26012186SJanice.Chang@Sun.COM }
26112186SJanice.Chang@Sun.COM
26212186SJanice.Chang@Sun.COM static int
ndmpd_zfs_open_fds(ndmpd_zfs_args_t * ndmpd_zfs_args)26312186SJanice.Chang@Sun.COM ndmpd_zfs_open_fds(ndmpd_zfs_args_t *ndmpd_zfs_args)
26412186SJanice.Chang@Sun.COM {
26512186SJanice.Chang@Sun.COM int err;
26612186SJanice.Chang@Sun.COM
26712186SJanice.Chang@Sun.COM err = pipe(ndmpd_zfs_args->nz_pipe_fd);
26812186SJanice.Chang@Sun.COM if (err)
26912186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "pipe(2) failed: %s:\n", strerror(errno));
27012186SJanice.Chang@Sun.COM
27112186SJanice.Chang@Sun.COM return (err);
27212186SJanice.Chang@Sun.COM }
27312186SJanice.Chang@Sun.COM
27412186SJanice.Chang@Sun.COM /*
27512186SJanice.Chang@Sun.COM * ndmpd_zfs_close_fds()
27612186SJanice.Chang@Sun.COM *
27712186SJanice.Chang@Sun.COM * In the abort case, use dup2() to redirect the end of the pipe that is
27812186SJanice.Chang@Sun.COM * being written to (to a new pipe). Close the ends of the new pipe to cause
27912186SJanice.Chang@Sun.COM * EPIPE to be returned to the writing thread. This will cause the writer
28012186SJanice.Chang@Sun.COM * and reader to terminate without having any of the writer's data erroneously
28112186SJanice.Chang@Sun.COM * go to any reopened descriptor.
28212186SJanice.Chang@Sun.COM */
28312186SJanice.Chang@Sun.COM
28412186SJanice.Chang@Sun.COM static void
ndmpd_zfs_close_fds(ndmpd_zfs_args_t * ndmpd_zfs_args)28512186SJanice.Chang@Sun.COM ndmpd_zfs_close_fds(ndmpd_zfs_args_t *ndmpd_zfs_args)
28612186SJanice.Chang@Sun.COM {
28712186SJanice.Chang@Sun.COM ndmpd_session_t *session = (ndmpd_session_t *)
28812186SJanice.Chang@Sun.COM (ndmpd_zfs_params->mp_daemon_cookie);
28912186SJanice.Chang@Sun.COM int pipe_end;
29012186SJanice.Chang@Sun.COM int fds[2];
29112186SJanice.Chang@Sun.COM
29212186SJanice.Chang@Sun.COM if (session->ns_data.dd_state != NDMP_DATA_STATE_ACTIVE) {
29312186SJanice.Chang@Sun.COM ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS);
29412186SJanice.Chang@Sun.COM ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
29512186SJanice.Chang@Sun.COM return;
29612186SJanice.Chang@Sun.COM }
29712186SJanice.Chang@Sun.COM
29812186SJanice.Chang@Sun.COM (void) mutex_lock(&ndmpd_zfs_fd_lock);
29912186SJanice.Chang@Sun.COM
30012186SJanice.Chang@Sun.COM if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP) {
30112186SJanice.Chang@Sun.COM pipe_end = PIPE_ZFS;
30212186SJanice.Chang@Sun.COM } else {
30312186SJanice.Chang@Sun.COM pipe_end = PIPE_TAPE;
30412186SJanice.Chang@Sun.COM }
30512186SJanice.Chang@Sun.COM
30612186SJanice.Chang@Sun.COM if (ndmpd_zfs_args->nz_pipe_fd[pipe_end] != -1) {
30712186SJanice.Chang@Sun.COM if (pipe(fds) != 0) {
30812186SJanice.Chang@Sun.COM (void) mutex_unlock(&ndmpd_zfs_fd_lock);
30912186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "pipe(2) failed: %s:\n",
31012186SJanice.Chang@Sun.COM strerror(errno));
31112186SJanice.Chang@Sun.COM return;
31212186SJanice.Chang@Sun.COM }
31312186SJanice.Chang@Sun.COM
31412186SJanice.Chang@Sun.COM (void) dup2(fds[0], ndmpd_zfs_args->nz_pipe_fd[pipe_end]);
31512186SJanice.Chang@Sun.COM (void) close(fds[0]);
31612186SJanice.Chang@Sun.COM (void) close(fds[1]);
31712186SJanice.Chang@Sun.COM
31812186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_pipe_fd[pipe_end] = -1;
31912186SJanice.Chang@Sun.COM }
32012186SJanice.Chang@Sun.COM
32112186SJanice.Chang@Sun.COM (void) mutex_unlock(&ndmpd_zfs_fd_lock);
32212186SJanice.Chang@Sun.COM }
32312186SJanice.Chang@Sun.COM
32412186SJanice.Chang@Sun.COM static void
ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t * ndmpd_zfs_args,int pipe_end)32512186SJanice.Chang@Sun.COM ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *ndmpd_zfs_args, int pipe_end)
32612186SJanice.Chang@Sun.COM {
32712186SJanice.Chang@Sun.COM (void) mutex_lock(&ndmpd_zfs_fd_lock);
32812186SJanice.Chang@Sun.COM (void) close(ndmpd_zfs_args->nz_pipe_fd[pipe_end]);
32912186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_pipe_fd[pipe_end] = -1;
33012186SJanice.Chang@Sun.COM (void) mutex_unlock(&ndmpd_zfs_fd_lock);
33112186SJanice.Chang@Sun.COM }
33212186SJanice.Chang@Sun.COM
33312186SJanice.Chang@Sun.COM static int
ndmpd_zfs_header_write(ndmpd_session_t * session)33412186SJanice.Chang@Sun.COM ndmpd_zfs_header_write(ndmpd_session_t *session)
33512186SJanice.Chang@Sun.COM {
33612186SJanice.Chang@Sun.COM ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
33712186SJanice.Chang@Sun.COM int32_t bufsize = ndmpd_zfs_args->nz_bufsize;
33812186SJanice.Chang@Sun.COM ndmpd_zfs_header_t *tape_header = &ndmpd_zfs_args->nz_tape_header;
33912186SJanice.Chang@Sun.COM char *buf;
34012186SJanice.Chang@Sun.COM
34112186SJanice.Chang@Sun.COM buf = ndmp_malloc(bufsize);
34212186SJanice.Chang@Sun.COM if (buf == NULL) {
34312186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "buf NULL");
34412186SJanice.Chang@Sun.COM return (-1);
34512186SJanice.Chang@Sun.COM }
34612186SJanice.Chang@Sun.COM
34712186SJanice.Chang@Sun.COM (void) strlcpy(tape_header->nzh_magic, NDMPUTF8MAGIC,
34812186SJanice.Chang@Sun.COM sizeof (NDMPUTF8MAGIC));
34912186SJanice.Chang@Sun.COM tape_header->nzh_major = LE_32(NDMPD_ZFS_MAJOR_VERSION);
35012186SJanice.Chang@Sun.COM tape_header->nzh_minor = LE_32(NDMPD_ZFS_MINOR_VERSION);
35112186SJanice.Chang@Sun.COM tape_header->nzh_hdrlen = LE_32(bufsize);
35212186SJanice.Chang@Sun.COM
35312186SJanice.Chang@Sun.COM bzero(buf, bufsize);
35412186SJanice.Chang@Sun.COM (void) memcpy(buf, tape_header, sizeof (ndmpd_zfs_header_t));
35512186SJanice.Chang@Sun.COM
35612186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "header (major, minor, length): %u %u %u",
35712186SJanice.Chang@Sun.COM NDMPD_ZFS_MAJOR_VERSION,
35812186SJanice.Chang@Sun.COM NDMPD_ZFS_MINOR_VERSION,
35912186SJanice.Chang@Sun.COM bufsize);
36012186SJanice.Chang@Sun.COM
36112186SJanice.Chang@Sun.COM if (MOD_WRITE(ndmpd_zfs_params, buf, bufsize) != 0) {
36212186SJanice.Chang@Sun.COM free(buf);
36312186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "MOD_WRITE error");
36412186SJanice.Chang@Sun.COM return (-1);
36512186SJanice.Chang@Sun.COM }
36612186SJanice.Chang@Sun.COM
36712186SJanice.Chang@Sun.COM free(buf);
36812186SJanice.Chang@Sun.COM
36912186SJanice.Chang@Sun.COM session->ns_data.dd_module.dm_stats.ms_bytes_processed = bufsize;
37012186SJanice.Chang@Sun.COM
37112186SJanice.Chang@Sun.COM return (0);
37212186SJanice.Chang@Sun.COM }
37312186SJanice.Chang@Sun.COM
37412186SJanice.Chang@Sun.COM static int
ndmpd_zfs_header_read(ndmpd_zfs_args_t * ndmpd_zfs_args)37512186SJanice.Chang@Sun.COM ndmpd_zfs_header_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
37612186SJanice.Chang@Sun.COM {
37712186SJanice.Chang@Sun.COM int32_t bufsize = ndmpd_zfs_args->nz_bufsize;
37812186SJanice.Chang@Sun.COM ndmpd_zfs_header_t *tape_header = &ndmpd_zfs_args->nz_tape_header;
37912186SJanice.Chang@Sun.COM uint32_t hdrlen;
38012186SJanice.Chang@Sun.COM int32_t header_left;
38112186SJanice.Chang@Sun.COM int err;
38212186SJanice.Chang@Sun.COM char *buf;
38312186SJanice.Chang@Sun.COM
38412186SJanice.Chang@Sun.COM buf = ndmp_malloc(bufsize);
38512186SJanice.Chang@Sun.COM if (buf == NULL) {
38612186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "buf NULL");
38712186SJanice.Chang@Sun.COM return (-1);
38812186SJanice.Chang@Sun.COM }
38912186SJanice.Chang@Sun.COM
39012186SJanice.Chang@Sun.COM bzero(buf, bufsize);
39112186SJanice.Chang@Sun.COM
39212186SJanice.Chang@Sun.COM /*
39312186SJanice.Chang@Sun.COM * Read nz_bufsize worth of bytes first (the size of a mover record).
39412186SJanice.Chang@Sun.COM */
39512186SJanice.Chang@Sun.COM
39612186SJanice.Chang@Sun.COM err = MOD_READ(ndmpd_zfs_params, buf, bufsize);
39712186SJanice.Chang@Sun.COM
39812186SJanice.Chang@Sun.COM if (err != 0) {
39912186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "MOD_READ error: %d", err);
40012186SJanice.Chang@Sun.COM free(buf);
40112186SJanice.Chang@Sun.COM return (-1);
40212186SJanice.Chang@Sun.COM }
40312186SJanice.Chang@Sun.COM
40412186SJanice.Chang@Sun.COM (void) memcpy(tape_header, buf, sizeof (ndmpd_zfs_header_t));
40512186SJanice.Chang@Sun.COM
40612186SJanice.Chang@Sun.COM if (strcmp(tape_header->nzh_magic, NDMPUTF8MAGIC) != 0) {
40712186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
40812186SJanice.Chang@Sun.COM "bad magic string\n");
40912186SJanice.Chang@Sun.COM goto _err;
41012186SJanice.Chang@Sun.COM }
41112186SJanice.Chang@Sun.COM
41212186SJanice.Chang@Sun.COM if (tape_header->nzh_major > LE_32(NDMPD_ZFS_MAJOR_VERSION)) {
41312186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
41412186SJanice.Chang@Sun.COM "major number larger than supported: (%d %d)\n",
41512186SJanice.Chang@Sun.COM LE_32(tape_header->nzh_major), NDMPD_ZFS_MAJOR_VERSION);
41612186SJanice.Chang@Sun.COM goto _err;
41712186SJanice.Chang@Sun.COM }
41812186SJanice.Chang@Sun.COM
41912186SJanice.Chang@Sun.COM /*
42012186SJanice.Chang@Sun.COM * Major version 0 (regardless of minor version):
42112186SJanice.Chang@Sun.COM * Header must be a multiple of the mover record size.
42212186SJanice.Chang@Sun.COM */
42312186SJanice.Chang@Sun.COM
42412186SJanice.Chang@Sun.COM hdrlen = LE_32(tape_header->nzh_hdrlen);
42512186SJanice.Chang@Sun.COM if (hdrlen > bufsize) {
42612186SJanice.Chang@Sun.COM header_left = hdrlen - bufsize;
42712186SJanice.Chang@Sun.COM while (header_left > 0) {
42812186SJanice.Chang@Sun.COM err = MOD_READ(ndmpd_zfs_params, buf, bufsize);
42912186SJanice.Chang@Sun.COM if (err == -1) {
43012186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args,
43112186SJanice.Chang@Sun.COM NDMP_LOG_ERROR, "bad header\n");
43212186SJanice.Chang@Sun.COM goto _err;
43312186SJanice.Chang@Sun.COM }
43412186SJanice.Chang@Sun.COM header_left -= bufsize;
43512186SJanice.Chang@Sun.COM }
43612186SJanice.Chang@Sun.COM }
43712186SJanice.Chang@Sun.COM
43812186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "tape header: %s; %u %u; %u ",
43912186SJanice.Chang@Sun.COM tape_header->nzh_magic,
44012186SJanice.Chang@Sun.COM LE_32(tape_header->nzh_major),
44112186SJanice.Chang@Sun.COM LE_32(tape_header->nzh_minor),
44212186SJanice.Chang@Sun.COM LE_32(tape_header->nzh_hdrlen));
44312186SJanice.Chang@Sun.COM
44412186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_nlp->nlp_bytes_total = hdrlen;
44512186SJanice.Chang@Sun.COM
44612186SJanice.Chang@Sun.COM free(buf);
44712186SJanice.Chang@Sun.COM return (0);
44812186SJanice.Chang@Sun.COM
44912186SJanice.Chang@Sun.COM _err:
45012186SJanice.Chang@Sun.COM
45112186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "tape header: %s; %u %u; %u ",
45212186SJanice.Chang@Sun.COM tape_header->nzh_magic,
45312186SJanice.Chang@Sun.COM LE_32(tape_header->nzh_major),
45412186SJanice.Chang@Sun.COM LE_32(tape_header->nzh_minor),
45512186SJanice.Chang@Sun.COM LE_32(tape_header->nzh_hdrlen));
45612186SJanice.Chang@Sun.COM
45712186SJanice.Chang@Sun.COM free(buf);
45812186SJanice.Chang@Sun.COM return (-1);
45912186SJanice.Chang@Sun.COM }
46012186SJanice.Chang@Sun.COM
46112186SJanice.Chang@Sun.COM int
ndmpd_zfs_backup_starter(void * arg)46212186SJanice.Chang@Sun.COM ndmpd_zfs_backup_starter(void *arg)
46312186SJanice.Chang@Sun.COM {
46412186SJanice.Chang@Sun.COM ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
46512186SJanice.Chang@Sun.COM ndmpd_session_t *session = (ndmpd_session_t *)
46612186SJanice.Chang@Sun.COM (ndmpd_zfs_params->mp_daemon_cookie);
46712186SJanice.Chang@Sun.COM int cleanup_err = 0;
46812186SJanice.Chang@Sun.COM int err = 0;
46912186SJanice.Chang@Sun.COM
47012186SJanice.Chang@Sun.COM ndmp_session_ref(session);
47112186SJanice.Chang@Sun.COM
47212186SJanice.Chang@Sun.COM if (ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args) != 0) {
47312186SJanice.Chang@Sun.COM err = -1;
47412186SJanice.Chang@Sun.COM goto _done;
47512186SJanice.Chang@Sun.COM }
47612186SJanice.Chang@Sun.COM
47712186SJanice.Chang@Sun.COM err = ndmpd_zfs_backup(ndmpd_zfs_args);
47812186SJanice.Chang@Sun.COM
47912186SJanice.Chang@Sun.COM cleanup_err = ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args, err);
48012186SJanice.Chang@Sun.COM
48112186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG,
48212186SJanice.Chang@Sun.COM "data bytes_total(including header):%llu",
48312186SJanice.Chang@Sun.COM session->ns_data.dd_module.dm_stats.ms_bytes_processed);
48412186SJanice.Chang@Sun.COM
48512669SReza.Sabdar@Sun.COM if (err == 0)
48612669SReza.Sabdar@Sun.COM err = ndmpd_zfs_send_fhist(ndmpd_zfs_args);
48712186SJanice.Chang@Sun.COM
48812186SJanice.Chang@Sun.COM _done:
48912186SJanice.Chang@Sun.COM NS_DEC(nbk);
49012186SJanice.Chang@Sun.COM MOD_DONE(ndmpd_zfs_params, err ? err : cleanup_err);
49112186SJanice.Chang@Sun.COM ndmp_session_unref(session);
49212186SJanice.Chang@Sun.COM ndmpd_zfs_fini(ndmpd_zfs_args);
49312186SJanice.Chang@Sun.COM
49412186SJanice.Chang@Sun.COM return (err);
49512186SJanice.Chang@Sun.COM }
49612186SJanice.Chang@Sun.COM
49712186SJanice.Chang@Sun.COM static int
ndmpd_zfs_send_fhist(ndmpd_zfs_args_t * ndmpd_zfs_args)49812669SReza.Sabdar@Sun.COM ndmpd_zfs_send_fhist(ndmpd_zfs_args_t *ndmpd_zfs_args)
49912669SReza.Sabdar@Sun.COM {
50012669SReza.Sabdar@Sun.COM ndmpd_session_t *session = (ndmpd_session_t *)
50112669SReza.Sabdar@Sun.COM (ndmpd_zfs_params->mp_daemon_cookie);
50212669SReza.Sabdar@Sun.COM struct stat64 st;
50312669SReza.Sabdar@Sun.COM char *envp;
50412669SReza.Sabdar@Sun.COM
50512669SReza.Sabdar@Sun.COM envp = MOD_GETENV(ndmpd_zfs_params, "HIST");
50612669SReza.Sabdar@Sun.COM if (!envp)
50712669SReza.Sabdar@Sun.COM return (0);
50812669SReza.Sabdar@Sun.COM
50912669SReza.Sabdar@Sun.COM if (!(strchr("YT", toupper(*envp)))) {
51012669SReza.Sabdar@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING,
51112669SReza.Sabdar@Sun.COM "HIST is not set. No file history will be "
51212669SReza.Sabdar@Sun.COM "generated.\n");
51312669SReza.Sabdar@Sun.COM return (0);
51412669SReza.Sabdar@Sun.COM }
51512669SReza.Sabdar@Sun.COM
51612764SReza.Sabdar@Sun.COM /* Build up a sample root dir stat */
51712764SReza.Sabdar@Sun.COM (void) memset(&st, 0, sizeof (struct stat64));
51812764SReza.Sabdar@Sun.COM st.st_mode = S_IFDIR | 0777;
51912764SReza.Sabdar@Sun.COM st.st_mtime = st.st_atime = st.st_ctime = time(NULL);
52012764SReza.Sabdar@Sun.COM st.st_uid = st.st_gid = 0;
52112764SReza.Sabdar@Sun.COM st.st_size = 1;
52212764SReza.Sabdar@Sun.COM st.st_nlink = 1;
52312669SReza.Sabdar@Sun.COM
52412669SReza.Sabdar@Sun.COM if (ndmpd_api_file_history_dir_v3(session, ".", ROOT_INODE,
52512669SReza.Sabdar@Sun.COM ROOT_INODE) != 0)
52612669SReza.Sabdar@Sun.COM return (-1);
52712669SReza.Sabdar@Sun.COM if (ndmpd_api_file_history_dir_v3(session, "..", ROOT_INODE,
52812669SReza.Sabdar@Sun.COM ROOT_INODE) != 0)
52912669SReza.Sabdar@Sun.COM return (-1);
53012669SReza.Sabdar@Sun.COM if (ndmpd_api_file_history_node_v3(session, ROOT_INODE, &st, 0) != 0)
53112669SReza.Sabdar@Sun.COM return (-1);
53212669SReza.Sabdar@Sun.COM
53312669SReza.Sabdar@Sun.COM ndmpd_file_history_cleanup(session, TRUE);
53412669SReza.Sabdar@Sun.COM return (0);
53512669SReza.Sabdar@Sun.COM }
53612669SReza.Sabdar@Sun.COM
53712669SReza.Sabdar@Sun.COM static int
ndmpd_zfs_backup(ndmpd_zfs_args_t * ndmpd_zfs_args)53812186SJanice.Chang@Sun.COM ndmpd_zfs_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
53912186SJanice.Chang@Sun.COM {
54012186SJanice.Chang@Sun.COM ndmpd_session_t *session = (ndmpd_session_t *)
54112186SJanice.Chang@Sun.COM (ndmpd_zfs_params->mp_daemon_cookie);
54212186SJanice.Chang@Sun.COM int *read_err = NULL;
54312186SJanice.Chang@Sun.COM int *write_err = NULL;
54412186SJanice.Chang@Sun.COM int result = 0;
54512186SJanice.Chang@Sun.COM int err;
54612186SJanice.Chang@Sun.COM
54712186SJanice.Chang@Sun.COM if (session->ns_eof)
54812186SJanice.Chang@Sun.COM return (-1);
54912186SJanice.Chang@Sun.COM
55012186SJanice.Chang@Sun.COM if (!session->ns_data.dd_abort) {
55112186SJanice.Chang@Sun.COM if (ndmpd_zfs_header_write(session)) {
55212186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
55312186SJanice.Chang@Sun.COM "ndmpd_zfs header write error\n");
55412186SJanice.Chang@Sun.COM return (-1);
55512186SJanice.Chang@Sun.COM }
55612186SJanice.Chang@Sun.COM
55712186SJanice.Chang@Sun.COM err = ndmpd_zfs_reader_writer(ndmpd_zfs_args,
55812186SJanice.Chang@Sun.COM &read_err, &write_err);
55912186SJanice.Chang@Sun.COM
56012186SJanice.Chang@Sun.COM if (err || read_err || write_err || session->ns_eof)
56112186SJanice.Chang@Sun.COM result = EPIPE;
56212186SJanice.Chang@Sun.COM }
56312186SJanice.Chang@Sun.COM
56412186SJanice.Chang@Sun.COM if (session->ns_data.dd_abort) {
56512186SJanice.Chang@Sun.COM ndmpd_audit_backup(session->ns_connection,
56612186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset,
56712186SJanice.Chang@Sun.COM session->ns_data.dd_data_addr.addr_type,
56812186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset, EINTR);
56912186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
57012186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset);
57112186SJanice.Chang@Sun.COM
57212186SJanice.Chang@Sun.COM (void) ndmpd_zfs_post_backup(ndmpd_zfs_args);
57312186SJanice.Chang@Sun.COM err = -1;
57412186SJanice.Chang@Sun.COM } else {
57512186SJanice.Chang@Sun.COM ndmpd_audit_backup(session->ns_connection,
57612186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset,
57712186SJanice.Chang@Sun.COM session->ns_data.dd_data_addr.addr_type,
57812186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset, result);
57912186SJanice.Chang@Sun.COM
58012186SJanice.Chang@Sun.COM err = ndmpd_zfs_post_backup(ndmpd_zfs_args);
58112186SJanice.Chang@Sun.COM if (err || result)
58212186SJanice.Chang@Sun.COM err = -1;
58312186SJanice.Chang@Sun.COM
58412186SJanice.Chang@Sun.COM if (err == 0) {
58512186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" finished.",
58612186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset);
58712186SJanice.Chang@Sun.COM } else {
58812186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "An error occurred while backing up"
58912186SJanice.Chang@Sun.COM " \"%s\"", ndmpd_zfs_args->nz_dataset);
59012186SJanice.Chang@Sun.COM }
59112186SJanice.Chang@Sun.COM }
59212186SJanice.Chang@Sun.COM
59312186SJanice.Chang@Sun.COM return (err);
59412186SJanice.Chang@Sun.COM }
59512186SJanice.Chang@Sun.COM
59612186SJanice.Chang@Sun.COM /*
59712186SJanice.Chang@Sun.COM * ndmpd_zfs_backup_send_read()
59812186SJanice.Chang@Sun.COM *
59912186SJanice.Chang@Sun.COM * This routine executes zfs_send() to create the backup data stream.
60012186SJanice.Chang@Sun.COM * The value of ZFS_MODE determines the type of zfs_send():
60112186SJanice.Chang@Sun.COM * dataset ('d'): Only the dataset specified (i.e., top level) is backed up
60212186SJanice.Chang@Sun.COM * recursive ('r'): The dataset and its child file systems are backed up
60312186SJanice.Chang@Sun.COM * package ('p'): Same as 'r', except all intermediate snapshots are also
60412186SJanice.Chang@Sun.COM * backed up
60512186SJanice.Chang@Sun.COM *
60612186SJanice.Chang@Sun.COM * Volumes do not have descednants, so 'd' and 'r' produce equivalent results.
60712186SJanice.Chang@Sun.COM */
60812186SJanice.Chang@Sun.COM
60912186SJanice.Chang@Sun.COM static int
ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t * ndmpd_zfs_args)61012186SJanice.Chang@Sun.COM ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
61112186SJanice.Chang@Sun.COM {
61212186SJanice.Chang@Sun.COM ndmpd_session_t *session = (ndmpd_session_t *)
61312186SJanice.Chang@Sun.COM (ndmpd_zfs_params->mp_daemon_cookie);
61412186SJanice.Chang@Sun.COM sendflags_t flags = { 0 };
61512186SJanice.Chang@Sun.COM char *fromsnap = NULL;
61612186SJanice.Chang@Sun.COM zfs_handle_t *zhp;
61712186SJanice.Chang@Sun.COM int err;
61812186SJanice.Chang@Sun.COM
61912186SJanice.Chang@Sun.COM zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
62012186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
62112186SJanice.Chang@Sun.COM
62212186SJanice.Chang@Sun.COM if (!zhp) {
62312186SJanice.Chang@Sun.COM if (!session->ns_data.dd_abort)
62412186SJanice.Chang@Sun.COM NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
62512186SJanice.Chang@Sun.COM return (-1);
62612186SJanice.Chang@Sun.COM }
62712186SJanice.Chang@Sun.COM
62812186SJanice.Chang@Sun.COM switch (ndmpd_zfs_args->nz_zfs_mode) {
62912186SJanice.Chang@Sun.COM case ('d'):
63012186SJanice.Chang@Sun.COM flags.props = B_TRUE;
63112186SJanice.Chang@Sun.COM break;
63212186SJanice.Chang@Sun.COM case ('r'):
63312186SJanice.Chang@Sun.COM flags.replicate = B_TRUE;
63412186SJanice.Chang@Sun.COM break;
63512186SJanice.Chang@Sun.COM case ('p'):
63612186SJanice.Chang@Sun.COM flags.doall = B_TRUE;
63712186SJanice.Chang@Sun.COM flags.replicate = B_TRUE;
63812186SJanice.Chang@Sun.COM break;
63912186SJanice.Chang@Sun.COM default:
64012186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "unknown zfs_mode: %c",
64112186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_zfs_mode);
64212186SJanice.Chang@Sun.COM zfs_close(zhp);
64312186SJanice.Chang@Sun.COM return (-1);
64412186SJanice.Chang@Sun.COM }
64512186SJanice.Chang@Sun.COM
64612186SJanice.Chang@Sun.COM if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
64712186SJanice.Chang@Sun.COM if (ndmpd_zfs_args->nz_fromsnap[0] == '\0') {
64812186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "no fromsnap");
64912186SJanice.Chang@Sun.COM zfs_close(zhp);
65012186SJanice.Chang@Sun.COM return (-1);
65112186SJanice.Chang@Sun.COM }
65212186SJanice.Chang@Sun.COM fromsnap = ndmpd_zfs_args->nz_fromsnap;
65312186SJanice.Chang@Sun.COM }
65412186SJanice.Chang@Sun.COM
65512186SJanice.Chang@Sun.COM err = zfs_send(zhp, fromsnap, ndmpd_zfs_args->nz_snapname, flags,
65612296SLin.Ling@Sun.COM ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL, NULL, NULL);
65712186SJanice.Chang@Sun.COM
65812186SJanice.Chang@Sun.COM if (err && !session->ns_data.dd_abort)
65912186SJanice.Chang@Sun.COM NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_send: %d", err);
66012186SJanice.Chang@Sun.COM
66112186SJanice.Chang@Sun.COM zfs_close(zhp);
66212186SJanice.Chang@Sun.COM
66312186SJanice.Chang@Sun.COM return (err);
66412186SJanice.Chang@Sun.COM }
66512186SJanice.Chang@Sun.COM
66612186SJanice.Chang@Sun.COM /*
66712186SJanice.Chang@Sun.COM * ndmpd_zfs_backup_tape_write()
66812186SJanice.Chang@Sun.COM *
66912186SJanice.Chang@Sun.COM * The data begins on a mover record boundary (because
67012186SJanice.Chang@Sun.COM * the header is the size of a mover record--i.e.
67112186SJanice.Chang@Sun.COM * ndmpd_zfs_args->nz_bufsize).
67212186SJanice.Chang@Sun.COM */
67312186SJanice.Chang@Sun.COM
67412186SJanice.Chang@Sun.COM static int
ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t * ndmpd_zfs_args)67512186SJanice.Chang@Sun.COM ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t *ndmpd_zfs_args)
67612186SJanice.Chang@Sun.COM {
67712186SJanice.Chang@Sun.COM ndmpd_session_t *session = (ndmpd_session_t *)
67812186SJanice.Chang@Sun.COM (ndmpd_zfs_params->mp_daemon_cookie);
67912186SJanice.Chang@Sun.COM int bufsize = ndmpd_zfs_args->nz_bufsize;
68012186SJanice.Chang@Sun.COM u_longlong_t *bytes_totalp;
68112186SJanice.Chang@Sun.COM int count;
68212186SJanice.Chang@Sun.COM char *buf;
68312186SJanice.Chang@Sun.COM
68412186SJanice.Chang@Sun.COM buf = ndmp_malloc(bufsize);
68512186SJanice.Chang@Sun.COM if (buf == NULL) {
68612186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "buf NULL");
68712186SJanice.Chang@Sun.COM return (-1);
68812186SJanice.Chang@Sun.COM }
68912186SJanice.Chang@Sun.COM
69012186SJanice.Chang@Sun.COM bytes_totalp =
69112186SJanice.Chang@Sun.COM &(session->ns_data.dd_module.dm_stats.ms_bytes_processed);
69212186SJanice.Chang@Sun.COM
69312186SJanice.Chang@Sun.COM for (;;) {
69412186SJanice.Chang@Sun.COM bzero(buf, bufsize);
69512186SJanice.Chang@Sun.COM
69612186SJanice.Chang@Sun.COM count = read(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
69712186SJanice.Chang@Sun.COM bufsize);
69812186SJanice.Chang@Sun.COM
69912186SJanice.Chang@Sun.COM if (count == 0) /* EOF */ {
70012186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG,
70112740SJanice.Chang@Sun.COM "zfs_send stream size: %llu bytes; "
70212740SJanice.Chang@Sun.COM "full backup size (including header): %llu",
70312740SJanice.Chang@Sun.COM *bytes_totalp - bufsize, *bytes_totalp);
70412186SJanice.Chang@Sun.COM free(buf);
70512740SJanice.Chang@Sun.COM
70612740SJanice.Chang@Sun.COM return (ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args,
70712740SJanice.Chang@Sun.COM *bytes_totalp));
70812186SJanice.Chang@Sun.COM }
70912186SJanice.Chang@Sun.COM
71012186SJanice.Chang@Sun.COM if (count == -1) {
71112186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "pipe read error (errno %d)",
71212186SJanice.Chang@Sun.COM errno);
71312186SJanice.Chang@Sun.COM free(buf);
71412186SJanice.Chang@Sun.COM return (-1);
71512186SJanice.Chang@Sun.COM }
71612669SReza.Sabdar@Sun.COM NS_ADD(rdisk, count);
71712186SJanice.Chang@Sun.COM
71812186SJanice.Chang@Sun.COM if (MOD_WRITE(ndmpd_zfs_params, buf, count) != 0) {
71912186SJanice.Chang@Sun.COM (void) ndmpd_zfs_abort((void *) ndmpd_zfs_args);
72012186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "MOD_WRITE error");
72112186SJanice.Chang@Sun.COM free(buf);
72212186SJanice.Chang@Sun.COM return (-1);
72312186SJanice.Chang@Sun.COM }
72412186SJanice.Chang@Sun.COM
72512186SJanice.Chang@Sun.COM *bytes_totalp += count;
72612186SJanice.Chang@Sun.COM }
72712186SJanice.Chang@Sun.COM /* NOTREACHED */
72812186SJanice.Chang@Sun.COM }
72912186SJanice.Chang@Sun.COM
73012740SJanice.Chang@Sun.COM static int
ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t * ndmpd_zfs_args,u_longlong_t bytes_total)73112740SJanice.Chang@Sun.COM ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args,
73212740SJanice.Chang@Sun.COM u_longlong_t bytes_total)
73312740SJanice.Chang@Sun.COM {
73412740SJanice.Chang@Sun.COM char zfs_backup_size[32];
73512740SJanice.Chang@Sun.COM int err;
73612740SJanice.Chang@Sun.COM
73712740SJanice.Chang@Sun.COM (void) snprintf(zfs_backup_size, sizeof (zfs_backup_size), "%llu",
73812740SJanice.Chang@Sun.COM bytes_total);
73912740SJanice.Chang@Sun.COM
74012740SJanice.Chang@Sun.COM err = MOD_ADDENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE", zfs_backup_size);
74112740SJanice.Chang@Sun.COM
74212740SJanice.Chang@Sun.COM if (err) {
74312740SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "Failed to add ZFS_BACKUP_SIZE env");
74412740SJanice.Chang@Sun.COM return (-1);
74512740SJanice.Chang@Sun.COM }
74612740SJanice.Chang@Sun.COM
74712740SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "Added ZFS_BACKUP_SIZE env: %s", zfs_backup_size);
74812740SJanice.Chang@Sun.COM
74912740SJanice.Chang@Sun.COM return (0);
75012740SJanice.Chang@Sun.COM }
75112740SJanice.Chang@Sun.COM
75212186SJanice.Chang@Sun.COM int
ndmpd_zfs_restore_starter(void * arg)75312186SJanice.Chang@Sun.COM ndmpd_zfs_restore_starter(void *arg)
75412186SJanice.Chang@Sun.COM {
75512186SJanice.Chang@Sun.COM ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
75612186SJanice.Chang@Sun.COM ndmpd_session_t *session = (ndmpd_session_t *)
75712186SJanice.Chang@Sun.COM (ndmpd_zfs_params->mp_daemon_cookie);
75812186SJanice.Chang@Sun.COM int err;
75912186SJanice.Chang@Sun.COM
76012186SJanice.Chang@Sun.COM ndmp_session_ref(session);
76112186SJanice.Chang@Sun.COM
76212186SJanice.Chang@Sun.COM err = ndmpd_zfs_restore(ndmpd_zfs_args);
76312186SJanice.Chang@Sun.COM
76412186SJanice.Chang@Sun.COM MOD_DONE(ndmpd_zfs_params, err);
76512186SJanice.Chang@Sun.COM
76612186SJanice.Chang@Sun.COM NS_DEC(nrs);
76712186SJanice.Chang@Sun.COM
76812186SJanice.Chang@Sun.COM ndmp_session_unref(session);
76912186SJanice.Chang@Sun.COM
77012186SJanice.Chang@Sun.COM ndmpd_zfs_fini(ndmpd_zfs_args);
77112186SJanice.Chang@Sun.COM
77212186SJanice.Chang@Sun.COM return (err);
77312186SJanice.Chang@Sun.COM }
77412186SJanice.Chang@Sun.COM
77512186SJanice.Chang@Sun.COM static int
ndmpd_zfs_restore(ndmpd_zfs_args_t * ndmpd_zfs_args)77612186SJanice.Chang@Sun.COM ndmpd_zfs_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
77712186SJanice.Chang@Sun.COM {
77812186SJanice.Chang@Sun.COM ndmpd_session_t *session = (ndmpd_session_t *)
77912186SJanice.Chang@Sun.COM (ndmpd_zfs_params->mp_daemon_cookie);
78012186SJanice.Chang@Sun.COM int *read_err = NULL;
78112186SJanice.Chang@Sun.COM int *write_err = NULL;
78212186SJanice.Chang@Sun.COM int result = 0;
78312186SJanice.Chang@Sun.COM int err;
78412186SJanice.Chang@Sun.COM
78512186SJanice.Chang@Sun.COM if (!session->ns_data.dd_abort) {
78612186SJanice.Chang@Sun.COM if (ndmpd_zfs_header_read(ndmpd_zfs_args)) {
78712186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
78812186SJanice.Chang@Sun.COM "ndmpd_zfs header read error\n");
78912186SJanice.Chang@Sun.COM return (-1);
79012186SJanice.Chang@Sun.COM }
79112186SJanice.Chang@Sun.COM
79212186SJanice.Chang@Sun.COM err = ndmpd_zfs_reader_writer(ndmpd_zfs_args,
79312186SJanice.Chang@Sun.COM &write_err, &read_err);
79412186SJanice.Chang@Sun.COM
79512186SJanice.Chang@Sun.COM if (err || read_err || write_err || session->ns_eof)
79612186SJanice.Chang@Sun.COM result = EIO;
79712186SJanice.Chang@Sun.COM }
79812186SJanice.Chang@Sun.COM
79912186SJanice.Chang@Sun.COM if (session->ns_data.dd_abort) {
80012186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
80112186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset);
80212186SJanice.Chang@Sun.COM ndmpd_audit_restore(session->ns_connection,
80312186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset,
80412186SJanice.Chang@Sun.COM session->ns_data.dd_data_addr.addr_type,
80512186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset, EINTR);
80612186SJanice.Chang@Sun.COM (void) ndmpd_zfs_post_restore(ndmpd_zfs_args);
80712186SJanice.Chang@Sun.COM err = -1;
80812186SJanice.Chang@Sun.COM } else {
80912186SJanice.Chang@Sun.COM ndmpd_audit_restore(session->ns_connection,
81012186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset,
81112186SJanice.Chang@Sun.COM session->ns_data.dd_data_addr.addr_type,
81212186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset, result);
81312186SJanice.Chang@Sun.COM err = ndmpd_zfs_post_restore(ndmpd_zfs_args);
81412186SJanice.Chang@Sun.COM if (err || result)
81512186SJanice.Chang@Sun.COM err = -1;
81612186SJanice.Chang@Sun.COM
81712186SJanice.Chang@Sun.COM if (err == 0) {
81812186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished",
81912186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset);
82012186SJanice.Chang@Sun.COM } else {
82112186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "An error occurred while restoring"
82212186SJanice.Chang@Sun.COM " to \"%s\"", ndmpd_zfs_args->nz_dataset);
82312186SJanice.Chang@Sun.COM }
82412186SJanice.Chang@Sun.COM }
82512186SJanice.Chang@Sun.COM
82612186SJanice.Chang@Sun.COM return (err);
82712186SJanice.Chang@Sun.COM }
82812186SJanice.Chang@Sun.COM
82912186SJanice.Chang@Sun.COM static int
ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t * ndmpd_zfs_args)83012186SJanice.Chang@Sun.COM ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
83112186SJanice.Chang@Sun.COM {
83212186SJanice.Chang@Sun.COM ndmpd_session_t *session = (ndmpd_session_t *)
83312186SJanice.Chang@Sun.COM (ndmpd_zfs_params->mp_daemon_cookie);
83412186SJanice.Chang@Sun.COM int bufsize = ndmpd_zfs_args->nz_bufsize;
83512740SJanice.Chang@Sun.COM u_longlong_t backup_size = ndmpd_zfs_args->nz_zfs_backup_size;
83612186SJanice.Chang@Sun.COM u_longlong_t *bytes_totalp;
83712740SJanice.Chang@Sun.COM u_longlong_t bytes;
83812186SJanice.Chang@Sun.COM char *buf;
83912186SJanice.Chang@Sun.COM int count;
84012186SJanice.Chang@Sun.COM int err;
84112186SJanice.Chang@Sun.COM
84212186SJanice.Chang@Sun.COM buf = ndmp_malloc(bufsize);
84312186SJanice.Chang@Sun.COM if (buf == NULL) {
84412186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "buf NULL");
84512186SJanice.Chang@Sun.COM return (-1);
84612186SJanice.Chang@Sun.COM }
84712186SJanice.Chang@Sun.COM
84812186SJanice.Chang@Sun.COM bytes_totalp = &ndmpd_zfs_args->nz_nlp->nlp_bytes_total;
84912186SJanice.Chang@Sun.COM
85012740SJanice.Chang@Sun.COM while (*bytes_totalp < backup_size) {
85112740SJanice.Chang@Sun.COM
85212740SJanice.Chang@Sun.COM bytes = backup_size - *bytes_totalp;
85312740SJanice.Chang@Sun.COM
85412740SJanice.Chang@Sun.COM if (bytes >= bufsize)
85512740SJanice.Chang@Sun.COM bytes = bufsize;
85612740SJanice.Chang@Sun.COM
85712740SJanice.Chang@Sun.COM err = MOD_READ(ndmpd_zfs_params, buf, bytes);
85812740SJanice.Chang@Sun.COM
85912740SJanice.Chang@Sun.COM if (err != 0) {
86012740SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "MOD_READ error: %d; returning -1",
86112740SJanice.Chang@Sun.COM err);
86212740SJanice.Chang@Sun.COM free(buf);
86312740SJanice.Chang@Sun.COM return (-1);
86412186SJanice.Chang@Sun.COM }
86512186SJanice.Chang@Sun.COM
86612186SJanice.Chang@Sun.COM count = write(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
86712740SJanice.Chang@Sun.COM bytes);
86812740SJanice.Chang@Sun.COM
86912740SJanice.Chang@Sun.COM if (count != bytes) {
87012740SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "count (%d) != bytes (%d)",
87112740SJanice.Chang@Sun.COM count, bytes);
87212740SJanice.Chang@Sun.COM
87312740SJanice.Chang@Sun.COM if (count == -1) {
87412740SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "pipe write error: errno: %d",
87512740SJanice.Chang@Sun.COM errno);
87612740SJanice.Chang@Sun.COM
87712740SJanice.Chang@Sun.COM if (session->ns_data.dd_abort)
87812740SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "abort set");
87912740SJanice.Chang@Sun.COM }
88012740SJanice.Chang@Sun.COM
88112186SJanice.Chang@Sun.COM free(buf);
88212186SJanice.Chang@Sun.COM return (-1);
88312186SJanice.Chang@Sun.COM }
88412740SJanice.Chang@Sun.COM
88512669SReza.Sabdar@Sun.COM NS_ADD(wdisk, count);
88612186SJanice.Chang@Sun.COM
88712186SJanice.Chang@Sun.COM *bytes_totalp += count;
88812186SJanice.Chang@Sun.COM }
88912186SJanice.Chang@Sun.COM
89012186SJanice.Chang@Sun.COM free(buf);
89112186SJanice.Chang@Sun.COM return (0);
89212186SJanice.Chang@Sun.COM }
89312186SJanice.Chang@Sun.COM
89412186SJanice.Chang@Sun.COM /*
89512186SJanice.Chang@Sun.COM * ndmpd_zfs_restore_recv_write()
89612186SJanice.Chang@Sun.COM *
89712186SJanice.Chang@Sun.COM * This routine executes zfs_receive() to restore the backup.
89812186SJanice.Chang@Sun.COM */
89912186SJanice.Chang@Sun.COM
90012186SJanice.Chang@Sun.COM static int
ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t * ndmpd_zfs_args)90112186SJanice.Chang@Sun.COM ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t *ndmpd_zfs_args)
90212186SJanice.Chang@Sun.COM {
90312186SJanice.Chang@Sun.COM ndmpd_session_t *session = (ndmpd_session_t *)
90412186SJanice.Chang@Sun.COM (ndmpd_zfs_params->mp_daemon_cookie);
90512186SJanice.Chang@Sun.COM recvflags_t flags;
90612186SJanice.Chang@Sun.COM int err;
90712186SJanice.Chang@Sun.COM
90812186SJanice.Chang@Sun.COM bzero(&flags, sizeof (recvflags_t));
90912186SJanice.Chang@Sun.COM
91012186SJanice.Chang@Sun.COM flags.nomount = B_TRUE;
91112186SJanice.Chang@Sun.COM
91212514SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "nz_zfs_force: %d\n", ndmpd_zfs_args->nz_zfs_force);
91312514SJanice.Chang@Sun.COM
91412186SJanice.Chang@Sun.COM if (ndmpd_zfs_args->nz_zfs_force)
91512186SJanice.Chang@Sun.COM flags.force = B_TRUE;
91612186SJanice.Chang@Sun.COM
91712186SJanice.Chang@Sun.COM err = zfs_receive(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
91812186SJanice.Chang@Sun.COM flags, ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL);
91912186SJanice.Chang@Sun.COM
92012186SJanice.Chang@Sun.COM if (err && !session->ns_data.dd_abort)
92112186SJanice.Chang@Sun.COM NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_receive: %d", err);
92212186SJanice.Chang@Sun.COM
92312186SJanice.Chang@Sun.COM return (err);
92412186SJanice.Chang@Sun.COM }
92512186SJanice.Chang@Sun.COM
92612186SJanice.Chang@Sun.COM /*
92712186SJanice.Chang@Sun.COM * ndmpd_zfs_reader_writer()
92812186SJanice.Chang@Sun.COM *
92912186SJanice.Chang@Sun.COM * Two separate threads are used for actual backup or restore.
93012186SJanice.Chang@Sun.COM */
93112186SJanice.Chang@Sun.COM
93212186SJanice.Chang@Sun.COM static int
ndmpd_zfs_reader_writer(ndmpd_zfs_args_t * ndmpd_zfs_args,int ** sendrecv_errp,int ** tape_errp)93312186SJanice.Chang@Sun.COM ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *ndmpd_zfs_args,
93412186SJanice.Chang@Sun.COM int **sendrecv_errp, int **tape_errp)
93512186SJanice.Chang@Sun.COM {
93612186SJanice.Chang@Sun.COM funct_t sendrecv_func;
93712186SJanice.Chang@Sun.COM funct_t tape_func;
93812186SJanice.Chang@Sun.COM int sendrecv_err;
93912186SJanice.Chang@Sun.COM int tape_err;
94012186SJanice.Chang@Sun.COM
94112186SJanice.Chang@Sun.COM switch (ndmpd_zfs_params->mp_operation) {
94212186SJanice.Chang@Sun.COM case NDMP_DATA_OP_BACKUP:
94312186SJanice.Chang@Sun.COM sendrecv_func = (funct_t)ndmpd_zfs_backup_send_read;
94412186SJanice.Chang@Sun.COM tape_func = (funct_t)ndmpd_zfs_backup_tape_write;
94512186SJanice.Chang@Sun.COM break;
94612186SJanice.Chang@Sun.COM case NDMP_DATA_OP_RECOVER:
94712186SJanice.Chang@Sun.COM sendrecv_func = (funct_t)ndmpd_zfs_restore_recv_write;
94812186SJanice.Chang@Sun.COM tape_func = (funct_t)ndmpd_zfs_restore_tape_read;
94912186SJanice.Chang@Sun.COM break;
95012186SJanice.Chang@Sun.COM }
95112186SJanice.Chang@Sun.COM
95212186SJanice.Chang@Sun.COM sendrecv_err = pthread_create(&ndmpd_zfs_args->nz_sendrecv_thread,
95312186SJanice.Chang@Sun.COM NULL, sendrecv_func, ndmpd_zfs_args);
95412186SJanice.Chang@Sun.COM
95512186SJanice.Chang@Sun.COM if (sendrecv_err == 0) {
95612186SJanice.Chang@Sun.COM tape_err = pthread_create(&ndmpd_zfs_args->nz_tape_thread,
95712186SJanice.Chang@Sun.COM NULL, tape_func, ndmpd_zfs_args);
95812186SJanice.Chang@Sun.COM
95912186SJanice.Chang@Sun.COM if (tape_err) {
96012186SJanice.Chang@Sun.COM /*
96112186SJanice.Chang@Sun.COM * The close of the tape side of the pipe will cause
96212186SJanice.Chang@Sun.COM * nz_sendrecv_thread to error in the zfs_send/recv()
96312186SJanice.Chang@Sun.COM * call and to return. Hence we do not need
96412186SJanice.Chang@Sun.COM * to explicitly cancel the sendrecv_thread here
96512186SJanice.Chang@Sun.COM * (the pthread_join() below is sufficient).
96612186SJanice.Chang@Sun.COM */
96712186SJanice.Chang@Sun.COM
96812186SJanice.Chang@Sun.COM (void) close(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE]);
96912186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "Could not start tape thread; "
97012186SJanice.Chang@Sun.COM "aborting z-op");
97112186SJanice.Chang@Sun.COM }
97212186SJanice.Chang@Sun.COM
97312186SJanice.Chang@Sun.COM (void) pthread_join(ndmpd_zfs_args->nz_sendrecv_thread,
97412186SJanice.Chang@Sun.COM (void **) sendrecv_errp);
97512186SJanice.Chang@Sun.COM }
97612186SJanice.Chang@Sun.COM
97712186SJanice.Chang@Sun.COM if ((tape_err == 0) &&
97812186SJanice.Chang@Sun.COM (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_RECOVER))
97912186SJanice.Chang@Sun.COM ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
98012186SJanice.Chang@Sun.COM
98112186SJanice.Chang@Sun.COM ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS);
98212186SJanice.Chang@Sun.COM
98312186SJanice.Chang@Sun.COM if ((sendrecv_err == 0) && (tape_err == 0)) {
98412186SJanice.Chang@Sun.COM (void) pthread_join(ndmpd_zfs_args->nz_tape_thread,
98512186SJanice.Chang@Sun.COM (void **) tape_errp);
98612186SJanice.Chang@Sun.COM }
98712186SJanice.Chang@Sun.COM
98812186SJanice.Chang@Sun.COM if ((tape_err == 0) &&
98912186SJanice.Chang@Sun.COM (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP))
99012186SJanice.Chang@Sun.COM ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
99112186SJanice.Chang@Sun.COM
99212186SJanice.Chang@Sun.COM return (sendrecv_err ? sendrecv_err : tape_err);
99312186SJanice.Chang@Sun.COM }
99412186SJanice.Chang@Sun.COM
99512186SJanice.Chang@Sun.COM int
ndmpd_zfs_abort(void * arg)99612186SJanice.Chang@Sun.COM ndmpd_zfs_abort(void *arg)
99712186SJanice.Chang@Sun.COM {
99812186SJanice.Chang@Sun.COM ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
99912186SJanice.Chang@Sun.COM char str[8];
100012186SJanice.Chang@Sun.COM
100112186SJanice.Chang@Sun.COM if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP)
100212186SJanice.Chang@Sun.COM (void) strlcpy(str, "backup", 8);
100312186SJanice.Chang@Sun.COM else
100412186SJanice.Chang@Sun.COM (void) strlcpy(str, "recover", 8);
100512186SJanice.Chang@Sun.COM
100612186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "ndmpd_zfs_abort() called...aborting %s operation",
100712186SJanice.Chang@Sun.COM str);
100812186SJanice.Chang@Sun.COM
100912186SJanice.Chang@Sun.COM ndmpd_zfs_close_fds(ndmpd_zfs_args);
101012186SJanice.Chang@Sun.COM
101112186SJanice.Chang@Sun.COM return (0);
101212186SJanice.Chang@Sun.COM }
101312186SJanice.Chang@Sun.COM
101412186SJanice.Chang@Sun.COM /*
101512186SJanice.Chang@Sun.COM * ndmpd_zfs_pre_backup()
101612186SJanice.Chang@Sun.COM *
101712186SJanice.Chang@Sun.COM * Note: The memset to 0 of nctxp ensures that nctx->nc_cmds == NULL.
101812186SJanice.Chang@Sun.COM * This ensures that ndmp_include_zfs() will fail, which is
101912186SJanice.Chang@Sun.COM * a requirement for "zfs"-type backup.
102012186SJanice.Chang@Sun.COM */
102112186SJanice.Chang@Sun.COM
102212186SJanice.Chang@Sun.COM int
ndmpd_zfs_pre_backup(ndmpd_zfs_args_t * ndmpd_zfs_args)102312186SJanice.Chang@Sun.COM ndmpd_zfs_pre_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
102412186SJanice.Chang@Sun.COM {
102512186SJanice.Chang@Sun.COM ndmpd_session_t *session = (ndmpd_session_t *)
102612186SJanice.Chang@Sun.COM (ndmpd_zfs_params->mp_daemon_cookie);
102712186SJanice.Chang@Sun.COM ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
102812186SJanice.Chang@Sun.COM int err;
102912186SJanice.Chang@Sun.COM
103012186SJanice.Chang@Sun.COM if (ndmp_pl == NULL || ndmp_pl->np_pre_backup == NULL)
103112186SJanice.Chang@Sun.COM return (0);
103212186SJanice.Chang@Sun.COM
103312186SJanice.Chang@Sun.COM (void) memset(nctxp, 0, sizeof (ndmp_context_t));
103412186SJanice.Chang@Sun.COM nctxp->nc_plversion = ndmp_pl->np_plversion;
103512186SJanice.Chang@Sun.COM nctxp->nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
103612186SJanice.Chang@Sun.COM nctxp->nc_ddata = (void *) session;
1037*13051SJanice.Chang@Sun.COM nctxp->nc_params = ndmpd_zfs_params;
103812186SJanice.Chang@Sun.COM
103912186SJanice.Chang@Sun.COM err = ndmp_pl->np_pre_backup(ndmp_pl, nctxp,
104012186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset);
104112186SJanice.Chang@Sun.COM
104212186SJanice.Chang@Sun.COM if (err != 0) {
104312186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "Pre-backup plug-in: %m");
104412186SJanice.Chang@Sun.COM (void) ndmpd_zfs_post_backup(ndmpd_zfs_args);
104512186SJanice.Chang@Sun.COM }
104612186SJanice.Chang@Sun.COM
104712186SJanice.Chang@Sun.COM return (err);
104812186SJanice.Chang@Sun.COM }
104912186SJanice.Chang@Sun.COM
105012186SJanice.Chang@Sun.COM int
ndmpd_zfs_post_backup(ndmpd_zfs_args_t * ndmpd_zfs_args)105112186SJanice.Chang@Sun.COM ndmpd_zfs_post_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
105212186SJanice.Chang@Sun.COM {
105312186SJanice.Chang@Sun.COM ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
105412186SJanice.Chang@Sun.COM int err = 0;
105512186SJanice.Chang@Sun.COM
105612186SJanice.Chang@Sun.COM if (ndmp_pl == NULL || ndmp_pl->np_post_backup == NULL)
105712186SJanice.Chang@Sun.COM return (0);
105812186SJanice.Chang@Sun.COM
105912186SJanice.Chang@Sun.COM err = ndmp_pl->np_post_backup(ndmp_pl, nctxp, err);
106012186SJanice.Chang@Sun.COM
106112186SJanice.Chang@Sun.COM if (err == -1)
106212186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m");
106312186SJanice.Chang@Sun.COM
106412186SJanice.Chang@Sun.COM return (err);
106512186SJanice.Chang@Sun.COM }
106612186SJanice.Chang@Sun.COM
106712186SJanice.Chang@Sun.COM int
ndmpd_zfs_pre_restore(ndmpd_zfs_args_t * ndmpd_zfs_args)106812186SJanice.Chang@Sun.COM ndmpd_zfs_pre_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
106912186SJanice.Chang@Sun.COM {
107012186SJanice.Chang@Sun.COM ndmpd_session_t *session = (ndmpd_session_t *)
107112186SJanice.Chang@Sun.COM (ndmpd_zfs_params->mp_daemon_cookie);
107212186SJanice.Chang@Sun.COM ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
107312186SJanice.Chang@Sun.COM char bkpath[ZFS_MAXNAMELEN];
107412186SJanice.Chang@Sun.COM int err;
107512186SJanice.Chang@Sun.COM
107612186SJanice.Chang@Sun.COM if (ndmp_pl == NULL || ndmp_pl->np_pre_restore == NULL)
107712186SJanice.Chang@Sun.COM return (0);
107812186SJanice.Chang@Sun.COM
107912186SJanice.Chang@Sun.COM err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, bkpath, ZFS_MAXNAMELEN);
108012186SJanice.Chang@Sun.COM
108112186SJanice.Chang@Sun.COM if (err != 0) {
108212186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "error getting bkup path: %d", err);
108312186SJanice.Chang@Sun.COM return (-1);
108412186SJanice.Chang@Sun.COM }
108512186SJanice.Chang@Sun.COM
108612186SJanice.Chang@Sun.COM err = ndmpd_zfs_restore_getpath(ndmpd_zfs_args);
108712186SJanice.Chang@Sun.COM
108812186SJanice.Chang@Sun.COM if (err != 0) {
108912186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "error getting restore path: %d", err);
109012186SJanice.Chang@Sun.COM return (-1);
109112186SJanice.Chang@Sun.COM }
109212186SJanice.Chang@Sun.COM
109312186SJanice.Chang@Sun.COM (void) memset(nctxp, 0, sizeof (ndmp_context_t));
109412186SJanice.Chang@Sun.COM nctxp->nc_ddata = (void *) session;
1095*13051SJanice.Chang@Sun.COM nctxp->nc_params = ndmpd_zfs_params;
109612186SJanice.Chang@Sun.COM
109712186SJanice.Chang@Sun.COM err = ndmp_pl->np_pre_restore(ndmp_pl, nctxp, bkpath,
109812186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset);
109912186SJanice.Chang@Sun.COM
110012186SJanice.Chang@Sun.COM if (err != 0) {
110112186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m");
110212186SJanice.Chang@Sun.COM return (-1);
110312186SJanice.Chang@Sun.COM }
110412186SJanice.Chang@Sun.COM
110512186SJanice.Chang@Sun.COM return (0);
110612186SJanice.Chang@Sun.COM }
110712186SJanice.Chang@Sun.COM
110812186SJanice.Chang@Sun.COM int
ndmpd_zfs_post_restore(ndmpd_zfs_args_t * ndmpd_zfs_args)110912186SJanice.Chang@Sun.COM ndmpd_zfs_post_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
111012186SJanice.Chang@Sun.COM {
111112186SJanice.Chang@Sun.COM ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
111212186SJanice.Chang@Sun.COM int err = 0;
111312186SJanice.Chang@Sun.COM
111412186SJanice.Chang@Sun.COM if (ndmp_pl == NULL || ndmp_pl->np_post_restore == NULL)
111512186SJanice.Chang@Sun.COM return (0);
111612186SJanice.Chang@Sun.COM
111712186SJanice.Chang@Sun.COM err = ndmp_pl->np_post_restore(ndmp_pl, nctxp, err);
111812186SJanice.Chang@Sun.COM
111912186SJanice.Chang@Sun.COM if (err == -1)
112012186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
112112186SJanice.Chang@Sun.COM
112212186SJanice.Chang@Sun.COM return (err);
112312186SJanice.Chang@Sun.COM }
112412186SJanice.Chang@Sun.COM
112512186SJanice.Chang@Sun.COM boolean_t
ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t * ndmpd_zfs_args)112612186SJanice.Chang@Sun.COM ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
112712186SJanice.Chang@Sun.COM {
112812186SJanice.Chang@Sun.COM ndmpd_zfs_snapfind_t snapdata;
112912186SJanice.Chang@Sun.COM
113012186SJanice.Chang@Sun.COM if (ndmpd_zfs_backup_getenv(ndmpd_zfs_args) != 0)
113112186SJanice.Chang@Sun.COM return (B_FALSE);
113212186SJanice.Chang@Sun.COM
113312186SJanice.Chang@Sun.COM if (!ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args))
113412186SJanice.Chang@Sun.COM return (B_FALSE);
113512186SJanice.Chang@Sun.COM
113612186SJanice.Chang@Sun.COM if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
113712186SJanice.Chang@Sun.COM (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
113812186SJanice.Chang@Sun.COM snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_TRUE);
113912186SJanice.Chang@Sun.COM
114012186SJanice.Chang@Sun.COM snapdata.nzs_snapname[0] = '\0';
114112186SJanice.Chang@Sun.COM snapdata.nzs_snapprop[0] = '\0';
114212186SJanice.Chang@Sun.COM
114312186SJanice.Chang@Sun.COM if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata))
114412186SJanice.Chang@Sun.COM return (B_FALSE);
114512186SJanice.Chang@Sun.COM
114612186SJanice.Chang@Sun.COM if (snapdata.nzs_snapname[0] == '\0') { /* not found */
114712186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
114812186SJanice.Chang@Sun.COM "Snapshot for level %d does not exist\n",
114912186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_level-1);
115012186SJanice.Chang@Sun.COM return (B_FALSE);
115112186SJanice.Chang@Sun.COM }
115212186SJanice.Chang@Sun.COM
115312186SJanice.Chang@Sun.COM (void) strlcpy(ndmpd_zfs_args->nz_fromsnap,
115412186SJanice.Chang@Sun.COM snapdata.nzs_snapname, ZFS_MAXNAMELEN);
115512186SJanice.Chang@Sun.COM }
115612186SJanice.Chang@Sun.COM
115712186SJanice.Chang@Sun.COM return (B_TRUE);
115812186SJanice.Chang@Sun.COM }
115912186SJanice.Chang@Sun.COM
116012186SJanice.Chang@Sun.COM /*
116112186SJanice.Chang@Sun.COM * ndmpd_zfs_backup_pathvalid()
116212186SJanice.Chang@Sun.COM *
116312186SJanice.Chang@Sun.COM * Make sure the path is of an existing dataset
116412186SJanice.Chang@Sun.COM */
116512186SJanice.Chang@Sun.COM
116612186SJanice.Chang@Sun.COM static boolean_t
ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t * ndmpd_zfs_args)116712186SJanice.Chang@Sun.COM ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
116812186SJanice.Chang@Sun.COM {
116912186SJanice.Chang@Sun.COM char zpath[ZFS_MAXNAMELEN];
117012186SJanice.Chang@Sun.COM char propstr[ZFS_MAXPROPLEN];
117112186SJanice.Chang@Sun.COM zfs_handle_t *zhp;
117212186SJanice.Chang@Sun.COM zfs_type_t ztype = 0;
117312186SJanice.Chang@Sun.COM int err;
117412186SJanice.Chang@Sun.COM
117512186SJanice.Chang@Sun.COM if (ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath, ZFS_MAXNAMELEN)
117612186SJanice.Chang@Sun.COM != 0)
117712186SJanice.Chang@Sun.COM return (B_FALSE);
117812186SJanice.Chang@Sun.COM
117912186SJanice.Chang@Sun.COM if (ndmpd_zfs_args->nz_snapname[0] != '\0') {
118012186SJanice.Chang@Sun.COM zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, zpath,
118112186SJanice.Chang@Sun.COM ZFS_TYPE_SNAPSHOT);
118212186SJanice.Chang@Sun.COM
118312186SJanice.Chang@Sun.COM if (!zhp) {
118412186SJanice.Chang@Sun.COM NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args,
118512186SJanice.Chang@Sun.COM "zfs_open (snap)");
118612186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_snapname[0] = '\0';
118712186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset[0] = '\0';
118812186SJanice.Chang@Sun.COM return (B_FALSE);
118912186SJanice.Chang@Sun.COM }
119012186SJanice.Chang@Sun.COM
119112186SJanice.Chang@Sun.COM err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
119212186SJanice.Chang@Sun.COM
119312186SJanice.Chang@Sun.COM zfs_close(zhp);
119412186SJanice.Chang@Sun.COM
119512186SJanice.Chang@Sun.COM if (err) {
119612186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG,
119712186SJanice.Chang@Sun.COM "ndmpd_zfs_snapshot_prop_get failed");
119812186SJanice.Chang@Sun.COM return (-1);
119912186SJanice.Chang@Sun.COM }
120012186SJanice.Chang@Sun.COM
120112186SJanice.Chang@Sun.COM if (propstr && ndmpd_zfs_snapshot_ndmpd_generated(propstr)) {
120212186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
120312186SJanice.Chang@Sun.COM "cannot use an ndmpd-generated snapshot\n");
120412186SJanice.Chang@Sun.COM return (B_FALSE);
120512186SJanice.Chang@Sun.COM }
120612186SJanice.Chang@Sun.COM }
120712186SJanice.Chang@Sun.COM
120812186SJanice.Chang@Sun.COM zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
120912186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset, ZFS_TYPE_DATASET);
121012186SJanice.Chang@Sun.COM
121112186SJanice.Chang@Sun.COM if (zhp) {
121212186SJanice.Chang@Sun.COM ztype = zfs_get_type(zhp);
121312186SJanice.Chang@Sun.COM zfs_close(zhp);
121412186SJanice.Chang@Sun.COM }
121512186SJanice.Chang@Sun.COM
121612186SJanice.Chang@Sun.COM if ((ztype == ZFS_TYPE_VOLUME) ||
121712186SJanice.Chang@Sun.COM (ztype == ZFS_TYPE_FILESYSTEM)) {
121812186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_type = ztype;
121912186SJanice.Chang@Sun.COM return (B_TRUE);
122012186SJanice.Chang@Sun.COM }
122112186SJanice.Chang@Sun.COM
122212186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
122312186SJanice.Chang@Sun.COM "Invalid file system or volume.\n");
122412186SJanice.Chang@Sun.COM
122512186SJanice.Chang@Sun.COM return (B_FALSE);
122612186SJanice.Chang@Sun.COM }
122712186SJanice.Chang@Sun.COM
122812186SJanice.Chang@Sun.COM /*
122912186SJanice.Chang@Sun.COM * ndmpd_zfs_backup_getpath()
123012186SJanice.Chang@Sun.COM *
123112186SJanice.Chang@Sun.COM * Retrieve the backup path from the environment, which should
123212186SJanice.Chang@Sun.COM * be of the form "/dataset[@snap]". The leading slash is required
123312186SJanice.Chang@Sun.COM * by certain DMA's but can otherwise be ignored.
123412186SJanice.Chang@Sun.COM *
123512186SJanice.Chang@Sun.COM * (Note: "dataset" can consist of more than one component,
123612186SJanice.Chang@Sun.COM * e.g. "pool", "pool/volume", "pool/fs/fs2".)
123712186SJanice.Chang@Sun.COM *
123812186SJanice.Chang@Sun.COM * The dataset name and the snapshot name (if any) will be
123912186SJanice.Chang@Sun.COM * stored in ndmpd_zfs_args.
124012186SJanice.Chang@Sun.COM */
124112186SJanice.Chang@Sun.COM
124212186SJanice.Chang@Sun.COM static int
ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t * ndmpd_zfs_args,char * zpath,int zlen)124312186SJanice.Chang@Sun.COM ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args, char *zpath,
124412186SJanice.Chang@Sun.COM int zlen)
124512186SJanice.Chang@Sun.COM {
124612186SJanice.Chang@Sun.COM char *env_path;
124712186SJanice.Chang@Sun.COM char *at;
124812186SJanice.Chang@Sun.COM
124912186SJanice.Chang@Sun.COM env_path = get_backup_path_v3(ndmpd_zfs_params);
125012186SJanice.Chang@Sun.COM if (env_path == NULL)
125112186SJanice.Chang@Sun.COM return (-1);
125212186SJanice.Chang@Sun.COM
125312186SJanice.Chang@Sun.COM if (env_path[0] != '/') {
125412186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
125512186SJanice.Chang@Sun.COM "Invalid path: %s (leading slash required)\n", env_path);
125612186SJanice.Chang@Sun.COM return (-1);
125712186SJanice.Chang@Sun.COM }
125812186SJanice.Chang@Sun.COM
125912186SJanice.Chang@Sun.COM (void) strlcpy(zpath, &env_path[1], zlen);
126012186SJanice.Chang@Sun.COM (void) strlcpy(ndmpd_zfs_args->nz_dataset, &env_path[1],
126112186SJanice.Chang@Sun.COM ZFS_MAXNAMELEN);
126212186SJanice.Chang@Sun.COM
126312186SJanice.Chang@Sun.COM at = strchr(ndmpd_zfs_args->nz_dataset, '@');
126412186SJanice.Chang@Sun.COM if (at) {
126512186SJanice.Chang@Sun.COM *at = '\0';
126612186SJanice.Chang@Sun.COM (void) strlcpy(ndmpd_zfs_args->nz_snapname, ++at,
126712186SJanice.Chang@Sun.COM ZFS_MAXNAMELEN);
126812186SJanice.Chang@Sun.COM } else {
126912186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_snapname[0] = '\0';
127012186SJanice.Chang@Sun.COM }
127112186SJanice.Chang@Sun.COM
127212514SJanice.Chang@Sun.COM (void) trim_whitespace(ndmpd_zfs_args->nz_dataset);
127312514SJanice.Chang@Sun.COM
127412186SJanice.Chang@Sun.COM return (0);
127512186SJanice.Chang@Sun.COM }
127612186SJanice.Chang@Sun.COM
127712186SJanice.Chang@Sun.COM static int
ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t * ndmpd_zfs_args)127812186SJanice.Chang@Sun.COM ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
127912186SJanice.Chang@Sun.COM {
128012186SJanice.Chang@Sun.COM return (ndmpd_zfs_getenv(ndmpd_zfs_args));
128112186SJanice.Chang@Sun.COM }
128212186SJanice.Chang@Sun.COM
128312186SJanice.Chang@Sun.COM boolean_t
ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t * ndmpd_zfs_args)128412186SJanice.Chang@Sun.COM ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
128512186SJanice.Chang@Sun.COM {
128612186SJanice.Chang@Sun.COM if (ndmpd_zfs_restore_getenv(ndmpd_zfs_args) != 0)
128712186SJanice.Chang@Sun.COM return (B_FALSE);
128812186SJanice.Chang@Sun.COM
128912186SJanice.Chang@Sun.COM if (!ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args))
129012186SJanice.Chang@Sun.COM return (B_FALSE);
129112186SJanice.Chang@Sun.COM
129212186SJanice.Chang@Sun.COM return (B_TRUE);
129312186SJanice.Chang@Sun.COM }
129412186SJanice.Chang@Sun.COM
129512186SJanice.Chang@Sun.COM static boolean_t
ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t * ndmpd_zfs_args)129612186SJanice.Chang@Sun.COM ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
129712186SJanice.Chang@Sun.COM {
129812186SJanice.Chang@Sun.COM zfs_handle_t *zhp;
129912186SJanice.Chang@Sun.COM char *at;
130012186SJanice.Chang@Sun.COM
130112186SJanice.Chang@Sun.COM if (ndmpd_zfs_restore_getpath(ndmpd_zfs_args) != 0)
130212186SJanice.Chang@Sun.COM return (B_FALSE);
130312186SJanice.Chang@Sun.COM
130412186SJanice.Chang@Sun.COM at = strchr(ndmpd_zfs_args->nz_dataset, '@');
130512186SJanice.Chang@Sun.COM
130612186SJanice.Chang@Sun.COM if (at) {
130712186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING,
130812186SJanice.Chang@Sun.COM "%s ignored in restore path\n", at);
130912186SJanice.Chang@Sun.COM *at = '\0';
131012186SJanice.Chang@Sun.COM }
131112186SJanice.Chang@Sun.COM
131212186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_type = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM;
131312186SJanice.Chang@Sun.COM
131412186SJanice.Chang@Sun.COM zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
131512186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
131612186SJanice.Chang@Sun.COM
131712186SJanice.Chang@Sun.COM if (zhp) {
131812186SJanice.Chang@Sun.COM zfs_close(zhp);
131912186SJanice.Chang@Sun.COM
132012186SJanice.Chang@Sun.COM if (!ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
132112186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
132212186SJanice.Chang@Sun.COM "Restore dataset exists.\n"
132312186SJanice.Chang@Sun.COM "A nonexistent dataset must be specified "
132412186SJanice.Chang@Sun.COM "for 'zfs' non-incremental restore.\n");
132512186SJanice.Chang@Sun.COM return (B_FALSE);
132612186SJanice.Chang@Sun.COM }
132712186SJanice.Chang@Sun.COM }
132812186SJanice.Chang@Sun.COM
132912186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "restore path: %s\n", ndmpd_zfs_args->nz_dataset);
133012186SJanice.Chang@Sun.COM
133112186SJanice.Chang@Sun.COM return (B_TRUE);
133212186SJanice.Chang@Sun.COM }
133312186SJanice.Chang@Sun.COM
133412186SJanice.Chang@Sun.COM /*
133512186SJanice.Chang@Sun.COM * ndmpd_zfs_restore_getpath()
133612186SJanice.Chang@Sun.COM *
133712186SJanice.Chang@Sun.COM * Be sure to not include the leading slash, which is required for
133812186SJanice.Chang@Sun.COM * compatibility with backup applications (NBU) but which is not part
133912186SJanice.Chang@Sun.COM * of the ZFS syntax. (Note that this done explicitly in all paths
134012186SJanice.Chang@Sun.COM * below except those calling ndmpd_zfs_backup_getpath(), because it is
134112186SJanice.Chang@Sun.COM * already stripped in that function.)
134212186SJanice.Chang@Sun.COM *
134312186SJanice.Chang@Sun.COM * In addition, the DMA might add a trailing slash to the path.
134412186SJanice.Chang@Sun.COM * Strip all such slashes.
134512186SJanice.Chang@Sun.COM */
134612186SJanice.Chang@Sun.COM
134712186SJanice.Chang@Sun.COM static int
ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t * ndmpd_zfs_args)134812186SJanice.Chang@Sun.COM ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args)
134912186SJanice.Chang@Sun.COM {
135012186SJanice.Chang@Sun.COM int version = ndmpd_zfs_params->mp_protocol_version;
135112186SJanice.Chang@Sun.COM char zpath[ZFS_MAXNAMELEN];
135212186SJanice.Chang@Sun.COM mem_ndmp_name_v3_t *namep_v3;
135312186SJanice.Chang@Sun.COM char *dataset = ndmpd_zfs_args->nz_dataset;
135412186SJanice.Chang@Sun.COM char *nm;
135512186SJanice.Chang@Sun.COM char *p;
135612186SJanice.Chang@Sun.COM int len;
135712186SJanice.Chang@Sun.COM int err;
135812186SJanice.Chang@Sun.COM
135912186SJanice.Chang@Sun.COM dataset = ndmpd_zfs_args->nz_dataset;
136012186SJanice.Chang@Sun.COM
136112186SJanice.Chang@Sun.COM namep_v3 = (mem_ndmp_name_v3_t *)MOD_GETNAME(ndmpd_zfs_params, 0);
136212186SJanice.Chang@Sun.COM
136312186SJanice.Chang@Sun.COM if (namep_v3 == NULL) {
136412186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "Can't get Nlist[0]");
136512186SJanice.Chang@Sun.COM return (-1);
136612186SJanice.Chang@Sun.COM }
136712186SJanice.Chang@Sun.COM
136812186SJanice.Chang@Sun.COM if (namep_v3->nm3_dpath) {
136912186SJanice.Chang@Sun.COM if (namep_v3->nm3_dpath[0] != '/') {
137012186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
137112186SJanice.Chang@Sun.COM "Invalid path: %s (leading slash required)\n",
137212186SJanice.Chang@Sun.COM namep_v3->nm3_dpath);
137312186SJanice.Chang@Sun.COM return (-1);
137412186SJanice.Chang@Sun.COM }
137512186SJanice.Chang@Sun.COM
137612186SJanice.Chang@Sun.COM (void) strlcpy(dataset, &(namep_v3->nm3_dpath[1]),
137712186SJanice.Chang@Sun.COM ZFS_MAXNAMELEN);
137812186SJanice.Chang@Sun.COM
137912186SJanice.Chang@Sun.COM if (namep_v3->nm3_newnm) {
138012186SJanice.Chang@Sun.COM (void) strlcat(dataset, "/", ZFS_MAXNAMELEN);
138112186SJanice.Chang@Sun.COM (void) strlcat(dataset, namep_v3->nm3_newnm,
138212186SJanice.Chang@Sun.COM ZFS_MAXNAMELEN);
138312186SJanice.Chang@Sun.COM
138412186SJanice.Chang@Sun.COM } else {
138512186SJanice.Chang@Sun.COM if (version == NDMPV3) {
138612186SJanice.Chang@Sun.COM /*
138712186SJanice.Chang@Sun.COM * The following does not apply for V4.
138812186SJanice.Chang@Sun.COM *
138912186SJanice.Chang@Sun.COM * Find the last component of nm3_opath.
139012186SJanice.Chang@Sun.COM * nm3_opath has no trailing '/'.
139112186SJanice.Chang@Sun.COM */
139212186SJanice.Chang@Sun.COM p = strrchr(namep_v3->nm3_opath, '/');
139312186SJanice.Chang@Sun.COM nm = p? p : namep_v3->nm3_opath;
139412186SJanice.Chang@Sun.COM (void) strlcat(dataset, "/", ZFS_MAXNAMELEN);
139512186SJanice.Chang@Sun.COM (void) strlcat(dataset, nm, ZFS_MAXNAMELEN);
139612186SJanice.Chang@Sun.COM }
139712186SJanice.Chang@Sun.COM }
139812186SJanice.Chang@Sun.COM } else {
139912186SJanice.Chang@Sun.COM err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath,
140012186SJanice.Chang@Sun.COM ZFS_MAXNAMELEN);
140112186SJanice.Chang@Sun.COM if (err)
140212186SJanice.Chang@Sun.COM return (err);
140312186SJanice.Chang@Sun.COM }
140412186SJanice.Chang@Sun.COM
140512186SJanice.Chang@Sun.COM len = strlen(dataset);
140612186SJanice.Chang@Sun.COM while (dataset[len-1] == '/') {
140712186SJanice.Chang@Sun.COM dataset[len-1] = '\0';
140812186SJanice.Chang@Sun.COM len--;
140912186SJanice.Chang@Sun.COM }
141012186SJanice.Chang@Sun.COM
141112186SJanice.Chang@Sun.COM return (0);
141212186SJanice.Chang@Sun.COM }
141312186SJanice.Chang@Sun.COM
141412186SJanice.Chang@Sun.COM static int
ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t * ndmpd_zfs_args)141512186SJanice.Chang@Sun.COM ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
141612186SJanice.Chang@Sun.COM {
141712740SJanice.Chang@Sun.COM if (ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args) != 0)
141812740SJanice.Chang@Sun.COM return (-1);
141912740SJanice.Chang@Sun.COM
142012186SJanice.Chang@Sun.COM return (ndmpd_zfs_getenv(ndmpd_zfs_args));
142112186SJanice.Chang@Sun.COM }
142212186SJanice.Chang@Sun.COM
142312186SJanice.Chang@Sun.COM static int
ndmpd_zfs_getenv(ndmpd_zfs_args_t * ndmpd_zfs_args)142412186SJanice.Chang@Sun.COM ndmpd_zfs_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
142512186SJanice.Chang@Sun.COM {
142612186SJanice.Chang@Sun.COM
142712186SJanice.Chang@Sun.COM if (ndmpd_zfs_getenv_level(ndmpd_zfs_args) != 0)
142812186SJanice.Chang@Sun.COM return (-1);
142912186SJanice.Chang@Sun.COM
143012186SJanice.Chang@Sun.COM if (ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args) != 0)
143112186SJanice.Chang@Sun.COM return (-1);
143212186SJanice.Chang@Sun.COM
143312186SJanice.Chang@Sun.COM if (ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args) != 0)
143412186SJanice.Chang@Sun.COM return (-1);
143512186SJanice.Chang@Sun.COM
143612186SJanice.Chang@Sun.COM if (ndmpd_zfs_getenv_update(ndmpd_zfs_args) != 0)
143712186SJanice.Chang@Sun.COM return (-1);
143812186SJanice.Chang@Sun.COM
143912186SJanice.Chang@Sun.COM if (ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args) != 0)
144012186SJanice.Chang@Sun.COM return (-1);
144112186SJanice.Chang@Sun.COM
144212186SJanice.Chang@Sun.COM return (0);
144312186SJanice.Chang@Sun.COM }
144412186SJanice.Chang@Sun.COM
144512186SJanice.Chang@Sun.COM static int
ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t * ndmpd_zfs_args)144612186SJanice.Chang@Sun.COM ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *ndmpd_zfs_args)
144712186SJanice.Chang@Sun.COM {
144812186SJanice.Chang@Sun.COM char *envp;
144912186SJanice.Chang@Sun.COM
145012186SJanice.Chang@Sun.COM envp = MOD_GETENV(ndmpd_zfs_params, "ZFS_MODE");
145112186SJanice.Chang@Sun.COM
145212186SJanice.Chang@Sun.COM if (envp == NULL) {
145312186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE) not specified, "
145412186SJanice.Chang@Sun.COM "defaulting to recursive");
145512186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_zfs_mode = 'r';
145612186SJanice.Chang@Sun.COM return (0);
145712186SJanice.Chang@Sun.COM }
145812186SJanice.Chang@Sun.COM
145912186SJanice.Chang@Sun.COM if ((strcmp(envp, "dataset") == 0) || (strcmp(envp, "d") == 0)) {
146012186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_zfs_mode = 'd';
146112186SJanice.Chang@Sun.COM } else if ((strcmp(envp, "recursive") == 0) ||
146212186SJanice.Chang@Sun.COM (strcmp(envp, "r") == 0)) {
146312186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_zfs_mode = 'r';
146412186SJanice.Chang@Sun.COM } else if ((strcmp(envp, "package") == 0) || (strcmp(envp, "p") == 0)) {
146512186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_zfs_mode = 'p';
146612186SJanice.Chang@Sun.COM } else {
146712186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
146812186SJanice.Chang@Sun.COM "Invalid ZFS_MODE value \"%s\".\n", envp);
146912186SJanice.Chang@Sun.COM return (-1);
147012186SJanice.Chang@Sun.COM }
147112186SJanice.Chang@Sun.COM
147212186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE): \"%c\"",
147312186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_zfs_mode);
147412186SJanice.Chang@Sun.COM
147512186SJanice.Chang@Sun.COM return (0);
147612186SJanice.Chang@Sun.COM }
147712186SJanice.Chang@Sun.COM
147812514SJanice.Chang@Sun.COM /*
147912514SJanice.Chang@Sun.COM * ndmpd_zfs_getenv_zfs_force()
148012514SJanice.Chang@Sun.COM *
148112514SJanice.Chang@Sun.COM * If SMF property zfs-force-override is set to "yes" or "no", this
148212514SJanice.Chang@Sun.COM * value will override any value of NDMP environment variable ZFS_FORCE
148312514SJanice.Chang@Sun.COM * as set by the DMA admin (or override the default of 'n', if ZFS_FORCE
148412514SJanice.Chang@Sun.COM * is not set). By default, zfs-force-override is "off", which means it
148512514SJanice.Chang@Sun.COM * will not override ZFS_FORCE.
148612514SJanice.Chang@Sun.COM */
148712514SJanice.Chang@Sun.COM
148812186SJanice.Chang@Sun.COM static int
ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t * ndmpd_zfs_args)148912186SJanice.Chang@Sun.COM ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *ndmpd_zfs_args)
149012186SJanice.Chang@Sun.COM {
149112186SJanice.Chang@Sun.COM char *envp_force;
149212514SJanice.Chang@Sun.COM char *override;
149312514SJanice.Chang@Sun.COM
149412514SJanice.Chang@Sun.COM override = ndmpd_get_prop(NDMP_ZFS_FORCE_OVERRIDE);
149512514SJanice.Chang@Sun.COM
149612514SJanice.Chang@Sun.COM if (strcasecmp(override, "yes") == 0) {
149712514SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_zfs_force = B_TRUE;
149812514SJanice.Chang@Sun.COM NDMP_LOG(LOG_NOTICE,
149912514SJanice.Chang@Sun.COM "SMF property zfs-force-override set to 'yes', "
150012514SJanice.Chang@Sun.COM "overriding ZFS_FORCE");
150112514SJanice.Chang@Sun.COM return (0);
150212514SJanice.Chang@Sun.COM }
150312514SJanice.Chang@Sun.COM
150412514SJanice.Chang@Sun.COM if (strcasecmp(override, "no") == 0) {
150512514SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_zfs_force = B_FALSE;
150612514SJanice.Chang@Sun.COM NDMP_LOG(LOG_NOTICE,
150712514SJanice.Chang@Sun.COM "SMF property zfs-force-override set to 'no', "
150812514SJanice.Chang@Sun.COM "overriding ZFS_FORCE");
150912514SJanice.Chang@Sun.COM return (0);
151012514SJanice.Chang@Sun.COM }
151112514SJanice.Chang@Sun.COM
151212514SJanice.Chang@Sun.COM if (strcasecmp(override, "off") != 0) {
151312514SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
151412514SJanice.Chang@Sun.COM "SMF property zfs-force-override set to invalid value of "
151512514SJanice.Chang@Sun.COM "'%s'; treating it as 'off'.", override);
151612514SJanice.Chang@Sun.COM }
151712186SJanice.Chang@Sun.COM
151812186SJanice.Chang@Sun.COM envp_force = MOD_GETENV(ndmpd_zfs_params, "ZFS_FORCE");
151912186SJanice.Chang@Sun.COM
152012186SJanice.Chang@Sun.COM if (envp_force == NULL) {
152112186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG,
152212186SJanice.Chang@Sun.COM "env(ZFS_FORCE) not specified, defaulting to FALSE");
152312186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_zfs_force = B_FALSE;
152412186SJanice.Chang@Sun.COM return (0);
152512186SJanice.Chang@Sun.COM }
152612186SJanice.Chang@Sun.COM
152712186SJanice.Chang@Sun.COM /*
152812186SJanice.Chang@Sun.COM * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
152912186SJanice.Chang@Sun.COM */
153012186SJanice.Chang@Sun.COM
153112186SJanice.Chang@Sun.COM if (strchr("tTyY", *envp_force))
153212186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_zfs_force = B_TRUE;
153312186SJanice.Chang@Sun.COM
153412186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "env(ZFS_FORCE): \"%s\"", envp_force);
153512186SJanice.Chang@Sun.COM
153612186SJanice.Chang@Sun.COM return (0);
153712186SJanice.Chang@Sun.COM }
153812186SJanice.Chang@Sun.COM
153912186SJanice.Chang@Sun.COM static int
ndmpd_zfs_getenv_level(ndmpd_zfs_args_t * ndmpd_zfs_args)154012186SJanice.Chang@Sun.COM ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *ndmpd_zfs_args)
154112186SJanice.Chang@Sun.COM {
154212186SJanice.Chang@Sun.COM char *envp;
154312186SJanice.Chang@Sun.COM
154412186SJanice.Chang@Sun.COM envp = MOD_GETENV(ndmpd_zfs_params, "LEVEL");
154512186SJanice.Chang@Sun.COM
154612186SJanice.Chang@Sun.COM if (envp == NULL) {
154712186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "env(LEVEL) not specified, "
154812186SJanice.Chang@Sun.COM "defaulting to 0");
154912186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_level = 0;
155012186SJanice.Chang@Sun.COM return (0);
155112186SJanice.Chang@Sun.COM }
155212186SJanice.Chang@Sun.COM
155312186SJanice.Chang@Sun.COM if (envp[1] != '\0') {
155412186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
155512186SJanice.Chang@Sun.COM "Invalid backup level \"%s\".\n", envp);
155612186SJanice.Chang@Sun.COM return (-1);
155712186SJanice.Chang@Sun.COM }
155812186SJanice.Chang@Sun.COM
155912186SJanice.Chang@Sun.COM if (!isdigit(*envp)) {
156012186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
156112186SJanice.Chang@Sun.COM "Invalid backup level \"%s\".\n", envp);
156212186SJanice.Chang@Sun.COM return (-1);
156312186SJanice.Chang@Sun.COM }
156412186SJanice.Chang@Sun.COM
156512186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_level = atoi(envp);
156612186SJanice.Chang@Sun.COM
156712186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "env(LEVEL): \"%d\"",
156812186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_level);
156912186SJanice.Chang@Sun.COM
157012186SJanice.Chang@Sun.COM return (0);
157112186SJanice.Chang@Sun.COM }
157212186SJanice.Chang@Sun.COM
157312186SJanice.Chang@Sun.COM static int
ndmpd_zfs_getenv_update(ndmpd_zfs_args_t * ndmpd_zfs_args)157412186SJanice.Chang@Sun.COM ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *ndmpd_zfs_args)
157512186SJanice.Chang@Sun.COM {
157612186SJanice.Chang@Sun.COM char *envp_update;
157712186SJanice.Chang@Sun.COM
157812186SJanice.Chang@Sun.COM envp_update = MOD_GETENV(ndmpd_zfs_params, "UPDATE");
157912186SJanice.Chang@Sun.COM
158012186SJanice.Chang@Sun.COM if (envp_update == NULL) {
158112186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG,
158212186SJanice.Chang@Sun.COM "env(UPDATE) not specified, defaulting to TRUE");
158312186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_update = B_TRUE;
158412186SJanice.Chang@Sun.COM return (0);
158512186SJanice.Chang@Sun.COM }
158612186SJanice.Chang@Sun.COM
158712186SJanice.Chang@Sun.COM /*
158812186SJanice.Chang@Sun.COM * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
158912186SJanice.Chang@Sun.COM */
159012186SJanice.Chang@Sun.COM
159112186SJanice.Chang@Sun.COM if (strchr("tTyY", *envp_update))
159212186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_update = B_TRUE;
159312186SJanice.Chang@Sun.COM
159412186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp_update);
159512186SJanice.Chang@Sun.COM
159612186SJanice.Chang@Sun.COM return (0);
159712186SJanice.Chang@Sun.COM }
159812186SJanice.Chang@Sun.COM
159912186SJanice.Chang@Sun.COM static int
ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t * ndmpd_zfs_args)160012186SJanice.Chang@Sun.COM ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *ndmpd_zfs_args)
160112186SJanice.Chang@Sun.COM {
160212186SJanice.Chang@Sun.COM char *envp;
160312186SJanice.Chang@Sun.COM
160412186SJanice.Chang@Sun.COM envp = MOD_GETENV(ndmpd_zfs_params, "DMP_NAME");
160512186SJanice.Chang@Sun.COM
160612186SJanice.Chang@Sun.COM if (envp == NULL) {
160712186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG,
160812186SJanice.Chang@Sun.COM "env(DMP_NAME) not specified, defaulting to 'level'");
160912186SJanice.Chang@Sun.COM (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, "level",
161012186SJanice.Chang@Sun.COM NDMPD_ZFS_DMP_NAME_MAX);
161112186SJanice.Chang@Sun.COM return (0);
161212186SJanice.Chang@Sun.COM }
161312186SJanice.Chang@Sun.COM
161412186SJanice.Chang@Sun.COM if (!ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args, envp))
161512186SJanice.Chang@Sun.COM return (-1);
161612186SJanice.Chang@Sun.COM
161712186SJanice.Chang@Sun.COM (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, envp,
161812186SJanice.Chang@Sun.COM NDMPD_ZFS_DMP_NAME_MAX);
161912186SJanice.Chang@Sun.COM
162012186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "env(DMP_NAME): \"%s\"", envp);
162112186SJanice.Chang@Sun.COM
162212186SJanice.Chang@Sun.COM return (0);
162312186SJanice.Chang@Sun.COM }
162412186SJanice.Chang@Sun.COM
162512740SJanice.Chang@Sun.COM static int
ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t * ndmpd_zfs_args)162612740SJanice.Chang@Sun.COM ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args)
162712740SJanice.Chang@Sun.COM {
162812740SJanice.Chang@Sun.COM char *zfs_backup_size;
162912740SJanice.Chang@Sun.COM
163012740SJanice.Chang@Sun.COM zfs_backup_size = MOD_GETENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE");
163112740SJanice.Chang@Sun.COM
163212740SJanice.Chang@Sun.COM if (zfs_backup_size == NULL) {
163312740SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "ZFS_BACKUP_SIZE env is NULL");
163412740SJanice.Chang@Sun.COM return (-1);
163512740SJanice.Chang@Sun.COM }
163612740SJanice.Chang@Sun.COM
163712740SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "ZFS_BACKUP_SIZE: %s\n", zfs_backup_size);
163812740SJanice.Chang@Sun.COM
163912740SJanice.Chang@Sun.COM (void) sscanf(zfs_backup_size, "%llu",
164012740SJanice.Chang@Sun.COM &ndmpd_zfs_args->nz_zfs_backup_size);
164112740SJanice.Chang@Sun.COM
164212740SJanice.Chang@Sun.COM return (0);
164312740SJanice.Chang@Sun.COM }
164412740SJanice.Chang@Sun.COM
164512186SJanice.Chang@Sun.COM /*
164612186SJanice.Chang@Sun.COM * ndmpd_zfs_dmp_name_valid()
164712186SJanice.Chang@Sun.COM *
164812186SJanice.Chang@Sun.COM * This function verifies that the dmp_name is valid.
164912186SJanice.Chang@Sun.COM *
165012186SJanice.Chang@Sun.COM * The dmp_name is restricted to alphanumeric characters plus
165112186SJanice.Chang@Sun.COM * the underscore and hyphen, and must be 31 characters or less.
165212186SJanice.Chang@Sun.COM * This is due to its use in the NDMPD_ZFS_PROP_INCR property
165312186SJanice.Chang@Sun.COM * and in the ZFS snapshot name (if an ndmpd-generated snapshot
165412186SJanice.Chang@Sun.COM * is required).
165512186SJanice.Chang@Sun.COM */
165612186SJanice.Chang@Sun.COM
165712186SJanice.Chang@Sun.COM static boolean_t
ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t * ndmpd_zfs_args,char * dmp_name)165812186SJanice.Chang@Sun.COM ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *ndmpd_zfs_args, char *dmp_name)
165912186SJanice.Chang@Sun.COM {
166012186SJanice.Chang@Sun.COM char *c;
166112186SJanice.Chang@Sun.COM
166212186SJanice.Chang@Sun.COM if (strlen(dmp_name) >= NDMPD_ZFS_DMP_NAME_MAX) {
166312186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
166412186SJanice.Chang@Sun.COM "DMP_NAME %s is longer than %d\n",
166512186SJanice.Chang@Sun.COM dmp_name, NDMPD_ZFS_DMP_NAME_MAX-1);
166612186SJanice.Chang@Sun.COM return (B_FALSE);
166712186SJanice.Chang@Sun.COM }
166812186SJanice.Chang@Sun.COM
166912186SJanice.Chang@Sun.COM for (c = dmp_name; *c != '\0'; c++) {
167012186SJanice.Chang@Sun.COM if (!isalpha(*c) && !isdigit(*c) &&
167112186SJanice.Chang@Sun.COM (*c != '_') && (*c != '-')) {
167212186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
167312186SJanice.Chang@Sun.COM "DMP_NAME %s contains illegal character %c\n",
167412186SJanice.Chang@Sun.COM dmp_name, *c);
167512186SJanice.Chang@Sun.COM return (B_FALSE);
167612186SJanice.Chang@Sun.COM }
167712186SJanice.Chang@Sun.COM }
167812186SJanice.Chang@Sun.COM
167912186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "DMP_NAME is valid: %s\n", dmp_name);
168012186SJanice.Chang@Sun.COM return (B_TRUE);
168112186SJanice.Chang@Sun.COM }
168212186SJanice.Chang@Sun.COM
168312186SJanice.Chang@Sun.COM /*
168412186SJanice.Chang@Sun.COM * ndmpd_zfs_is_incremental()
168512186SJanice.Chang@Sun.COM *
168612186SJanice.Chang@Sun.COM * This can only be called after ndmpd_zfs_getenv_level()
168712186SJanice.Chang@Sun.COM * has been called.
168812186SJanice.Chang@Sun.COM */
168912186SJanice.Chang@Sun.COM
169012186SJanice.Chang@Sun.COM static boolean_t
ndmpd_zfs_is_incremental(ndmpd_zfs_args_t * ndmpd_zfs_args)169112186SJanice.Chang@Sun.COM ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *ndmpd_zfs_args)
169212186SJanice.Chang@Sun.COM {
169312186SJanice.Chang@Sun.COM return (ndmpd_zfs_args->nz_level != 0);
169412186SJanice.Chang@Sun.COM }
169512186SJanice.Chang@Sun.COM
169612186SJanice.Chang@Sun.COM /*
169712186SJanice.Chang@Sun.COM * ndmpd_zfs_snapshot_prepare()
169812186SJanice.Chang@Sun.COM *
169912186SJanice.Chang@Sun.COM * If no snapshot was supplied by the user, create a snapshot
170012186SJanice.Chang@Sun.COM * for use by ndmpd.
170112186SJanice.Chang@Sun.COM */
170212186SJanice.Chang@Sun.COM
170312186SJanice.Chang@Sun.COM static int
ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t * ndmpd_zfs_args)170412186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *ndmpd_zfs_args)
170512186SJanice.Chang@Sun.COM {
170612186SJanice.Chang@Sun.COM ndmpd_session_t *session = (ndmpd_session_t *)
170712186SJanice.Chang@Sun.COM (ndmpd_zfs_params->mp_daemon_cookie);
170812186SJanice.Chang@Sun.COM boolean_t recursive = B_FALSE;
170912186SJanice.Chang@Sun.COM int zfs_err = 0;
171012186SJanice.Chang@Sun.COM
171112186SJanice.Chang@Sun.COM if (session->ns_data.dd_abort) {
171212186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
171312186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset);
171412186SJanice.Chang@Sun.COM return (-1);
171512186SJanice.Chang@Sun.COM }
171612186SJanice.Chang@Sun.COM
171712186SJanice.Chang@Sun.COM if (ndmpd_zfs_args->nz_snapname[0] == '\0') {
171812186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_ndmpd_snap = B_TRUE;
171912186SJanice.Chang@Sun.COM
172012186SJanice.Chang@Sun.COM if (ndmpd_zfs_snapshot_create(ndmpd_zfs_args) != 0) {
172112186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_snapname[0] = '\0';
172212186SJanice.Chang@Sun.COM
172312186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
172412186SJanice.Chang@Sun.COM "Error creating snapshot for %s\n",
172512186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset);
172612186SJanice.Chang@Sun.COM
172712186SJanice.Chang@Sun.COM return (-1);
172812186SJanice.Chang@Sun.COM }
172912186SJanice.Chang@Sun.COM }
173012186SJanice.Chang@Sun.COM
173112186SJanice.Chang@Sun.COM if (ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args)) {
173212186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG,
173312186SJanice.Chang@Sun.COM "ndmpd_zfs_snapshot_prop_add error\n");
173412186SJanice.Chang@Sun.COM
173512186SJanice.Chang@Sun.COM if (ndmpd_zfs_args->nz_ndmpd_snap) {
173612186SJanice.Chang@Sun.COM
173712186SJanice.Chang@Sun.COM if (ndmpd_zfs_args->nz_zfs_mode != 'd')
173812186SJanice.Chang@Sun.COM recursive = B_TRUE;
173912186SJanice.Chang@Sun.COM
174012186SJanice.Chang@Sun.COM (void) snapshot_destroy(ndmpd_zfs_args->nz_dataset,
174112904SReza.Sabdar@Sun.COM ndmpd_zfs_args->nz_snapname, recursive, B_FALSE,
174212904SReza.Sabdar@Sun.COM &zfs_err);
174312186SJanice.Chang@Sun.COM }
174412186SJanice.Chang@Sun.COM
174512186SJanice.Chang@Sun.COM return (-1);
174612186SJanice.Chang@Sun.COM }
174712186SJanice.Chang@Sun.COM
174812186SJanice.Chang@Sun.COM return (0);
174912186SJanice.Chang@Sun.COM }
175012186SJanice.Chang@Sun.COM
175112186SJanice.Chang@Sun.COM /*
175212186SJanice.Chang@Sun.COM * ndmpd_zfs_snapshot_cleanup()
175312186SJanice.Chang@Sun.COM *
175412186SJanice.Chang@Sun.COM * If UPDATE = y, find the old snapshot (if any) corresponding to
175512514SJanice.Chang@Sun.COM * {LEVEL, DMP_NAME, ZFS_MODE}. If it was ndmpd-generated,
175612186SJanice.Chang@Sun.COM * remove the snapshot. Otherwise, update its NDMPD_ZFS_PROP_INCR
175712186SJanice.Chang@Sun.COM * property to remove {L, D, Z}.
175812186SJanice.Chang@Sun.COM *
175912186SJanice.Chang@Sun.COM * If UPDATE = n, if an ndmpd-generated snapshot was used for backup,
176012186SJanice.Chang@Sun.COM * remove the snapshot. Otherwise, update its NDMPD_ZFS_PROP_INCR
176112186SJanice.Chang@Sun.COM * property to remove {L, D, Z}.
176212186SJanice.Chang@Sun.COM */
176312186SJanice.Chang@Sun.COM
176412186SJanice.Chang@Sun.COM static int
ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t * ndmpd_zfs_args,int err)176512186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *ndmpd_zfs_args, int err)
176612186SJanice.Chang@Sun.COM {
176712186SJanice.Chang@Sun.COM ndmpd_session_t *session = (ndmpd_session_t *)
176812186SJanice.Chang@Sun.COM (ndmpd_zfs_params->mp_daemon_cookie);
176912186SJanice.Chang@Sun.COM ndmpd_zfs_snapfind_t snapdata;
177012186SJanice.Chang@Sun.COM boolean_t ndmpd_generated = B_FALSE;
177112186SJanice.Chang@Sun.COM
177212186SJanice.Chang@Sun.COM bzero(&snapdata, sizeof (ndmpd_zfs_snapfind_t));
177312186SJanice.Chang@Sun.COM
177412186SJanice.Chang@Sun.COM (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
177512186SJanice.Chang@Sun.COM snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_FALSE);
177612186SJanice.Chang@Sun.COM
177712186SJanice.Chang@Sun.COM if (ndmpd_zfs_args->nz_update && !session->ns_data.dd_abort && !err) {
177812186SJanice.Chang@Sun.COM /*
177912186SJanice.Chang@Sun.COM * Find the existing snapshot, if any, to "unuse."
178012186SJanice.Chang@Sun.COM * Indicate that the current snapshot used for backup
178112186SJanice.Chang@Sun.COM * should be skipped in the search. (The search is
178212186SJanice.Chang@Sun.COM * sorted by creation time but this cannot be relied
178312186SJanice.Chang@Sun.COM * upon for user-supplied snapshots.)
178412186SJanice.Chang@Sun.COM */
178512186SJanice.Chang@Sun.COM
178612186SJanice.Chang@Sun.COM (void) snprintf(snapdata.nzs_snapskip, ZFS_MAXNAMELEN, "%s",
178712186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_snapname);
178812186SJanice.Chang@Sun.COM
178912186SJanice.Chang@Sun.COM if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata)) {
179012186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_find error\n");
179112186SJanice.Chang@Sun.COM goto _remove_tmp_snap;
179212186SJanice.Chang@Sun.COM }
179312186SJanice.Chang@Sun.COM
179412186SJanice.Chang@Sun.COM if (snapdata.nzs_snapname[0] != '\0') { /* snapshot found */
179512186SJanice.Chang@Sun.COM ndmpd_generated = ndmpd_zfs_snapshot_ndmpd_generated
179612186SJanice.Chang@Sun.COM (snapdata.nzs_snapprop);
179712186SJanice.Chang@Sun.COM
179812186SJanice.Chang@Sun.COM if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args,
179912186SJanice.Chang@Sun.COM ndmpd_generated, &snapdata) != 0) {
180012186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG,
180112186SJanice.Chang@Sun.COM "ndmpd_zfs_snapshot_unuse error\n");
180212186SJanice.Chang@Sun.COM goto _remove_tmp_snap;
180312186SJanice.Chang@Sun.COM }
180412186SJanice.Chang@Sun.COM }
180512186SJanice.Chang@Sun.COM
180612186SJanice.Chang@Sun.COM if (session->ns_data.dd_abort)
180712186SJanice.Chang@Sun.COM goto _remove_tmp_snap;
180812186SJanice.Chang@Sun.COM
180912186SJanice.Chang@Sun.COM return (0);
181012186SJanice.Chang@Sun.COM }
181112186SJanice.Chang@Sun.COM
181212186SJanice.Chang@Sun.COM _remove_tmp_snap:
181312186SJanice.Chang@Sun.COM
181412186SJanice.Chang@Sun.COM (void) snprintf(snapdata.nzs_snapname, ZFS_MAXNAMELEN, "%s",
181512186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_snapname);
181612186SJanice.Chang@Sun.COM
181712186SJanice.Chang@Sun.COM (void) strlcpy(snapdata.nzs_snapprop, ndmpd_zfs_args->nz_snapprop,
181812186SJanice.Chang@Sun.COM ZFS_MAXPROPLEN);
181912186SJanice.Chang@Sun.COM
182012186SJanice.Chang@Sun.COM snapdata.nzs_snapskip[0] = '\0';
182112186SJanice.Chang@Sun.COM
182212186SJanice.Chang@Sun.COM if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args,
182312186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_ndmpd_snap, &snapdata) != 0) {
182412186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_unuse error\n");
182512186SJanice.Chang@Sun.COM return (-1);
182612186SJanice.Chang@Sun.COM }
182712186SJanice.Chang@Sun.COM
182812186SJanice.Chang@Sun.COM if (!ndmpd_zfs_args->nz_update)
182912186SJanice.Chang@Sun.COM return (0);
183012186SJanice.Chang@Sun.COM
183112186SJanice.Chang@Sun.COM return (-1);
183212186SJanice.Chang@Sun.COM }
183312186SJanice.Chang@Sun.COM
183412186SJanice.Chang@Sun.COM static int
ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t * ndmpd_zfs_args)183512186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *ndmpd_zfs_args)
183612186SJanice.Chang@Sun.COM {
183712186SJanice.Chang@Sun.COM boolean_t recursive = B_FALSE;
183812186SJanice.Chang@Sun.COM
183912186SJanice.Chang@Sun.COM if (ndmpd_zfs_snapname_create(ndmpd_zfs_args,
184012186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_snapname, ZFS_MAXNAMELEN -1) < 0) {
184112186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "Error (%d) creating snapshot name for %s",
184212186SJanice.Chang@Sun.COM errno, ndmpd_zfs_args->nz_dataset);
184312186SJanice.Chang@Sun.COM return (-1);
184412186SJanice.Chang@Sun.COM }
184512186SJanice.Chang@Sun.COM
184612186SJanice.Chang@Sun.COM if (ndmpd_zfs_args->nz_zfs_mode != 'd')
184712186SJanice.Chang@Sun.COM recursive = B_TRUE;
184812186SJanice.Chang@Sun.COM
184912186SJanice.Chang@Sun.COM if (snapshot_create(ndmpd_zfs_args->nz_dataset,
185012904SReza.Sabdar@Sun.COM ndmpd_zfs_args->nz_snapname, recursive, B_FALSE) != 0) {
185112186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "could not create snapshot %s@%s",
185212186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname);
185312186SJanice.Chang@Sun.COM return (-1);
185412186SJanice.Chang@Sun.COM }
185512186SJanice.Chang@Sun.COM
185612186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "created snapshot %s@%s",
185712186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname);
185812186SJanice.Chang@Sun.COM
185912186SJanice.Chang@Sun.COM return (0);
186012186SJanice.Chang@Sun.COM }
186112186SJanice.Chang@Sun.COM
186212186SJanice.Chang@Sun.COM /*
186312186SJanice.Chang@Sun.COM * ndmpd_zfs_snapshot_unuse()
186412186SJanice.Chang@Sun.COM *
186512186SJanice.Chang@Sun.COM * Given a pre-existing snapshot of the given {L, D, Z}:
186612186SJanice.Chang@Sun.COM * If snapshot is ndmpd-generated, remove snapshot.
186712186SJanice.Chang@Sun.COM * If not ndmpd-generated, or if the ndmpd-generated snapshot
186812186SJanice.Chang@Sun.COM * cannot be destroyed, remove the {L, D, Z} substring from the
186912186SJanice.Chang@Sun.COM * snapshot's NDMPD_ZFS_PROP_INCR property.
187012186SJanice.Chang@Sun.COM *
187112186SJanice.Chang@Sun.COM * In the event of a failure, it may be that two snapshots will
187212186SJanice.Chang@Sun.COM * have the {L, D, Z} property set on them. This is not desirable,
187312186SJanice.Chang@Sun.COM * so return an error and log the failure.
187412186SJanice.Chang@Sun.COM */
187512186SJanice.Chang@Sun.COM
187612186SJanice.Chang@Sun.COM static int
ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t * ndmpd_zfs_args,boolean_t ndmpd_generated,ndmpd_zfs_snapfind_t * snapdata_p)187712186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *ndmpd_zfs_args,
187812186SJanice.Chang@Sun.COM boolean_t ndmpd_generated, ndmpd_zfs_snapfind_t *snapdata_p)
187912186SJanice.Chang@Sun.COM {
188012186SJanice.Chang@Sun.COM boolean_t recursive = B_FALSE;
188112186SJanice.Chang@Sun.COM int zfs_err = 0;
188212186SJanice.Chang@Sun.COM int err = 0;
188312186SJanice.Chang@Sun.COM
188412186SJanice.Chang@Sun.COM if (ndmpd_generated) {
188512186SJanice.Chang@Sun.COM if (ndmpd_zfs_args->nz_zfs_mode != 'd')
188612186SJanice.Chang@Sun.COM recursive = B_TRUE;
188712186SJanice.Chang@Sun.COM
188812186SJanice.Chang@Sun.COM err = snapshot_destroy(ndmpd_zfs_args->nz_dataset,
188912904SReza.Sabdar@Sun.COM snapdata_p->nzs_snapname, recursive, B_FALSE, &zfs_err);
189012186SJanice.Chang@Sun.COM
189112186SJanice.Chang@Sun.COM if (err) {
189212186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "snapshot_destroy: %s@%s;"
189312186SJanice.Chang@Sun.COM " err: %d; zfs_err: %d",
189412186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset,
189512186SJanice.Chang@Sun.COM snapdata_p->nzs_snapname, err, zfs_err);
189612186SJanice.Chang@Sun.COM return (-1);
189712186SJanice.Chang@Sun.COM }
189812186SJanice.Chang@Sun.COM }
189912186SJanice.Chang@Sun.COM
190012186SJanice.Chang@Sun.COM if (!ndmpd_generated || zfs_err) {
190112186SJanice.Chang@Sun.COM if (ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args, snapdata_p))
190212186SJanice.Chang@Sun.COM return (-1);
190312186SJanice.Chang@Sun.COM }
190412186SJanice.Chang@Sun.COM
190512186SJanice.Chang@Sun.COM return (0);
190612186SJanice.Chang@Sun.COM }
190712186SJanice.Chang@Sun.COM
190812186SJanice.Chang@Sun.COM static boolean_t
ndmpd_zfs_snapshot_ndmpd_generated(char * snapprop)190912186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_ndmpd_generated(char *snapprop)
191012186SJanice.Chang@Sun.COM {
191112186SJanice.Chang@Sun.COM char origin;
191212186SJanice.Chang@Sun.COM
191312186SJanice.Chang@Sun.COM (void) sscanf(snapprop, "%*u.%*u.%c%*s", &origin);
191412186SJanice.Chang@Sun.COM
191512186SJanice.Chang@Sun.COM return (origin == 'n');
191612186SJanice.Chang@Sun.COM }
191712186SJanice.Chang@Sun.COM
191812186SJanice.Chang@Sun.COM /*
191912186SJanice.Chang@Sun.COM * ndmpd_zfs_snapshot_find()
192012186SJanice.Chang@Sun.COM *
192112186SJanice.Chang@Sun.COM * Find a snapshot with a particular value for
192212186SJanice.Chang@Sun.COM * the NDMPD_ZFS_PROP_INCR property.
192312186SJanice.Chang@Sun.COM */
192412186SJanice.Chang@Sun.COM
192512186SJanice.Chang@Sun.COM static int
ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t * ndmpd_zfs_args,ndmpd_zfs_snapfind_t * snapdata)192612186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *ndmpd_zfs_args,
192712186SJanice.Chang@Sun.COM ndmpd_zfs_snapfind_t *snapdata)
192812186SJanice.Chang@Sun.COM {
192912186SJanice.Chang@Sun.COM zfs_handle_t *zhp;
193012186SJanice.Chang@Sun.COM int err;
193112186SJanice.Chang@Sun.COM
193212186SJanice.Chang@Sun.COM zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
193312186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_type);
193412186SJanice.Chang@Sun.COM
193512186SJanice.Chang@Sun.COM if (!zhp) {
193612186SJanice.Chang@Sun.COM NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
193712186SJanice.Chang@Sun.COM return (-1);
193812186SJanice.Chang@Sun.COM }
193912186SJanice.Chang@Sun.COM
194012186SJanice.Chang@Sun.COM err = zfs_iter_snapshots_sorted(zhp, ndmpd_zfs_snapshot_prop_find,
194112186SJanice.Chang@Sun.COM snapdata);
194212186SJanice.Chang@Sun.COM
194312186SJanice.Chang@Sun.COM zfs_close(zhp);
194412186SJanice.Chang@Sun.COM
194512186SJanice.Chang@Sun.COM if (err) {
194612186SJanice.Chang@Sun.COM NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_iter_snapshots: %d",
194712186SJanice.Chang@Sun.COM err);
194812186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
194912186SJanice.Chang@Sun.COM "Error iterating snapshots\n");
195012186SJanice.Chang@Sun.COM return (-1);
195112186SJanice.Chang@Sun.COM }
195212186SJanice.Chang@Sun.COM
195312186SJanice.Chang@Sun.COM return (0);
195412186SJanice.Chang@Sun.COM }
195512186SJanice.Chang@Sun.COM
195612186SJanice.Chang@Sun.COM /*
195712186SJanice.Chang@Sun.COM * ndmpd_zfs_snapshot_prop_find()
195812186SJanice.Chang@Sun.COM *
195912186SJanice.Chang@Sun.COM * Find a snapshot with a particular value for
196012186SJanice.Chang@Sun.COM * NDMPD_ZFS_PROP_INCR. Fill in data for the first one
196112186SJanice.Chang@Sun.COM * found (sorted by creation time). However, skip the
196212186SJanice.Chang@Sun.COM * the snapshot indicated in nzs_snapskip, if any.
196312186SJanice.Chang@Sun.COM */
196412186SJanice.Chang@Sun.COM
196512186SJanice.Chang@Sun.COM static int
ndmpd_zfs_snapshot_prop_find(zfs_handle_t * zhp,void * arg)196612186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_prop_find(zfs_handle_t *zhp, void *arg)
196712186SJanice.Chang@Sun.COM {
196812186SJanice.Chang@Sun.COM ndmpd_zfs_snapfind_t *snapdata_p = (ndmpd_zfs_snapfind_t *)arg;
196912186SJanice.Chang@Sun.COM char propstr[ZFS_MAXPROPLEN];
197012186SJanice.Chang@Sun.COM char findprop_plus_slash[ZFS_MAXPROPLEN];
197112186SJanice.Chang@Sun.COM char *justsnap;
197212186SJanice.Chang@Sun.COM int err = 0;
197312186SJanice.Chang@Sun.COM
197412186SJanice.Chang@Sun.COM if (snapdata_p->nzs_snapname[0] != '\0') {
197512186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "no need to get prop for snapshot %s",
197612186SJanice.Chang@Sun.COM (char *)zfs_get_name(zhp));
197712186SJanice.Chang@Sun.COM goto _done;
197812186SJanice.Chang@Sun.COM }
197912186SJanice.Chang@Sun.COM
198012186SJanice.Chang@Sun.COM err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
198112186SJanice.Chang@Sun.COM
198212186SJanice.Chang@Sun.COM if (err) {
198312186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_prop_get failed");
198412186SJanice.Chang@Sun.COM goto _done;
198512186SJanice.Chang@Sun.COM }
198612186SJanice.Chang@Sun.COM
198712186SJanice.Chang@Sun.COM if (propstr[0] == '\0') {
198812186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "snapshot %s: propr not set",
198912186SJanice.Chang@Sun.COM (char *)zfs_get_name(zhp));
199012186SJanice.Chang@Sun.COM goto _done;
199112186SJanice.Chang@Sun.COM }
199212186SJanice.Chang@Sun.COM
199312186SJanice.Chang@Sun.COM (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
199412186SJanice.Chang@Sun.COM snapdata_p->nzs_findprop);
199512186SJanice.Chang@Sun.COM
199612186SJanice.Chang@Sun.COM if (!strstr((const char *)propstr,
199712186SJanice.Chang@Sun.COM (const char *)findprop_plus_slash)) {
199812186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s not found)",
199912186SJanice.Chang@Sun.COM (char *)zfs_get_name(zhp), propstr,
200012186SJanice.Chang@Sun.COM snapdata_p->nzs_findprop);
200112186SJanice.Chang@Sun.COM goto _done;
200212186SJanice.Chang@Sun.COM }
200312186SJanice.Chang@Sun.COM
200412186SJanice.Chang@Sun.COM if (!ndmpd_zfs_prop_version_check(propstr,
200512186SJanice.Chang@Sun.COM &snapdata_p->nzs_prop_major, &snapdata_p->nzs_prop_minor)) {
200612186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s found)",
200712186SJanice.Chang@Sun.COM (char *)zfs_get_name(zhp), propstr,
200812186SJanice.Chang@Sun.COM snapdata_p->nzs_findprop);
200912186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "did not pass version check");
201012186SJanice.Chang@Sun.COM goto _done;
201112186SJanice.Chang@Sun.COM }
201212186SJanice.Chang@Sun.COM
201312186SJanice.Chang@Sun.COM justsnap = strchr(zfs_get_name(zhp), '@') + 1;
201412186SJanice.Chang@Sun.COM
201512186SJanice.Chang@Sun.COM if (strcmp(justsnap, snapdata_p->nzs_snapskip) != 0) {
201612186SJanice.Chang@Sun.COM (void) strlcpy(snapdata_p->nzs_snapname, justsnap,
201712186SJanice.Chang@Sun.COM ZFS_MAXNAMELEN);
201812186SJanice.Chang@Sun.COM
201912186SJanice.Chang@Sun.COM (void) strlcpy(snapdata_p->nzs_snapprop, propstr,
202012186SJanice.Chang@Sun.COM ZFS_MAXPROPLEN);
202112186SJanice.Chang@Sun.COM
202212186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "found match: %s [%s]\n",
202312186SJanice.Chang@Sun.COM snapdata_p->nzs_snapname, snapdata_p->nzs_snapprop);
202412186SJanice.Chang@Sun.COM }
202512186SJanice.Chang@Sun.COM
202612186SJanice.Chang@Sun.COM _done:
202712186SJanice.Chang@Sun.COM zfs_close(zhp);
202812186SJanice.Chang@Sun.COM return (err);
202912186SJanice.Chang@Sun.COM }
203012186SJanice.Chang@Sun.COM
203112186SJanice.Chang@Sun.COM /*
203212186SJanice.Chang@Sun.COM * ndmpd_zfs_snapshot_prop_get()
203312186SJanice.Chang@Sun.COM *
203412186SJanice.Chang@Sun.COM * Retrieve NDMPD_ZFS_PROP_INCR property from snapshot
203512186SJanice.Chang@Sun.COM */
203612186SJanice.Chang@Sun.COM
203712186SJanice.Chang@Sun.COM static int
ndmpd_zfs_snapshot_prop_get(zfs_handle_t * zhp,char * propstr)203812186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_prop_get(zfs_handle_t *zhp, char *propstr)
203912186SJanice.Chang@Sun.COM {
204012186SJanice.Chang@Sun.COM nvlist_t *userprop;
204112186SJanice.Chang@Sun.COM nvlist_t *propval;
204212186SJanice.Chang@Sun.COM char *strval;
204312186SJanice.Chang@Sun.COM int err;
204412186SJanice.Chang@Sun.COM
204512186SJanice.Chang@Sun.COM propstr[0] = '\0';
204612186SJanice.Chang@Sun.COM
204712186SJanice.Chang@Sun.COM userprop = zfs_get_user_props(zhp);
204812186SJanice.Chang@Sun.COM
204912186SJanice.Chang@Sun.COM if (userprop == NULL)
205012186SJanice.Chang@Sun.COM return (0);
205112186SJanice.Chang@Sun.COM
205212186SJanice.Chang@Sun.COM err = nvlist_lookup_nvlist(userprop, NDMPD_ZFS_PROP_INCR, &propval);
205312186SJanice.Chang@Sun.COM
205412186SJanice.Chang@Sun.COM if (err != 0) {
205512186SJanice.Chang@Sun.COM if (err == ENOENT)
205612186SJanice.Chang@Sun.COM return (0);
205712186SJanice.Chang@Sun.COM
205812186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "nvlist_lookup_nvlist error: %d\n", err);
205912186SJanice.Chang@Sun.COM
206012186SJanice.Chang@Sun.COM return (-1);
206112186SJanice.Chang@Sun.COM }
206212186SJanice.Chang@Sun.COM
206312186SJanice.Chang@Sun.COM err = nvlist_lookup_string(propval, ZPROP_VALUE, &strval);
206412186SJanice.Chang@Sun.COM
206512186SJanice.Chang@Sun.COM if (err != 0) {
206612186SJanice.Chang@Sun.COM if (err == ENOENT)
206712186SJanice.Chang@Sun.COM return (0);
206812186SJanice.Chang@Sun.COM
206912186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "nvlist_lookup_string error: %d\n", err);
207012186SJanice.Chang@Sun.COM
207112186SJanice.Chang@Sun.COM return (-1);
207212186SJanice.Chang@Sun.COM }
207312186SJanice.Chang@Sun.COM
207412186SJanice.Chang@Sun.COM (void) strlcpy(propstr, strval, ZFS_MAXPROPLEN);
207512186SJanice.Chang@Sun.COM
207612186SJanice.Chang@Sun.COM return (0);
207712186SJanice.Chang@Sun.COM }
207812186SJanice.Chang@Sun.COM
207912186SJanice.Chang@Sun.COM /*
208012186SJanice.Chang@Sun.COM * ndmpd_zfs_snapshot_prop_add()
208112186SJanice.Chang@Sun.COM *
208212186SJanice.Chang@Sun.COM * Update snapshot's NDMPD_ZFS_PROP_INCR property with
208312514SJanice.Chang@Sun.COM * the current LEVEL, DMP_NAME, and ZFS_MODE values
208412186SJanice.Chang@Sun.COM * (add property if it doesn't exist)
208512186SJanice.Chang@Sun.COM */
208612186SJanice.Chang@Sun.COM
208712186SJanice.Chang@Sun.COM static int
ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t * ndmpd_zfs_args)208812186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *ndmpd_zfs_args)
208912186SJanice.Chang@Sun.COM {
209012186SJanice.Chang@Sun.COM char fullname[ZFS_MAXNAMELEN];
209112186SJanice.Chang@Sun.COM char propstr[ZFS_MAXPROPLEN];
209212186SJanice.Chang@Sun.COM zfs_handle_t *zhp;
209312186SJanice.Chang@Sun.COM boolean_t set;
209412186SJanice.Chang@Sun.COM int err;
209512186SJanice.Chang@Sun.COM
209612186SJanice.Chang@Sun.COM (void) snprintf(fullname, ZFS_MAXNAMELEN, "%s@%s",
209712186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset,
209812186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_snapname);
209912186SJanice.Chang@Sun.COM
210012186SJanice.Chang@Sun.COM zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
210112186SJanice.Chang@Sun.COM
210212186SJanice.Chang@Sun.COM if (!zhp) {
210312186SJanice.Chang@Sun.COM NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open (snap)");
210412186SJanice.Chang@Sun.COM return (-1);
210512186SJanice.Chang@Sun.COM }
210612186SJanice.Chang@Sun.COM
210712186SJanice.Chang@Sun.COM bzero(propstr, ZFS_MAXPROPLEN);
210812186SJanice.Chang@Sun.COM
210912186SJanice.Chang@Sun.COM if (ndmpd_zfs_snapshot_prop_get(zhp, propstr)) {
211012186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "error getting property");
211112186SJanice.Chang@Sun.COM zfs_close(zhp);
211212186SJanice.Chang@Sun.COM return (-1);
211312186SJanice.Chang@Sun.COM }
211412186SJanice.Chang@Sun.COM
211512186SJanice.Chang@Sun.COM if (ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args, propstr, &set)) {
211612186SJanice.Chang@Sun.COM zfs_close(zhp);
211712186SJanice.Chang@Sun.COM return (-1);
211812186SJanice.Chang@Sun.COM }
211912186SJanice.Chang@Sun.COM
212012186SJanice.Chang@Sun.COM if (set) {
212112186SJanice.Chang@Sun.COM err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, propstr);
212212186SJanice.Chang@Sun.COM if (err) {
212312186SJanice.Chang@Sun.COM NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
212412186SJanice.Chang@Sun.COM err);
212512186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "error setting property %s",
212612186SJanice.Chang@Sun.COM propstr);
212712186SJanice.Chang@Sun.COM zfs_close(zhp);
212812186SJanice.Chang@Sun.COM return (-1);
212912186SJanice.Chang@Sun.COM }
213012186SJanice.Chang@Sun.COM }
213112186SJanice.Chang@Sun.COM
213212186SJanice.Chang@Sun.COM zfs_close(zhp);
213312186SJanice.Chang@Sun.COM
213412186SJanice.Chang@Sun.COM (void) strlcpy(ndmpd_zfs_args->nz_snapprop, propstr, ZFS_MAXPROPLEN);
213512186SJanice.Chang@Sun.COM
213612186SJanice.Chang@Sun.COM return (0);
213712186SJanice.Chang@Sun.COM }
213812186SJanice.Chang@Sun.COM
213912186SJanice.Chang@Sun.COM static int
ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t * ndmpd_zfs_args,char * propstr,boolean_t * set)214012186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
214112186SJanice.Chang@Sun.COM char *propstr, boolean_t *set)
214212186SJanice.Chang@Sun.COM {
214312186SJanice.Chang@Sun.COM char subprop[ZFS_MAXPROPLEN];
214412514SJanice.Chang@Sun.COM char *p = propstr;
214512514SJanice.Chang@Sun.COM int slash_count = 0;
214612186SJanice.Chang@Sun.COM
214712186SJanice.Chang@Sun.COM *set = B_TRUE;
214812186SJanice.Chang@Sun.COM
214912186SJanice.Chang@Sun.COM (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
215012186SJanice.Chang@Sun.COM subprop, ZFS_MAXPROPLEN, B_FALSE);
215112186SJanice.Chang@Sun.COM
215212186SJanice.Chang@Sun.COM if (propstr[0] == '\0') {
215312186SJanice.Chang@Sun.COM (void) snprintf(propstr, ZFS_MAXPROPLEN, "%u.%u.%c/%s",
215412186SJanice.Chang@Sun.COM NDMPD_ZFS_PROP_MAJOR_VERSION,
215512186SJanice.Chang@Sun.COM NDMPD_ZFS_PROP_MINOR_VERSION,
215612186SJanice.Chang@Sun.COM (ndmpd_zfs_args->nz_ndmpd_snap) ? 'n' : 'u',
215712186SJanice.Chang@Sun.COM subprop);
215812186SJanice.Chang@Sun.COM return (0);
215912186SJanice.Chang@Sun.COM }
216012186SJanice.Chang@Sun.COM
216112186SJanice.Chang@Sun.COM if (strstr((const char *)propstr, (const char *)subprop)) {
216212186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "Did not add entry %s as it already exists",
216312186SJanice.Chang@Sun.COM subprop);
216412186SJanice.Chang@Sun.COM *set = B_FALSE;
216512186SJanice.Chang@Sun.COM return (0);
216612186SJanice.Chang@Sun.COM }
216712186SJanice.Chang@Sun.COM
216812514SJanice.Chang@Sun.COM while (*p) {
216912514SJanice.Chang@Sun.COM if (*(p++) == '/')
217012514SJanice.Chang@Sun.COM slash_count++;
217112514SJanice.Chang@Sun.COM }
217212514SJanice.Chang@Sun.COM
217312514SJanice.Chang@Sun.COM if (slash_count >= NDMPD_ZFS_SUBPROP_MAX) {
217412514SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
217512514SJanice.Chang@Sun.COM "snapshot %s: user property %s limit of %d subprops "
217612514SJanice.Chang@Sun.COM "reached; cannot complete operation",
217712186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_snapname,
217812514SJanice.Chang@Sun.COM NDMPD_ZFS_PROP_INCR,
217912514SJanice.Chang@Sun.COM NDMPD_ZFS_SUBPROP_MAX);
218012186SJanice.Chang@Sun.COM return (-1);
218112186SJanice.Chang@Sun.COM }
218212186SJanice.Chang@Sun.COM
218312514SJanice.Chang@Sun.COM assert((strlen(propstr) + strlen(subprop) + 2) < ZFS_MAXPROPLEN);
218412514SJanice.Chang@Sun.COM
218512186SJanice.Chang@Sun.COM (void) strlcat(propstr, "/", ZFS_MAXPROPLEN);
218612186SJanice.Chang@Sun.COM (void) strlcat(propstr, subprop, ZFS_MAXPROPLEN);
218712186SJanice.Chang@Sun.COM
218812186SJanice.Chang@Sun.COM return (0);
218912186SJanice.Chang@Sun.COM }
219012186SJanice.Chang@Sun.COM
219112186SJanice.Chang@Sun.COM static int
ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t * ndmpd_zfs_args,char * subprop,int len,boolean_t prev_level)219212186SJanice.Chang@Sun.COM ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *ndmpd_zfs_args,
219312186SJanice.Chang@Sun.COM char *subprop, int len, boolean_t prev_level)
219412186SJanice.Chang@Sun.COM {
219512186SJanice.Chang@Sun.COM return (snprintf(subprop, len, "%d.%s.%c",
219612186SJanice.Chang@Sun.COM prev_level ? ndmpd_zfs_args->nz_level-1 : ndmpd_zfs_args->nz_level,
219712186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dmp_name,
219812186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_zfs_mode));
219912186SJanice.Chang@Sun.COM }
220012186SJanice.Chang@Sun.COM
220112186SJanice.Chang@Sun.COM /*
220212186SJanice.Chang@Sun.COM * ndmpd_zfs_snapshot_prop_remove()
220312186SJanice.Chang@Sun.COM *
220412186SJanice.Chang@Sun.COM * Remove specified substring from the snapshot's
220512186SJanice.Chang@Sun.COM * NDMPD_ZFS_PROP_INCR property
220612186SJanice.Chang@Sun.COM */
220712186SJanice.Chang@Sun.COM
220812186SJanice.Chang@Sun.COM static int
ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t * ndmpd_zfs_args,ndmpd_zfs_snapfind_t * snapdata_p)220912186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *ndmpd_zfs_args,
221012186SJanice.Chang@Sun.COM ndmpd_zfs_snapfind_t *snapdata_p)
221112186SJanice.Chang@Sun.COM {
221212186SJanice.Chang@Sun.COM char findprop_plus_slash[ZFS_MAXPROPLEN];
221312186SJanice.Chang@Sun.COM char fullname[ZFS_MAXNAMELEN];
221412186SJanice.Chang@Sun.COM char newprop[ZFS_MAXPROPLEN];
221512186SJanice.Chang@Sun.COM char tmpstr[ZFS_MAXPROPLEN];
221612186SJanice.Chang@Sun.COM zfs_handle_t *zhp;
221712186SJanice.Chang@Sun.COM char *ptr;
221812186SJanice.Chang@Sun.COM int err;
221912186SJanice.Chang@Sun.COM
222012186SJanice.Chang@Sun.COM (void) snprintf(fullname, ZFS_MAXNAMELEN, "%s@%s",
222112186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset,
222212186SJanice.Chang@Sun.COM snapdata_p->nzs_snapname);
222312186SJanice.Chang@Sun.COM
222412186SJanice.Chang@Sun.COM zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
222512186SJanice.Chang@Sun.COM
222612186SJanice.Chang@Sun.COM if (!zhp) {
222712186SJanice.Chang@Sun.COM NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
222812186SJanice.Chang@Sun.COM return (-1);
222912186SJanice.Chang@Sun.COM }
223012186SJanice.Chang@Sun.COM
223112186SJanice.Chang@Sun.COM bzero(newprop, ZFS_MAXPROPLEN);
223212186SJanice.Chang@Sun.COM
223312186SJanice.Chang@Sun.COM /*
223412186SJanice.Chang@Sun.COM * If the substring to be removed is the only {L, D, Z}
223512186SJanice.Chang@Sun.COM * in the property, remove the entire property
223612186SJanice.Chang@Sun.COM */
223712186SJanice.Chang@Sun.COM
223812186SJanice.Chang@Sun.COM tmpstr[0] = '\0';
223912186SJanice.Chang@Sun.COM
224012186SJanice.Chang@Sun.COM (void) sscanf(snapdata_p->nzs_snapprop, "%*u.%*u.%*c/%1023s", tmpstr);
224112186SJanice.Chang@Sun.COM
224212186SJanice.Chang@Sun.COM if (strcmp(tmpstr, snapdata_p->nzs_findprop) == 0) {
224312186SJanice.Chang@Sun.COM
224412186SJanice.Chang@Sun.COM err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
224512186SJanice.Chang@Sun.COM
224612186SJanice.Chang@Sun.COM zfs_close(zhp);
224712186SJanice.Chang@Sun.COM
224812186SJanice.Chang@Sun.COM if (err) {
224912186SJanice.Chang@Sun.COM NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
225012186SJanice.Chang@Sun.COM err);
225112186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "error setting property %s", newprop);
225212186SJanice.Chang@Sun.COM return (-1);
225312186SJanice.Chang@Sun.COM }
225412186SJanice.Chang@Sun.COM
225512186SJanice.Chang@Sun.COM return (0);
225612186SJanice.Chang@Sun.COM }
225712186SJanice.Chang@Sun.COM
225812186SJanice.Chang@Sun.COM (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
225912186SJanice.Chang@Sun.COM snapdata_p->nzs_findprop);
226012186SJanice.Chang@Sun.COM
226112186SJanice.Chang@Sun.COM ptr = strstr((const char *)snapdata_p->nzs_snapprop,
226212186SJanice.Chang@Sun.COM (const char *)findprop_plus_slash);
226312186SJanice.Chang@Sun.COM
226412186SJanice.Chang@Sun.COM if (ptr == NULL) {
226512186SJanice.Chang@Sun.COM /*
226612186SJanice.Chang@Sun.COM * This shouldn't happen. Just return success.
226712186SJanice.Chang@Sun.COM */
226812186SJanice.Chang@Sun.COM zfs_close(zhp);
226912186SJanice.Chang@Sun.COM
227012186SJanice.Chang@Sun.COM return (0);
227112186SJanice.Chang@Sun.COM }
227212186SJanice.Chang@Sun.COM
227312186SJanice.Chang@Sun.COM /*
227412186SJanice.Chang@Sun.COM * Remove "nzs_findprop" substring from property
227512186SJanice.Chang@Sun.COM *
227612186SJanice.Chang@Sun.COM * Example property:
227712186SJanice.Chang@Sun.COM * 0.0.u/1.bob.p/0.jane.d
227812186SJanice.Chang@Sun.COM *
227912186SJanice.Chang@Sun.COM * Note that there will always be a prefix to the
228012186SJanice.Chang@Sun.COM * strstr() result. Hence the below code works for
228112186SJanice.Chang@Sun.COM * all cases.
228212186SJanice.Chang@Sun.COM */
228312186SJanice.Chang@Sun.COM
228412186SJanice.Chang@Sun.COM ptr--;
228512186SJanice.Chang@Sun.COM (void) strncpy(newprop, snapdata_p->nzs_snapprop,
228612186SJanice.Chang@Sun.COM (char *)ptr - snapdata_p->nzs_snapprop);
228712186SJanice.Chang@Sun.COM ptr += strlen(snapdata_p->nzs_findprop) + 1;
228812186SJanice.Chang@Sun.COM (void) strlcat(newprop, ptr, ZFS_MAXPROPLEN);
228912186SJanice.Chang@Sun.COM
229012186SJanice.Chang@Sun.COM err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
229112186SJanice.Chang@Sun.COM
229212186SJanice.Chang@Sun.COM zfs_close(zhp);
229312186SJanice.Chang@Sun.COM
229412186SJanice.Chang@Sun.COM if (err) {
229512186SJanice.Chang@Sun.COM NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", err);
229612186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "error modifying property %s", newprop);
229712186SJanice.Chang@Sun.COM return (-1);
229812186SJanice.Chang@Sun.COM }
229912186SJanice.Chang@Sun.COM
230012186SJanice.Chang@Sun.COM return (0);
230112186SJanice.Chang@Sun.COM }
230212186SJanice.Chang@Sun.COM
230312186SJanice.Chang@Sun.COM static boolean_t
ndmpd_zfs_prop_version_check(char * propstr,uint32_t * major,uint32_t * minor)230412186SJanice.Chang@Sun.COM ndmpd_zfs_prop_version_check(char *propstr, uint32_t *major, uint32_t *minor)
230512186SJanice.Chang@Sun.COM {
230612186SJanice.Chang@Sun.COM (void) sscanf(propstr, "%u.%u.%*c%*s", major, minor);
230712186SJanice.Chang@Sun.COM
230812186SJanice.Chang@Sun.COM if (*major > NDMPD_ZFS_PROP_MAJOR_VERSION) {
230912186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "unsupported prop major (%u > %u)",
231012186SJanice.Chang@Sun.COM *major, NDMPD_ZFS_PROP_MAJOR_VERSION);
231112186SJanice.Chang@Sun.COM return (B_FALSE);
231212186SJanice.Chang@Sun.COM }
231312186SJanice.Chang@Sun.COM
231412186SJanice.Chang@Sun.COM if (*minor > NDMPD_ZFS_PROP_MINOR_VERSION) {
231512186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "later prop minor (%u > %u)",
231612186SJanice.Chang@Sun.COM *minor, NDMPD_ZFS_PROP_MINOR_VERSION);
231712186SJanice.Chang@Sun.COM }
231812186SJanice.Chang@Sun.COM
231912186SJanice.Chang@Sun.COM NDMP_LOG(LOG_DEBUG, "passed version check: "
232012186SJanice.Chang@Sun.COM "supported prop major (%u <= %u); (snapprop minor: %u [%u])",
232112186SJanice.Chang@Sun.COM *major, NDMPD_ZFS_PROP_MAJOR_VERSION,
232212186SJanice.Chang@Sun.COM *minor, NDMPD_ZFS_PROP_MINOR_VERSION);
232312186SJanice.Chang@Sun.COM
232412186SJanice.Chang@Sun.COM return (B_TRUE);
232512186SJanice.Chang@Sun.COM }
232612186SJanice.Chang@Sun.COM
232712186SJanice.Chang@Sun.COM static int
ndmpd_zfs_snapname_create(ndmpd_zfs_args_t * ndmpd_zfs_args,char * snapname,int namelen)232812186SJanice.Chang@Sun.COM ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
232912186SJanice.Chang@Sun.COM char *snapname, int namelen)
233012186SJanice.Chang@Sun.COM {
233112186SJanice.Chang@Sun.COM char subprop[ZFS_MAXPROPLEN];
233212186SJanice.Chang@Sun.COM struct timeval tp;
233312186SJanice.Chang@Sun.COM int err = 0;
233412186SJanice.Chang@Sun.COM
233512186SJanice.Chang@Sun.COM (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
233612186SJanice.Chang@Sun.COM subprop, ZFS_MAXPROPLEN, B_FALSE);
233712186SJanice.Chang@Sun.COM
233812186SJanice.Chang@Sun.COM (void) gettimeofday(&tp, NULL);
233912186SJanice.Chang@Sun.COM
234012186SJanice.Chang@Sun.COM err = snprintf(snapname, namelen,
234112186SJanice.Chang@Sun.COM "ndmp.%s.%ld.%ld",
234212186SJanice.Chang@Sun.COM subprop,
234312186SJanice.Chang@Sun.COM tp.tv_sec,
234412186SJanice.Chang@Sun.COM tp.tv_usec);
234512186SJanice.Chang@Sun.COM
234612186SJanice.Chang@Sun.COM if (err > namelen) {
234712186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, "name of snapshot [%s...] would exceed %d",
234812186SJanice.Chang@Sun.COM snapname, namelen);
234912186SJanice.Chang@Sun.COM return (-1);
235012186SJanice.Chang@Sun.COM }
235112186SJanice.Chang@Sun.COM
235212186SJanice.Chang@Sun.COM return (0);
235312186SJanice.Chang@Sun.COM }
235412186SJanice.Chang@Sun.COM
235512186SJanice.Chang@Sun.COM static void
ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t * ndmpd_zfs_args)235612186SJanice.Chang@Sun.COM ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args)
235712186SJanice.Chang@Sun.COM {
235812186SJanice.Chang@Sun.COM switch (libzfs_errno(ndmpd_zfs_args->nz_zlibh)) {
235912186SJanice.Chang@Sun.COM case EZFS_EXISTS:
236012186SJanice.Chang@Sun.COM case EZFS_BUSY:
236112186SJanice.Chang@Sun.COM case EZFS_NOENT:
236212186SJanice.Chang@Sun.COM case EZFS_INVALIDNAME:
236312186SJanice.Chang@Sun.COM case EZFS_MOUNTFAILED:
236412186SJanice.Chang@Sun.COM case EZFS_UMOUNTFAILED:
236512186SJanice.Chang@Sun.COM case EZFS_NAMETOOLONG:
236612186SJanice.Chang@Sun.COM case EZFS_BADRESTORE:
236712186SJanice.Chang@Sun.COM
236812186SJanice.Chang@Sun.COM /* use existing error text */
236912186SJanice.Chang@Sun.COM
237012186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
237112186SJanice.Chang@Sun.COM "%s: %s: %s\n",
237212186SJanice.Chang@Sun.COM ndmpd_zfs_args->nz_dataset,
237312186SJanice.Chang@Sun.COM libzfs_error_action(ndmpd_zfs_args->nz_zlibh),
237412186SJanice.Chang@Sun.COM libzfs_error_description(ndmpd_zfs_args->nz_zlibh));
237512186SJanice.Chang@Sun.COM
237612186SJanice.Chang@Sun.COM break;
237712186SJanice.Chang@Sun.COM
237812186SJanice.Chang@Sun.COM case EZFS_NOMEM:
237912186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
238012186SJanice.Chang@Sun.COM "Unable to obtain memory for operation\n");
238112186SJanice.Chang@Sun.COM break;
238212186SJanice.Chang@Sun.COM
238312186SJanice.Chang@Sun.COM case EZFS_PROPSPACE:
238412186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
238512186SJanice.Chang@Sun.COM "A bad ZFS quota or reservation was encountered.\n");
238612186SJanice.Chang@Sun.COM break;
238712186SJanice.Chang@Sun.COM
238812186SJanice.Chang@Sun.COM case EZFS_BADSTREAM:
238912186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
239012186SJanice.Chang@Sun.COM "The backup stream is invalid.\n");
239112186SJanice.Chang@Sun.COM break;
239212186SJanice.Chang@Sun.COM
239312186SJanice.Chang@Sun.COM case EZFS_ZONED:
239412186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
239512186SJanice.Chang@Sun.COM "An error related to the local zone occurred.\n");
239612186SJanice.Chang@Sun.COM break;
239712186SJanice.Chang@Sun.COM
239812186SJanice.Chang@Sun.COM case EZFS_NOSPC:
239912186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
240012186SJanice.Chang@Sun.COM "No more space is available\n");
240112186SJanice.Chang@Sun.COM break;
240212186SJanice.Chang@Sun.COM
240312186SJanice.Chang@Sun.COM case EZFS_IO:
240412186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
240512186SJanice.Chang@Sun.COM "An I/O error occurred.\n");
240612186SJanice.Chang@Sun.COM break;
240712186SJanice.Chang@Sun.COM
240812186SJanice.Chang@Sun.COM default:
240912186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
241012186SJanice.Chang@Sun.COM "An internal ndmpd error occurred. "
241112186SJanice.Chang@Sun.COM "Please contact support\n");
241212186SJanice.Chang@Sun.COM break;
241312186SJanice.Chang@Sun.COM }
241412186SJanice.Chang@Sun.COM }
241512186SJanice.Chang@Sun.COM
241612186SJanice.Chang@Sun.COM void
ndmpd_zfs_dma_log(ndmpd_zfs_args_t * ndmpd_zfs_args,ndmp_log_type log_type,char * format,...)241712186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args, ndmp_log_type log_type,
241812186SJanice.Chang@Sun.COM char *format, ...)
241912186SJanice.Chang@Sun.COM {
242012186SJanice.Chang@Sun.COM static char buf[1024];
242112186SJanice.Chang@Sun.COM va_list ap;
242212186SJanice.Chang@Sun.COM
242312186SJanice.Chang@Sun.COM va_start(ap, format);
242412186SJanice.Chang@Sun.COM
242512186SJanice.Chang@Sun.COM /*LINTED variable format specifier */
242612186SJanice.Chang@Sun.COM (void) vsnprintf(buf, sizeof (buf), format, ap);
242712186SJanice.Chang@Sun.COM va_end(ap);
242812186SJanice.Chang@Sun.COM
242912186SJanice.Chang@Sun.COM MOD_LOGV3(ndmpd_zfs_params, log_type, buf);
243012186SJanice.Chang@Sun.COM
243112186SJanice.Chang@Sun.COM if ((log_type) == NDMP_LOG_ERROR) {
243212186SJanice.Chang@Sun.COM NDMP_LOG(LOG_ERR, buf);
243312186SJanice.Chang@Sun.COM } else {
243412514SJanice.Chang@Sun.COM NDMP_LOG(LOG_NOTICE, buf);
243512186SJanice.Chang@Sun.COM }
243612186SJanice.Chang@Sun.COM }
2437