]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/zfsbootcfg/zfsbootcfg.c
zfs: merge openzfs/zfs@8f2f6cd2a
[FreeBSD/FreeBSD.git] / sbin / zfsbootcfg / zfsbootcfg.c
1 /*-
2  * Copyright (c) 2016 Andriy Gapon <avg@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include <sys/types.h>
27 #include <errno.h>
28 #include <limits.h>
29 #include <inttypes.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdbool.h>
33 #include <string.h>
34 #include <kenv.h>
35 #include <unistd.h>
36
37 #include <libzfsbootenv.h>
38
39 #ifndef ZFS_MAXNAMELEN
40 #define ZFS_MAXNAMELEN  256
41 #endif
42
43 static int
44 add_pair(const char *name, const char *nvlist, const char *key,
45     const char *type, const char *value)
46 {
47         void *data, *nv;
48         size_t size;
49         int rv;
50         char *end;
51
52         rv = lzbe_nvlist_get(name, nvlist, &nv);
53         if (rv != 0)
54                 return (rv);
55
56         data = NULL;
57         rv = EINVAL;
58         if (strcmp(type, "DATA_TYPE_STRING") == 0) {
59                 data = __DECONST(void *, value);
60                 size = strlen(data) + 1;
61                 rv = lzbe_add_pair(nv, key, type, data, size);
62         } else if (strcmp(type, "DATA_TYPE_UINT64") == 0) {
63                 uint64_t v;
64
65                 v = strtoull(value, &end, 0);
66                 if (errno != 0 || *end != '\0')
67                         goto done;
68                 size = sizeof (v);
69                 rv = lzbe_add_pair(nv, key, type, &v, size);
70         } else if (strcmp(type, "DATA_TYPE_INT64") == 0) {
71                 int64_t v;
72
73                 v = strtoll(value, &end, 0);
74                 if (errno != 0 || *end != '\0')
75                         goto done;
76                 size = sizeof (v);
77                 rv = lzbe_add_pair(nv, key, type, &v, size);
78         } else if (strcmp(type, "DATA_TYPE_UINT32") == 0) {
79                 uint32_t v;
80
81                 v = strtoul(value, &end, 0);
82                 if (errno != 0 || *end != '\0')
83                         goto done;
84                 size = sizeof (v);
85                 rv = lzbe_add_pair(nv, key, type, &v, size);
86         } else if (strcmp(type, "DATA_TYPE_INT32") == 0) {
87                 int32_t v;
88
89                 v = strtol(value, &end, 0);
90                 if (errno != 0 || *end != '\0')
91                         goto done;
92                 size = sizeof (v);
93                 rv = lzbe_add_pair(nv, key, type, &v, size);
94         } else if (strcmp(type, "DATA_TYPE_UINT16") == 0) {
95                 uint16_t v;
96
97                 v = strtoul(value, &end, 0);
98                 if (errno != 0 || *end != '\0')
99                         goto done;
100                 size = sizeof (v);
101                 rv = lzbe_add_pair(nv, key, type, &v, size);
102         } else if (strcmp(type, "DATA_TYPE_INT16") == 0) {
103                 int16_t v;
104
105                 v = strtol(value, &end, 0);
106                 if (errno != 0 || *end != '\0')
107                         goto done;
108                 size = sizeof (v);
109                 rv = lzbe_add_pair(nv, key, type, &v, size);
110         } else if (strcmp(type, "DATA_TYPE_UINT8") == 0) {
111                 uint8_t v;
112
113                 v = strtoul(value, &end, 0);
114                 if (errno != 0 || *end != '\0')
115                         goto done;
116                 size = sizeof (v);
117                 rv = lzbe_add_pair(nv, key, type, &v, size);
118         } else if (strcmp(type, "DATA_TYPE_INT8") == 0) {
119                 int8_t v;
120
121                 v = strtol(value, &end, 0);
122                 if (errno != 0 || *end != '\0')
123                         goto done;
124                 size = sizeof (v);
125                 rv = lzbe_add_pair(nv, key, type, &v, size);
126         } else if (strcmp(type, "DATA_TYPE_BYTE") == 0) {
127                 uint8_t v;
128
129                 v = strtoul(value, &end, 0);
130                 if (errno != 0 || *end != '\0')
131                         goto done;
132                 size = sizeof (v);
133                 rv = lzbe_add_pair(nv, key, type, &v, size);
134         } else if (strcmp(type, "DATA_TYPE_BOOLEAN_VALUE") == 0) {
135                 int32_t v;
136
137                 v = strtol(value, &end, 0);
138                 if (errno != 0 || *end != '\0') {
139                         if (strcasecmp(value, "YES") == 0)
140                                 v = 1;
141                         else if (strcasecmp(value, "NO") == 0)
142                                 v = 0;
143                         if (strcasecmp(value, "true") == 0)
144                                 v = 1;
145                         else if (strcasecmp(value, "false") == 0)
146                                 v = 0;
147                         else goto done;
148                 }
149                 size = sizeof (v);
150                 rv = lzbe_add_pair(nv, key, type, &v, size);
151         }
152
153         if (rv == 0)
154                 rv = lzbe_nvlist_set(name, nvlist, nv);
155
156 done:
157         lzbe_nvlist_free(nv);
158         return (rv);
159 }
160
161 static int
162 delete_pair(const char *name, const char *nvlist, const char *key)
163 {
164         void *nv;
165         int rv;
166
167         rv = lzbe_nvlist_get(name, nvlist, &nv);
168         if (rv == 0) {
169                 rv = lzbe_remove_pair(nv, key);
170         }
171         if (rv == 0)
172                 rv = lzbe_nvlist_set(name, nvlist, nv);
173
174         lzbe_nvlist_free(nv);
175         return (rv);
176 }
177
178 /*
179  * Usage: zfsbootcfg [-z pool] [-d key] [-k key -t type -v value] [-p]
180  *      zfsbootcfg [-z pool] -n nvlist [-d key] [-k key -t type -v value] [-p]
181  *
182  * if nvlist is set, we will update nvlist in bootenv.
183  * if nvlist is not set, we update pairs in bootenv.
184  */
185 int
186 main(int argc, char * const *argv)
187 {
188         char buf[ZFS_MAXNAMELEN], *name;
189         const char *key, *value, *type, *nvlist;
190         int rv;
191         bool print, delete;
192
193         nvlist = NULL;
194         name = NULL;
195         key = NULL;
196         type = NULL;
197         value = NULL;
198         print = delete = false;
199         while ((rv = getopt(argc, argv, "d:k:n:pt:v:z:")) != -1) {
200                 switch (rv) {
201                 case 'd':
202                         delete = true;
203                         key = optarg;
204                         break;
205                 case 'k':
206                         key = optarg;
207                         break;
208                 case 'n':
209                         nvlist = optarg;
210                         break;
211                 case 'p':
212                         print = true;
213                         break;
214                 case 't':
215                         type = optarg;
216                         break;
217                 case 'v':
218                         value = optarg;
219                         break;
220                 case 'z':
221                         name = optarg;
222                         break;
223                 }
224         }
225
226         argc -= optind;
227         argv += optind;
228
229         if (argc == 1)
230                 value = argv[0];
231
232         if (argc > 1) {
233                 fprintf(stderr, "usage: zfsbootcfg <boot.config(5) options>\n");
234                 return (1);
235         }
236
237         if (name == NULL) {
238                 rv = kenv(KENV_GET, "vfs.root.mountfrom", buf, sizeof(buf));
239                 if (rv <= 0) {
240                         perror("can't get vfs.root.mountfrom");
241                         return (1);
242                 }
243
244                 if (strncmp(buf, "zfs:", 4) == 0) {
245                         name = strchr(buf + 4, '/');
246                         if (name != NULL)
247                                 *name = '\0';
248                         name = buf + 4;
249                 } else {
250                         perror("not a zfs root");
251                         return (1);
252                 }
253         }
254
255         rv = 0;
256         if (key != NULL || value != NULL) {
257                 if (type == NULL)
258                         type = "DATA_TYPE_STRING";
259
260                 if (delete)
261                         rv = delete_pair(name, nvlist, key);
262                 else if (key == NULL || strcmp(key, "command") == 0)
263                         rv = lzbe_set_boot_device(name, lzbe_add, value);
264                 else
265                         rv = add_pair(name, nvlist, key, type, value);
266
267                 if (rv == 0)
268                         printf("zfs bootenv is successfully written\n");
269                 else
270                         printf("error: %d\n", rv);
271         } else if (!print) {
272                 char *ptr;
273
274                 if (lzbe_get_boot_device(name, &ptr) == 0) {
275                         printf("zfs:%s:\n", ptr);
276                         free(ptr);
277                 }
278         }
279
280         if (print) {
281                 rv = lzbe_bootenv_print(name, nvlist, stdout);
282         }
283
284         return (rv);
285 }