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