]> git.proxmox.com Git - mirror_zfs.git/blame - lib/libzfsbootenv/lzbe_device.c
Rename fallthrough to zfs_fallthrough
[mirror_zfs.git] / lib / libzfsbootenv / lzbe_device.c
CommitLineData
1db9e6e4
TS
1/*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11/*
12 * Copyright 2020 Toomas Soome <tsoome@me.com>
13 */
14
15#include <sys/types.h>
16#include <string.h>
17#include <libzfs.h>
18#include <libzfsbootenv.h>
19#include <sys/zfs_bootenv.h>
20#include <sys/vdev_impl.h>
21
22/*
23 * Store device name to zpool label bootenv area.
24 * This call will set bootenv version to VB_NVLIST, if bootenv currently
25 * does contain other version, then old data will be replaced.
26 */
27int
28lzbe_set_boot_device(const char *pool, lzbe_flags_t flag, const char *device)
29{
30 libzfs_handle_t *hdl;
31 zpool_handle_t *zphdl;
32 nvlist_t *nv;
33 char *descriptor;
34 uint64_t version;
35 int rv = -1;
36
37 if (pool == NULL || *pool == '\0')
38 return (rv);
39
40 if ((hdl = libzfs_init()) == NULL)
41 return (rv);
42
43 zphdl = zpool_open(hdl, pool);
44 if (zphdl == NULL) {
45 libzfs_fini(hdl);
46 return (rv);
47 }
48
49 switch (flag) {
50 case lzbe_add:
51 rv = zpool_get_bootenv(zphdl, &nv);
52 if (rv == 0) {
53 /*
54 * We got the nvlist, check for version.
55 * if version is missing or is not VB_NVLIST,
56 * create new list.
57 */
58 rv = nvlist_lookup_uint64(nv, BOOTENV_VERSION,
59 &version);
60 if (rv == 0 && version == VB_NVLIST)
61 break;
62
63 /* Drop this nvlist */
64 fnvlist_free(nv);
65 }
9a70e97f 66 zfs_fallthrough;
1db9e6e4
TS
67 case lzbe_replace:
68 nv = fnvlist_alloc();
69 break;
70 default:
71 return (rv);
72 }
73
74 /* version is mandatory */
75 fnvlist_add_uint64(nv, BOOTENV_VERSION, VB_NVLIST);
76
77 /*
78 * If device name is empty, remove boot device configuration.
79 */
80 if ((device == NULL || *device == '\0')) {
81 if (nvlist_exists(nv, OS_BOOTONCE))
82 fnvlist_remove(nv, OS_BOOTONCE);
83 } else {
84 /*
85 * Use device name directly if it does start with
bf169e9f 86 * prefix "zfs:". Otherwise, add prefix and suffix.
1db9e6e4
TS
87 */
88 if (strncmp(device, "zfs:", 4) == 0) {
89 fnvlist_add_string(nv, OS_BOOTONCE, device);
90 } else {
87b671f3 91 if (asprintf(&descriptor, "zfs:%s:", device) > 0) {
1db9e6e4 92 fnvlist_add_string(nv, OS_BOOTONCE, descriptor);
87b671f3
AZ
93 free(descriptor);
94 } else
1db9e6e4 95 rv = ENOMEM;
1db9e6e4
TS
96 }
97 }
98
99 rv = zpool_set_bootenv(zphdl, nv);
100 if (rv != 0)
101 fprintf(stderr, "%s\n", libzfs_error_description(hdl));
102
103 fnvlist_free(nv);
104 zpool_close(zphdl);
105 libzfs_fini(hdl);
106 return (rv);
107}
108
109/*
110 * Return boot device name from bootenv, if set.
111 */
112int
113lzbe_get_boot_device(const char *pool, char **device)
114{
115 libzfs_handle_t *hdl;
116 zpool_handle_t *zphdl;
117 nvlist_t *nv;
118 char *val;
119 int rv = -1;
120
121 if (pool == NULL || *pool == '\0' || device == NULL)
122 return (rv);
123
124 if ((hdl = libzfs_init()) == NULL)
125 return (rv);
126
127 zphdl = zpool_open(hdl, pool);
128 if (zphdl == NULL) {
129 libzfs_fini(hdl);
130 return (rv);
131 }
132
133 rv = zpool_get_bootenv(zphdl, &nv);
134 if (rv == 0) {
135 rv = nvlist_lookup_string(nv, OS_BOOTONCE, &val);
136 if (rv == 0) {
137 /*
138 * zfs device descriptor is in form of "zfs:dataset:",
139 * we only do need dataset name.
140 */
141 if (strncmp(val, "zfs:", 4) == 0) {
142 val += 4;
143 val = strdup(val);
144 if (val != NULL) {
145 size_t len = strlen(val);
146
147 if (val[len - 1] == ':')
148 val[len - 1] = '\0';
149 *device = val;
150 } else {
151 rv = ENOMEM;
152 }
153 } else {
154 rv = EINVAL;
155 }
156 }
157 nvlist_free(nv);
158 }
159
160 zpool_close(zphdl);
161 libzfs_fini(hdl);
162 return (rv);
163}