]>
Commit | Line | Data |
---|---|---|
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 | */ | |
27 | int | |
28 | lzbe_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 | */ | |
112 | int | |
113 | lzbe_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 | } |