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