1f169c0eaSGlenn Lagasse /*
2f169c0eaSGlenn Lagasse * CDDL HEADER START
3f169c0eaSGlenn Lagasse *
4f169c0eaSGlenn Lagasse * The contents of this file are subject to the terms of the
5f169c0eaSGlenn Lagasse * Common Development and Distribution License (the "License").
6f169c0eaSGlenn Lagasse * You may not use this file except in compliance with the License.
7f169c0eaSGlenn Lagasse *
8f169c0eaSGlenn Lagasse * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f169c0eaSGlenn Lagasse * or http://www.opensolaris.org/os/licensing.
10f169c0eaSGlenn Lagasse * See the License for the specific language governing permissions
11f169c0eaSGlenn Lagasse * and limitations under the License.
12f169c0eaSGlenn Lagasse *
13f169c0eaSGlenn Lagasse * When distributing Covered Code, include this CDDL HEADER in each
14f169c0eaSGlenn Lagasse * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f169c0eaSGlenn Lagasse * If applicable, add the following below this CDDL HEADER, with the
16f169c0eaSGlenn Lagasse * fields enclosed by brackets "[]" replaced with your own identifying
17f169c0eaSGlenn Lagasse * information: Portions Copyright [yyyy] [name of copyright owner]
18f169c0eaSGlenn Lagasse *
19f169c0eaSGlenn Lagasse * CDDL HEADER END
20f169c0eaSGlenn Lagasse */
21f169c0eaSGlenn Lagasse
22f169c0eaSGlenn Lagasse /*
23f169c0eaSGlenn Lagasse * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
247e0e2549SAlexander Eremin * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
25a63c99a2SToomas Soome * Copyright 2015 Toomas Soome <tsoome@me.com>
2640a5c998SMatthew Ahrens * Copyright (c) 2015 by Delphix. All rights reserved.
27*4fef13f1SAndy Fiddaman * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
286b1d07a4SAlexander Eremin */
296b1d07a4SAlexander Eremin
306b1d07a4SAlexander Eremin
316b1d07a4SAlexander Eremin /*
32f169c0eaSGlenn Lagasse * System includes
33f169c0eaSGlenn Lagasse */
34f169c0eaSGlenn Lagasse #include <assert.h>
35f169c0eaSGlenn Lagasse #include <errno.h>
36f169c0eaSGlenn Lagasse #include <libgen.h>
37f169c0eaSGlenn Lagasse #include <libintl.h>
38f169c0eaSGlenn Lagasse #include <libnvpair.h>
39f169c0eaSGlenn Lagasse #include <libzfs.h>
40f169c0eaSGlenn Lagasse #include <libgen.h>
41f169c0eaSGlenn Lagasse #include <stdio.h>
42f169c0eaSGlenn Lagasse #include <stdlib.h>
43f169c0eaSGlenn Lagasse #include <string.h>
44f169c0eaSGlenn Lagasse #include <sys/stat.h>
45f169c0eaSGlenn Lagasse #include <sys/types.h>
46f169c0eaSGlenn Lagasse #include <sys/vfstab.h>
47f169c0eaSGlenn Lagasse #include <sys/param.h>
48f169c0eaSGlenn Lagasse #include <sys/systeminfo.h>
49f169c0eaSGlenn Lagasse #include <ctype.h>
50f169c0eaSGlenn Lagasse #include <time.h>
51f169c0eaSGlenn Lagasse #include <unistd.h>
52f169c0eaSGlenn Lagasse #include <fcntl.h>
53de1ab35cSAlexander Eremin #include <deflt.h>
54f169c0eaSGlenn Lagasse #include <wait.h>
556b1d07a4SAlexander Eremin #include <libdevinfo.h>
567e0e2549SAlexander Eremin #include <libgen.h>
57f169c0eaSGlenn Lagasse
58f169c0eaSGlenn Lagasse #include <libbe.h>
59f169c0eaSGlenn Lagasse #include <libbe_priv.h>
60a63c99a2SToomas Soome #include <boot_utils.h>
61f169c0eaSGlenn Lagasse
62f169c0eaSGlenn Lagasse /* Private function prototypes */
63f169c0eaSGlenn Lagasse static int update_dataset(char *, int, char *, char *, char *);
64f169c0eaSGlenn Lagasse static int _update_vfstab(char *, char *, char *, char *, be_fs_list_data_t *);
65de1ab35cSAlexander Eremin static int be_open_menu(char *, char *, FILE **, char *, boolean_t);
66de1ab35cSAlexander Eremin static int be_create_menu(char *, char *, FILE **, char *);
67f169c0eaSGlenn Lagasse static char *be_get_auto_name(char *, char *, boolean_t);
68f169c0eaSGlenn Lagasse
69f169c0eaSGlenn Lagasse /*
70f169c0eaSGlenn Lagasse * Global error printing
71f169c0eaSGlenn Lagasse */
72f169c0eaSGlenn Lagasse boolean_t do_print = B_FALSE;
73f169c0eaSGlenn Lagasse
74f169c0eaSGlenn Lagasse /*
75f169c0eaSGlenn Lagasse * Private datatypes
76f169c0eaSGlenn Lagasse */
77f169c0eaSGlenn Lagasse typedef struct zone_be_name_cb_data {
78f169c0eaSGlenn Lagasse char *base_be_name;
79f169c0eaSGlenn Lagasse int num;
80f169c0eaSGlenn Lagasse } zone_be_name_cb_data_t;
81f169c0eaSGlenn Lagasse
82f169c0eaSGlenn Lagasse /* ******************************************************************** */
83f169c0eaSGlenn Lagasse /* Public Functions */
84f169c0eaSGlenn Lagasse /* ******************************************************************** */
85f169c0eaSGlenn Lagasse
86f169c0eaSGlenn Lagasse /*
87f169c0eaSGlenn Lagasse * Function: be_max_avail
88f169c0eaSGlenn Lagasse * Description: Returns the available size for the zfs dataset passed in.
89f169c0eaSGlenn Lagasse * Parameters:
90f169c0eaSGlenn Lagasse * dataset - The dataset we want to get the available space for.
91f169c0eaSGlenn Lagasse * ret - The available size will be returned in this.
92f169c0eaSGlenn Lagasse * Returns:
93f169c0eaSGlenn Lagasse * The error returned by the zfs get property function.
94f169c0eaSGlenn Lagasse * Scope:
95f169c0eaSGlenn Lagasse * Public
96f169c0eaSGlenn Lagasse */
97f169c0eaSGlenn Lagasse int
be_max_avail(char * dataset,uint64_t * ret)98f169c0eaSGlenn Lagasse be_max_avail(char *dataset, uint64_t *ret)
99f169c0eaSGlenn Lagasse {
100f169c0eaSGlenn Lagasse zfs_handle_t *zhp;
101f169c0eaSGlenn Lagasse int err = 0;
102f169c0eaSGlenn Lagasse
103f169c0eaSGlenn Lagasse /* Initialize libzfs handle */
104f169c0eaSGlenn Lagasse if (!be_zfs_init())
105f169c0eaSGlenn Lagasse return (BE_ERR_INIT);
106f169c0eaSGlenn Lagasse
107f169c0eaSGlenn Lagasse zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET);
108f169c0eaSGlenn Lagasse if (zhp == NULL) {
109f169c0eaSGlenn Lagasse /*
110f169c0eaSGlenn Lagasse * The zfs_open failed return an error
111f169c0eaSGlenn Lagasse */
112f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs);
113f169c0eaSGlenn Lagasse } else {
114f169c0eaSGlenn Lagasse err = be_maxsize_avail(zhp, ret);
115f169c0eaSGlenn Lagasse }
116f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
117f169c0eaSGlenn Lagasse be_zfs_fini();
118f169c0eaSGlenn Lagasse return (err);
119f169c0eaSGlenn Lagasse }
120f169c0eaSGlenn Lagasse
121f169c0eaSGlenn Lagasse /*
122f169c0eaSGlenn Lagasse * Function: libbe_print_errors
123f169c0eaSGlenn Lagasse * Description: Turns on/off error output for the library.
124f169c0eaSGlenn Lagasse * Parameter:
125f169c0eaSGlenn Lagasse * set_do_print - Boolean that turns library error
126f169c0eaSGlenn Lagasse * printing on or off.
127f169c0eaSGlenn Lagasse * Returns:
128f169c0eaSGlenn Lagasse * None
129f169c0eaSGlenn Lagasse * Scope:
130f169c0eaSGlenn Lagasse * Public;
131f169c0eaSGlenn Lagasse */
132f169c0eaSGlenn Lagasse void
libbe_print_errors(boolean_t set_do_print)133f169c0eaSGlenn Lagasse libbe_print_errors(boolean_t set_do_print)
134f169c0eaSGlenn Lagasse {
135f169c0eaSGlenn Lagasse do_print = set_do_print;
136f169c0eaSGlenn Lagasse }
137f169c0eaSGlenn Lagasse
138f169c0eaSGlenn Lagasse /* ******************************************************************** */
139f169c0eaSGlenn Lagasse /* Semi-Private Functions */
140f169c0eaSGlenn Lagasse /* ******************************************************************** */
141f169c0eaSGlenn Lagasse
142f169c0eaSGlenn Lagasse /*
143f169c0eaSGlenn Lagasse * Function: be_zfs_init
144f169c0eaSGlenn Lagasse * Description: Initializes the libary global libzfs handle.
145f169c0eaSGlenn Lagasse * Parameters:
146f169c0eaSGlenn Lagasse * None
147f169c0eaSGlenn Lagasse * Returns:
148f169c0eaSGlenn Lagasse * B_TRUE - Success
149f169c0eaSGlenn Lagasse * B_FALSE - Failure
150f169c0eaSGlenn Lagasse * Scope:
151f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
152f169c0eaSGlenn Lagasse */
153f169c0eaSGlenn Lagasse boolean_t
be_zfs_init(void)154f169c0eaSGlenn Lagasse be_zfs_init(void)
155f169c0eaSGlenn Lagasse {
156f169c0eaSGlenn Lagasse be_zfs_fini();
157f169c0eaSGlenn Lagasse
158f169c0eaSGlenn Lagasse if ((g_zfs = libzfs_init()) == NULL) {
159f169c0eaSGlenn Lagasse be_print_err(gettext("be_zfs_init: failed to initialize ZFS "
160f169c0eaSGlenn Lagasse "library\n"));
161f169c0eaSGlenn Lagasse return (B_FALSE);
162f169c0eaSGlenn Lagasse }
163f169c0eaSGlenn Lagasse
164f169c0eaSGlenn Lagasse return (B_TRUE);
165f169c0eaSGlenn Lagasse }
166f169c0eaSGlenn Lagasse
167f169c0eaSGlenn Lagasse /*
168f169c0eaSGlenn Lagasse * Function: be_zfs_fini
169f169c0eaSGlenn Lagasse * Description: Closes the library global libzfs handle if it currently open.
170f169c0eaSGlenn Lagasse * Parameter:
171f169c0eaSGlenn Lagasse * None
172f169c0eaSGlenn Lagasse * Returns:
173f169c0eaSGlenn Lagasse * None
174f169c0eaSGlenn Lagasse * Scope:
175f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
176f169c0eaSGlenn Lagasse */
177f169c0eaSGlenn Lagasse void
be_zfs_fini(void)178f169c0eaSGlenn Lagasse be_zfs_fini(void)
179f169c0eaSGlenn Lagasse {
180f169c0eaSGlenn Lagasse if (g_zfs)
181f169c0eaSGlenn Lagasse libzfs_fini(g_zfs);
182f169c0eaSGlenn Lagasse
183f169c0eaSGlenn Lagasse g_zfs = NULL;
184f169c0eaSGlenn Lagasse }
185f169c0eaSGlenn Lagasse
186f169c0eaSGlenn Lagasse /*
187de1ab35cSAlexander Eremin * Function: be_get_defaults
188de1ab35cSAlexander Eremin * Description: Open defaults and gets be default paramets
189de1ab35cSAlexander Eremin * Parameters:
190de1ab35cSAlexander Eremin * defaults - be defaults struct
191de1ab35cSAlexander Eremin * Returns:
192de1ab35cSAlexander Eremin * None
193de1ab35cSAlexander Eremin * Scope:
194de1ab35cSAlexander Eremin * Semi-private (library wide use only)
195de1ab35cSAlexander Eremin */
196de1ab35cSAlexander Eremin void
be_get_defaults(struct be_defaults * defaults)197de1ab35cSAlexander Eremin be_get_defaults(struct be_defaults *defaults)
198de1ab35cSAlexander Eremin {
199de1ab35cSAlexander Eremin void *defp;
200de1ab35cSAlexander Eremin
201de1ab35cSAlexander Eremin defaults->be_deflt_rpool_container = B_FALSE;
202de1ab35cSAlexander Eremin defaults->be_deflt_bename_starts_with[0] = '\0';
203de1ab35cSAlexander Eremin
204de1ab35cSAlexander Eremin if ((defp = defopen_r(BE_DEFAULTS)) != NULL) {
205de1ab35cSAlexander Eremin const char *res = defread_r(BE_DFLT_BENAME_STARTS, defp);
206de1ab35cSAlexander Eremin if (res != NULL && res[0] != NULL) {
207de1ab35cSAlexander Eremin (void) strlcpy(defaults->be_deflt_bename_starts_with,
20840a5c998SMatthew Ahrens res, ZFS_MAX_DATASET_NAME_LEN);
209de1ab35cSAlexander Eremin defaults->be_deflt_rpool_container = B_TRUE;
210de1ab35cSAlexander Eremin }
211de1ab35cSAlexander Eremin defclose_r(defp);
212de1ab35cSAlexander Eremin }
213de1ab35cSAlexander Eremin }
214de1ab35cSAlexander Eremin
215de1ab35cSAlexander Eremin /*
216f169c0eaSGlenn Lagasse * Function: be_make_root_ds
217f169c0eaSGlenn Lagasse * Description: Generate string for BE's root dataset given the pool
218f169c0eaSGlenn Lagasse * it lives in and the BE name.
219f169c0eaSGlenn Lagasse * Parameters:
220f169c0eaSGlenn Lagasse * zpool - pointer zpool name.
221f169c0eaSGlenn Lagasse * be_name - pointer to BE name.
222f169c0eaSGlenn Lagasse * be_root_ds - pointer to buffer to return BE root dataset in.
223f169c0eaSGlenn Lagasse * be_root_ds_size - size of be_root_ds
224f169c0eaSGlenn Lagasse * Returns:
225f169c0eaSGlenn Lagasse * None
226f169c0eaSGlenn Lagasse * Scope:
227f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
228f169c0eaSGlenn Lagasse */
229f169c0eaSGlenn Lagasse void
be_make_root_ds(const char * zpool,const char * be_name,char * be_root_ds,int be_root_ds_size)230f169c0eaSGlenn Lagasse be_make_root_ds(const char *zpool, const char *be_name, char *be_root_ds,
231f169c0eaSGlenn Lagasse int be_root_ds_size)
232f169c0eaSGlenn Lagasse {
233de1ab35cSAlexander Eremin struct be_defaults be_defaults;
234de1ab35cSAlexander Eremin be_get_defaults(&be_defaults);
2357e0e2549SAlexander Eremin char *root_ds = NULL;
236de1ab35cSAlexander Eremin
2377e0e2549SAlexander Eremin if (getzoneid() == GLOBAL_ZONEID) {
2387e0e2549SAlexander Eremin if (be_defaults.be_deflt_rpool_container) {
2397e0e2549SAlexander Eremin (void) snprintf(be_root_ds, be_root_ds_size,
2407e0e2549SAlexander Eremin "%s/%s", zpool, be_name);
2417e0e2549SAlexander Eremin } else {
2427e0e2549SAlexander Eremin (void) snprintf(be_root_ds, be_root_ds_size,
2437e0e2549SAlexander Eremin "%s/%s/%s", zpool, BE_CONTAINER_DS_NAME, be_name);
2447e0e2549SAlexander Eremin }
2457e0e2549SAlexander Eremin } else {
2467e0e2549SAlexander Eremin /*
2477e0e2549SAlexander Eremin * In non-global zone we can use path from mounted root dataset
2487e0e2549SAlexander Eremin * to generate BE's root dataset string.
2497e0e2549SAlexander Eremin */
2507e0e2549SAlexander Eremin if ((root_ds = be_get_ds_from_dir("/")) != NULL) {
2517e0e2549SAlexander Eremin (void) snprintf(be_root_ds, be_root_ds_size, "%s/%s",
2527e0e2549SAlexander Eremin dirname(root_ds), be_name);
2537e0e2549SAlexander Eremin } else {
2547e0e2549SAlexander Eremin be_print_err(gettext("be_make_root_ds: zone root "
2557e0e2549SAlexander Eremin "dataset is not mounted\n"));
2567e0e2549SAlexander Eremin return;
2577e0e2549SAlexander Eremin }
2587e0e2549SAlexander Eremin }
259f169c0eaSGlenn Lagasse }
260f169c0eaSGlenn Lagasse
261f169c0eaSGlenn Lagasse /*
262f169c0eaSGlenn Lagasse * Function: be_make_container_ds
263f169c0eaSGlenn Lagasse * Description: Generate string for the BE container dataset given a pool name.
264f169c0eaSGlenn Lagasse * Parameters:
265f169c0eaSGlenn Lagasse * zpool - pointer zpool name.
266f169c0eaSGlenn Lagasse * container_ds - pointer to buffer to return BE container
267f169c0eaSGlenn Lagasse * dataset in.
268f169c0eaSGlenn Lagasse * container_ds_size - size of container_ds
269f169c0eaSGlenn Lagasse * Returns:
270f169c0eaSGlenn Lagasse * None
271f169c0eaSGlenn Lagasse * Scope:
272f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
273f169c0eaSGlenn Lagasse */
274f169c0eaSGlenn Lagasse void
be_make_container_ds(const char * zpool,char * container_ds,int container_ds_size)275f169c0eaSGlenn Lagasse be_make_container_ds(const char *zpool, char *container_ds,
276f169c0eaSGlenn Lagasse int container_ds_size)
277f169c0eaSGlenn Lagasse {
278de1ab35cSAlexander Eremin struct be_defaults be_defaults;
279de1ab35cSAlexander Eremin be_get_defaults(&be_defaults);
2807e0e2549SAlexander Eremin char *root_ds = NULL;
281de1ab35cSAlexander Eremin
2827e0e2549SAlexander Eremin if (getzoneid() == GLOBAL_ZONEID) {
2837e0e2549SAlexander Eremin if (be_defaults.be_deflt_rpool_container) {
2847e0e2549SAlexander Eremin (void) snprintf(container_ds, container_ds_size,
2857e0e2549SAlexander Eremin "%s", zpool);
2867e0e2549SAlexander Eremin } else {
2877e0e2549SAlexander Eremin (void) snprintf(container_ds, container_ds_size,
2887e0e2549SAlexander Eremin "%s/%s", zpool, BE_CONTAINER_DS_NAME);
2897e0e2549SAlexander Eremin }
2907e0e2549SAlexander Eremin } else {
2917e0e2549SAlexander Eremin if ((root_ds = be_get_ds_from_dir("/")) != NULL) {
2927e0e2549SAlexander Eremin (void) strlcpy(container_ds, dirname(root_ds),
2937e0e2549SAlexander Eremin container_ds_size);
2947e0e2549SAlexander Eremin } else {
2957e0e2549SAlexander Eremin be_print_err(gettext("be_make_container_ds: zone root "
2967e0e2549SAlexander Eremin "dataset is not mounted\n"));
2977e0e2549SAlexander Eremin return;
2987e0e2549SAlexander Eremin }
2997e0e2549SAlexander Eremin }
300f169c0eaSGlenn Lagasse }
301f169c0eaSGlenn Lagasse
302f169c0eaSGlenn Lagasse /*
303f169c0eaSGlenn Lagasse * Function: be_make_name_from_ds
304f169c0eaSGlenn Lagasse * Description: This function takes a dataset name and strips off the
305f169c0eaSGlenn Lagasse * BE container dataset portion from the beginning. The
306f169c0eaSGlenn Lagasse * returned name is allocated in heap storage, so the caller
307f169c0eaSGlenn Lagasse * is responsible for freeing it.
308f169c0eaSGlenn Lagasse * Parameters:
309f169c0eaSGlenn Lagasse * dataset - dataset to get name from.
310f169c0eaSGlenn Lagasse * rc_loc - dataset underwhich the root container dataset lives.
311f169c0eaSGlenn Lagasse * Returns:
312f169c0eaSGlenn Lagasse * name of dataset relative to BE container dataset.
313f169c0eaSGlenn Lagasse * NULL if dataset is not under a BE root dataset.
314f169c0eaSGlenn Lagasse * Scope:
315f169c0eaSGlenn Lagasse * Semi-primate (library wide use only)
316f169c0eaSGlenn Lagasse */
317f169c0eaSGlenn Lagasse char *
be_make_name_from_ds(const char * dataset,char * rc_loc)318f169c0eaSGlenn Lagasse be_make_name_from_ds(const char *dataset, char *rc_loc)
319f169c0eaSGlenn Lagasse {
32040a5c998SMatthew Ahrens char ds[ZFS_MAX_DATASET_NAME_LEN];
321f169c0eaSGlenn Lagasse char *tok = NULL;
322f169c0eaSGlenn Lagasse char *name = NULL;
323de1ab35cSAlexander Eremin struct be_defaults be_defaults;
324de1ab35cSAlexander Eremin int rlen = strlen(rc_loc);
325de1ab35cSAlexander Eremin
326de1ab35cSAlexander Eremin be_get_defaults(&be_defaults);
327f169c0eaSGlenn Lagasse
328f169c0eaSGlenn Lagasse /*
329f169c0eaSGlenn Lagasse * First token is the location of where the root container dataset
330f169c0eaSGlenn Lagasse * lives; it must match rc_loc.
331f169c0eaSGlenn Lagasse */
332de1ab35cSAlexander Eremin if (strncmp(dataset, rc_loc, rlen) == 0 && dataset[rlen] == '/')
333de1ab35cSAlexander Eremin (void) strlcpy(ds, dataset + rlen + 1, sizeof (ds));
334de1ab35cSAlexander Eremin else
335de1ab35cSAlexander Eremin return (NULL);
336de1ab35cSAlexander Eremin
337de1ab35cSAlexander Eremin if (be_defaults.be_deflt_rpool_container) {
338de1ab35cSAlexander Eremin if ((name = strdup(ds)) == NULL) {
339de1ab35cSAlexander Eremin be_print_err(gettext("be_make_name_from_ds: "
340de1ab35cSAlexander Eremin "memory allocation failed\n"));
341f169c0eaSGlenn Lagasse return (NULL);
342f169c0eaSGlenn Lagasse }
343de1ab35cSAlexander Eremin } else {
344f169c0eaSGlenn Lagasse /* Second token must be BE container dataset name */
345f169c0eaSGlenn Lagasse if ((tok = strtok(ds, "/")) == NULL ||
346f169c0eaSGlenn Lagasse strcmp(tok, BE_CONTAINER_DS_NAME) != 0)
347f169c0eaSGlenn Lagasse return (NULL);
348f169c0eaSGlenn Lagasse
349f169c0eaSGlenn Lagasse /* Return the remaining token if one exists */
350f169c0eaSGlenn Lagasse if ((tok = strtok(NULL, "")) == NULL)
351f169c0eaSGlenn Lagasse return (NULL);
352f169c0eaSGlenn Lagasse
353f169c0eaSGlenn Lagasse if ((name = strdup(tok)) == NULL) {
354f169c0eaSGlenn Lagasse be_print_err(gettext("be_make_name_from_ds: "
355f169c0eaSGlenn Lagasse "memory allocation failed\n"));
356f169c0eaSGlenn Lagasse return (NULL);
357f169c0eaSGlenn Lagasse }
358de1ab35cSAlexander Eremin }
359f169c0eaSGlenn Lagasse
360f169c0eaSGlenn Lagasse return (name);
361f169c0eaSGlenn Lagasse }
362f169c0eaSGlenn Lagasse
363f169c0eaSGlenn Lagasse /*
364f169c0eaSGlenn Lagasse * Function: be_maxsize_avail
365f169c0eaSGlenn Lagasse * Description: Returns the available size for the zfs handle passed in.
366f169c0eaSGlenn Lagasse * Parameters:
367f169c0eaSGlenn Lagasse * zhp - A pointer to the open zfs handle.
368f169c0eaSGlenn Lagasse * ret - The available size will be returned in this.
369f169c0eaSGlenn Lagasse * Returns:
370f169c0eaSGlenn Lagasse * The error returned by the zfs get property function.
371f169c0eaSGlenn Lagasse * Scope:
372f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
373f169c0eaSGlenn Lagasse */
374f169c0eaSGlenn Lagasse int
be_maxsize_avail(zfs_handle_t * zhp,uint64_t * ret)375f169c0eaSGlenn Lagasse be_maxsize_avail(zfs_handle_t *zhp, uint64_t *ret)
376f169c0eaSGlenn Lagasse {
377f169c0eaSGlenn Lagasse return ((*ret = zfs_prop_get_int(zhp, ZFS_PROP_AVAILABLE)));
378f169c0eaSGlenn Lagasse }
379f169c0eaSGlenn Lagasse
380f169c0eaSGlenn Lagasse /*
381f169c0eaSGlenn Lagasse * Function: be_append_menu
382f169c0eaSGlenn Lagasse * Description: Appends an entry for a BE into the menu.lst.
383f169c0eaSGlenn Lagasse * Parameters:
384f169c0eaSGlenn Lagasse * be_name - pointer to name of BE to add boot menu entry for.
385f169c0eaSGlenn Lagasse * be_root_pool - pointer to name of pool BE lives in.
386f169c0eaSGlenn Lagasse * boot_pool - Used if the pool containing the grub menu is
387f169c0eaSGlenn Lagasse * different than the one contaiing the BE. This
388f169c0eaSGlenn Lagasse * will normally be NULL.
389f169c0eaSGlenn Lagasse * be_orig_root_ds - The root dataset for the BE. This is
390f169c0eaSGlenn Lagasse * used to check to see if an entry already exists
391f169c0eaSGlenn Lagasse * for this BE.
392f169c0eaSGlenn Lagasse * description - pointer to description of BE to be added in
393f169c0eaSGlenn Lagasse * the title line for this BEs entry.
394f169c0eaSGlenn Lagasse * Returns:
395f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
396f169c0eaSGlenn Lagasse * be_errno_t - Failure
397f169c0eaSGlenn Lagasse * Scope:
398f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
399f169c0eaSGlenn Lagasse */
400f169c0eaSGlenn Lagasse int
be_append_menu(char * be_name,char * be_root_pool,char * boot_pool,char * be_orig_root_ds,char * description)401f169c0eaSGlenn Lagasse be_append_menu(char *be_name, char *be_root_pool, char *boot_pool,
402f169c0eaSGlenn Lagasse char *be_orig_root_ds, char *description)
403f169c0eaSGlenn Lagasse {
404f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL;
405f169c0eaSGlenn Lagasse char menu_file[MAXPATHLEN];
406f169c0eaSGlenn Lagasse char be_root_ds[MAXPATHLEN];
407f169c0eaSGlenn Lagasse char line[BUFSIZ];
408f169c0eaSGlenn Lagasse char temp_line[BUFSIZ];
409f169c0eaSGlenn Lagasse char title[MAXPATHLEN];
410f169c0eaSGlenn Lagasse char *entries[BUFSIZ];
411f169c0eaSGlenn Lagasse char *tmp_entries[BUFSIZ];
412f169c0eaSGlenn Lagasse char *pool_mntpnt = NULL;
413f169c0eaSGlenn Lagasse char *ptmp_mntpnt = NULL;
414f169c0eaSGlenn Lagasse char *orig_mntpnt = NULL;
415f169c0eaSGlenn Lagasse boolean_t found_be = B_FALSE;
416f169c0eaSGlenn Lagasse boolean_t found_orig_be = B_FALSE;
417f169c0eaSGlenn Lagasse boolean_t found_title = B_FALSE;
418f169c0eaSGlenn Lagasse boolean_t pool_mounted = B_FALSE;
419f169c0eaSGlenn Lagasse boolean_t collect_lines = B_FALSE;
420f169c0eaSGlenn Lagasse FILE *menu_fp = NULL;
421f169c0eaSGlenn Lagasse int err = 0, ret = BE_SUCCESS;
422f169c0eaSGlenn Lagasse int i, num_tmp_lines = 0, num_lines = 0;
423f169c0eaSGlenn Lagasse
424f169c0eaSGlenn Lagasse if (be_name == NULL || be_root_pool == NULL)
425f169c0eaSGlenn Lagasse return (BE_ERR_INVAL);
426f169c0eaSGlenn Lagasse
427f169c0eaSGlenn Lagasse if (boot_pool == NULL)
428f169c0eaSGlenn Lagasse boot_pool = be_root_pool;
429f169c0eaSGlenn Lagasse
430f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
431f169c0eaSGlenn Lagasse be_print_err(gettext("be_append_menu: failed to open "
432f169c0eaSGlenn Lagasse "pool dataset for %s: %s\n"), be_root_pool,
433f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
434f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs));
435f169c0eaSGlenn Lagasse }
436f169c0eaSGlenn Lagasse
437f169c0eaSGlenn Lagasse /*
438f169c0eaSGlenn Lagasse * Check to see if the pool's dataset is mounted. If it isn't we'll
439f169c0eaSGlenn Lagasse * attempt to mount it.
440f169c0eaSGlenn Lagasse */
441f169c0eaSGlenn Lagasse if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
442f169c0eaSGlenn Lagasse &pool_mounted)) != BE_SUCCESS) {
443f169c0eaSGlenn Lagasse be_print_err(gettext("be_append_menu: pool dataset "
444f169c0eaSGlenn Lagasse "(%s) could not be mounted\n"), be_root_pool);
445f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
446f169c0eaSGlenn Lagasse return (ret);
447f169c0eaSGlenn Lagasse }
448f169c0eaSGlenn Lagasse
449f169c0eaSGlenn Lagasse /*
450f169c0eaSGlenn Lagasse * Get the mountpoint for the root pool dataset.
451f169c0eaSGlenn Lagasse */
452f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
453f169c0eaSGlenn Lagasse be_print_err(gettext("be_append_menu: pool "
454f169c0eaSGlenn Lagasse "dataset (%s) is not mounted. Can't set "
455f169c0eaSGlenn Lagasse "the default BE in the grub menu.\n"), be_root_pool);
456f169c0eaSGlenn Lagasse ret = BE_ERR_NO_MENU;
457f169c0eaSGlenn Lagasse goto cleanup;
458f169c0eaSGlenn Lagasse }
459f169c0eaSGlenn Lagasse
460f169c0eaSGlenn Lagasse /*
461f169c0eaSGlenn Lagasse * Check to see if this system supports grub
462f169c0eaSGlenn Lagasse */
463f169c0eaSGlenn Lagasse if (be_has_grub()) {
464f169c0eaSGlenn Lagasse (void) snprintf(menu_file, sizeof (menu_file),
465f169c0eaSGlenn Lagasse "%s%s", pool_mntpnt, BE_GRUB_MENU);
466f169c0eaSGlenn Lagasse } else {
467f169c0eaSGlenn Lagasse (void) snprintf(menu_file, sizeof (menu_file),
468f169c0eaSGlenn Lagasse "%s%s", pool_mntpnt, BE_SPARC_MENU);
469f169c0eaSGlenn Lagasse }
470f169c0eaSGlenn Lagasse
471f169c0eaSGlenn Lagasse be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds));
472f169c0eaSGlenn Lagasse
473f169c0eaSGlenn Lagasse /*
474f169c0eaSGlenn Lagasse * Iterate through menu first to make sure the BE doesn't already
475f169c0eaSGlenn Lagasse * have an entry in the menu.
476f169c0eaSGlenn Lagasse *
477f169c0eaSGlenn Lagasse * Additionally while iterating through the menu, if we have an
478f169c0eaSGlenn Lagasse * original root dataset for a BE we're cloning from, we need to keep
479f169c0eaSGlenn Lagasse * track of that BE's menu entry. We will then use the lines from
480f169c0eaSGlenn Lagasse * that entry to create the entry for the new BE.
481f169c0eaSGlenn Lagasse */
482de1ab35cSAlexander Eremin if ((ret = be_open_menu(be_root_pool, menu_file,
483f169c0eaSGlenn Lagasse &menu_fp, "r", B_TRUE)) != BE_SUCCESS) {
484f169c0eaSGlenn Lagasse goto cleanup;
485f169c0eaSGlenn Lagasse } else if (menu_fp == NULL) {
486f169c0eaSGlenn Lagasse ret = BE_ERR_NO_MENU;
487f169c0eaSGlenn Lagasse goto cleanup;
488f169c0eaSGlenn Lagasse }
489f169c0eaSGlenn Lagasse
490f169c0eaSGlenn Lagasse free(pool_mntpnt);
491f169c0eaSGlenn Lagasse pool_mntpnt = NULL;
492f169c0eaSGlenn Lagasse
493f169c0eaSGlenn Lagasse while (fgets(line, BUFSIZ, menu_fp)) {
494f169c0eaSGlenn Lagasse char *tok = NULL;
495f169c0eaSGlenn Lagasse
496f169c0eaSGlenn Lagasse (void) strlcpy(temp_line, line, BUFSIZ);
497f169c0eaSGlenn Lagasse tok = strtok(line, BE_WHITE_SPACE);
498f169c0eaSGlenn Lagasse
499f169c0eaSGlenn Lagasse if (tok == NULL || tok[0] == '#') {
500f169c0eaSGlenn Lagasse continue;
501f169c0eaSGlenn Lagasse } else if (strcmp(tok, "title") == 0) {
502f169c0eaSGlenn Lagasse collect_lines = B_FALSE;
503f169c0eaSGlenn Lagasse if ((tok = strtok(NULL, "\n")) == NULL)
504f169c0eaSGlenn Lagasse (void) strlcpy(title, "", sizeof (title));
505f169c0eaSGlenn Lagasse else
506f169c0eaSGlenn Lagasse (void) strlcpy(title, tok, sizeof (title));
507f169c0eaSGlenn Lagasse found_title = B_TRUE;
508f169c0eaSGlenn Lagasse
509f169c0eaSGlenn Lagasse if (num_tmp_lines != 0) {
510f169c0eaSGlenn Lagasse for (i = 0; i < num_tmp_lines; i++) {
511f169c0eaSGlenn Lagasse free(tmp_entries[i]);
512f169c0eaSGlenn Lagasse tmp_entries[i] = NULL;
513f169c0eaSGlenn Lagasse }
514f169c0eaSGlenn Lagasse num_tmp_lines = 0;
515f169c0eaSGlenn Lagasse }
516f169c0eaSGlenn Lagasse } else if (strcmp(tok, "bootfs") == 0) {
517f169c0eaSGlenn Lagasse char *bootfs = strtok(NULL, BE_WHITE_SPACE);
518f169c0eaSGlenn Lagasse found_title = B_FALSE;
519f169c0eaSGlenn Lagasse if (bootfs == NULL)
520f169c0eaSGlenn Lagasse continue;
521f169c0eaSGlenn Lagasse
522f169c0eaSGlenn Lagasse if (strcmp(bootfs, be_root_ds) == 0) {
523f169c0eaSGlenn Lagasse found_be = B_TRUE;
524f169c0eaSGlenn Lagasse break;
525f169c0eaSGlenn Lagasse }
526f169c0eaSGlenn Lagasse
527f169c0eaSGlenn Lagasse if (be_orig_root_ds != NULL &&
528f169c0eaSGlenn Lagasse strcmp(bootfs, be_orig_root_ds) == 0 &&
529f169c0eaSGlenn Lagasse !found_orig_be) {
530f169c0eaSGlenn Lagasse char str[BUFSIZ];
531f169c0eaSGlenn Lagasse found_orig_be = B_TRUE;
532f169c0eaSGlenn Lagasse num_lines = 0;
533f169c0eaSGlenn Lagasse /*
534f169c0eaSGlenn Lagasse * Store the new title line
535f169c0eaSGlenn Lagasse */
536f169c0eaSGlenn Lagasse (void) snprintf(str, BUFSIZ, "title %s\n",
537f169c0eaSGlenn Lagasse description ? description : be_name);
538f169c0eaSGlenn Lagasse entries[num_lines] = strdup(str);
539f169c0eaSGlenn Lagasse num_lines++;
540f169c0eaSGlenn Lagasse /*
541f169c0eaSGlenn Lagasse * If there are any lines between the title
542f169c0eaSGlenn Lagasse * and the bootfs line store these. Also
543f169c0eaSGlenn Lagasse * free the temporary lines.
544f169c0eaSGlenn Lagasse */
545f169c0eaSGlenn Lagasse for (i = 0; i < num_tmp_lines; i++) {
546f169c0eaSGlenn Lagasse entries[num_lines] = tmp_entries[i];
547f169c0eaSGlenn Lagasse tmp_entries[i] = NULL;
548f169c0eaSGlenn Lagasse num_lines++;
549f169c0eaSGlenn Lagasse }
550f169c0eaSGlenn Lagasse num_tmp_lines = 0;
551f169c0eaSGlenn Lagasse /*
552f169c0eaSGlenn Lagasse * Store the new bootfs line.
553f169c0eaSGlenn Lagasse */
554f169c0eaSGlenn Lagasse (void) snprintf(str, BUFSIZ, "bootfs %s\n",
555f169c0eaSGlenn Lagasse be_root_ds);
556f169c0eaSGlenn Lagasse entries[num_lines] = strdup(str);
557f169c0eaSGlenn Lagasse num_lines++;
558f169c0eaSGlenn Lagasse collect_lines = B_TRUE;
559f169c0eaSGlenn Lagasse }
560f169c0eaSGlenn Lagasse } else if (found_orig_be && collect_lines) {
561f169c0eaSGlenn Lagasse /*
562f169c0eaSGlenn Lagasse * get the rest of the lines for the original BE and
563f169c0eaSGlenn Lagasse * store them.
564f169c0eaSGlenn Lagasse */
565f169c0eaSGlenn Lagasse if (strstr(line, BE_GRUB_COMMENT) != NULL ||
566f169c0eaSGlenn Lagasse strstr(line, "BOOTADM") != NULL)
567f169c0eaSGlenn Lagasse continue;
568e77c795bSGarrett D'Amore if (strcmp(tok, "splashimage") == 0) {
569e77c795bSGarrett D'Amore entries[num_lines] =
570e77c795bSGarrett D'Amore strdup("splashimage "
571e77c795bSGarrett D'Amore "/boot/splashimage.xpm\n");
572e77c795bSGarrett D'Amore } else {
573f169c0eaSGlenn Lagasse entries[num_lines] = strdup(temp_line);
574e77c795bSGarrett D'Amore }
575f169c0eaSGlenn Lagasse num_lines++;
576f169c0eaSGlenn Lagasse } else if (found_title && !found_orig_be) {
577f169c0eaSGlenn Lagasse tmp_entries[num_tmp_lines] = strdup(temp_line);
578f169c0eaSGlenn Lagasse num_tmp_lines++;
579f169c0eaSGlenn Lagasse }
580f169c0eaSGlenn Lagasse }
581f169c0eaSGlenn Lagasse
582f169c0eaSGlenn Lagasse (void) fclose(menu_fp);
583f169c0eaSGlenn Lagasse
584f169c0eaSGlenn Lagasse if (found_be) {
585f169c0eaSGlenn Lagasse /*
586f169c0eaSGlenn Lagasse * If an entry for this BE was already in the menu, then if
587f169c0eaSGlenn Lagasse * that entry's title matches what we would have put in
588f169c0eaSGlenn Lagasse * return success. Otherwise return failure.
589f169c0eaSGlenn Lagasse */
590f169c0eaSGlenn Lagasse char *new_title = description ? description : be_name;
591f169c0eaSGlenn Lagasse
592f169c0eaSGlenn Lagasse if (strcmp(title, new_title) == 0) {
593f169c0eaSGlenn Lagasse ret = BE_SUCCESS;
594f169c0eaSGlenn Lagasse goto cleanup;
595f169c0eaSGlenn Lagasse } else {
596f169c0eaSGlenn Lagasse if (be_remove_menu(be_name, be_root_pool,
597f169c0eaSGlenn Lagasse boot_pool) != BE_SUCCESS) {
598f169c0eaSGlenn Lagasse be_print_err(gettext("be_append_menu: "
599f169c0eaSGlenn Lagasse "Failed to remove existing unusable "
600f169c0eaSGlenn Lagasse "entry '%s' in boot menu.\n"), be_name);
601f169c0eaSGlenn Lagasse ret = BE_ERR_BE_EXISTS;
602f169c0eaSGlenn Lagasse goto cleanup;
603f169c0eaSGlenn Lagasse }
604f169c0eaSGlenn Lagasse }
605f169c0eaSGlenn Lagasse }
606f169c0eaSGlenn Lagasse
607f169c0eaSGlenn Lagasse /* Append BE entry to the end of the file */
608f169c0eaSGlenn Lagasse menu_fp = fopen(menu_file, "a+");
609f169c0eaSGlenn Lagasse err = errno;
610f169c0eaSGlenn Lagasse if (menu_fp == NULL) {
611f169c0eaSGlenn Lagasse be_print_err(gettext("be_append_menu: failed "
612f169c0eaSGlenn Lagasse "to open menu.lst file %s\n"), menu_file);
613f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
614f169c0eaSGlenn Lagasse goto cleanup;
615f169c0eaSGlenn Lagasse }
616f169c0eaSGlenn Lagasse
617f169c0eaSGlenn Lagasse if (found_orig_be) {
618f169c0eaSGlenn Lagasse /*
619f169c0eaSGlenn Lagasse * write out all the stored lines
620f169c0eaSGlenn Lagasse */
621f169c0eaSGlenn Lagasse for (i = 0; i < num_lines; i++) {
622f169c0eaSGlenn Lagasse (void) fprintf(menu_fp, "%s", entries[i]);
623f169c0eaSGlenn Lagasse free(entries[i]);
624f169c0eaSGlenn Lagasse }
625f169c0eaSGlenn Lagasse num_lines = 0;
626f169c0eaSGlenn Lagasse
627f169c0eaSGlenn Lagasse /*
628f169c0eaSGlenn Lagasse * Check to see if this system supports grub
629f169c0eaSGlenn Lagasse */
630f169c0eaSGlenn Lagasse if (be_has_grub())
631f169c0eaSGlenn Lagasse (void) fprintf(menu_fp, "%s\n", BE_GRUB_COMMENT);
632f169c0eaSGlenn Lagasse ret = BE_SUCCESS;
633f169c0eaSGlenn Lagasse } else {
634f169c0eaSGlenn Lagasse (void) fprintf(menu_fp, "title %s\n",
635f169c0eaSGlenn Lagasse description ? description : be_name);
636f169c0eaSGlenn Lagasse (void) fprintf(menu_fp, "bootfs %s\n", be_root_ds);
637f169c0eaSGlenn Lagasse
638f169c0eaSGlenn Lagasse /*
639f169c0eaSGlenn Lagasse * Check to see if this system supports grub
640f169c0eaSGlenn Lagasse */
641f169c0eaSGlenn Lagasse if (be_has_grub()) {
642f169c0eaSGlenn Lagasse (void) fprintf(menu_fp, "kernel$ "
643f169c0eaSGlenn Lagasse "/platform/i86pc/kernel/$ISADIR/unix -B "
644f169c0eaSGlenn Lagasse "$ZFS-BOOTFS\n");
645f169c0eaSGlenn Lagasse (void) fprintf(menu_fp, "module$ "
646f169c0eaSGlenn Lagasse "/platform/i86pc/$ISADIR/boot_archive\n");
647f169c0eaSGlenn Lagasse (void) fprintf(menu_fp, "%s\n", BE_GRUB_COMMENT);
648f169c0eaSGlenn Lagasse }
649f169c0eaSGlenn Lagasse ret = BE_SUCCESS;
650f169c0eaSGlenn Lagasse }
651f169c0eaSGlenn Lagasse (void) fclose(menu_fp);
652f169c0eaSGlenn Lagasse cleanup:
653f169c0eaSGlenn Lagasse if (pool_mounted) {
654f169c0eaSGlenn Lagasse int err = BE_SUCCESS;
655f169c0eaSGlenn Lagasse err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
656f169c0eaSGlenn Lagasse if (ret == BE_SUCCESS)
657f169c0eaSGlenn Lagasse ret = err;
658f169c0eaSGlenn Lagasse free(orig_mntpnt);
659f169c0eaSGlenn Lagasse free(ptmp_mntpnt);
660f169c0eaSGlenn Lagasse }
661f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
662f169c0eaSGlenn Lagasse if (num_tmp_lines > 0) {
663f169c0eaSGlenn Lagasse for (i = 0; i < num_tmp_lines; i++) {
664f169c0eaSGlenn Lagasse free(tmp_entries[i]);
665f169c0eaSGlenn Lagasse tmp_entries[i] = NULL;
666f169c0eaSGlenn Lagasse }
667f169c0eaSGlenn Lagasse }
668f169c0eaSGlenn Lagasse if (num_lines > 0) {
669f169c0eaSGlenn Lagasse for (i = 0; i < num_lines; i++) {
670f169c0eaSGlenn Lagasse free(entries[i]);
671f169c0eaSGlenn Lagasse entries[i] = NULL;
672f169c0eaSGlenn Lagasse }
673f169c0eaSGlenn Lagasse }
674f169c0eaSGlenn Lagasse return (ret);
675f169c0eaSGlenn Lagasse }
676f169c0eaSGlenn Lagasse
677f169c0eaSGlenn Lagasse /*
678f169c0eaSGlenn Lagasse * Function: be_remove_menu
679f169c0eaSGlenn Lagasse * Description: Removes a BE's entry from a menu.lst file.
680f169c0eaSGlenn Lagasse * Parameters:
681f169c0eaSGlenn Lagasse * be_name - the name of BE whose entry is to be removed from
682f169c0eaSGlenn Lagasse * the menu.lst file.
683f169c0eaSGlenn Lagasse * be_root_pool - the pool that be_name lives in.
684f169c0eaSGlenn Lagasse * boot_pool - the pool where the BE is, if different than
685f169c0eaSGlenn Lagasse * the pool containing the boot menu. If this is
686f169c0eaSGlenn Lagasse * NULL it will be set to be_root_pool.
687f169c0eaSGlenn Lagasse * Returns:
688f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
689f169c0eaSGlenn Lagasse * be_errno_t - Failure
690f169c0eaSGlenn Lagasse * Scope:
691f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
692f169c0eaSGlenn Lagasse */
693f169c0eaSGlenn Lagasse int
be_remove_menu(char * be_name,char * be_root_pool,char * boot_pool)694f169c0eaSGlenn Lagasse be_remove_menu(char *be_name, char *be_root_pool, char *boot_pool)
695f169c0eaSGlenn Lagasse {
696f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL;
697f169c0eaSGlenn Lagasse char be_root_ds[MAXPATHLEN];
698f169c0eaSGlenn Lagasse char **buffer = NULL;
699f169c0eaSGlenn Lagasse char menu_buf[BUFSIZ];
700f169c0eaSGlenn Lagasse char menu[MAXPATHLEN];
701f169c0eaSGlenn Lagasse char *pool_mntpnt = NULL;
702f169c0eaSGlenn Lagasse char *ptmp_mntpnt = NULL;
703f169c0eaSGlenn Lagasse char *orig_mntpnt = NULL;
704f169c0eaSGlenn Lagasse char *tmp_menu = NULL;
705f169c0eaSGlenn Lagasse FILE *menu_fp = NULL;
706f169c0eaSGlenn Lagasse FILE *tmp_menu_fp = NULL;
707f169c0eaSGlenn Lagasse struct stat sb;
708f169c0eaSGlenn Lagasse int ret = BE_SUCCESS;
709f169c0eaSGlenn Lagasse int i;
710f169c0eaSGlenn Lagasse int fd;
711f169c0eaSGlenn Lagasse int err = 0;
712f169c0eaSGlenn Lagasse int nlines = 0;
713f169c0eaSGlenn Lagasse int default_entry = 0;
714f169c0eaSGlenn Lagasse int entry_cnt = 0;
715f169c0eaSGlenn Lagasse int entry_del = 0;
716f169c0eaSGlenn Lagasse int num_entry_del = 0;
717f169c0eaSGlenn Lagasse int tmp_menu_len = 0;
718f169c0eaSGlenn Lagasse boolean_t write = B_TRUE;
719f169c0eaSGlenn Lagasse boolean_t do_buffer = B_FALSE;
720f169c0eaSGlenn Lagasse boolean_t pool_mounted = B_FALSE;
721f169c0eaSGlenn Lagasse
722f169c0eaSGlenn Lagasse if (boot_pool == NULL)
723f169c0eaSGlenn Lagasse boot_pool = be_root_pool;
724f169c0eaSGlenn Lagasse
725f169c0eaSGlenn Lagasse /* Get name of BE's root dataset */
726f169c0eaSGlenn Lagasse be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds));
727f169c0eaSGlenn Lagasse
728f169c0eaSGlenn Lagasse /* Get handle to pool dataset */
729f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
730f169c0eaSGlenn Lagasse be_print_err(gettext("be_remove_menu: "
731f169c0eaSGlenn Lagasse "failed to open pool dataset for %s: %s"),
732f169c0eaSGlenn Lagasse be_root_pool, libzfs_error_description(g_zfs));
733f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs));
734f169c0eaSGlenn Lagasse }
735f169c0eaSGlenn Lagasse
736f169c0eaSGlenn Lagasse /*
737f169c0eaSGlenn Lagasse * Check to see if the pool's dataset is mounted. If it isn't we'll
738f169c0eaSGlenn Lagasse * attempt to mount it.
739f169c0eaSGlenn Lagasse */
740f169c0eaSGlenn Lagasse if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
741f169c0eaSGlenn Lagasse &pool_mounted)) != BE_SUCCESS) {
742f169c0eaSGlenn Lagasse be_print_err(gettext("be_remove_menu: pool dataset "
743f169c0eaSGlenn Lagasse "(%s) could not be mounted\n"), be_root_pool);
744f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
745f169c0eaSGlenn Lagasse return (ret);
746f169c0eaSGlenn Lagasse }
747f169c0eaSGlenn Lagasse
748f169c0eaSGlenn Lagasse /*
749f169c0eaSGlenn Lagasse * Get the mountpoint for the root pool dataset.
750f169c0eaSGlenn Lagasse */
751f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
752f169c0eaSGlenn Lagasse be_print_err(gettext("be_remove_menu: pool "
753f169c0eaSGlenn Lagasse "dataset (%s) is not mounted. Can't set "
754f169c0eaSGlenn Lagasse "the default BE in the grub menu.\n"), be_root_pool);
755f169c0eaSGlenn Lagasse ret = BE_ERR_NO_MENU;
756f169c0eaSGlenn Lagasse goto cleanup;
757f169c0eaSGlenn Lagasse }
758f169c0eaSGlenn Lagasse
759f169c0eaSGlenn Lagasse /* Get path to boot menu */
760f169c0eaSGlenn Lagasse (void) strlcpy(menu, pool_mntpnt, sizeof (menu));
761f169c0eaSGlenn Lagasse
762f169c0eaSGlenn Lagasse /*
763f169c0eaSGlenn Lagasse * Check to see if this system supports grub
764f169c0eaSGlenn Lagasse */
765f169c0eaSGlenn Lagasse if (be_has_grub())
766f169c0eaSGlenn Lagasse (void) strlcat(menu, BE_GRUB_MENU, sizeof (menu));
767f169c0eaSGlenn Lagasse else
768f169c0eaSGlenn Lagasse (void) strlcat(menu, BE_SPARC_MENU, sizeof (menu));
769f169c0eaSGlenn Lagasse
770f169c0eaSGlenn Lagasse /* Get handle to boot menu file */
771de1ab35cSAlexander Eremin if ((ret = be_open_menu(be_root_pool, menu, &menu_fp, "r",
772f169c0eaSGlenn Lagasse B_TRUE)) != BE_SUCCESS) {
773f169c0eaSGlenn Lagasse goto cleanup;
774f169c0eaSGlenn Lagasse } else if (menu_fp == NULL) {
775f169c0eaSGlenn Lagasse ret = BE_ERR_NO_MENU;
776f169c0eaSGlenn Lagasse goto cleanup;
777f169c0eaSGlenn Lagasse }
778f169c0eaSGlenn Lagasse
779f169c0eaSGlenn Lagasse free(pool_mntpnt);
780f169c0eaSGlenn Lagasse pool_mntpnt = NULL;
781f169c0eaSGlenn Lagasse
782f169c0eaSGlenn Lagasse /* Grab the stats of the original menu file */
783f169c0eaSGlenn Lagasse if (stat(menu, &sb) != 0) {
784f169c0eaSGlenn Lagasse err = errno;
785f169c0eaSGlenn Lagasse be_print_err(gettext("be_remove_menu: "
786f169c0eaSGlenn Lagasse "failed to stat file %s: %s\n"), menu, strerror(err));
787f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
788f169c0eaSGlenn Lagasse goto cleanup;
789f169c0eaSGlenn Lagasse }
790f169c0eaSGlenn Lagasse
791f169c0eaSGlenn Lagasse /* Create a tmp file for the modified menu.lst */
792f169c0eaSGlenn Lagasse tmp_menu_len = strlen(menu) + 7;
793f169c0eaSGlenn Lagasse if ((tmp_menu = (char *)malloc(tmp_menu_len)) == NULL) {
794f169c0eaSGlenn Lagasse be_print_err(gettext("be_remove_menu: malloc failed\n"));
795f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM;
796f169c0eaSGlenn Lagasse goto cleanup;
797f169c0eaSGlenn Lagasse }
798f169c0eaSGlenn Lagasse (void) memset(tmp_menu, 0, tmp_menu_len);
799f169c0eaSGlenn Lagasse (void) strlcpy(tmp_menu, menu, tmp_menu_len);
800f169c0eaSGlenn Lagasse (void) strlcat(tmp_menu, "XXXXXX", tmp_menu_len);
801f169c0eaSGlenn Lagasse if ((fd = mkstemp(tmp_menu)) == -1) {
802f169c0eaSGlenn Lagasse err = errno;
803f169c0eaSGlenn Lagasse be_print_err(gettext("be_remove_menu: mkstemp failed\n"));
804f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
805f169c0eaSGlenn Lagasse free(tmp_menu);
806f169c0eaSGlenn Lagasse tmp_menu = NULL;
807f169c0eaSGlenn Lagasse goto cleanup;
808f169c0eaSGlenn Lagasse }
809f169c0eaSGlenn Lagasse if ((tmp_menu_fp = fdopen(fd, "w")) == NULL) {
810f169c0eaSGlenn Lagasse err = errno;
811f169c0eaSGlenn Lagasse be_print_err(gettext("be_remove_menu: "
812f169c0eaSGlenn Lagasse "could not open tmp file for write: %s\n"), strerror(err));
813f169c0eaSGlenn Lagasse (void) close(fd);
814f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
815f169c0eaSGlenn Lagasse goto cleanup;
816f169c0eaSGlenn Lagasse }
817f169c0eaSGlenn Lagasse
818f169c0eaSGlenn Lagasse while (fgets(menu_buf, BUFSIZ, menu_fp)) {
819f169c0eaSGlenn Lagasse char tline [BUFSIZ];
820f169c0eaSGlenn Lagasse char *tok = NULL;
821f169c0eaSGlenn Lagasse
822f169c0eaSGlenn Lagasse (void) strlcpy(tline, menu_buf, sizeof (tline));
823f169c0eaSGlenn Lagasse
824f169c0eaSGlenn Lagasse /* Tokenize line */
825f169c0eaSGlenn Lagasse tok = strtok(tline, BE_WHITE_SPACE);
826f169c0eaSGlenn Lagasse
827f169c0eaSGlenn Lagasse if (tok == NULL || tok[0] == '#') {
828f169c0eaSGlenn Lagasse /* Found empty line or comment line */
829f169c0eaSGlenn Lagasse if (do_buffer) {
830f169c0eaSGlenn Lagasse /* Buffer this line */
831f169c0eaSGlenn Lagasse if ((buffer = (char **)realloc(buffer,
832f169c0eaSGlenn Lagasse sizeof (char *)*(nlines + 1))) == NULL) {
833f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM;
834f169c0eaSGlenn Lagasse goto cleanup;
835f169c0eaSGlenn Lagasse }
836f169c0eaSGlenn Lagasse if ((buffer[nlines++] = strdup(menu_buf))
837f169c0eaSGlenn Lagasse == NULL) {
838f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM;
839f169c0eaSGlenn Lagasse goto cleanup;
840f169c0eaSGlenn Lagasse }
841f169c0eaSGlenn Lagasse
842f169c0eaSGlenn Lagasse } else if (write || strncmp(menu_buf, BE_GRUB_COMMENT,
843f169c0eaSGlenn Lagasse strlen(BE_GRUB_COMMENT)) != 0) {
844f169c0eaSGlenn Lagasse /* Write this line out */
845f169c0eaSGlenn Lagasse (void) fputs(menu_buf, tmp_menu_fp);
846f169c0eaSGlenn Lagasse }
847f169c0eaSGlenn Lagasse } else if (strcmp(tok, "default") == 0) {
848f169c0eaSGlenn Lagasse /*
849f169c0eaSGlenn Lagasse * Record what 'default' is set to because we might
850f169c0eaSGlenn Lagasse * need to adjust this upon deleting an entry.
851f169c0eaSGlenn Lagasse */
852f169c0eaSGlenn Lagasse tok = strtok(NULL, BE_WHITE_SPACE);
853f169c0eaSGlenn Lagasse
854f169c0eaSGlenn Lagasse if (tok != NULL) {
855f169c0eaSGlenn Lagasse default_entry = atoi(tok);
856f169c0eaSGlenn Lagasse }
857f169c0eaSGlenn Lagasse
858f169c0eaSGlenn Lagasse (void) fputs(menu_buf, tmp_menu_fp);
859f169c0eaSGlenn Lagasse } else if (strcmp(tok, "title") == 0) {
860f169c0eaSGlenn Lagasse /*
861f169c0eaSGlenn Lagasse * If we've reached a 'title' line and do_buffer is
862f169c0eaSGlenn Lagasse * is true, that means we've just buffered an entire
863f169c0eaSGlenn Lagasse * entry without finding a 'bootfs' directive. We
864f169c0eaSGlenn Lagasse * need to write that entry out and keep searching.
865f169c0eaSGlenn Lagasse */
866f169c0eaSGlenn Lagasse if (do_buffer) {
867f169c0eaSGlenn Lagasse for (i = 0; i < nlines; i++) {
868f169c0eaSGlenn Lagasse (void) fputs(buffer[i], tmp_menu_fp);
869f169c0eaSGlenn Lagasse free(buffer[i]);
870f169c0eaSGlenn Lagasse }
871f169c0eaSGlenn Lagasse free(buffer);
872f169c0eaSGlenn Lagasse buffer = NULL;
873f169c0eaSGlenn Lagasse nlines = 0;
874f169c0eaSGlenn Lagasse }
875f169c0eaSGlenn Lagasse
876f169c0eaSGlenn Lagasse /*
877f169c0eaSGlenn Lagasse * Turn writing off and buffering on, and increment
878f169c0eaSGlenn Lagasse * our entry counter.
879f169c0eaSGlenn Lagasse */
880f169c0eaSGlenn Lagasse write = B_FALSE;
881f169c0eaSGlenn Lagasse do_buffer = B_TRUE;
882f169c0eaSGlenn Lagasse entry_cnt++;
883f169c0eaSGlenn Lagasse
884f169c0eaSGlenn Lagasse /* Buffer this 'title' line */
885f169c0eaSGlenn Lagasse if ((buffer = (char **)realloc(buffer,
886f169c0eaSGlenn Lagasse sizeof (char *)*(nlines + 1))) == NULL) {
887f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM;
888f169c0eaSGlenn Lagasse goto cleanup;
889f169c0eaSGlenn Lagasse }
890f169c0eaSGlenn Lagasse if ((buffer[nlines++] = strdup(menu_buf)) == NULL) {
891f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM;
892f169c0eaSGlenn Lagasse goto cleanup;
893f169c0eaSGlenn Lagasse }
894f169c0eaSGlenn Lagasse
895f169c0eaSGlenn Lagasse } else if (strcmp(tok, "bootfs") == 0) {
896f169c0eaSGlenn Lagasse char *bootfs = NULL;
897f169c0eaSGlenn Lagasse
898f169c0eaSGlenn Lagasse /*
899f169c0eaSGlenn Lagasse * Found a 'bootfs' line. See if it matches the
900f169c0eaSGlenn Lagasse * BE we're looking for.
901f169c0eaSGlenn Lagasse */
902f169c0eaSGlenn Lagasse if ((bootfs = strtok(NULL, BE_WHITE_SPACE)) == NULL ||
903f169c0eaSGlenn Lagasse strcmp(bootfs, be_root_ds) != 0) {
904f169c0eaSGlenn Lagasse /*
905f169c0eaSGlenn Lagasse * Either there's nothing after the 'bootfs'
906f169c0eaSGlenn Lagasse * or this is not the BE we're looking for,
907f169c0eaSGlenn Lagasse * write out the line(s) we've buffered since
908f169c0eaSGlenn Lagasse * finding the title.
909f169c0eaSGlenn Lagasse */
910f169c0eaSGlenn Lagasse for (i = 0; i < nlines; i++) {
911f169c0eaSGlenn Lagasse (void) fputs(buffer[i], tmp_menu_fp);
912f169c0eaSGlenn Lagasse free(buffer[i]);
913f169c0eaSGlenn Lagasse }
914f169c0eaSGlenn Lagasse free(buffer);
915f169c0eaSGlenn Lagasse buffer = NULL;
916f169c0eaSGlenn Lagasse nlines = 0;
917f169c0eaSGlenn Lagasse
918f169c0eaSGlenn Lagasse /*
919f169c0eaSGlenn Lagasse * Turn writing back on, and turn off buffering
920f169c0eaSGlenn Lagasse * since this isn't the entry we're looking
921f169c0eaSGlenn Lagasse * for.
922f169c0eaSGlenn Lagasse */
923f169c0eaSGlenn Lagasse write = B_TRUE;
924f169c0eaSGlenn Lagasse do_buffer = B_FALSE;
925f169c0eaSGlenn Lagasse
926f169c0eaSGlenn Lagasse /* Write this 'bootfs' line out. */
927f169c0eaSGlenn Lagasse (void) fputs(menu_buf, tmp_menu_fp);
928f169c0eaSGlenn Lagasse } else {
929f169c0eaSGlenn Lagasse /*
930f169c0eaSGlenn Lagasse * Found the entry we're looking for.
931f169c0eaSGlenn Lagasse * Record its entry number, increment the
932f169c0eaSGlenn Lagasse * number of entries we've deleted, and turn
933f169c0eaSGlenn Lagasse * writing off. Also, throw away the lines
934f169c0eaSGlenn Lagasse * we've buffered for this entry so far, we
935f169c0eaSGlenn Lagasse * don't need them.
936f169c0eaSGlenn Lagasse */
937f169c0eaSGlenn Lagasse entry_del = entry_cnt - 1;
938f169c0eaSGlenn Lagasse num_entry_del++;
939f169c0eaSGlenn Lagasse write = B_FALSE;
940f169c0eaSGlenn Lagasse do_buffer = B_FALSE;
941f169c0eaSGlenn Lagasse
942f169c0eaSGlenn Lagasse for (i = 0; i < nlines; i++) {
943f169c0eaSGlenn Lagasse free(buffer[i]);
944f169c0eaSGlenn Lagasse }
945f169c0eaSGlenn Lagasse free(buffer);
946f169c0eaSGlenn Lagasse buffer = NULL;
947f169c0eaSGlenn Lagasse nlines = 0;
948f169c0eaSGlenn Lagasse }
949f169c0eaSGlenn Lagasse } else {
950f169c0eaSGlenn Lagasse if (do_buffer) {
951f169c0eaSGlenn Lagasse /* Buffer this line */
952f169c0eaSGlenn Lagasse if ((buffer = (char **)realloc(buffer,
953f169c0eaSGlenn Lagasse sizeof (char *)*(nlines + 1))) == NULL) {
954f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM;
955f169c0eaSGlenn Lagasse goto cleanup;
956f169c0eaSGlenn Lagasse }
957f169c0eaSGlenn Lagasse if ((buffer[nlines++] = strdup(menu_buf))
958f169c0eaSGlenn Lagasse == NULL) {
959f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM;
960f169c0eaSGlenn Lagasse goto cleanup;
961f169c0eaSGlenn Lagasse }
962f169c0eaSGlenn Lagasse } else if (write) {
963f169c0eaSGlenn Lagasse /* Write this line out */
964f169c0eaSGlenn Lagasse (void) fputs(menu_buf, tmp_menu_fp);
965f169c0eaSGlenn Lagasse }
966f169c0eaSGlenn Lagasse }
967f169c0eaSGlenn Lagasse }
968f169c0eaSGlenn Lagasse
969f169c0eaSGlenn Lagasse (void) fclose(menu_fp);
970f169c0eaSGlenn Lagasse menu_fp = NULL;
971f169c0eaSGlenn Lagasse (void) fclose(tmp_menu_fp);
972f169c0eaSGlenn Lagasse tmp_menu_fp = NULL;
973f169c0eaSGlenn Lagasse
974f169c0eaSGlenn Lagasse /* Copy the modified menu.lst into place */
975f169c0eaSGlenn Lagasse if (rename(tmp_menu, menu) != 0) {
976f169c0eaSGlenn Lagasse err = errno;
977f169c0eaSGlenn Lagasse be_print_err(gettext("be_remove_menu: "
978f169c0eaSGlenn Lagasse "failed to rename file %s to %s: %s\n"),
979f169c0eaSGlenn Lagasse tmp_menu, menu, strerror(err));
980f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
981f169c0eaSGlenn Lagasse goto cleanup;
982f169c0eaSGlenn Lagasse }
983f169c0eaSGlenn Lagasse free(tmp_menu);
984f169c0eaSGlenn Lagasse tmp_menu = NULL;
985f169c0eaSGlenn Lagasse
986f169c0eaSGlenn Lagasse /*
987f169c0eaSGlenn Lagasse * If we've removed an entry, see if we need to
988f169c0eaSGlenn Lagasse * adjust the default value in the menu.lst. If the
989f169c0eaSGlenn Lagasse * entry we've deleted comes before the default entry
990f169c0eaSGlenn Lagasse * we need to adjust the default value accordingly.
991f169c0eaSGlenn Lagasse *
992f169c0eaSGlenn Lagasse * be_has_grub is used here to check to see if this system
993f169c0eaSGlenn Lagasse * supports grub.
994f169c0eaSGlenn Lagasse */
995f169c0eaSGlenn Lagasse if (be_has_grub() && num_entry_del > 0) {
996f169c0eaSGlenn Lagasse if (entry_del <= default_entry) {
997f169c0eaSGlenn Lagasse default_entry = default_entry - num_entry_del;
998f169c0eaSGlenn Lagasse if (default_entry < 0)
999f169c0eaSGlenn Lagasse default_entry = 0;
1000f169c0eaSGlenn Lagasse
1001f169c0eaSGlenn Lagasse /*
1002f169c0eaSGlenn Lagasse * Adjust the default value by rewriting the
1003f169c0eaSGlenn Lagasse * menu.lst file. This may be overkill, but to
1004f169c0eaSGlenn Lagasse * preserve the location of the 'default' entry
1005f169c0eaSGlenn Lagasse * in the file, we need to do this.
1006f169c0eaSGlenn Lagasse */
1007f169c0eaSGlenn Lagasse
1008f169c0eaSGlenn Lagasse /* Get handle to boot menu file */
1009f169c0eaSGlenn Lagasse if ((menu_fp = fopen(menu, "r")) == NULL) {
1010f169c0eaSGlenn Lagasse err = errno;
1011f169c0eaSGlenn Lagasse be_print_err(gettext("be_remove_menu: "
1012f169c0eaSGlenn Lagasse "failed to open menu.lst (%s): %s\n"),
1013f169c0eaSGlenn Lagasse menu, strerror(err));
1014f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1015f169c0eaSGlenn Lagasse goto cleanup;
1016f169c0eaSGlenn Lagasse }
1017f169c0eaSGlenn Lagasse
1018f169c0eaSGlenn Lagasse /* Create a tmp file for the modified menu.lst */
1019f169c0eaSGlenn Lagasse tmp_menu_len = strlen(menu) + 7;
1020f169c0eaSGlenn Lagasse if ((tmp_menu = (char *)malloc(tmp_menu_len))
1021f169c0eaSGlenn Lagasse == NULL) {
1022f169c0eaSGlenn Lagasse be_print_err(gettext("be_remove_menu: "
1023f169c0eaSGlenn Lagasse "malloc failed\n"));
1024f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM;
1025f169c0eaSGlenn Lagasse goto cleanup;
1026f169c0eaSGlenn Lagasse }
1027f169c0eaSGlenn Lagasse (void) memset(tmp_menu, 0, tmp_menu_len);
1028f169c0eaSGlenn Lagasse (void) strlcpy(tmp_menu, menu, tmp_menu_len);
1029f169c0eaSGlenn Lagasse (void) strlcat(tmp_menu, "XXXXXX", tmp_menu_len);
1030f169c0eaSGlenn Lagasse if ((fd = mkstemp(tmp_menu)) == -1) {
1031f169c0eaSGlenn Lagasse err = errno;
1032f169c0eaSGlenn Lagasse be_print_err(gettext("be_remove_menu: "
1033f169c0eaSGlenn Lagasse "mkstemp failed: %s\n"), strerror(err));
1034f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1035f169c0eaSGlenn Lagasse free(tmp_menu);
1036f169c0eaSGlenn Lagasse tmp_menu = NULL;
1037f169c0eaSGlenn Lagasse goto cleanup;
1038f169c0eaSGlenn Lagasse }
1039f169c0eaSGlenn Lagasse if ((tmp_menu_fp = fdopen(fd, "w")) == NULL) {
1040f169c0eaSGlenn Lagasse err = errno;
1041f169c0eaSGlenn Lagasse be_print_err(gettext("be_remove_menu: "
1042f169c0eaSGlenn Lagasse "could not open tmp file for write: %s\n"),
1043f169c0eaSGlenn Lagasse strerror(err));
1044f169c0eaSGlenn Lagasse (void) close(fd);
1045f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1046f169c0eaSGlenn Lagasse goto cleanup;
1047f169c0eaSGlenn Lagasse }
1048f169c0eaSGlenn Lagasse
1049f169c0eaSGlenn Lagasse while (fgets(menu_buf, BUFSIZ, menu_fp)) {
1050f169c0eaSGlenn Lagasse char tline [BUFSIZ];
1051f169c0eaSGlenn Lagasse char *tok = NULL;
1052f169c0eaSGlenn Lagasse
1053f169c0eaSGlenn Lagasse (void) strlcpy(tline, menu_buf, sizeof (tline));
1054f169c0eaSGlenn Lagasse
1055f169c0eaSGlenn Lagasse /* Tokenize line */
1056f169c0eaSGlenn Lagasse tok = strtok(tline, BE_WHITE_SPACE);
1057f169c0eaSGlenn Lagasse
1058f169c0eaSGlenn Lagasse if (tok == NULL) {
1059f169c0eaSGlenn Lagasse /* Found empty line, write it out */
1060f169c0eaSGlenn Lagasse (void) fputs(menu_buf, tmp_menu_fp);
1061f169c0eaSGlenn Lagasse } else if (strcmp(tok, "default") == 0) {
1062f169c0eaSGlenn Lagasse /* Found the default line, adjust it */
1063f169c0eaSGlenn Lagasse (void) snprintf(tline, sizeof (tline),
1064f169c0eaSGlenn Lagasse "default %d\n", default_entry);
1065f169c0eaSGlenn Lagasse
1066f169c0eaSGlenn Lagasse (void) fputs(tline, tmp_menu_fp);
1067f169c0eaSGlenn Lagasse } else {
1068f169c0eaSGlenn Lagasse /* Pass through all other lines */
1069f169c0eaSGlenn Lagasse (void) fputs(menu_buf, tmp_menu_fp);
1070f169c0eaSGlenn Lagasse }
1071f169c0eaSGlenn Lagasse }
1072f169c0eaSGlenn Lagasse
1073f169c0eaSGlenn Lagasse (void) fclose(menu_fp);
1074f169c0eaSGlenn Lagasse menu_fp = NULL;
1075f169c0eaSGlenn Lagasse (void) fclose(tmp_menu_fp);
1076f169c0eaSGlenn Lagasse tmp_menu_fp = NULL;
1077f169c0eaSGlenn Lagasse
1078f169c0eaSGlenn Lagasse /* Copy the modified menu.lst into place */
1079f169c0eaSGlenn Lagasse if (rename(tmp_menu, menu) != 0) {
1080f169c0eaSGlenn Lagasse err = errno;
1081f169c0eaSGlenn Lagasse be_print_err(gettext("be_remove_menu: "
1082f169c0eaSGlenn Lagasse "failed to rename file %s to %s: %s\n"),
1083f169c0eaSGlenn Lagasse tmp_menu, menu, strerror(err));
1084f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1085f169c0eaSGlenn Lagasse goto cleanup;
1086f169c0eaSGlenn Lagasse }
1087f169c0eaSGlenn Lagasse
1088f169c0eaSGlenn Lagasse free(tmp_menu);
1089f169c0eaSGlenn Lagasse tmp_menu = NULL;
1090f169c0eaSGlenn Lagasse }
1091f169c0eaSGlenn Lagasse }
1092f169c0eaSGlenn Lagasse
1093f169c0eaSGlenn Lagasse /* Set the perms and ownership of the updated file */
1094f169c0eaSGlenn Lagasse if (chmod(menu, sb.st_mode) != 0) {
1095f169c0eaSGlenn Lagasse err = errno;
1096f169c0eaSGlenn Lagasse be_print_err(gettext("be_remove_menu: "
1097f169c0eaSGlenn Lagasse "failed to chmod %s: %s\n"), menu, strerror(err));
1098f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1099f169c0eaSGlenn Lagasse goto cleanup;
1100f169c0eaSGlenn Lagasse }
1101f169c0eaSGlenn Lagasse if (chown(menu, sb.st_uid, sb.st_gid) != 0) {
1102f169c0eaSGlenn Lagasse err = errno;
1103f169c0eaSGlenn Lagasse be_print_err(gettext("be_remove_menu: "
1104f169c0eaSGlenn Lagasse "failed to chown %s: %s\n"), menu, strerror(err));
1105f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1106f169c0eaSGlenn Lagasse goto cleanup;
1107f169c0eaSGlenn Lagasse }
1108f169c0eaSGlenn Lagasse
1109f169c0eaSGlenn Lagasse cleanup:
1110f169c0eaSGlenn Lagasse if (pool_mounted) {
1111f169c0eaSGlenn Lagasse int err = BE_SUCCESS;
1112f169c0eaSGlenn Lagasse err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1113f169c0eaSGlenn Lagasse if (ret == BE_SUCCESS)
1114f169c0eaSGlenn Lagasse ret = err;
1115f169c0eaSGlenn Lagasse free(orig_mntpnt);
1116f169c0eaSGlenn Lagasse free(ptmp_mntpnt);
1117f169c0eaSGlenn Lagasse }
1118f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1119f169c0eaSGlenn Lagasse
1120f169c0eaSGlenn Lagasse free(buffer);
1121f169c0eaSGlenn Lagasse if (menu_fp != NULL)
1122f169c0eaSGlenn Lagasse (void) fclose(menu_fp);
1123f169c0eaSGlenn Lagasse if (tmp_menu_fp != NULL)
1124f169c0eaSGlenn Lagasse (void) fclose(tmp_menu_fp);
1125f169c0eaSGlenn Lagasse if (tmp_menu != NULL) {
1126f169c0eaSGlenn Lagasse (void) unlink(tmp_menu);
1127f169c0eaSGlenn Lagasse free(tmp_menu);
1128f169c0eaSGlenn Lagasse }
1129f169c0eaSGlenn Lagasse
1130f169c0eaSGlenn Lagasse return (ret);
1131f169c0eaSGlenn Lagasse }
1132f169c0eaSGlenn Lagasse
1133f169c0eaSGlenn Lagasse /*
1134f169c0eaSGlenn Lagasse * Function: be_default_grub_bootfs
1135f169c0eaSGlenn Lagasse * Description: This function returns the dataset in the default entry of
1136f169c0eaSGlenn Lagasse * the grub menu. If no default entry is found with a valid bootfs
1137f169c0eaSGlenn Lagasse * entry NULL is returned.
1138f169c0eaSGlenn Lagasse * Parameters:
1139f169c0eaSGlenn Lagasse * be_root_pool - This is the name of the root pool where the
1140f169c0eaSGlenn Lagasse * grub menu can be found.
1141f169c0eaSGlenn Lagasse * def_bootfs - This is used to pass back the bootfs string. On
1142f169c0eaSGlenn Lagasse * error NULL is returned here.
1143f169c0eaSGlenn Lagasse * Returns:
1144f169c0eaSGlenn Lagasse * Success - BE_SUCCESS is returned.
1145f169c0eaSGlenn Lagasse * Failure - a be_errno_t is returned.
1146f169c0eaSGlenn Lagasse * Scope:
1147f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
1148f169c0eaSGlenn Lagasse */
1149f169c0eaSGlenn Lagasse int
be_default_grub_bootfs(const char * be_root_pool,char ** def_bootfs)1150f169c0eaSGlenn Lagasse be_default_grub_bootfs(const char *be_root_pool, char **def_bootfs)
1151f169c0eaSGlenn Lagasse {
1152f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL;
1153f169c0eaSGlenn Lagasse char grub_file[MAXPATHLEN];
1154f169c0eaSGlenn Lagasse FILE *menu_fp;
1155f169c0eaSGlenn Lagasse char line[BUFSIZ];
1156f169c0eaSGlenn Lagasse char *pool_mntpnt = NULL;
1157f169c0eaSGlenn Lagasse char *ptmp_mntpnt = NULL;
1158f169c0eaSGlenn Lagasse char *orig_mntpnt = NULL;
1159f169c0eaSGlenn Lagasse int default_entry = 0, entries = 0;
1160f169c0eaSGlenn Lagasse int found_default = 0;
1161f169c0eaSGlenn Lagasse int ret = BE_SUCCESS;
1162f169c0eaSGlenn Lagasse boolean_t pool_mounted = B_FALSE;
1163f169c0eaSGlenn Lagasse
1164f169c0eaSGlenn Lagasse errno = 0;
1165f169c0eaSGlenn Lagasse
1166f169c0eaSGlenn Lagasse /*
1167f169c0eaSGlenn Lagasse * Check to see if this system supports grub
1168f169c0eaSGlenn Lagasse */
1169f169c0eaSGlenn Lagasse if (!be_has_grub()) {
1170f169c0eaSGlenn Lagasse be_print_err(gettext("be_default_grub_bootfs: operation "
1171f169c0eaSGlenn Lagasse "not supported on this architecture\n"));
1172f169c0eaSGlenn Lagasse return (BE_ERR_NOTSUP);
1173f169c0eaSGlenn Lagasse }
1174f169c0eaSGlenn Lagasse
1175f169c0eaSGlenn Lagasse *def_bootfs = NULL;
1176f169c0eaSGlenn Lagasse
1177f169c0eaSGlenn Lagasse /* Get handle to pool dataset */
1178f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
1179f169c0eaSGlenn Lagasse be_print_err(gettext("be_default_grub_bootfs: "
1180f169c0eaSGlenn Lagasse "failed to open pool dataset for %s: %s"),
1181f169c0eaSGlenn Lagasse be_root_pool, libzfs_error_description(g_zfs));
1182f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs));
1183f169c0eaSGlenn Lagasse }
1184f169c0eaSGlenn Lagasse
1185f169c0eaSGlenn Lagasse /*
1186f169c0eaSGlenn Lagasse * Check to see if the pool's dataset is mounted. If it isn't we'll
1187f169c0eaSGlenn Lagasse * attempt to mount it.
1188f169c0eaSGlenn Lagasse */
1189f169c0eaSGlenn Lagasse if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
1190f169c0eaSGlenn Lagasse &pool_mounted)) != BE_SUCCESS) {
1191f169c0eaSGlenn Lagasse be_print_err(gettext("be_default_grub_bootfs: pool dataset "
1192f169c0eaSGlenn Lagasse "(%s) could not be mounted\n"), be_root_pool);
1193f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1194f169c0eaSGlenn Lagasse return (ret);
1195f169c0eaSGlenn Lagasse }
1196f169c0eaSGlenn Lagasse
1197f169c0eaSGlenn Lagasse /*
1198f169c0eaSGlenn Lagasse * Get the mountpoint for the root pool dataset.
1199f169c0eaSGlenn Lagasse */
1200f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1201f169c0eaSGlenn Lagasse be_print_err(gettext("be_default_grub_bootfs: failed "
1202f169c0eaSGlenn Lagasse "to get mount point for the root pool. Can't set "
1203f169c0eaSGlenn Lagasse "the default BE in the grub menu.\n"));
1204f169c0eaSGlenn Lagasse ret = BE_ERR_NO_MENU;
1205f169c0eaSGlenn Lagasse goto cleanup;
1206f169c0eaSGlenn Lagasse }
1207f169c0eaSGlenn Lagasse
1208f169c0eaSGlenn Lagasse (void) snprintf(grub_file, MAXPATHLEN, "%s%s",
1209f169c0eaSGlenn Lagasse pool_mntpnt, BE_GRUB_MENU);
1210f169c0eaSGlenn Lagasse
1211de1ab35cSAlexander Eremin if ((ret = be_open_menu((char *)be_root_pool, grub_file,
1212f169c0eaSGlenn Lagasse &menu_fp, "r", B_FALSE)) != BE_SUCCESS) {
1213f169c0eaSGlenn Lagasse goto cleanup;
1214f169c0eaSGlenn Lagasse } else if (menu_fp == NULL) {
1215f169c0eaSGlenn Lagasse ret = BE_ERR_NO_MENU;
1216f169c0eaSGlenn Lagasse goto cleanup;
1217f169c0eaSGlenn Lagasse }
1218f169c0eaSGlenn Lagasse
1219f169c0eaSGlenn Lagasse free(pool_mntpnt);
1220f169c0eaSGlenn Lagasse pool_mntpnt = NULL;
1221f169c0eaSGlenn Lagasse
1222f169c0eaSGlenn Lagasse while (fgets(line, BUFSIZ, menu_fp)) {
1223f169c0eaSGlenn Lagasse char *tok = strtok(line, BE_WHITE_SPACE);
1224f169c0eaSGlenn Lagasse
1225f169c0eaSGlenn Lagasse if (tok != NULL && tok[0] != '#') {
1226f169c0eaSGlenn Lagasse if (!found_default) {
1227f169c0eaSGlenn Lagasse if (strcmp(tok, "default") == 0) {
1228f169c0eaSGlenn Lagasse tok = strtok(NULL, BE_WHITE_SPACE);
1229f169c0eaSGlenn Lagasse if (tok != NULL) {
1230f169c0eaSGlenn Lagasse default_entry = atoi(tok);
1231f169c0eaSGlenn Lagasse rewind(menu_fp);
1232f169c0eaSGlenn Lagasse found_default = 1;
1233f169c0eaSGlenn Lagasse }
1234f169c0eaSGlenn Lagasse }
1235f169c0eaSGlenn Lagasse continue;
1236f169c0eaSGlenn Lagasse }
1237f169c0eaSGlenn Lagasse if (strcmp(tok, "title") == 0) {
1238f169c0eaSGlenn Lagasse entries++;
1239f169c0eaSGlenn Lagasse } else if (default_entry == entries - 1) {
1240f169c0eaSGlenn Lagasse if (strcmp(tok, "bootfs") == 0) {
1241f169c0eaSGlenn Lagasse tok = strtok(NULL, BE_WHITE_SPACE);
1242f169c0eaSGlenn Lagasse (void) fclose(menu_fp);
1243f169c0eaSGlenn Lagasse
1244f169c0eaSGlenn Lagasse if (tok == NULL) {
1245f169c0eaSGlenn Lagasse ret = BE_SUCCESS;
1246f169c0eaSGlenn Lagasse goto cleanup;
1247f169c0eaSGlenn Lagasse }
1248f169c0eaSGlenn Lagasse
1249f169c0eaSGlenn Lagasse if ((*def_bootfs = strdup(tok)) !=
1250f169c0eaSGlenn Lagasse NULL) {
1251f169c0eaSGlenn Lagasse ret = BE_SUCCESS;
1252f169c0eaSGlenn Lagasse goto cleanup;
1253f169c0eaSGlenn Lagasse }
1254f169c0eaSGlenn Lagasse be_print_err(gettext(
1255f169c0eaSGlenn Lagasse "be_default_grub_bootfs: "
1256f169c0eaSGlenn Lagasse "memory allocation failed\n"));
1257f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM;
1258f169c0eaSGlenn Lagasse goto cleanup;
1259f169c0eaSGlenn Lagasse }
1260f169c0eaSGlenn Lagasse } else if (default_entry < entries - 1) {
1261f169c0eaSGlenn Lagasse /*
1262f169c0eaSGlenn Lagasse * no bootfs entry for the default entry.
1263f169c0eaSGlenn Lagasse */
1264f169c0eaSGlenn Lagasse break;
1265f169c0eaSGlenn Lagasse }
1266f169c0eaSGlenn Lagasse }
1267f169c0eaSGlenn Lagasse }
1268f169c0eaSGlenn Lagasse (void) fclose(menu_fp);
1269f169c0eaSGlenn Lagasse
1270f169c0eaSGlenn Lagasse cleanup:
1271f169c0eaSGlenn Lagasse if (pool_mounted) {
1272f169c0eaSGlenn Lagasse int err = BE_SUCCESS;
1273f169c0eaSGlenn Lagasse err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1274f169c0eaSGlenn Lagasse if (ret == BE_SUCCESS)
1275f169c0eaSGlenn Lagasse ret = err;
1276f169c0eaSGlenn Lagasse free(orig_mntpnt);
1277f169c0eaSGlenn Lagasse free(ptmp_mntpnt);
1278f169c0eaSGlenn Lagasse }
1279f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1280f169c0eaSGlenn Lagasse return (ret);
1281f169c0eaSGlenn Lagasse }
1282f169c0eaSGlenn Lagasse
1283f169c0eaSGlenn Lagasse /*
1284f169c0eaSGlenn Lagasse * Function: be_change_grub_default
1285f169c0eaSGlenn Lagasse * Description: This function takes two parameters. These are the name of
1286f169c0eaSGlenn Lagasse * the BE we want to have as the default booted in the grub
1287f169c0eaSGlenn Lagasse * menu and the root pool where the path to the grub menu exists.
1288f169c0eaSGlenn Lagasse * The code takes this and finds the BE's entry in the grub menu
1289f169c0eaSGlenn Lagasse * and changes the default entry to point to that entry in the
1290f169c0eaSGlenn Lagasse * list.
1291f169c0eaSGlenn Lagasse * Parameters:
1292f169c0eaSGlenn Lagasse * be_name - This is the name of the BE wanted as the default
1293f169c0eaSGlenn Lagasse * for the next boot.
1294f169c0eaSGlenn Lagasse * be_root_pool - This is the name of the root pool where the
1295f169c0eaSGlenn Lagasse * grub menu can be found.
1296f169c0eaSGlenn Lagasse * Returns:
1297f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
1298f169c0eaSGlenn Lagasse * be_errno_t - Failure
1299f169c0eaSGlenn Lagasse * Scope:
1300f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
1301f169c0eaSGlenn Lagasse */
1302f169c0eaSGlenn Lagasse int
be_change_grub_default(char * be_name,char * be_root_pool)1303f169c0eaSGlenn Lagasse be_change_grub_default(char *be_name, char *be_root_pool)
1304f169c0eaSGlenn Lagasse {
1305f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL;
1306f169c0eaSGlenn Lagasse char grub_file[MAXPATHLEN];
1307f169c0eaSGlenn Lagasse char *temp_grub;
1308f169c0eaSGlenn Lagasse char *pool_mntpnt = NULL;
1309f169c0eaSGlenn Lagasse char *ptmp_mntpnt = NULL;
1310f169c0eaSGlenn Lagasse char *orig_mntpnt = NULL;
1311f169c0eaSGlenn Lagasse char line[BUFSIZ];
1312f169c0eaSGlenn Lagasse char temp_line[BUFSIZ];
1313f169c0eaSGlenn Lagasse char be_root_ds[MAXPATHLEN];
1314f169c0eaSGlenn Lagasse FILE *grub_fp = NULL;
1315f169c0eaSGlenn Lagasse FILE *temp_fp = NULL;
1316f169c0eaSGlenn Lagasse struct stat sb;
1317f169c0eaSGlenn Lagasse int temp_grub_len = 0;
1318f169c0eaSGlenn Lagasse int fd, entries = 0;
1319f169c0eaSGlenn Lagasse int err = 0;
1320f169c0eaSGlenn Lagasse int ret = BE_SUCCESS;
1321f169c0eaSGlenn Lagasse boolean_t found_default = B_FALSE;
1322f169c0eaSGlenn Lagasse boolean_t pool_mounted = B_FALSE;
1323f169c0eaSGlenn Lagasse
1324f169c0eaSGlenn Lagasse errno = 0;
1325f169c0eaSGlenn Lagasse
1326f169c0eaSGlenn Lagasse /*
1327f169c0eaSGlenn Lagasse * Check to see if this system supports grub
1328f169c0eaSGlenn Lagasse */
1329f169c0eaSGlenn Lagasse if (!be_has_grub()) {
1330f169c0eaSGlenn Lagasse be_print_err(gettext("be_change_grub_default: operation "
1331f169c0eaSGlenn Lagasse "not supported on this architecture\n"));
1332f169c0eaSGlenn Lagasse return (BE_ERR_NOTSUP);
1333f169c0eaSGlenn Lagasse }
1334f169c0eaSGlenn Lagasse
1335f169c0eaSGlenn Lagasse /* Generate string for BE's root dataset */
1336f169c0eaSGlenn Lagasse be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds));
1337f169c0eaSGlenn Lagasse
1338f169c0eaSGlenn Lagasse /* Get handle to pool dataset */
1339f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
1340f169c0eaSGlenn Lagasse be_print_err(gettext("be_change_grub_default: "
1341f169c0eaSGlenn Lagasse "failed to open pool dataset for %s: %s"),
1342f169c0eaSGlenn Lagasse be_root_pool, libzfs_error_description(g_zfs));
1343f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs));
1344f169c0eaSGlenn Lagasse }
1345f169c0eaSGlenn Lagasse
1346f169c0eaSGlenn Lagasse /*
1347f169c0eaSGlenn Lagasse * Check to see if the pool's dataset is mounted. If it isn't we'll
1348f169c0eaSGlenn Lagasse * attempt to mount it.
1349f169c0eaSGlenn Lagasse */
1350f169c0eaSGlenn Lagasse if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
1351f169c0eaSGlenn Lagasse &pool_mounted)) != BE_SUCCESS) {
1352f169c0eaSGlenn Lagasse be_print_err(gettext("be_change_grub_default: pool dataset "
1353f169c0eaSGlenn Lagasse "(%s) could not be mounted\n"), be_root_pool);
1354f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1355f169c0eaSGlenn Lagasse return (ret);
1356f169c0eaSGlenn Lagasse }
1357f169c0eaSGlenn Lagasse
1358f169c0eaSGlenn Lagasse /*
1359f169c0eaSGlenn Lagasse * Get the mountpoint for the root pool dataset.
1360f169c0eaSGlenn Lagasse */
1361f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1362f169c0eaSGlenn Lagasse be_print_err(gettext("be_change_grub_default: pool "
1363f169c0eaSGlenn Lagasse "dataset (%s) is not mounted. Can't set "
1364f169c0eaSGlenn Lagasse "the default BE in the grub menu.\n"), be_root_pool);
1365f169c0eaSGlenn Lagasse ret = BE_ERR_NO_MENU;
1366f169c0eaSGlenn Lagasse goto cleanup;
1367f169c0eaSGlenn Lagasse }
1368f169c0eaSGlenn Lagasse
1369f169c0eaSGlenn Lagasse (void) snprintf(grub_file, MAXPATHLEN, "%s%s",
1370f169c0eaSGlenn Lagasse pool_mntpnt, BE_GRUB_MENU);
1371f169c0eaSGlenn Lagasse
1372de1ab35cSAlexander Eremin if ((ret = be_open_menu(be_root_pool, grub_file,
1373f169c0eaSGlenn Lagasse &grub_fp, "r+", B_TRUE)) != BE_SUCCESS) {
1374f169c0eaSGlenn Lagasse goto cleanup;
1375f169c0eaSGlenn Lagasse } else if (grub_fp == NULL) {
1376f169c0eaSGlenn Lagasse ret = BE_ERR_NO_MENU;
1377f169c0eaSGlenn Lagasse goto cleanup;
1378f169c0eaSGlenn Lagasse }
1379f169c0eaSGlenn Lagasse
1380f169c0eaSGlenn Lagasse free(pool_mntpnt);
1381f169c0eaSGlenn Lagasse pool_mntpnt = NULL;
1382f169c0eaSGlenn Lagasse
1383f169c0eaSGlenn Lagasse /* Grab the stats of the original menu file */
1384f169c0eaSGlenn Lagasse if (stat(grub_file, &sb) != 0) {
1385f169c0eaSGlenn Lagasse err = errno;
1386f169c0eaSGlenn Lagasse be_print_err(gettext("be_change_grub_default: "
1387f169c0eaSGlenn Lagasse "failed to stat file %s: %s\n"), grub_file, strerror(err));
1388f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1389f169c0eaSGlenn Lagasse goto cleanup;
1390f169c0eaSGlenn Lagasse }
1391f169c0eaSGlenn Lagasse
1392f169c0eaSGlenn Lagasse /* Create a tmp file for the modified menu.lst */
1393f169c0eaSGlenn Lagasse temp_grub_len = strlen(grub_file) + 7;
1394f169c0eaSGlenn Lagasse if ((temp_grub = (char *)malloc(temp_grub_len)) == NULL) {
1395f169c0eaSGlenn Lagasse be_print_err(gettext("be_change_grub_default: "
1396f169c0eaSGlenn Lagasse "malloc failed\n"));
1397f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM;
1398f169c0eaSGlenn Lagasse goto cleanup;
1399f169c0eaSGlenn Lagasse }
1400f169c0eaSGlenn Lagasse (void) memset(temp_grub, 0, temp_grub_len);
1401f169c0eaSGlenn Lagasse (void) strlcpy(temp_grub, grub_file, temp_grub_len);
1402f169c0eaSGlenn Lagasse (void) strlcat(temp_grub, "XXXXXX", temp_grub_len);
1403f169c0eaSGlenn Lagasse if ((fd = mkstemp(temp_grub)) == -1) {
1404f169c0eaSGlenn Lagasse err = errno;
1405f169c0eaSGlenn Lagasse be_print_err(gettext("be_change_grub_default: "
1406f169c0eaSGlenn Lagasse "mkstemp failed: %s\n"), strerror(err));
1407f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1408f169c0eaSGlenn Lagasse free(temp_grub);
1409f169c0eaSGlenn Lagasse temp_grub = NULL;
1410f169c0eaSGlenn Lagasse goto cleanup;
1411f169c0eaSGlenn Lagasse }
1412f169c0eaSGlenn Lagasse if ((temp_fp = fdopen(fd, "w")) == NULL) {
1413f169c0eaSGlenn Lagasse err = errno;
1414f169c0eaSGlenn Lagasse be_print_err(gettext("be_change_grub_default: "
1415f169c0eaSGlenn Lagasse "failed to open %s file: %s\n"),
1416f169c0eaSGlenn Lagasse temp_grub, strerror(err));
1417f169c0eaSGlenn Lagasse (void) close(fd);
1418f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1419f169c0eaSGlenn Lagasse goto cleanup;
1420f169c0eaSGlenn Lagasse }
1421f169c0eaSGlenn Lagasse
1422f169c0eaSGlenn Lagasse while (fgets(line, BUFSIZ, grub_fp)) {
1423f169c0eaSGlenn Lagasse char *tok = strtok(line, BE_WHITE_SPACE);
1424f169c0eaSGlenn Lagasse
1425f169c0eaSGlenn Lagasse if (tok == NULL || tok[0] == '#') {
1426f169c0eaSGlenn Lagasse continue;
1427f169c0eaSGlenn Lagasse } else if (strcmp(tok, "title") == 0) {
1428f169c0eaSGlenn Lagasse entries++;
1429f169c0eaSGlenn Lagasse continue;
1430f169c0eaSGlenn Lagasse } else if (strcmp(tok, "bootfs") == 0) {
1431f169c0eaSGlenn Lagasse char *bootfs = strtok(NULL, BE_WHITE_SPACE);
1432f169c0eaSGlenn Lagasse if (bootfs == NULL)
1433f169c0eaSGlenn Lagasse continue;
1434f169c0eaSGlenn Lagasse
1435f169c0eaSGlenn Lagasse if (strcmp(bootfs, be_root_ds) == 0) {
1436f169c0eaSGlenn Lagasse found_default = B_TRUE;
1437f169c0eaSGlenn Lagasse break;
1438f169c0eaSGlenn Lagasse }
1439f169c0eaSGlenn Lagasse }
1440f169c0eaSGlenn Lagasse }
1441f169c0eaSGlenn Lagasse
1442f169c0eaSGlenn Lagasse if (!found_default) {
1443f169c0eaSGlenn Lagasse be_print_err(gettext("be_change_grub_default: failed "
1444f169c0eaSGlenn Lagasse "to find entry for %s in the grub menu\n"),
1445f169c0eaSGlenn Lagasse be_name);
1446f169c0eaSGlenn Lagasse ret = BE_ERR_BE_NOENT;
1447f169c0eaSGlenn Lagasse goto cleanup;
1448f169c0eaSGlenn Lagasse }
1449f169c0eaSGlenn Lagasse
1450f169c0eaSGlenn Lagasse rewind(grub_fp);
1451f169c0eaSGlenn Lagasse
1452f169c0eaSGlenn Lagasse while (fgets(line, BUFSIZ, grub_fp)) {
1453f169c0eaSGlenn Lagasse char *tok = NULL;
1454f169c0eaSGlenn Lagasse
1455f169c0eaSGlenn Lagasse (void) strncpy(temp_line, line, BUFSIZ);
1456f169c0eaSGlenn Lagasse
1457f169c0eaSGlenn Lagasse if ((tok = strtok(temp_line, BE_WHITE_SPACE)) != NULL &&
1458f169c0eaSGlenn Lagasse strcmp(tok, "default") == 0) {
1459f169c0eaSGlenn Lagasse (void) snprintf(temp_line, BUFSIZ, "default %d\n",
1460f169c0eaSGlenn Lagasse entries - 1 >= 0 ? entries - 1 : 0);
1461f169c0eaSGlenn Lagasse (void) fputs(temp_line, temp_fp);
1462f169c0eaSGlenn Lagasse } else {
1463f169c0eaSGlenn Lagasse (void) fputs(line, temp_fp);
1464f169c0eaSGlenn Lagasse }
1465f169c0eaSGlenn Lagasse }
1466f169c0eaSGlenn Lagasse
1467f169c0eaSGlenn Lagasse (void) fclose(grub_fp);
1468f169c0eaSGlenn Lagasse grub_fp = NULL;
1469f169c0eaSGlenn Lagasse (void) fclose(temp_fp);
1470f169c0eaSGlenn Lagasse temp_fp = NULL;
1471f169c0eaSGlenn Lagasse
1472f169c0eaSGlenn Lagasse if (rename(temp_grub, grub_file) != 0) {
1473f169c0eaSGlenn Lagasse err = errno;
1474f169c0eaSGlenn Lagasse be_print_err(gettext("be_change_grub_default: "
1475f169c0eaSGlenn Lagasse "failed to rename file %s to %s: %s\n"),
1476f169c0eaSGlenn Lagasse temp_grub, grub_file, strerror(err));
1477f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1478f169c0eaSGlenn Lagasse goto cleanup;
1479f169c0eaSGlenn Lagasse }
1480f169c0eaSGlenn Lagasse free(temp_grub);
1481f169c0eaSGlenn Lagasse temp_grub = NULL;
1482f169c0eaSGlenn Lagasse
1483f169c0eaSGlenn Lagasse /* Set the perms and ownership of the updated file */
1484f169c0eaSGlenn Lagasse if (chmod(grub_file, sb.st_mode) != 0) {
1485f169c0eaSGlenn Lagasse err = errno;
1486f169c0eaSGlenn Lagasse be_print_err(gettext("be_change_grub_default: "
1487f169c0eaSGlenn Lagasse "failed to chmod %s: %s\n"), grub_file, strerror(err));
1488f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1489f169c0eaSGlenn Lagasse goto cleanup;
1490f169c0eaSGlenn Lagasse }
1491f169c0eaSGlenn Lagasse if (chown(grub_file, sb.st_uid, sb.st_gid) != 0) {
1492f169c0eaSGlenn Lagasse err = errno;
1493f169c0eaSGlenn Lagasse be_print_err(gettext("be_change_grub_default: "
1494f169c0eaSGlenn Lagasse "failed to chown %s: %s\n"), grub_file, strerror(err));
1495f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1496f169c0eaSGlenn Lagasse }
1497f169c0eaSGlenn Lagasse
1498f169c0eaSGlenn Lagasse cleanup:
1499f169c0eaSGlenn Lagasse if (pool_mounted) {
1500f169c0eaSGlenn Lagasse int err = BE_SUCCESS;
1501f169c0eaSGlenn Lagasse err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1502f169c0eaSGlenn Lagasse if (ret == BE_SUCCESS)
1503f169c0eaSGlenn Lagasse ret = err;
1504f169c0eaSGlenn Lagasse free(orig_mntpnt);
1505f169c0eaSGlenn Lagasse free(ptmp_mntpnt);
1506f169c0eaSGlenn Lagasse }
1507f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1508f169c0eaSGlenn Lagasse if (grub_fp != NULL)
1509f169c0eaSGlenn Lagasse (void) fclose(grub_fp);
1510f169c0eaSGlenn Lagasse if (temp_fp != NULL)
1511f169c0eaSGlenn Lagasse (void) fclose(temp_fp);
1512f169c0eaSGlenn Lagasse if (temp_grub != NULL) {
1513f169c0eaSGlenn Lagasse (void) unlink(temp_grub);
1514f169c0eaSGlenn Lagasse free(temp_grub);
1515f169c0eaSGlenn Lagasse }
1516f169c0eaSGlenn Lagasse
1517f169c0eaSGlenn Lagasse return (ret);
1518f169c0eaSGlenn Lagasse }
1519f169c0eaSGlenn Lagasse
1520f169c0eaSGlenn Lagasse /*
1521f169c0eaSGlenn Lagasse * Function: be_update_menu
1522f169c0eaSGlenn Lagasse * Description: This function is used by be_rename to change the BE name in
1523f169c0eaSGlenn Lagasse * an existing entry in the grub menu to the new name of the BE.
1524f169c0eaSGlenn Lagasse * Parameters:
1525f169c0eaSGlenn Lagasse * be_orig_name - the original name of the BE
1526f169c0eaSGlenn Lagasse * be_new_name - the new name the BE is being renameed to.
1527f169c0eaSGlenn Lagasse * be_root_pool - The pool which contains the grub menu
1528f169c0eaSGlenn Lagasse * boot_pool - the pool where the BE is, if different than
1529f169c0eaSGlenn Lagasse * the pool containing the boot menu. If this is
1530f169c0eaSGlenn Lagasse * NULL it will be set to be_root_pool.
1531f169c0eaSGlenn Lagasse * Returns:
1532f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
1533f169c0eaSGlenn Lagasse * be_errno_t - Failure
1534f169c0eaSGlenn Lagasse * Scope:
1535f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
1536f169c0eaSGlenn Lagasse */
1537f169c0eaSGlenn Lagasse int
be_update_menu(char * be_orig_name,char * be_new_name,char * be_root_pool,char * boot_pool)1538f169c0eaSGlenn Lagasse be_update_menu(char *be_orig_name, char *be_new_name, char *be_root_pool,
1539f169c0eaSGlenn Lagasse char *boot_pool)
1540f169c0eaSGlenn Lagasse {
1541f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL;
1542f169c0eaSGlenn Lagasse char menu_file[MAXPATHLEN];
1543f169c0eaSGlenn Lagasse char be_root_ds[MAXPATHLEN];
1544f169c0eaSGlenn Lagasse char be_new_root_ds[MAXPATHLEN];
1545f169c0eaSGlenn Lagasse char line[BUFSIZ];
1546f169c0eaSGlenn Lagasse char *pool_mntpnt = NULL;
1547f169c0eaSGlenn Lagasse char *ptmp_mntpnt = NULL;
1548f169c0eaSGlenn Lagasse char *orig_mntpnt = NULL;
1549f169c0eaSGlenn Lagasse char *temp_menu = NULL;
1550f169c0eaSGlenn Lagasse FILE *menu_fp = NULL;
1551f169c0eaSGlenn Lagasse FILE *new_fp = NULL;
1552f169c0eaSGlenn Lagasse struct stat sb;
1553f169c0eaSGlenn Lagasse int temp_menu_len = 0;
1554f169c0eaSGlenn Lagasse int tmp_fd;
1555f169c0eaSGlenn Lagasse int ret = BE_SUCCESS;
1556f169c0eaSGlenn Lagasse int err = 0;
1557f169c0eaSGlenn Lagasse boolean_t pool_mounted = B_FALSE;
1558f169c0eaSGlenn Lagasse
1559f169c0eaSGlenn Lagasse errno = 0;
1560f169c0eaSGlenn Lagasse
1561f169c0eaSGlenn Lagasse if (boot_pool == NULL)
1562f169c0eaSGlenn Lagasse boot_pool = be_root_pool;
1563f169c0eaSGlenn Lagasse
1564f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
1565f169c0eaSGlenn Lagasse be_print_err(gettext("be_update_menu: failed to open "
1566f169c0eaSGlenn Lagasse "pool dataset for %s: %s\n"), be_root_pool,
1567f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
1568f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs));
1569f169c0eaSGlenn Lagasse }
1570f169c0eaSGlenn Lagasse
1571f169c0eaSGlenn Lagasse /*
1572f169c0eaSGlenn Lagasse * Check to see if the pool's dataset is mounted. If it isn't we'll
1573f169c0eaSGlenn Lagasse * attempt to mount it.
1574f169c0eaSGlenn Lagasse */
1575f169c0eaSGlenn Lagasse if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
1576f169c0eaSGlenn Lagasse &pool_mounted)) != BE_SUCCESS) {
1577f169c0eaSGlenn Lagasse be_print_err(gettext("be_update_menu: pool dataset "
1578f169c0eaSGlenn Lagasse "(%s) could not be mounted\n"), be_root_pool);
1579f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1580f169c0eaSGlenn Lagasse return (ret);
1581f169c0eaSGlenn Lagasse }
1582f169c0eaSGlenn Lagasse
1583f169c0eaSGlenn Lagasse /*
1584f169c0eaSGlenn Lagasse * Get the mountpoint for the root pool dataset.
1585f169c0eaSGlenn Lagasse */
1586f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1587f169c0eaSGlenn Lagasse be_print_err(gettext("be_update_menu: failed "
1588f169c0eaSGlenn Lagasse "to get mount point for the root pool. Can't set "
1589f169c0eaSGlenn Lagasse "the default BE in the grub menu.\n"));
1590f169c0eaSGlenn Lagasse ret = BE_ERR_NO_MENU;
1591f169c0eaSGlenn Lagasse goto cleanup;
1592f169c0eaSGlenn Lagasse }
1593f169c0eaSGlenn Lagasse
1594f169c0eaSGlenn Lagasse /*
1595f169c0eaSGlenn Lagasse * Check to see if this system supports grub
1596f169c0eaSGlenn Lagasse */
1597f169c0eaSGlenn Lagasse if (be_has_grub()) {
1598f169c0eaSGlenn Lagasse (void) snprintf(menu_file, sizeof (menu_file),
1599f169c0eaSGlenn Lagasse "%s%s", pool_mntpnt, BE_GRUB_MENU);
1600f169c0eaSGlenn Lagasse } else {
1601f169c0eaSGlenn Lagasse (void) snprintf(menu_file, sizeof (menu_file),
1602f169c0eaSGlenn Lagasse "%s%s", pool_mntpnt, BE_SPARC_MENU);
1603f169c0eaSGlenn Lagasse }
1604f169c0eaSGlenn Lagasse
1605f169c0eaSGlenn Lagasse be_make_root_ds(be_root_pool, be_orig_name, be_root_ds,
1606f169c0eaSGlenn Lagasse sizeof (be_root_ds));
1607f169c0eaSGlenn Lagasse be_make_root_ds(be_root_pool, be_new_name, be_new_root_ds,
1608f169c0eaSGlenn Lagasse sizeof (be_new_root_ds));
1609f169c0eaSGlenn Lagasse
1610de1ab35cSAlexander Eremin if ((ret = be_open_menu(be_root_pool, menu_file,
1611f169c0eaSGlenn Lagasse &menu_fp, "r", B_TRUE)) != BE_SUCCESS) {
1612f169c0eaSGlenn Lagasse goto cleanup;
1613f169c0eaSGlenn Lagasse } else if (menu_fp == NULL) {
1614f169c0eaSGlenn Lagasse ret = BE_ERR_NO_MENU;
1615f169c0eaSGlenn Lagasse goto cleanup;
1616f169c0eaSGlenn Lagasse }
1617f169c0eaSGlenn Lagasse
1618f169c0eaSGlenn Lagasse free(pool_mntpnt);
1619f169c0eaSGlenn Lagasse pool_mntpnt = NULL;
1620f169c0eaSGlenn Lagasse
1621f169c0eaSGlenn Lagasse /* Grab the stat of the original menu file */
1622f169c0eaSGlenn Lagasse if (stat(menu_file, &sb) != 0) {
1623f169c0eaSGlenn Lagasse err = errno;
1624f169c0eaSGlenn Lagasse be_print_err(gettext("be_update_menu: "
1625f169c0eaSGlenn Lagasse "failed to stat file %s: %s\n"), menu_file, strerror(err));
1626f169c0eaSGlenn Lagasse (void) fclose(menu_fp);
1627f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1628f169c0eaSGlenn Lagasse goto cleanup;
1629f169c0eaSGlenn Lagasse }
1630f169c0eaSGlenn Lagasse
1631f169c0eaSGlenn Lagasse /* Create tmp file for modified menu.lst */
1632f169c0eaSGlenn Lagasse temp_menu_len = strlen(menu_file) + 7;
1633f169c0eaSGlenn Lagasse if ((temp_menu = (char *)malloc(temp_menu_len))
1634f169c0eaSGlenn Lagasse == NULL) {
1635f169c0eaSGlenn Lagasse be_print_err(gettext("be_update_menu: "
1636f169c0eaSGlenn Lagasse "malloc failed\n"));
1637f169c0eaSGlenn Lagasse (void) fclose(menu_fp);
1638f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM;
1639f169c0eaSGlenn Lagasse goto cleanup;
1640f169c0eaSGlenn Lagasse }
1641f169c0eaSGlenn Lagasse (void) memset(temp_menu, 0, temp_menu_len);
1642f169c0eaSGlenn Lagasse (void) strlcpy(temp_menu, menu_file, temp_menu_len);
1643f169c0eaSGlenn Lagasse (void) strlcat(temp_menu, "XXXXXX", temp_menu_len);
1644f169c0eaSGlenn Lagasse if ((tmp_fd = mkstemp(temp_menu)) == -1) {
1645f169c0eaSGlenn Lagasse err = errno;
1646f169c0eaSGlenn Lagasse be_print_err(gettext("be_update_menu: "
1647f169c0eaSGlenn Lagasse "mkstemp failed: %s\n"), strerror(err));
1648f169c0eaSGlenn Lagasse (void) fclose(menu_fp);
1649f169c0eaSGlenn Lagasse free(temp_menu);
1650f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1651f169c0eaSGlenn Lagasse goto cleanup;
1652f169c0eaSGlenn Lagasse }
1653f169c0eaSGlenn Lagasse if ((new_fp = fdopen(tmp_fd, "w")) == NULL) {
1654f169c0eaSGlenn Lagasse err = errno;
1655f169c0eaSGlenn Lagasse be_print_err(gettext("be_update_menu: "
1656f169c0eaSGlenn Lagasse "fdopen failed: %s\n"), strerror(err));
1657f169c0eaSGlenn Lagasse (void) close(tmp_fd);
1658f169c0eaSGlenn Lagasse (void) fclose(menu_fp);
1659f169c0eaSGlenn Lagasse free(temp_menu);
1660f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1661f169c0eaSGlenn Lagasse goto cleanup;
1662f169c0eaSGlenn Lagasse }
1663f169c0eaSGlenn Lagasse
1664f169c0eaSGlenn Lagasse while (fgets(line, BUFSIZ, menu_fp)) {
1665f169c0eaSGlenn Lagasse char tline[BUFSIZ];
1666f169c0eaSGlenn Lagasse char new_line[BUFSIZ];
1667f169c0eaSGlenn Lagasse char *c = NULL;
1668f169c0eaSGlenn Lagasse
1669f169c0eaSGlenn Lagasse (void) strlcpy(tline, line, sizeof (tline));
1670f169c0eaSGlenn Lagasse
1671f169c0eaSGlenn Lagasse /* Tokenize line */
1672f169c0eaSGlenn Lagasse c = strtok(tline, BE_WHITE_SPACE);
1673f169c0eaSGlenn Lagasse
1674f169c0eaSGlenn Lagasse if (c == NULL) {
1675f169c0eaSGlenn Lagasse /* Found empty line, write it out. */
1676f169c0eaSGlenn Lagasse (void) fputs(line, new_fp);
1677f169c0eaSGlenn Lagasse } else if (c[0] == '#') {
1678f169c0eaSGlenn Lagasse /* Found a comment line, write it out. */
1679f169c0eaSGlenn Lagasse (void) fputs(line, new_fp);
1680f169c0eaSGlenn Lagasse } else if (strcmp(c, "title") == 0) {
1681f169c0eaSGlenn Lagasse char *name = NULL;
1682f169c0eaSGlenn Lagasse char *desc = NULL;
1683f169c0eaSGlenn Lagasse
1684f169c0eaSGlenn Lagasse /*
1685f169c0eaSGlenn Lagasse * Found a 'title' line, parse out BE name or
1686f169c0eaSGlenn Lagasse * the description.
1687f169c0eaSGlenn Lagasse */
1688f169c0eaSGlenn Lagasse name = strtok(NULL, BE_WHITE_SPACE);
1689f169c0eaSGlenn Lagasse
1690f169c0eaSGlenn Lagasse if (name == NULL) {
1691f169c0eaSGlenn Lagasse /*
1692f169c0eaSGlenn Lagasse * Nothing after 'title', just push
1693f169c0eaSGlenn Lagasse * this line through
1694f169c0eaSGlenn Lagasse */
1695f169c0eaSGlenn Lagasse (void) fputs(line, new_fp);
1696f169c0eaSGlenn Lagasse } else {
1697f169c0eaSGlenn Lagasse /*
1698f169c0eaSGlenn Lagasse * Grab the remainder of the title which
1699f169c0eaSGlenn Lagasse * could be a multi worded description
1700f169c0eaSGlenn Lagasse */
1701f169c0eaSGlenn Lagasse desc = strtok(NULL, "\n");
1702f169c0eaSGlenn Lagasse
1703f169c0eaSGlenn Lagasse if (strcmp(name, be_orig_name) == 0) {
1704f169c0eaSGlenn Lagasse /*
1705f169c0eaSGlenn Lagasse * The first token of the title is
1706f169c0eaSGlenn Lagasse * the old BE name, replace it with
1707f169c0eaSGlenn Lagasse * the new one, and write it out
1708f169c0eaSGlenn Lagasse * along with the remainder of
1709f169c0eaSGlenn Lagasse * description if there is one.
1710f169c0eaSGlenn Lagasse */
1711f169c0eaSGlenn Lagasse if (desc) {
1712f169c0eaSGlenn Lagasse (void) snprintf(new_line,
1713f169c0eaSGlenn Lagasse sizeof (new_line),
1714f169c0eaSGlenn Lagasse "title %s %s\n",
1715f169c0eaSGlenn Lagasse be_new_name, desc);
1716f169c0eaSGlenn Lagasse } else {
1717f169c0eaSGlenn Lagasse (void) snprintf(new_line,
1718f169c0eaSGlenn Lagasse sizeof (new_line),
1719f169c0eaSGlenn Lagasse "title %s\n", be_new_name);
1720f169c0eaSGlenn Lagasse }
1721f169c0eaSGlenn Lagasse
1722f169c0eaSGlenn Lagasse (void) fputs(new_line, new_fp);
1723f169c0eaSGlenn Lagasse } else {
1724f169c0eaSGlenn Lagasse (void) fputs(line, new_fp);
1725f169c0eaSGlenn Lagasse }
1726f169c0eaSGlenn Lagasse }
1727f169c0eaSGlenn Lagasse } else if (strcmp(c, "bootfs") == 0) {
1728f169c0eaSGlenn Lagasse /*
1729f169c0eaSGlenn Lagasse * Found a 'bootfs' line, parse out the BE root
1730f169c0eaSGlenn Lagasse * dataset value.
1731f169c0eaSGlenn Lagasse */
1732f169c0eaSGlenn Lagasse char *root_ds = strtok(NULL, BE_WHITE_SPACE);
1733f169c0eaSGlenn Lagasse
1734f169c0eaSGlenn Lagasse if (root_ds == NULL) {
1735f169c0eaSGlenn Lagasse /*
1736f169c0eaSGlenn Lagasse * Nothing after 'bootfs', just push
1737f169c0eaSGlenn Lagasse * this line through
1738f169c0eaSGlenn Lagasse */
1739f169c0eaSGlenn Lagasse (void) fputs(line, new_fp);
1740f169c0eaSGlenn Lagasse } else {
1741f169c0eaSGlenn Lagasse /*
1742f169c0eaSGlenn Lagasse * If this bootfs is the one we're renaming,
1743f169c0eaSGlenn Lagasse * write out the new root dataset value
1744f169c0eaSGlenn Lagasse */
1745f169c0eaSGlenn Lagasse if (strcmp(root_ds, be_root_ds) == 0) {
1746f169c0eaSGlenn Lagasse (void) snprintf(new_line,
1747f169c0eaSGlenn Lagasse sizeof (new_line), "bootfs %s\n",
1748f169c0eaSGlenn Lagasse be_new_root_ds);
1749f169c0eaSGlenn Lagasse
1750f169c0eaSGlenn Lagasse (void) fputs(new_line, new_fp);
1751f169c0eaSGlenn Lagasse } else {
1752f169c0eaSGlenn Lagasse (void) fputs(line, new_fp);
1753f169c0eaSGlenn Lagasse }
1754f169c0eaSGlenn Lagasse }
1755f169c0eaSGlenn Lagasse } else {
1756f169c0eaSGlenn Lagasse /*
1757f169c0eaSGlenn Lagasse * Found some other line we don't care
1758f169c0eaSGlenn Lagasse * about, write it out.
1759f169c0eaSGlenn Lagasse */
1760f169c0eaSGlenn Lagasse (void) fputs(line, new_fp);
1761f169c0eaSGlenn Lagasse }
1762f169c0eaSGlenn Lagasse }
1763f169c0eaSGlenn Lagasse
1764f169c0eaSGlenn Lagasse (void) fclose(menu_fp);
1765f169c0eaSGlenn Lagasse (void) fclose(new_fp);
1766f169c0eaSGlenn Lagasse (void) close(tmp_fd);
1767f169c0eaSGlenn Lagasse
1768f169c0eaSGlenn Lagasse if (rename(temp_menu, menu_file) != 0) {
1769f169c0eaSGlenn Lagasse err = errno;
1770f169c0eaSGlenn Lagasse be_print_err(gettext("be_update_menu: "
1771f169c0eaSGlenn Lagasse "failed to rename file %s to %s: %s\n"),
1772f169c0eaSGlenn Lagasse temp_menu, menu_file, strerror(err));
1773f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1774f169c0eaSGlenn Lagasse }
1775f169c0eaSGlenn Lagasse free(temp_menu);
1776f169c0eaSGlenn Lagasse
1777f169c0eaSGlenn Lagasse /* Set the perms and ownership of the updated file */
1778f169c0eaSGlenn Lagasse if (chmod(menu_file, sb.st_mode) != 0) {
1779f169c0eaSGlenn Lagasse err = errno;
1780f169c0eaSGlenn Lagasse be_print_err(gettext("be_update_menu: "
1781f169c0eaSGlenn Lagasse "failed to chmod %s: %s\n"), menu_file, strerror(err));
1782f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1783f169c0eaSGlenn Lagasse goto cleanup;
1784f169c0eaSGlenn Lagasse }
1785f169c0eaSGlenn Lagasse if (chown(menu_file, sb.st_uid, sb.st_gid) != 0) {
1786f169c0eaSGlenn Lagasse err = errno;
1787f169c0eaSGlenn Lagasse be_print_err(gettext("be_update_menu: "
1788f169c0eaSGlenn Lagasse "failed to chown %s: %s\n"), menu_file, strerror(err));
1789f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1790f169c0eaSGlenn Lagasse }
1791f169c0eaSGlenn Lagasse
1792f169c0eaSGlenn Lagasse cleanup:
1793f169c0eaSGlenn Lagasse if (pool_mounted) {
1794f169c0eaSGlenn Lagasse int err = BE_SUCCESS;
1795f169c0eaSGlenn Lagasse err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1796f169c0eaSGlenn Lagasse if (ret == BE_SUCCESS)
1797f169c0eaSGlenn Lagasse ret = err;
1798f169c0eaSGlenn Lagasse free(orig_mntpnt);
1799f169c0eaSGlenn Lagasse free(ptmp_mntpnt);
1800f169c0eaSGlenn Lagasse }
1801f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1802f169c0eaSGlenn Lagasse return (ret);
1803f169c0eaSGlenn Lagasse }
1804f169c0eaSGlenn Lagasse
1805f169c0eaSGlenn Lagasse /*
1806f169c0eaSGlenn Lagasse * Function: be_has_menu_entry
1807f169c0eaSGlenn Lagasse * Description: Checks to see if the BEs root dataset has an entry in the grub
1808f169c0eaSGlenn Lagasse * menu.
1809f169c0eaSGlenn Lagasse * Parameters:
1810f169c0eaSGlenn Lagasse * be_dataset - The root dataset of the BE
1811f169c0eaSGlenn Lagasse * be_root_pool - The pool which contains the boot menu
1812f169c0eaSGlenn Lagasse * entry - A pointer the the entry number of the BE if found.
1813f169c0eaSGlenn Lagasse * Returns:
1814f169c0eaSGlenn Lagasse * B_TRUE - Success
1815f169c0eaSGlenn Lagasse * B_FALSE - Failure
1816f169c0eaSGlenn Lagasse * Scope:
1817f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
1818f169c0eaSGlenn Lagasse */
1819f169c0eaSGlenn Lagasse boolean_t
be_has_menu_entry(char * be_dataset,char * be_root_pool,int * entry)1820f169c0eaSGlenn Lagasse be_has_menu_entry(char *be_dataset, char *be_root_pool, int *entry)
1821f169c0eaSGlenn Lagasse {
1822f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL;
1823f169c0eaSGlenn Lagasse char menu_file[MAXPATHLEN];
1824f169c0eaSGlenn Lagasse FILE *menu_fp;
1825f169c0eaSGlenn Lagasse char line[BUFSIZ];
1826f169c0eaSGlenn Lagasse char *last;
1827f169c0eaSGlenn Lagasse char *rpool_mntpnt = NULL;
1828f169c0eaSGlenn Lagasse char *ptmp_mntpnt = NULL;
1829f169c0eaSGlenn Lagasse char *orig_mntpnt = NULL;
1830f169c0eaSGlenn Lagasse int ent_num = 0;
1831f169c0eaSGlenn Lagasse boolean_t ret = 0;
1832f169c0eaSGlenn Lagasse boolean_t pool_mounted = B_FALSE;
1833f169c0eaSGlenn Lagasse
1834f169c0eaSGlenn Lagasse
1835f169c0eaSGlenn Lagasse /*
1836f169c0eaSGlenn Lagasse * Check to see if this system supports grub
1837f169c0eaSGlenn Lagasse */
1838f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
1839f169c0eaSGlenn Lagasse be_print_err(gettext("be_has_menu_entry: failed to open "
1840f169c0eaSGlenn Lagasse "pool dataset for %s: %s\n"), be_root_pool,
1841f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
1842f169c0eaSGlenn Lagasse return (B_FALSE);
1843f169c0eaSGlenn Lagasse }
1844f169c0eaSGlenn Lagasse
1845f169c0eaSGlenn Lagasse /*
1846f169c0eaSGlenn Lagasse * Check to see if the pool's dataset is mounted. If it isn't we'll
1847f169c0eaSGlenn Lagasse * attempt to mount it.
1848f169c0eaSGlenn Lagasse */
1849f169c0eaSGlenn Lagasse if (be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
1850f169c0eaSGlenn Lagasse &pool_mounted) != 0) {
1851f169c0eaSGlenn Lagasse be_print_err(gettext("be_has_menu_entry: pool dataset "
1852f169c0eaSGlenn Lagasse "(%s) could not be mounted\n"), be_root_pool);
1853f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1854f169c0eaSGlenn Lagasse return (B_FALSE);
1855f169c0eaSGlenn Lagasse }
1856f169c0eaSGlenn Lagasse
1857f169c0eaSGlenn Lagasse /*
1858f169c0eaSGlenn Lagasse * Get the mountpoint for the root pool dataset.
1859f169c0eaSGlenn Lagasse */
1860f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &rpool_mntpnt)) {
1861f169c0eaSGlenn Lagasse be_print_err(gettext("be_has_menu_entry: pool "
1862f169c0eaSGlenn Lagasse "dataset (%s) is not mounted. Can't set "
1863f169c0eaSGlenn Lagasse "the default BE in the grub menu.\n"), be_root_pool);
1864f169c0eaSGlenn Lagasse ret = B_FALSE;
1865f169c0eaSGlenn Lagasse goto cleanup;
1866f169c0eaSGlenn Lagasse }
1867f169c0eaSGlenn Lagasse
1868f169c0eaSGlenn Lagasse if (be_has_grub()) {
1869f169c0eaSGlenn Lagasse (void) snprintf(menu_file, MAXPATHLEN, "/%s%s",
1870f169c0eaSGlenn Lagasse rpool_mntpnt, BE_GRUB_MENU);
1871f169c0eaSGlenn Lagasse } else {
1872f169c0eaSGlenn Lagasse (void) snprintf(menu_file, MAXPATHLEN, "/%s%s",
1873f169c0eaSGlenn Lagasse rpool_mntpnt, BE_SPARC_MENU);
1874f169c0eaSGlenn Lagasse }
1875f169c0eaSGlenn Lagasse
1876de1ab35cSAlexander Eremin if (be_open_menu(be_root_pool, menu_file, &menu_fp, "r",
1877f169c0eaSGlenn Lagasse B_FALSE) != 0) {
1878f169c0eaSGlenn Lagasse ret = B_FALSE;
1879f169c0eaSGlenn Lagasse goto cleanup;
1880f169c0eaSGlenn Lagasse } else if (menu_fp == NULL) {
1881f169c0eaSGlenn Lagasse ret = B_FALSE;
1882f169c0eaSGlenn Lagasse goto cleanup;
1883f169c0eaSGlenn Lagasse }
1884f169c0eaSGlenn Lagasse
1885f169c0eaSGlenn Lagasse free(rpool_mntpnt);
1886f169c0eaSGlenn Lagasse rpool_mntpnt = NULL;
1887f169c0eaSGlenn Lagasse
1888f169c0eaSGlenn Lagasse while (fgets(line, BUFSIZ, menu_fp)) {
1889f169c0eaSGlenn Lagasse char *tok = strtok_r(line, BE_WHITE_SPACE, &last);
1890f169c0eaSGlenn Lagasse
1891f169c0eaSGlenn Lagasse if (tok != NULL && tok[0] != '#') {
1892f169c0eaSGlenn Lagasse if (strcmp(tok, "bootfs") == 0) {
1893f169c0eaSGlenn Lagasse tok = strtok_r(last, BE_WHITE_SPACE, &last);
1894f169c0eaSGlenn Lagasse if (tok != NULL && strcmp(tok,
1895f169c0eaSGlenn Lagasse be_dataset) == 0) {
1896f169c0eaSGlenn Lagasse (void) fclose(menu_fp);
1897f169c0eaSGlenn Lagasse /*
1898f169c0eaSGlenn Lagasse * The entry number needs to be
1899f169c0eaSGlenn Lagasse * decremented here because the title
1900f169c0eaSGlenn Lagasse * will always be the first line for
1901f169c0eaSGlenn Lagasse * an entry. Because of this we'll
1902f169c0eaSGlenn Lagasse * always be off by one entry when we
1903f169c0eaSGlenn Lagasse * check for bootfs.
1904f169c0eaSGlenn Lagasse */
1905f169c0eaSGlenn Lagasse *entry = ent_num - 1;
1906f169c0eaSGlenn Lagasse ret = B_TRUE;
1907f169c0eaSGlenn Lagasse goto cleanup;
1908f169c0eaSGlenn Lagasse }
1909f169c0eaSGlenn Lagasse } else if (strcmp(tok, "title") == 0)
1910f169c0eaSGlenn Lagasse ent_num++;
1911f169c0eaSGlenn Lagasse }
1912f169c0eaSGlenn Lagasse }
1913f169c0eaSGlenn Lagasse
1914f169c0eaSGlenn Lagasse cleanup:
1915f169c0eaSGlenn Lagasse if (pool_mounted) {
1916f169c0eaSGlenn Lagasse (void) be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1917f169c0eaSGlenn Lagasse free(orig_mntpnt);
1918f169c0eaSGlenn Lagasse free(ptmp_mntpnt);
1919f169c0eaSGlenn Lagasse }
1920f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1921f169c0eaSGlenn Lagasse (void) fclose(menu_fp);
1922f169c0eaSGlenn Lagasse return (ret);
1923f169c0eaSGlenn Lagasse }
1924f169c0eaSGlenn Lagasse
1925f169c0eaSGlenn Lagasse /*
1926f169c0eaSGlenn Lagasse * Function: be_update_vfstab
1927f169c0eaSGlenn Lagasse * Description: This function digs into a BE's vfstab and updates all
1928f169c0eaSGlenn Lagasse * entries with file systems listed in be_fs_list_data_t.
1929f169c0eaSGlenn Lagasse * The entry's root container dataset and be_name will be
1930f169c0eaSGlenn Lagasse * updated with the parameters passed in.
1931f169c0eaSGlenn Lagasse * Parameters:
1932f169c0eaSGlenn Lagasse * be_name - name of BE to update
1933f169c0eaSGlenn Lagasse * old_rc_loc - dataset under which the root container dataset
1934f169c0eaSGlenn Lagasse * of the old BE resides in.
1935f169c0eaSGlenn Lagasse * new_rc_loc - dataset under which the root container dataset
1936f169c0eaSGlenn Lagasse * of the new BE resides in.
1937f169c0eaSGlenn Lagasse * fld - be_fs_list_data_t pointer providing the list of
1938f169c0eaSGlenn Lagasse * file systems to look for in vfstab.
1939f169c0eaSGlenn Lagasse * mountpoint - directory of where BE is currently mounted.
1940f169c0eaSGlenn Lagasse * If NULL, then BE is not currently mounted.
1941f169c0eaSGlenn Lagasse * Returns:
1942f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
1943f169c0eaSGlenn Lagasse * be_errno_t - Failure
1944f169c0eaSGlenn Lagasse * Scope:
1945f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
1946f169c0eaSGlenn Lagasse */
1947f169c0eaSGlenn Lagasse int
be_update_vfstab(char * be_name,char * old_rc_loc,char * new_rc_loc,be_fs_list_data_t * fld,char * mountpoint)1948f169c0eaSGlenn Lagasse be_update_vfstab(char *be_name, char *old_rc_loc, char *new_rc_loc,
1949f169c0eaSGlenn Lagasse be_fs_list_data_t *fld, char *mountpoint)
1950f169c0eaSGlenn Lagasse {
1951f169c0eaSGlenn Lagasse char *tmp_mountpoint = NULL;
1952f169c0eaSGlenn Lagasse char alt_vfstab[MAXPATHLEN];
1953f169c0eaSGlenn Lagasse int ret = BE_SUCCESS, err = BE_SUCCESS;
1954f169c0eaSGlenn Lagasse
1955f169c0eaSGlenn Lagasse if (fld == NULL || fld->fs_list == NULL || fld->fs_num == 0)
1956f169c0eaSGlenn Lagasse return (BE_SUCCESS);
1957f169c0eaSGlenn Lagasse
1958f169c0eaSGlenn Lagasse /* If BE not already mounted, mount the BE */
1959f169c0eaSGlenn Lagasse if (mountpoint == NULL) {
1960f169c0eaSGlenn Lagasse if ((ret = _be_mount(be_name, &tmp_mountpoint,
1961f169c0eaSGlenn Lagasse BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1962f169c0eaSGlenn Lagasse be_print_err(gettext("be_update_vfstab: "
1963f169c0eaSGlenn Lagasse "failed to mount BE (%s)\n"), be_name);
1964f169c0eaSGlenn Lagasse return (ret);
1965f169c0eaSGlenn Lagasse }
1966f169c0eaSGlenn Lagasse } else {
1967f169c0eaSGlenn Lagasse tmp_mountpoint = mountpoint;
1968f169c0eaSGlenn Lagasse }
1969f169c0eaSGlenn Lagasse
1970f169c0eaSGlenn Lagasse /* Get string for vfstab in the mounted BE. */
1971f169c0eaSGlenn Lagasse (void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab",
1972f169c0eaSGlenn Lagasse tmp_mountpoint);
1973f169c0eaSGlenn Lagasse
1974f169c0eaSGlenn Lagasse /* Update the vfstab */
1975f169c0eaSGlenn Lagasse ret = _update_vfstab(alt_vfstab, be_name, old_rc_loc, new_rc_loc,
1976f169c0eaSGlenn Lagasse fld);
1977f169c0eaSGlenn Lagasse
1978f169c0eaSGlenn Lagasse /* Unmount BE if we mounted it */
1979f169c0eaSGlenn Lagasse if (mountpoint == NULL) {
1980f169c0eaSGlenn Lagasse if ((err = _be_unmount(be_name, 0)) == BE_SUCCESS) {
1981f169c0eaSGlenn Lagasse /* Remove temporary mountpoint */
1982f169c0eaSGlenn Lagasse (void) rmdir(tmp_mountpoint);
1983f169c0eaSGlenn Lagasse } else {
1984f169c0eaSGlenn Lagasse be_print_err(gettext("be_update_vfstab: "
1985f169c0eaSGlenn Lagasse "failed to unmount BE %s mounted at %s\n"),
1986f169c0eaSGlenn Lagasse be_name, tmp_mountpoint);
1987f169c0eaSGlenn Lagasse if (ret == BE_SUCCESS)
1988f169c0eaSGlenn Lagasse ret = err;
1989f169c0eaSGlenn Lagasse }
1990f169c0eaSGlenn Lagasse
1991f169c0eaSGlenn Lagasse free(tmp_mountpoint);
1992f169c0eaSGlenn Lagasse }
1993f169c0eaSGlenn Lagasse
1994f169c0eaSGlenn Lagasse return (ret);
1995f169c0eaSGlenn Lagasse }
1996f169c0eaSGlenn Lagasse
1997f169c0eaSGlenn Lagasse /*
1998f169c0eaSGlenn Lagasse * Function: be_update_zone_vfstab
1999f169c0eaSGlenn Lagasse * Description: This function digs into a zone BE's vfstab and updates all
2000f169c0eaSGlenn Lagasse * entries with file systems listed in be_fs_list_data_t.
2001f169c0eaSGlenn Lagasse * The entry's root container dataset and be_name will be
2002f169c0eaSGlenn Lagasse * updated with the parameters passed in.
2003f169c0eaSGlenn Lagasse * Parameters:
2004f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to zone root dataset.
2005f169c0eaSGlenn Lagasse * be_name - name of zone BE to update
2006f169c0eaSGlenn Lagasse * old_rc_loc - dataset under which the root container dataset
2007f169c0eaSGlenn Lagasse * of the old zone BE resides in.
2008f169c0eaSGlenn Lagasse * new_rc_loc - dataset under which the root container dataset
2009f169c0eaSGlenn Lagasse * of the new zone BE resides in.
2010f169c0eaSGlenn Lagasse * fld - be_fs_list_data_t pointer providing the list of
2011f169c0eaSGlenn Lagasse * file systems to look for in vfstab.
2012f169c0eaSGlenn Lagasse * Returns:
2013f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
2014f169c0eaSGlenn Lagasse * be_errno_t - Failure
2015f169c0eaSGlenn Lagasse * Scope:
2016f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2017f169c0eaSGlenn Lagasse */
2018f169c0eaSGlenn Lagasse int
be_update_zone_vfstab(zfs_handle_t * zhp,char * be_name,char * old_rc_loc,char * new_rc_loc,be_fs_list_data_t * fld)2019f169c0eaSGlenn Lagasse be_update_zone_vfstab(zfs_handle_t *zhp, char *be_name, char *old_rc_loc,
2020f169c0eaSGlenn Lagasse char *new_rc_loc, be_fs_list_data_t *fld)
2021f169c0eaSGlenn Lagasse {
2022f169c0eaSGlenn Lagasse be_mount_data_t md = { 0 };
2023f169c0eaSGlenn Lagasse be_unmount_data_t ud = { 0 };
2024f169c0eaSGlenn Lagasse char alt_vfstab[MAXPATHLEN];
2025f169c0eaSGlenn Lagasse boolean_t mounted_here = B_FALSE;
2026f169c0eaSGlenn Lagasse int ret = BE_SUCCESS;
2027f169c0eaSGlenn Lagasse
2028f169c0eaSGlenn Lagasse /*
2029f169c0eaSGlenn Lagasse * If zone root not already mounted, mount it at a
2030f169c0eaSGlenn Lagasse * temporary location.
2031f169c0eaSGlenn Lagasse */
2032f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &md.altroot)) {
2033f169c0eaSGlenn Lagasse /* Generate temporary mountpoint to mount zone root */
2034f169c0eaSGlenn Lagasse if ((ret = be_make_tmp_mountpoint(&md.altroot)) != BE_SUCCESS) {
2035f169c0eaSGlenn Lagasse be_print_err(gettext("be_update_zone_vfstab: "
2036f169c0eaSGlenn Lagasse "failed to make temporary mountpoint to "
2037f169c0eaSGlenn Lagasse "mount zone root\n"));
2038f169c0eaSGlenn Lagasse return (ret);
2039f169c0eaSGlenn Lagasse }
2040f169c0eaSGlenn Lagasse
2041f169c0eaSGlenn Lagasse if (be_mount_zone_root(zhp, &md) != BE_SUCCESS) {
2042f169c0eaSGlenn Lagasse be_print_err(gettext("be_update_zone_vfstab: "
2043f169c0eaSGlenn Lagasse "failed to mount zone root %s\n"),
2044f169c0eaSGlenn Lagasse zfs_get_name(zhp));
2045f169c0eaSGlenn Lagasse free(md.altroot);
2046f169c0eaSGlenn Lagasse return (BE_ERR_MOUNT_ZONEROOT);
2047f169c0eaSGlenn Lagasse }
2048f169c0eaSGlenn Lagasse mounted_here = B_TRUE;
2049f169c0eaSGlenn Lagasse }
2050f169c0eaSGlenn Lagasse
2051f169c0eaSGlenn Lagasse /* Get string from vfstab in the mounted zone BE */
2052f169c0eaSGlenn Lagasse (void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab",
2053f169c0eaSGlenn Lagasse md.altroot);
2054f169c0eaSGlenn Lagasse
2055f169c0eaSGlenn Lagasse /* Update the vfstab */
2056f169c0eaSGlenn Lagasse ret = _update_vfstab(alt_vfstab, be_name, old_rc_loc, new_rc_loc,
2057f169c0eaSGlenn Lagasse fld);
2058f169c0eaSGlenn Lagasse
2059f169c0eaSGlenn Lagasse /* Unmount zone root if we mounted it */
2060f169c0eaSGlenn Lagasse if (mounted_here) {
2061f169c0eaSGlenn Lagasse ud.force = B_TRUE;
2062f169c0eaSGlenn Lagasse
2063f169c0eaSGlenn Lagasse if (be_unmount_zone_root(zhp, &ud) == BE_SUCCESS) {
2064f169c0eaSGlenn Lagasse /* Remove the temporary mountpoint */
2065f169c0eaSGlenn Lagasse (void) rmdir(md.altroot);
2066f169c0eaSGlenn Lagasse } else {
2067f169c0eaSGlenn Lagasse be_print_err(gettext("be_update_zone_vfstab: "
2068f169c0eaSGlenn Lagasse "failed to unmount zone root %s from %s\n"),
2069f169c0eaSGlenn Lagasse zfs_get_name(zhp), md.altroot);
2070f169c0eaSGlenn Lagasse if (ret == 0)
2071f169c0eaSGlenn Lagasse ret = BE_ERR_UMOUNT_ZONEROOT;
2072f169c0eaSGlenn Lagasse }
2073f169c0eaSGlenn Lagasse }
2074f169c0eaSGlenn Lagasse
2075f169c0eaSGlenn Lagasse free(md.altroot);
2076f169c0eaSGlenn Lagasse return (ret);
2077f169c0eaSGlenn Lagasse }
2078f169c0eaSGlenn Lagasse
2079f169c0eaSGlenn Lagasse /*
2080f169c0eaSGlenn Lagasse * Function: be_auto_snap_name
2081f169c0eaSGlenn Lagasse * Description: Generate an auto snapshot name constructed based on the
2082f169c0eaSGlenn Lagasse * current date and time. The auto snapshot name is of the form:
2083f169c0eaSGlenn Lagasse *
2084f169c0eaSGlenn Lagasse * <date>-<time>
2085f169c0eaSGlenn Lagasse *
2086f169c0eaSGlenn Lagasse * where <date> is in ISO standard format, so the resultant name
2087f169c0eaSGlenn Lagasse * is of the form:
2088f169c0eaSGlenn Lagasse *
2089f169c0eaSGlenn Lagasse * %Y-%m-%d-%H:%M:%S
2090f169c0eaSGlenn Lagasse *
2091f169c0eaSGlenn Lagasse * Parameters:
2092f169c0eaSGlenn Lagasse * None
2093f169c0eaSGlenn Lagasse * Returns:
2094f169c0eaSGlenn Lagasse * Success - pointer to auto generated snapshot name. The name
2095f169c0eaSGlenn Lagasse * is allocated in heap storage so the caller is
2096f169c0eaSGlenn Lagasse * responsible for free'ing the name.
2097f169c0eaSGlenn Lagasse * Failure - NULL
2098f169c0eaSGlenn Lagasse * Scope:
2099f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2100f169c0eaSGlenn Lagasse */
2101f169c0eaSGlenn Lagasse char *
be_auto_snap_name(void)2102f169c0eaSGlenn Lagasse be_auto_snap_name(void)
2103f169c0eaSGlenn Lagasse {
2104f169c0eaSGlenn Lagasse time_t utc_tm = NULL;
2105f169c0eaSGlenn Lagasse struct tm *gmt_tm = NULL;
2106f169c0eaSGlenn Lagasse char gmt_time_str[64];
2107f169c0eaSGlenn Lagasse char *auto_snap_name = NULL;
2108f169c0eaSGlenn Lagasse
2109f169c0eaSGlenn Lagasse if (time(&utc_tm) == -1) {
2110f169c0eaSGlenn Lagasse be_print_err(gettext("be_auto_snap_name: time() failed\n"));
2111f169c0eaSGlenn Lagasse return (NULL);
2112f169c0eaSGlenn Lagasse }
2113f169c0eaSGlenn Lagasse
2114f169c0eaSGlenn Lagasse if ((gmt_tm = gmtime(&utc_tm)) == NULL) {
2115f169c0eaSGlenn Lagasse be_print_err(gettext("be_auto_snap_name: gmtime() failed\n"));
2116f169c0eaSGlenn Lagasse return (NULL);
2117f169c0eaSGlenn Lagasse }
2118f169c0eaSGlenn Lagasse
2119f169c0eaSGlenn Lagasse (void) strftime(gmt_time_str, sizeof (gmt_time_str), "%F-%T", gmt_tm);
2120f169c0eaSGlenn Lagasse
2121f169c0eaSGlenn Lagasse if ((auto_snap_name = strdup(gmt_time_str)) == NULL) {
2122f169c0eaSGlenn Lagasse be_print_err(gettext("be_auto_snap_name: "
2123f169c0eaSGlenn Lagasse "memory allocation failed\n"));
2124f169c0eaSGlenn Lagasse return (NULL);
2125f169c0eaSGlenn Lagasse }
2126f169c0eaSGlenn Lagasse
2127f169c0eaSGlenn Lagasse return (auto_snap_name);
2128f169c0eaSGlenn Lagasse }
2129f169c0eaSGlenn Lagasse
2130f169c0eaSGlenn Lagasse /*
2131f169c0eaSGlenn Lagasse * Function: be_auto_be_name
2132f169c0eaSGlenn Lagasse * Description: Generate an auto BE name constructed based on the BE name
2133f169c0eaSGlenn Lagasse * of the original BE being cloned.
2134f169c0eaSGlenn Lagasse * Parameters:
2135f169c0eaSGlenn Lagasse * obe_name - name of the original BE being cloned.
2136f169c0eaSGlenn Lagasse * Returns:
2137f169c0eaSGlenn Lagasse * Success - pointer to auto generated BE name. The name
2138f169c0eaSGlenn Lagasse * is allocated in heap storage so the caller is
2139f169c0eaSGlenn Lagasse * responsible for free'ing the name.
2140f169c0eaSGlenn Lagasse * Failure - NULL
2141f169c0eaSGlenn Lagasse * Scope:
2142f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2143f169c0eaSGlenn Lagasse */
2144f169c0eaSGlenn Lagasse char *
be_auto_be_name(char * obe_name)2145f169c0eaSGlenn Lagasse be_auto_be_name(char *obe_name)
2146f169c0eaSGlenn Lagasse {
2147f169c0eaSGlenn Lagasse return (be_get_auto_name(obe_name, NULL, B_FALSE));
2148f169c0eaSGlenn Lagasse }
2149f169c0eaSGlenn Lagasse
2150f169c0eaSGlenn Lagasse /*
2151f169c0eaSGlenn Lagasse * Function: be_auto_zone_be_name
2152f169c0eaSGlenn Lagasse * Description: Generate an auto BE name for a zone constructed based on
2153f169c0eaSGlenn Lagasse * the BE name of the original zone BE being cloned.
2154f169c0eaSGlenn Lagasse * Parameters:
2155f169c0eaSGlenn Lagasse * container_ds - container dataset for the zone.
2156f169c0eaSGlenn Lagasse * zbe_name - name of the original zone BE being cloned.
2157f169c0eaSGlenn Lagasse * Returns:
2158f169c0eaSGlenn Lagasse * Success - pointer to auto generated BE name. The name
2159f169c0eaSGlenn Lagasse * is allocated in heap storage so the caller is
2160f169c0eaSGlenn Lagasse * responsible for free'ing the name.
2161f169c0eaSGlenn Lagasse * Failure - NULL
2162f169c0eaSGlenn Lagasse * Scope:
2163f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2164f169c0eaSGlenn Lagasse */
2165f169c0eaSGlenn Lagasse char *
be_auto_zone_be_name(char * container_ds,char * zbe_name)2166f169c0eaSGlenn Lagasse be_auto_zone_be_name(char *container_ds, char *zbe_name)
2167f169c0eaSGlenn Lagasse {
2168f169c0eaSGlenn Lagasse return (be_get_auto_name(zbe_name, container_ds, B_TRUE));
2169f169c0eaSGlenn Lagasse }
2170f169c0eaSGlenn Lagasse
2171f169c0eaSGlenn Lagasse /*
2172f169c0eaSGlenn Lagasse * Function: be_valid_be_name
2173f169c0eaSGlenn Lagasse * Description: Validates a BE name.
2174f169c0eaSGlenn Lagasse * Parameters:
2175f169c0eaSGlenn Lagasse * be_name - name of BE to validate
2176f169c0eaSGlenn Lagasse * Returns:
2177f169c0eaSGlenn Lagasse * B_TRUE - be_name is valid
2178f169c0eaSGlenn Lagasse * B_FALSE - be_name is invalid
2179f169c0eaSGlenn Lagasse * Scope:
2180f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2181f169c0eaSGlenn Lagasse */
2182f169c0eaSGlenn Lagasse
2183f169c0eaSGlenn Lagasse boolean_t
be_valid_be_name(const char * be_name)2184f169c0eaSGlenn Lagasse be_valid_be_name(const char *be_name)
2185f169c0eaSGlenn Lagasse {
2186f169c0eaSGlenn Lagasse const char *c = NULL;
2187de1ab35cSAlexander Eremin struct be_defaults be_defaults;
2188f169c0eaSGlenn Lagasse
2189f169c0eaSGlenn Lagasse if (be_name == NULL)
2190f169c0eaSGlenn Lagasse return (B_FALSE);
2191f169c0eaSGlenn Lagasse
2192de1ab35cSAlexander Eremin be_get_defaults(&be_defaults);
2193de1ab35cSAlexander Eremin
2194f169c0eaSGlenn Lagasse /*
2195f169c0eaSGlenn Lagasse * A BE name must not be a multi-level dataset name. We also check
2196f169c0eaSGlenn Lagasse * that it does not contain the ' ' and '%' characters. The ' ' is
2197f169c0eaSGlenn Lagasse * a valid character for datasets, however we don't allow that in a
2198f169c0eaSGlenn Lagasse * BE name. The '%' is invalid, but zfs_name_valid() allows it for
2199f169c0eaSGlenn Lagasse * internal reasons, so we explicitly check for it here.
2200f169c0eaSGlenn Lagasse */
2201f169c0eaSGlenn Lagasse c = be_name;
2202f169c0eaSGlenn Lagasse while (*c != '\0' && *c != '/' && *c != ' ' && *c != '%')
2203f169c0eaSGlenn Lagasse c++;
2204f169c0eaSGlenn Lagasse
2205f169c0eaSGlenn Lagasse if (*c != '\0')
2206f169c0eaSGlenn Lagasse return (B_FALSE);
2207f169c0eaSGlenn Lagasse
2208f169c0eaSGlenn Lagasse /*
2209f169c0eaSGlenn Lagasse * The BE name must comply with a zfs dataset filesystem. We also
2210f169c0eaSGlenn Lagasse * verify its length to be < BE_NAME_MAX_LEN.
2211f169c0eaSGlenn Lagasse */
2212f169c0eaSGlenn Lagasse if (!zfs_name_valid(be_name, ZFS_TYPE_FILESYSTEM) ||
2213f169c0eaSGlenn Lagasse strlen(be_name) > BE_NAME_MAX_LEN)
2214f169c0eaSGlenn Lagasse return (B_FALSE);
2215f169c0eaSGlenn Lagasse
2216de1ab35cSAlexander Eremin if (be_defaults.be_deflt_bename_starts_with[0] != '\0' &&
2217de1ab35cSAlexander Eremin strstr(be_name, be_defaults.be_deflt_bename_starts_with) == NULL) {
2218de1ab35cSAlexander Eremin return (B_FALSE);
2219de1ab35cSAlexander Eremin }
2220de1ab35cSAlexander Eremin
2221f169c0eaSGlenn Lagasse return (B_TRUE);
2222f169c0eaSGlenn Lagasse }
2223f169c0eaSGlenn Lagasse
2224f169c0eaSGlenn Lagasse /*
2225f169c0eaSGlenn Lagasse * Function: be_valid_auto_snap_name
2226f169c0eaSGlenn Lagasse * Description: This function checks that a snapshot name is a valid auto
2227f169c0eaSGlenn Lagasse * generated snapshot name. A valid auto generated snapshot
2228f169c0eaSGlenn Lagasse * name is of the form:
2229f169c0eaSGlenn Lagasse *
2230f169c0eaSGlenn Lagasse * %Y-%m-%d-%H:%M:%S
2231f169c0eaSGlenn Lagasse *
2232f169c0eaSGlenn Lagasse * An older form of the auto generated snapshot name also
2233f169c0eaSGlenn Lagasse * included the snapshot's BE cleanup policy and a reserved
2234f169c0eaSGlenn Lagasse * field. Those names will also be verified by this function.
2235f169c0eaSGlenn Lagasse *
2236f169c0eaSGlenn Lagasse * Examples of valid auto snapshot names are:
2237f169c0eaSGlenn Lagasse *
2238f169c0eaSGlenn Lagasse * 2008-03-31-18:41:30
2239f169c0eaSGlenn Lagasse * 2008-03-31-22:17:24
2240f169c0eaSGlenn Lagasse * <policy>:-:2008:04-05-09:12:55
2241f169c0eaSGlenn Lagasse * <policy>:-:2008:04-06-15:34:12
2242f169c0eaSGlenn Lagasse *
2243f169c0eaSGlenn Lagasse * Parameters:
2244f169c0eaSGlenn Lagasse * name - name of the snapshot to be validated.
2245f169c0eaSGlenn Lagasse * Returns:
2246f169c0eaSGlenn Lagasse * B_TRUE - the name is a valid auto snapshot name.
2247f169c0eaSGlenn Lagasse * B_FALSE - the name is not a valid auto snapshot name.
2248f169c0eaSGlenn Lagasse * Scope:
2249f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2250f169c0eaSGlenn Lagasse */
2251f169c0eaSGlenn Lagasse boolean_t
be_valid_auto_snap_name(char * name)2252f169c0eaSGlenn Lagasse be_valid_auto_snap_name(char *name)
2253f169c0eaSGlenn Lagasse {
2254f169c0eaSGlenn Lagasse struct tm gmt_tm;
2255f169c0eaSGlenn Lagasse
2256f169c0eaSGlenn Lagasse char *policy = NULL;
2257f169c0eaSGlenn Lagasse char *reserved = NULL;
2258f169c0eaSGlenn Lagasse char *date = NULL;
2259f169c0eaSGlenn Lagasse char *c = NULL;
2260f169c0eaSGlenn Lagasse
2261f169c0eaSGlenn Lagasse /* Validate the snapshot name by converting it into utc time */
2262f169c0eaSGlenn Lagasse if (strptime(name, "%Y-%m-%d-%T", &gmt_tm) != NULL &&
2263f169c0eaSGlenn Lagasse (mktime(&gmt_tm) != -1)) {
2264f169c0eaSGlenn Lagasse return (B_TRUE);
2265f169c0eaSGlenn Lagasse }
2266f169c0eaSGlenn Lagasse
2267f169c0eaSGlenn Lagasse /*
2268f169c0eaSGlenn Lagasse * Validate the snapshot name against the older form of an
2269f169c0eaSGlenn Lagasse * auto generated snapshot name.
2270f169c0eaSGlenn Lagasse */
2271f169c0eaSGlenn Lagasse policy = strdup(name);
2272f169c0eaSGlenn Lagasse
2273f169c0eaSGlenn Lagasse /*
2274f169c0eaSGlenn Lagasse * Get the first field from the snapshot name,
2275f169c0eaSGlenn Lagasse * which is the BE policy
2276f169c0eaSGlenn Lagasse */
2277f169c0eaSGlenn Lagasse c = strchr(policy, ':');
2278f169c0eaSGlenn Lagasse if (c == NULL) {
2279f169c0eaSGlenn Lagasse free(policy);
2280f169c0eaSGlenn Lagasse return (B_FALSE);
2281f169c0eaSGlenn Lagasse }
2282f169c0eaSGlenn Lagasse c[0] = '\0';
2283f169c0eaSGlenn Lagasse
2284f169c0eaSGlenn Lagasse /* Validate the policy name */
2285f169c0eaSGlenn Lagasse if (!valid_be_policy(policy)) {
2286f169c0eaSGlenn Lagasse free(policy);
2287f169c0eaSGlenn Lagasse return (B_FALSE);
2288f169c0eaSGlenn Lagasse }
2289f169c0eaSGlenn Lagasse
2290f169c0eaSGlenn Lagasse /* Get the next field, which is the reserved field. */
2291f169c0eaSGlenn Lagasse if (c[1] == NULL || c[1] == '\0') {
2292f169c0eaSGlenn Lagasse free(policy);
2293f169c0eaSGlenn Lagasse return (B_FALSE);
2294f169c0eaSGlenn Lagasse }
2295f169c0eaSGlenn Lagasse reserved = c+1;
2296f169c0eaSGlenn Lagasse c = strchr(reserved, ':');
2297f169c0eaSGlenn Lagasse if (c == NULL) {
2298f169c0eaSGlenn Lagasse free(policy);
2299f169c0eaSGlenn Lagasse return (B_FALSE);
2300f169c0eaSGlenn Lagasse }
2301f169c0eaSGlenn Lagasse c[0] = '\0';
2302f169c0eaSGlenn Lagasse
2303f169c0eaSGlenn Lagasse /* Validate the reserved field */
2304f169c0eaSGlenn Lagasse if (strcmp(reserved, "-") != 0) {
2305f169c0eaSGlenn Lagasse free(policy);
2306f169c0eaSGlenn Lagasse return (B_FALSE);
2307f169c0eaSGlenn Lagasse }
2308f169c0eaSGlenn Lagasse
2309f169c0eaSGlenn Lagasse /* The remaining string should be the date field */
2310f169c0eaSGlenn Lagasse if (c[1] == NULL || c[1] == '\0') {
2311f169c0eaSGlenn Lagasse free(policy);
2312f169c0eaSGlenn Lagasse return (B_FALSE);
2313f169c0eaSGlenn Lagasse }
2314f169c0eaSGlenn Lagasse date = c+1;
2315f169c0eaSGlenn Lagasse
2316f169c0eaSGlenn Lagasse /* Validate the date string by converting it into utc time */
2317f169c0eaSGlenn Lagasse if (strptime(date, "%Y-%m-%d-%T", &gmt_tm) == NULL ||
2318f169c0eaSGlenn Lagasse (mktime(&gmt_tm) == -1)) {
2319f169c0eaSGlenn Lagasse be_print_err(gettext("be_valid_auto_snap_name: "
2320f169c0eaSGlenn Lagasse "invalid auto snapshot name\n"));
2321f169c0eaSGlenn Lagasse free(policy);
2322f169c0eaSGlenn Lagasse return (B_FALSE);
2323f169c0eaSGlenn Lagasse }
2324f169c0eaSGlenn Lagasse
2325f169c0eaSGlenn Lagasse free(policy);
2326f169c0eaSGlenn Lagasse return (B_TRUE);
2327f169c0eaSGlenn Lagasse }
2328f169c0eaSGlenn Lagasse
2329f169c0eaSGlenn Lagasse /*
2330f169c0eaSGlenn Lagasse * Function: be_default_policy
2331f169c0eaSGlenn Lagasse * Description: Temporary hardcoded policy support. This function returns
2332f169c0eaSGlenn Lagasse * the default policy type to be used to create a BE or a BE
2333f169c0eaSGlenn Lagasse * snapshot.
2334f169c0eaSGlenn Lagasse * Parameters:
2335f169c0eaSGlenn Lagasse * None
2336f169c0eaSGlenn Lagasse * Returns:
2337f169c0eaSGlenn Lagasse * Name of default BE policy.
2338f169c0eaSGlenn Lagasse * Scope:
2339f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2340f169c0eaSGlenn Lagasse */
2341f169c0eaSGlenn Lagasse char *
be_default_policy(void)2342f169c0eaSGlenn Lagasse be_default_policy(void)
2343f169c0eaSGlenn Lagasse {
2344f169c0eaSGlenn Lagasse return (BE_PLCY_STATIC);
2345f169c0eaSGlenn Lagasse }
2346f169c0eaSGlenn Lagasse
2347f169c0eaSGlenn Lagasse /*
2348f169c0eaSGlenn Lagasse * Function: valid_be_policy
2349f169c0eaSGlenn Lagasse * Description: Temporary hardcoded policy support. This function valids
2350f169c0eaSGlenn Lagasse * whether a policy is a valid known policy or not.
2351f169c0eaSGlenn Lagasse * Paramters:
2352f169c0eaSGlenn Lagasse * policy - name of policy to validate.
2353f169c0eaSGlenn Lagasse * Returns:
2354f169c0eaSGlenn Lagasse * B_TRUE - policy is a valid.
2355f169c0eaSGlenn Lagasse * B_FALSE - policy is invalid.
2356f169c0eaSGlenn Lagasse * Scope:
2357f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2358f169c0eaSGlenn Lagasse */
2359f169c0eaSGlenn Lagasse boolean_t
valid_be_policy(char * policy)2360f169c0eaSGlenn Lagasse valid_be_policy(char *policy)
2361f169c0eaSGlenn Lagasse {
2362f169c0eaSGlenn Lagasse if (policy == NULL)
2363f169c0eaSGlenn Lagasse return (B_FALSE);
2364f169c0eaSGlenn Lagasse
2365f169c0eaSGlenn Lagasse if (strcmp(policy, BE_PLCY_STATIC) == 0 ||
2366f169c0eaSGlenn Lagasse strcmp(policy, BE_PLCY_VOLATILE) == 0) {
2367f169c0eaSGlenn Lagasse return (B_TRUE);
2368f169c0eaSGlenn Lagasse }
2369f169c0eaSGlenn Lagasse
2370f169c0eaSGlenn Lagasse return (B_FALSE);
2371f169c0eaSGlenn Lagasse }
2372f169c0eaSGlenn Lagasse
2373f169c0eaSGlenn Lagasse /*
2374f169c0eaSGlenn Lagasse * Function: be_print_err
2375f169c0eaSGlenn Lagasse * Description: This function prints out error messages if do_print is
2376f169c0eaSGlenn Lagasse * set to B_TRUE or if the BE_PRINT_ERR environment variable
2377f169c0eaSGlenn Lagasse * is set to true.
2378f169c0eaSGlenn Lagasse * Paramters:
2379f169c0eaSGlenn Lagasse * prnt_str - the string we wish to print and any arguments
2380f169c0eaSGlenn Lagasse * for the format of that string.
2381f169c0eaSGlenn Lagasse * Returns:
2382f169c0eaSGlenn Lagasse * void
2383f169c0eaSGlenn Lagasse * Scope:
2384f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2385f169c0eaSGlenn Lagasse */
2386f169c0eaSGlenn Lagasse void
be_print_err(char * prnt_str,...)2387f169c0eaSGlenn Lagasse be_print_err(char *prnt_str, ...)
2388f169c0eaSGlenn Lagasse {
2389f169c0eaSGlenn Lagasse va_list ap;
2390f169c0eaSGlenn Lagasse char buf[BUFSIZ];
2391f169c0eaSGlenn Lagasse char *env_buf;
2392f169c0eaSGlenn Lagasse static boolean_t env_checked = B_FALSE;
2393f169c0eaSGlenn Lagasse
2394f169c0eaSGlenn Lagasse if (!env_checked) {
2395f169c0eaSGlenn Lagasse if ((env_buf = getenv("BE_PRINT_ERR")) != NULL) {
2396f169c0eaSGlenn Lagasse if (strcasecmp(env_buf, "true") == 0) {
2397f169c0eaSGlenn Lagasse do_print = B_TRUE;
2398f169c0eaSGlenn Lagasse }
2399f169c0eaSGlenn Lagasse }
2400f169c0eaSGlenn Lagasse env_checked = B_TRUE;
2401f169c0eaSGlenn Lagasse }
2402f169c0eaSGlenn Lagasse
2403f169c0eaSGlenn Lagasse if (do_print) {
2404f169c0eaSGlenn Lagasse va_start(ap, prnt_str);
2405f169c0eaSGlenn Lagasse /* LINTED variable format specifier */
2406f169c0eaSGlenn Lagasse (void) vsnprintf(buf, BUFSIZ, prnt_str, ap);
2407f169c0eaSGlenn Lagasse (void) fputs(buf, stderr);
2408f169c0eaSGlenn Lagasse va_end(ap);
2409f169c0eaSGlenn Lagasse }
2410f169c0eaSGlenn Lagasse }
2411f169c0eaSGlenn Lagasse
2412f169c0eaSGlenn Lagasse /*
2413f169c0eaSGlenn Lagasse * Function: be_find_current_be
2414f169c0eaSGlenn Lagasse * Description: Find the currently "active" BE. Fill in the
2415f169c0eaSGlenn Lagasse * passed in be_transaction_data_t reference with the
2416f169c0eaSGlenn Lagasse * active BE's data.
2417f169c0eaSGlenn Lagasse * Paramters:
2418f169c0eaSGlenn Lagasse * none
2419f169c0eaSGlenn Lagasse * Returns:
2420f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
2421f169c0eaSGlenn Lagasse * be_errnot_t - Failure
2422f169c0eaSGlenn Lagasse * Scope:
2423f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2424f169c0eaSGlenn Lagasse * Notes:
2425f169c0eaSGlenn Lagasse * The caller is responsible for initializing the libzfs handle
2426f169c0eaSGlenn Lagasse * and freeing the memory used by the active be_name.
2427f169c0eaSGlenn Lagasse */
2428f169c0eaSGlenn Lagasse int
be_find_current_be(be_transaction_data_t * bt)2429f169c0eaSGlenn Lagasse be_find_current_be(be_transaction_data_t *bt)
2430f169c0eaSGlenn Lagasse {
2431f169c0eaSGlenn Lagasse int zret;
2432f169c0eaSGlenn Lagasse
2433f169c0eaSGlenn Lagasse if ((zret = zpool_iter(g_zfs, be_zpool_find_current_be_callback,
2434f169c0eaSGlenn Lagasse bt)) == 0) {
2435f169c0eaSGlenn Lagasse be_print_err(gettext("be_find_current_be: failed to "
2436f169c0eaSGlenn Lagasse "find current BE name\n"));
2437f169c0eaSGlenn Lagasse return (BE_ERR_BE_NOENT);
2438f169c0eaSGlenn Lagasse } else if (zret < 0) {
2439f169c0eaSGlenn Lagasse be_print_err(gettext("be_find_current_be: "
2440f169c0eaSGlenn Lagasse "zpool_iter failed: %s\n"),
2441f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
2442f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs));
2443f169c0eaSGlenn Lagasse }
2444f169c0eaSGlenn Lagasse
2445f169c0eaSGlenn Lagasse return (BE_SUCCESS);
2446f169c0eaSGlenn Lagasse }
2447f169c0eaSGlenn Lagasse
2448f169c0eaSGlenn Lagasse /*
2449f169c0eaSGlenn Lagasse * Function: be_zpool_find_current_be_callback
2450f169c0eaSGlenn Lagasse * Description: Callback function used to iterate through all existing pools
2451f169c0eaSGlenn Lagasse * to find the BE that is the currently booted BE.
2452f169c0eaSGlenn Lagasse * Parameters:
2453f169c0eaSGlenn Lagasse * zlp - zpool_handle_t pointer to the current pool being
2454f169c0eaSGlenn Lagasse * looked at.
2455f169c0eaSGlenn Lagasse * data - be_transaction_data_t pointer.
2456f169c0eaSGlenn Lagasse * Upon successfully finding the current BE, the
2457f169c0eaSGlenn Lagasse * obe_zpool member of this parameter is set to the
2458f169c0eaSGlenn Lagasse * pool it is found in.
2459f169c0eaSGlenn Lagasse * Return:
2460f169c0eaSGlenn Lagasse * 1 - Found current BE in this pool.
2461f169c0eaSGlenn Lagasse * 0 - Did not find current BE in this pool.
2462f169c0eaSGlenn Lagasse * Scope:
2463f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2464f169c0eaSGlenn Lagasse */
2465f169c0eaSGlenn Lagasse int
be_zpool_find_current_be_callback(zpool_handle_t * zlp,void * data)2466f169c0eaSGlenn Lagasse be_zpool_find_current_be_callback(zpool_handle_t *zlp, void *data)
2467f169c0eaSGlenn Lagasse {
2468f169c0eaSGlenn Lagasse be_transaction_data_t *bt = data;
2469f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL;
2470f169c0eaSGlenn Lagasse const char *zpool = zpool_get_name(zlp);
2471f169c0eaSGlenn Lagasse char be_container_ds[MAXPATHLEN];
24727e0e2549SAlexander Eremin char *zpath = NULL;
2473f169c0eaSGlenn Lagasse
2474f169c0eaSGlenn Lagasse /*
2475f169c0eaSGlenn Lagasse * Generate string for BE container dataset
2476f169c0eaSGlenn Lagasse */
24777e0e2549SAlexander Eremin if (getzoneid() != GLOBAL_ZONEID) {
24787e0e2549SAlexander Eremin if ((zpath = be_get_ds_from_dir("/")) != NULL) {
24797e0e2549SAlexander Eremin (void) strlcpy(be_container_ds, dirname(zpath),
24807e0e2549SAlexander Eremin sizeof (be_container_ds));
24817e0e2549SAlexander Eremin } else {
24827e0e2549SAlexander Eremin be_print_err(gettext(
24837e0e2549SAlexander Eremin "be_zpool_find_current_be_callback: "
24847e0e2549SAlexander Eremin "zone root dataset is not mounted\n"));
24857e0e2549SAlexander Eremin return (0);
24867e0e2549SAlexander Eremin }
24877e0e2549SAlexander Eremin } else {
24887e0e2549SAlexander Eremin be_make_container_ds(zpool, be_container_ds,
24897e0e2549SAlexander Eremin sizeof (be_container_ds));
24907e0e2549SAlexander Eremin }
2491f169c0eaSGlenn Lagasse
2492f169c0eaSGlenn Lagasse /*
2493f169c0eaSGlenn Lagasse * Check if a BE container dataset exists in this pool.
2494f169c0eaSGlenn Lagasse */
2495f169c0eaSGlenn Lagasse if (!zfs_dataset_exists(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) {
2496f169c0eaSGlenn Lagasse zpool_close(zlp);
2497f169c0eaSGlenn Lagasse return (0);
2498f169c0eaSGlenn Lagasse }
2499f169c0eaSGlenn Lagasse
2500f169c0eaSGlenn Lagasse /*
2501f169c0eaSGlenn Lagasse * Get handle to this zpool's BE container dataset.
2502f169c0eaSGlenn Lagasse */
2503f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) ==
2504f169c0eaSGlenn Lagasse NULL) {
2505f169c0eaSGlenn Lagasse be_print_err(gettext("be_zpool_find_current_be_callback: "
2506f169c0eaSGlenn Lagasse "failed to open BE container dataset (%s)\n"),
2507f169c0eaSGlenn Lagasse be_container_ds);
2508f169c0eaSGlenn Lagasse zpool_close(zlp);
2509f169c0eaSGlenn Lagasse return (0);
2510f169c0eaSGlenn Lagasse }
2511f169c0eaSGlenn Lagasse
2512f169c0eaSGlenn Lagasse /*
2513f169c0eaSGlenn Lagasse * Iterate through all potential BEs in this zpool
2514f169c0eaSGlenn Lagasse */
2515f169c0eaSGlenn Lagasse if (zfs_iter_filesystems(zhp, be_zfs_find_current_be_callback, bt)) {
2516f169c0eaSGlenn Lagasse /*
2517f169c0eaSGlenn Lagasse * Found current BE dataset; set obe_zpool
2518f169c0eaSGlenn Lagasse */
2519f169c0eaSGlenn Lagasse if ((bt->obe_zpool = strdup(zpool)) == NULL) {
2520f169c0eaSGlenn Lagasse be_print_err(gettext(
2521f169c0eaSGlenn Lagasse "be_zpool_find_current_be_callback: "
2522f169c0eaSGlenn Lagasse "memory allocation failed\n"));
2523f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
2524f169c0eaSGlenn Lagasse zpool_close(zlp);
2525f169c0eaSGlenn Lagasse return (0);
2526f169c0eaSGlenn Lagasse }
2527f169c0eaSGlenn Lagasse
2528f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
2529f169c0eaSGlenn Lagasse zpool_close(zlp);
2530f169c0eaSGlenn Lagasse return (1);
2531f169c0eaSGlenn Lagasse }
2532f169c0eaSGlenn Lagasse
2533f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
2534f169c0eaSGlenn Lagasse zpool_close(zlp);
2535f169c0eaSGlenn Lagasse
2536f169c0eaSGlenn Lagasse return (0);
2537f169c0eaSGlenn Lagasse }
2538f169c0eaSGlenn Lagasse
2539f169c0eaSGlenn Lagasse /*
2540f169c0eaSGlenn Lagasse * Function: be_zfs_find_current_be_callback
2541f169c0eaSGlenn Lagasse * Description: Callback function used to iterate through all BEs in a
2542f169c0eaSGlenn Lagasse * pool to find the BE that is the currently booted BE.
2543f169c0eaSGlenn Lagasse * Parameters:
2544f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to current filesystem being checked.
2545f169c0eaSGlenn Lagasse * data - be_transaction-data_t pointer
2546f169c0eaSGlenn Lagasse * Upon successfully finding the current BE, the
2547f169c0eaSGlenn Lagasse * obe_name and obe_root_ds members of this parameter
2548f169c0eaSGlenn Lagasse * are set to the BE name and BE's root dataset
2549f169c0eaSGlenn Lagasse * respectively.
2550f169c0eaSGlenn Lagasse * Return:
2551f169c0eaSGlenn Lagasse * 1 - Found current BE.
2552f169c0eaSGlenn Lagasse * 0 - Did not find current BE.
2553f169c0eaSGlenn Lagasse * Scope:
2554f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2555f169c0eaSGlenn Lagasse */
2556f169c0eaSGlenn Lagasse int
be_zfs_find_current_be_callback(zfs_handle_t * zhp,void * data)2557f169c0eaSGlenn Lagasse be_zfs_find_current_be_callback(zfs_handle_t *zhp, void *data)
2558f169c0eaSGlenn Lagasse {
2559f169c0eaSGlenn Lagasse be_transaction_data_t *bt = data;
2560f169c0eaSGlenn Lagasse char *mp = NULL;
2561f169c0eaSGlenn Lagasse
2562f169c0eaSGlenn Lagasse /*
2563f169c0eaSGlenn Lagasse * Check if dataset is mounted, and if so where.
2564f169c0eaSGlenn Lagasse */
2565f169c0eaSGlenn Lagasse if (zfs_is_mounted(zhp, &mp)) {
2566f169c0eaSGlenn Lagasse /*
2567f169c0eaSGlenn Lagasse * If mounted at root, set obe_root_ds and obe_name
2568f169c0eaSGlenn Lagasse */
2569f169c0eaSGlenn Lagasse if (mp != NULL && strcmp(mp, "/") == 0) {
2570f169c0eaSGlenn Lagasse free(mp);
2571f169c0eaSGlenn Lagasse
2572f169c0eaSGlenn Lagasse if ((bt->obe_root_ds = strdup(zfs_get_name(zhp)))
2573f169c0eaSGlenn Lagasse == NULL) {
2574f169c0eaSGlenn Lagasse be_print_err(gettext(
2575f169c0eaSGlenn Lagasse "be_zfs_find_current_be_callback: "
2576f169c0eaSGlenn Lagasse "memory allocation failed\n"));
2577f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
2578f169c0eaSGlenn Lagasse return (0);
2579f169c0eaSGlenn Lagasse }
2580de1ab35cSAlexander Eremin
2581f169c0eaSGlenn Lagasse if ((bt->obe_name = strdup(basename(bt->obe_root_ds)))
2582f169c0eaSGlenn Lagasse == NULL) {
2583f169c0eaSGlenn Lagasse be_print_err(gettext(
2584f169c0eaSGlenn Lagasse "be_zfs_find_current_be_callback: "
2585f169c0eaSGlenn Lagasse "memory allocation failed\n"));
2586f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
2587f169c0eaSGlenn Lagasse return (0);
2588f169c0eaSGlenn Lagasse }
2589f169c0eaSGlenn Lagasse
2590f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
2591f169c0eaSGlenn Lagasse return (1);
2592f169c0eaSGlenn Lagasse }
2593f169c0eaSGlenn Lagasse
2594f169c0eaSGlenn Lagasse free(mp);
2595f169c0eaSGlenn Lagasse }
2596f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
2597f169c0eaSGlenn Lagasse
2598f169c0eaSGlenn Lagasse return (0);
2599f169c0eaSGlenn Lagasse }
2600f169c0eaSGlenn Lagasse
2601f169c0eaSGlenn Lagasse /*
2602f169c0eaSGlenn Lagasse * Function: be_check_be_roots_callback
2603f169c0eaSGlenn Lagasse * Description: This function checks whether or not the dataset name passed
2604f169c0eaSGlenn Lagasse * is hierachically located under the BE root container dataset
2605f169c0eaSGlenn Lagasse * for this pool.
2606f169c0eaSGlenn Lagasse * Parameters:
2607f169c0eaSGlenn Lagasse * zlp - zpool_handle_t pointer to current pool being processed.
2608f169c0eaSGlenn Lagasse * data - name of dataset to check
2609f169c0eaSGlenn Lagasse * Returns:
2610f169c0eaSGlenn Lagasse * 0 - dataset is not in this pool's BE root container dataset
2611f169c0eaSGlenn Lagasse * 1 - dataset is in this pool's BE root container dataset
2612f169c0eaSGlenn Lagasse * Scope:
2613f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2614f169c0eaSGlenn Lagasse */
2615f169c0eaSGlenn Lagasse int
be_check_be_roots_callback(zpool_handle_t * zlp,void * data)2616f169c0eaSGlenn Lagasse be_check_be_roots_callback(zpool_handle_t *zlp, void *data)
2617f169c0eaSGlenn Lagasse {
2618f169c0eaSGlenn Lagasse const char *zpool = zpool_get_name(zlp);
2619f169c0eaSGlenn Lagasse char *ds = data;
2620f169c0eaSGlenn Lagasse char be_container_ds[MAXPATHLEN];
2621f169c0eaSGlenn Lagasse
2622f169c0eaSGlenn Lagasse /* Generate string for this pool's BE root container dataset */
2623f169c0eaSGlenn Lagasse be_make_container_ds(zpool, be_container_ds, sizeof (be_container_ds));
2624f169c0eaSGlenn Lagasse
2625f169c0eaSGlenn Lagasse /*
2626f169c0eaSGlenn Lagasse * If dataset lives under the BE root container dataset
2627f169c0eaSGlenn Lagasse * of this pool, return failure.
2628f169c0eaSGlenn Lagasse */
2629f169c0eaSGlenn Lagasse if (strncmp(be_container_ds, ds, strlen(be_container_ds)) == 0 &&
2630f169c0eaSGlenn Lagasse ds[strlen(be_container_ds)] == '/') {
2631f169c0eaSGlenn Lagasse zpool_close(zlp);
2632f169c0eaSGlenn Lagasse return (1);
2633f169c0eaSGlenn Lagasse }
2634f169c0eaSGlenn Lagasse
2635f169c0eaSGlenn Lagasse zpool_close(zlp);
2636f169c0eaSGlenn Lagasse return (0);
2637f169c0eaSGlenn Lagasse }
2638f169c0eaSGlenn Lagasse
2639f169c0eaSGlenn Lagasse /*
2640f169c0eaSGlenn Lagasse * Function: zfs_err_to_be_err
2641f169c0eaSGlenn Lagasse * Description: This function takes the error stored in the libzfs handle
2642f169c0eaSGlenn Lagasse * and maps it to an be_errno_t. If there are no matching
2643f169c0eaSGlenn Lagasse * be_errno_t's then BE_ERR_ZFS is returned.
2644f169c0eaSGlenn Lagasse * Paramters:
2645f169c0eaSGlenn Lagasse * zfsh - The libzfs handle containing the error we're looking up.
2646f169c0eaSGlenn Lagasse * Returns:
2647f169c0eaSGlenn Lagasse * be_errno_t
2648f169c0eaSGlenn Lagasse * Scope:
2649f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2650f169c0eaSGlenn Lagasse */
2651f169c0eaSGlenn Lagasse int
zfs_err_to_be_err(libzfs_handle_t * zfsh)2652f169c0eaSGlenn Lagasse zfs_err_to_be_err(libzfs_handle_t *zfsh)
2653f169c0eaSGlenn Lagasse {
2654f169c0eaSGlenn Lagasse int err = libzfs_errno(zfsh);
2655f169c0eaSGlenn Lagasse
2656f169c0eaSGlenn Lagasse switch (err) {
2657f169c0eaSGlenn Lagasse case 0:
2658f169c0eaSGlenn Lagasse return (BE_SUCCESS);
2659f169c0eaSGlenn Lagasse case EZFS_PERM:
2660f169c0eaSGlenn Lagasse return (BE_ERR_PERM);
2661f169c0eaSGlenn Lagasse case EZFS_INTR:
2662f169c0eaSGlenn Lagasse return (BE_ERR_INTR);
2663f169c0eaSGlenn Lagasse case EZFS_NOENT:
2664f169c0eaSGlenn Lagasse return (BE_ERR_NOENT);
2665f169c0eaSGlenn Lagasse case EZFS_NOSPC:
2666f169c0eaSGlenn Lagasse return (BE_ERR_NOSPC);
2667f169c0eaSGlenn Lagasse case EZFS_MOUNTFAILED:
2668f169c0eaSGlenn Lagasse return (BE_ERR_MOUNT);
2669f169c0eaSGlenn Lagasse case EZFS_UMOUNTFAILED:
2670f169c0eaSGlenn Lagasse return (BE_ERR_UMOUNT);
2671f169c0eaSGlenn Lagasse case EZFS_EXISTS:
2672f169c0eaSGlenn Lagasse return (BE_ERR_BE_EXISTS);
2673f169c0eaSGlenn Lagasse case EZFS_BUSY:
2674f169c0eaSGlenn Lagasse return (BE_ERR_DEV_BUSY);
2675f9af39baSGeorge Wilson case EZFS_POOLREADONLY:
2676f169c0eaSGlenn Lagasse return (BE_ERR_ROFS);
2677f169c0eaSGlenn Lagasse case EZFS_NAMETOOLONG:
2678f169c0eaSGlenn Lagasse return (BE_ERR_NAMETOOLONG);
2679f169c0eaSGlenn Lagasse case EZFS_NODEVICE:
2680f169c0eaSGlenn Lagasse return (BE_ERR_NODEV);
2681f169c0eaSGlenn Lagasse case EZFS_POOL_INVALARG:
2682f169c0eaSGlenn Lagasse return (BE_ERR_INVAL);
2683f169c0eaSGlenn Lagasse case EZFS_PROPTYPE:
2684f169c0eaSGlenn Lagasse return (BE_ERR_INVALPROP);
2685f169c0eaSGlenn Lagasse case EZFS_BADTYPE:
2686f169c0eaSGlenn Lagasse return (BE_ERR_DSTYPE);
2687f169c0eaSGlenn Lagasse case EZFS_PROPNONINHERIT:
2688f169c0eaSGlenn Lagasse return (BE_ERR_NONINHERIT);
2689f169c0eaSGlenn Lagasse case EZFS_PROPREADONLY:
2690f169c0eaSGlenn Lagasse return (BE_ERR_READONLYPROP);
2691f169c0eaSGlenn Lagasse case EZFS_RESILVERING:
2692f169c0eaSGlenn Lagasse case EZFS_POOLUNAVAIL:
2693f169c0eaSGlenn Lagasse return (BE_ERR_UNAVAIL);
2694f169c0eaSGlenn Lagasse case EZFS_DSREADONLY:
2695f169c0eaSGlenn Lagasse return (BE_ERR_READONLYDS);
2696f169c0eaSGlenn Lagasse default:
2697f169c0eaSGlenn Lagasse return (BE_ERR_ZFS);
2698f169c0eaSGlenn Lagasse }
2699f169c0eaSGlenn Lagasse }
2700f169c0eaSGlenn Lagasse
2701f169c0eaSGlenn Lagasse /*
2702f169c0eaSGlenn Lagasse * Function: errno_to_be_err
2703f169c0eaSGlenn Lagasse * Description: This function takes an errno and maps it to an be_errno_t.
2704f169c0eaSGlenn Lagasse * If there are no matching be_errno_t's then BE_ERR_UNKNOWN is
2705f169c0eaSGlenn Lagasse * returned.
2706f169c0eaSGlenn Lagasse * Paramters:
2707f169c0eaSGlenn Lagasse * err - The errno we're compairing against.
2708f169c0eaSGlenn Lagasse * Returns:
2709f169c0eaSGlenn Lagasse * be_errno_t
2710f169c0eaSGlenn Lagasse * Scope:
2711f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2712f169c0eaSGlenn Lagasse */
2713f169c0eaSGlenn Lagasse int
errno_to_be_err(int err)2714f169c0eaSGlenn Lagasse errno_to_be_err(int err)
2715f169c0eaSGlenn Lagasse {
2716f169c0eaSGlenn Lagasse switch (err) {
2717f169c0eaSGlenn Lagasse case EPERM:
2718f169c0eaSGlenn Lagasse return (BE_ERR_PERM);
2719f169c0eaSGlenn Lagasse case EACCES:
2720f169c0eaSGlenn Lagasse return (BE_ERR_ACCESS);
2721f169c0eaSGlenn Lagasse case ECANCELED:
2722f169c0eaSGlenn Lagasse return (BE_ERR_CANCELED);
2723f169c0eaSGlenn Lagasse case EINTR:
2724f169c0eaSGlenn Lagasse return (BE_ERR_INTR);
2725f169c0eaSGlenn Lagasse case ENOENT:
2726f169c0eaSGlenn Lagasse return (BE_ERR_NOENT);
2727f169c0eaSGlenn Lagasse case ENOSPC:
2728f169c0eaSGlenn Lagasse case EDQUOT:
2729f169c0eaSGlenn Lagasse return (BE_ERR_NOSPC);
2730f169c0eaSGlenn Lagasse case EEXIST:
2731f169c0eaSGlenn Lagasse return (BE_ERR_BE_EXISTS);
2732f169c0eaSGlenn Lagasse case EBUSY:
2733f169c0eaSGlenn Lagasse return (BE_ERR_BUSY);
2734f169c0eaSGlenn Lagasse case EROFS:
2735f169c0eaSGlenn Lagasse return (BE_ERR_ROFS);
2736f169c0eaSGlenn Lagasse case ENAMETOOLONG:
2737f169c0eaSGlenn Lagasse return (BE_ERR_NAMETOOLONG);
2738f169c0eaSGlenn Lagasse case ENXIO:
2739f169c0eaSGlenn Lagasse return (BE_ERR_NXIO);
2740f169c0eaSGlenn Lagasse case EINVAL:
2741f169c0eaSGlenn Lagasse return (BE_ERR_INVAL);
2742f169c0eaSGlenn Lagasse case EFAULT:
2743f169c0eaSGlenn Lagasse return (BE_ERR_FAULT);
2744f169c0eaSGlenn Lagasse default:
2745f169c0eaSGlenn Lagasse return (BE_ERR_UNKNOWN);
2746f169c0eaSGlenn Lagasse }
2747f169c0eaSGlenn Lagasse }
2748f169c0eaSGlenn Lagasse
2749f169c0eaSGlenn Lagasse /*
2750f169c0eaSGlenn Lagasse * Function: be_err_to_str
2751f169c0eaSGlenn Lagasse * Description: This function takes a be_errno_t and maps it to a message.
2752f169c0eaSGlenn Lagasse * If there are no matching be_errno_t's then NULL is returned.
2753f169c0eaSGlenn Lagasse * Paramters:
2754f169c0eaSGlenn Lagasse * be_errno_t - The be_errno_t we're mapping.
2755f169c0eaSGlenn Lagasse * Returns:
2756f169c0eaSGlenn Lagasse * string or NULL if the error code is not known.
2757f169c0eaSGlenn Lagasse * Scope:
2758f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2759f169c0eaSGlenn Lagasse */
2760f169c0eaSGlenn Lagasse char *
be_err_to_str(int err)2761f169c0eaSGlenn Lagasse be_err_to_str(int err)
2762f169c0eaSGlenn Lagasse {
2763f169c0eaSGlenn Lagasse switch (err) {
2764f169c0eaSGlenn Lagasse case BE_ERR_ACCESS:
2765f169c0eaSGlenn Lagasse return (gettext("Permission denied."));
2766f169c0eaSGlenn Lagasse case BE_ERR_ACTIVATE_CURR:
2767f169c0eaSGlenn Lagasse return (gettext("Activation of current BE failed."));
2768f169c0eaSGlenn Lagasse case BE_ERR_AUTONAME:
2769f169c0eaSGlenn Lagasse return (gettext("Auto naming failed."));
2770f169c0eaSGlenn Lagasse case BE_ERR_BE_NOENT:
2771f169c0eaSGlenn Lagasse return (gettext("No such BE."));
2772f169c0eaSGlenn Lagasse case BE_ERR_BUSY:
2773f169c0eaSGlenn Lagasse return (gettext("Mount busy."));
2774f169c0eaSGlenn Lagasse case BE_ERR_DEV_BUSY:
2775f169c0eaSGlenn Lagasse return (gettext("Device busy."));
2776f169c0eaSGlenn Lagasse case BE_ERR_CANCELED:
2777f169c0eaSGlenn Lagasse return (gettext("Operation canceled."));
2778f169c0eaSGlenn Lagasse case BE_ERR_CLONE:
2779f169c0eaSGlenn Lagasse return (gettext("BE clone failed."));
2780f169c0eaSGlenn Lagasse case BE_ERR_COPY:
2781f169c0eaSGlenn Lagasse return (gettext("BE copy failed."));
2782f169c0eaSGlenn Lagasse case BE_ERR_CREATDS:
2783f169c0eaSGlenn Lagasse return (gettext("Dataset creation failed."));
2784f169c0eaSGlenn Lagasse case BE_ERR_CURR_BE_NOT_FOUND:
2785f169c0eaSGlenn Lagasse return (gettext("Can't find current BE."));
2786f169c0eaSGlenn Lagasse case BE_ERR_DESTROY:
2787f169c0eaSGlenn Lagasse return (gettext("Failed to destroy BE or snapshot."));
2788f169c0eaSGlenn Lagasse case BE_ERR_DESTROY_CURR_BE:
2789f169c0eaSGlenn Lagasse return (gettext("Cannot destroy current BE."));
2790f169c0eaSGlenn Lagasse case BE_ERR_DEMOTE:
2791f169c0eaSGlenn Lagasse return (gettext("BE demotion failed."));
2792f169c0eaSGlenn Lagasse case BE_ERR_DSTYPE:
2793f169c0eaSGlenn Lagasse return (gettext("Invalid dataset type."));
2794f169c0eaSGlenn Lagasse case BE_ERR_BE_EXISTS:
2795f169c0eaSGlenn Lagasse return (gettext("BE exists."));
2796f169c0eaSGlenn Lagasse case BE_ERR_INIT:
2797f169c0eaSGlenn Lagasse return (gettext("be_zfs_init failed."));
2798f169c0eaSGlenn Lagasse case BE_ERR_INTR:
2799f169c0eaSGlenn Lagasse return (gettext("Interupted system call."));
2800f169c0eaSGlenn Lagasse case BE_ERR_INVAL:
2801f169c0eaSGlenn Lagasse return (gettext("Invalid argument."));
2802f169c0eaSGlenn Lagasse case BE_ERR_INVALPROP:
2803f169c0eaSGlenn Lagasse return (gettext("Invalid property for dataset."));
2804f169c0eaSGlenn Lagasse case BE_ERR_INVALMOUNTPOINT:
2805f169c0eaSGlenn Lagasse return (gettext("Unexpected mountpoint."));
2806f169c0eaSGlenn Lagasse case BE_ERR_MOUNT:
2807f169c0eaSGlenn Lagasse return (gettext("Mount failed."));
2808f169c0eaSGlenn Lagasse case BE_ERR_MOUNTED:
2809f169c0eaSGlenn Lagasse return (gettext("Already mounted."));
2810f169c0eaSGlenn Lagasse case BE_ERR_NAMETOOLONG:
2811f169c0eaSGlenn Lagasse return (gettext("name > BUFSIZ."));
2812f169c0eaSGlenn Lagasse case BE_ERR_NOENT:
2813f169c0eaSGlenn Lagasse return (gettext("Doesn't exist."));
2814f169c0eaSGlenn Lagasse case BE_ERR_POOL_NOENT:
2815f169c0eaSGlenn Lagasse return (gettext("No such pool."));
2816f169c0eaSGlenn Lagasse case BE_ERR_NODEV:
2817f169c0eaSGlenn Lagasse return (gettext("No such device."));
2818f169c0eaSGlenn Lagasse case BE_ERR_NOTMOUNTED:
2819f169c0eaSGlenn Lagasse return (gettext("File system not mounted."));
2820f169c0eaSGlenn Lagasse case BE_ERR_NOMEM:
2821f169c0eaSGlenn Lagasse return (gettext("Not enough memory."));
2822f169c0eaSGlenn Lagasse case BE_ERR_NONINHERIT:
2823f169c0eaSGlenn Lagasse return (gettext(
2824f169c0eaSGlenn Lagasse "Property is not inheritable for the BE dataset."));
2825f169c0eaSGlenn Lagasse case BE_ERR_NXIO:
2826f169c0eaSGlenn Lagasse return (gettext("No such device or address."));
2827f169c0eaSGlenn Lagasse case BE_ERR_NOSPC:
2828f169c0eaSGlenn Lagasse return (gettext("No space on device."));
2829f169c0eaSGlenn Lagasse case BE_ERR_NOTSUP:
2830f169c0eaSGlenn Lagasse return (gettext("Operation not supported."));
2831f169c0eaSGlenn Lagasse case BE_ERR_OPEN:
2832f169c0eaSGlenn Lagasse return (gettext("Open failed."));
2833f169c0eaSGlenn Lagasse case BE_ERR_PERM:
2834f169c0eaSGlenn Lagasse return (gettext("Not owner."));
2835f169c0eaSGlenn Lagasse case BE_ERR_UNAVAIL:
2836f169c0eaSGlenn Lagasse return (gettext("The BE is currently unavailable."));
2837f169c0eaSGlenn Lagasse case BE_ERR_PROMOTE:
2838f169c0eaSGlenn Lagasse return (gettext("BE promotion failed."));
2839f169c0eaSGlenn Lagasse case BE_ERR_ROFS:
2840f169c0eaSGlenn Lagasse return (gettext("Read only file system."));
2841f169c0eaSGlenn Lagasse case BE_ERR_READONLYDS:
2842f169c0eaSGlenn Lagasse return (gettext("Read only dataset."));
2843f169c0eaSGlenn Lagasse case BE_ERR_READONLYPROP:
2844f169c0eaSGlenn Lagasse return (gettext("Read only property."));
2845f169c0eaSGlenn Lagasse case BE_ERR_RENAME_ACTIVE:
2846f169c0eaSGlenn Lagasse return (gettext("Renaming the active BE is not supported."));
2847f169c0eaSGlenn Lagasse case BE_ERR_SS_EXISTS:
2848f169c0eaSGlenn Lagasse return (gettext("Snapshot exists."));
2849f169c0eaSGlenn Lagasse case BE_ERR_SS_NOENT:
2850f169c0eaSGlenn Lagasse return (gettext("No such snapshot."));
2851f169c0eaSGlenn Lagasse case BE_ERR_UMOUNT:
2852f169c0eaSGlenn Lagasse return (gettext("Unmount failed."));
2853f169c0eaSGlenn Lagasse case BE_ERR_UMOUNT_CURR_BE:
2854f169c0eaSGlenn Lagasse return (gettext("Can't unmount the current BE."));
2855f169c0eaSGlenn Lagasse case BE_ERR_UMOUNT_SHARED:
2856f169c0eaSGlenn Lagasse return (gettext("Unmount of a shared File System failed."));
2857f169c0eaSGlenn Lagasse case BE_ERR_FAULT:
2858f169c0eaSGlenn Lagasse return (gettext("Bad address."));
2859f169c0eaSGlenn Lagasse case BE_ERR_UNKNOWN:
2860f169c0eaSGlenn Lagasse return (gettext("Unknown error."));
2861f169c0eaSGlenn Lagasse case BE_ERR_ZFS:
2862f169c0eaSGlenn Lagasse return (gettext("ZFS returned an error."));
2863f169c0eaSGlenn Lagasse case BE_ERR_GEN_UUID:
2864f169c0eaSGlenn Lagasse return (gettext("Failed to generate uuid."));
2865f169c0eaSGlenn Lagasse case BE_ERR_PARSE_UUID:
2866f169c0eaSGlenn Lagasse return (gettext("Failed to parse uuid."));
2867f169c0eaSGlenn Lagasse case BE_ERR_NO_UUID:
2868f169c0eaSGlenn Lagasse return (gettext("No uuid"));
2869f169c0eaSGlenn Lagasse case BE_ERR_ZONE_NO_PARENTBE:
2870f169c0eaSGlenn Lagasse return (gettext("No parent uuid"));
2871f169c0eaSGlenn Lagasse case BE_ERR_ZONE_MULTIPLE_ACTIVE:
2872f169c0eaSGlenn Lagasse return (gettext("Multiple active zone roots"));
2873f169c0eaSGlenn Lagasse case BE_ERR_ZONE_NO_ACTIVE_ROOT:
2874f169c0eaSGlenn Lagasse return (gettext("No active zone root"));
2875f169c0eaSGlenn Lagasse case BE_ERR_ZONE_ROOT_NOT_LEGACY:
2876f169c0eaSGlenn Lagasse return (gettext("Zone root not legacy"));
2877f169c0eaSGlenn Lagasse case BE_ERR_MOUNT_ZONEROOT:
2878f169c0eaSGlenn Lagasse return (gettext("Failed to mount a zone root."));
2879f169c0eaSGlenn Lagasse case BE_ERR_UMOUNT_ZONEROOT:
2880f169c0eaSGlenn Lagasse return (gettext("Failed to unmount a zone root."));
2881f169c0eaSGlenn Lagasse case BE_ERR_NO_MOUNTED_ZONE:
2882f169c0eaSGlenn Lagasse return (gettext("Zone is not mounted"));
2883f169c0eaSGlenn Lagasse case BE_ERR_ZONES_UNMOUNT:
2884f169c0eaSGlenn Lagasse return (gettext("Unable to unmount a zone BE."));
2885f169c0eaSGlenn Lagasse case BE_ERR_NO_MENU:
2886f169c0eaSGlenn Lagasse return (gettext("Missing boot menu file."));
2887f169c0eaSGlenn Lagasse case BE_ERR_BAD_MENU_PATH:
2888f169c0eaSGlenn Lagasse return (gettext("Invalid path for menu.lst file"));
2889f169c0eaSGlenn Lagasse case BE_ERR_ZONE_SS_EXISTS:
2890f169c0eaSGlenn Lagasse return (gettext("Zone snapshot exists."));
2891f169c0eaSGlenn Lagasse case BE_ERR_BOOTFILE_INST:
2892f169c0eaSGlenn Lagasse return (gettext("Error installing boot files."));
2893f169c0eaSGlenn Lagasse case BE_ERR_EXTCMD:
2894f169c0eaSGlenn Lagasse return (gettext("Error running an external command."));
2895f169c0eaSGlenn Lagasse default:
2896f169c0eaSGlenn Lagasse return (NULL);
2897f169c0eaSGlenn Lagasse }
2898f169c0eaSGlenn Lagasse }
2899f169c0eaSGlenn Lagasse
2900f169c0eaSGlenn Lagasse /*
2901f169c0eaSGlenn Lagasse * Function: be_has_grub
2902f169c0eaSGlenn Lagasse * Description: Boolean function indicating whether the current system
2903f169c0eaSGlenn Lagasse * uses grub.
2904f169c0eaSGlenn Lagasse * Return: B_FALSE - the system does not have grub
2905f169c0eaSGlenn Lagasse * B_TRUE - the system does have grub.
2906f169c0eaSGlenn Lagasse * Scope:
2907f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2908f169c0eaSGlenn Lagasse */
2909f169c0eaSGlenn Lagasse boolean_t
be_has_grub(void)2910f169c0eaSGlenn Lagasse be_has_grub(void)
2911f169c0eaSGlenn Lagasse {
2912f169c0eaSGlenn Lagasse /*
2913f169c0eaSGlenn Lagasse * TODO: This will need to be expanded to check for the existence of
2914f169c0eaSGlenn Lagasse * grub if and when there is grub support for SPARC.
2915f169c0eaSGlenn Lagasse */
2916f169c0eaSGlenn Lagasse return (be_is_isa("i386"));
2917f169c0eaSGlenn Lagasse }
2918f169c0eaSGlenn Lagasse
2919f169c0eaSGlenn Lagasse /*
2920f169c0eaSGlenn Lagasse * Function: be_is_isa
2921f169c0eaSGlenn Lagasse * Description: Boolean function indicating whether the instruction set
2922f169c0eaSGlenn Lagasse * architecture of the executing system matches the name provided.
2923f169c0eaSGlenn Lagasse * The string must match a system defined architecture (e.g.
2924f169c0eaSGlenn Lagasse * "i386", "sparc") and is case sensitive.
2925f169c0eaSGlenn Lagasse * Parameters: name - string representing the name of instruction set
2926f169c0eaSGlenn Lagasse * architecture being tested
2927f169c0eaSGlenn Lagasse * Returns: B_FALSE - the system instruction set architecture is different
2928f169c0eaSGlenn Lagasse * from the one specified
2929f169c0eaSGlenn Lagasse * B_TRUE - the system instruction set architecture is the same
2930f169c0eaSGlenn Lagasse * as the one specified
2931f169c0eaSGlenn Lagasse * Scope:
2932f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2933f169c0eaSGlenn Lagasse */
2934f169c0eaSGlenn Lagasse boolean_t
be_is_isa(char * name)2935f169c0eaSGlenn Lagasse be_is_isa(char *name)
2936f169c0eaSGlenn Lagasse {
2937f169c0eaSGlenn Lagasse return ((strcmp((char *)be_get_default_isa(), name) == 0));
2938f169c0eaSGlenn Lagasse }
2939f169c0eaSGlenn Lagasse
2940f169c0eaSGlenn Lagasse /*
2941f169c0eaSGlenn Lagasse * Function: be_get_default_isa
2942f169c0eaSGlenn Lagasse * Description:
2943f169c0eaSGlenn Lagasse * Returns the default instruction set architecture of the
2944f169c0eaSGlenn Lagasse * machine it is executed on. (eg. sparc, i386, ...)
2945f169c0eaSGlenn Lagasse * NOTE: SYS_INST environment variable may override default
2946f169c0eaSGlenn Lagasse * return value
2947f169c0eaSGlenn Lagasse * Parameters:
2948f169c0eaSGlenn Lagasse * none
2949f169c0eaSGlenn Lagasse * Returns:
2950f169c0eaSGlenn Lagasse * NULL - the architecture returned by sysinfo() was too
2951f169c0eaSGlenn Lagasse * long for local variables
2952f169c0eaSGlenn Lagasse * char * - pointer to a string containing the default
2953f169c0eaSGlenn Lagasse * implementation
2954f169c0eaSGlenn Lagasse * Scope:
2955f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
2956f169c0eaSGlenn Lagasse */
2957f169c0eaSGlenn Lagasse char *
be_get_default_isa(void)2958f169c0eaSGlenn Lagasse be_get_default_isa(void)
2959f169c0eaSGlenn Lagasse {
2960f169c0eaSGlenn Lagasse int i;
2961f169c0eaSGlenn Lagasse char *envp;
2962f169c0eaSGlenn Lagasse static char default_inst[ARCH_LENGTH] = "";
2963f169c0eaSGlenn Lagasse
2964f169c0eaSGlenn Lagasse if (default_inst[0] == '\0') {
2965f169c0eaSGlenn Lagasse if ((envp = getenv("SYS_INST")) != NULL) {
2966f169c0eaSGlenn Lagasse if ((int)strlen(envp) >= ARCH_LENGTH)
2967f169c0eaSGlenn Lagasse return (NULL);
2968f169c0eaSGlenn Lagasse else
2969f169c0eaSGlenn Lagasse (void) strcpy(default_inst, envp);
2970f169c0eaSGlenn Lagasse } else {
2971f169c0eaSGlenn Lagasse i = sysinfo(SI_ARCHITECTURE, default_inst, ARCH_LENGTH);
2972f169c0eaSGlenn Lagasse if (i < 0 || i > ARCH_LENGTH)
2973f169c0eaSGlenn Lagasse return (NULL);
2974f169c0eaSGlenn Lagasse }
2975f169c0eaSGlenn Lagasse }
2976f169c0eaSGlenn Lagasse return (default_inst);
2977f169c0eaSGlenn Lagasse }
2978f169c0eaSGlenn Lagasse
2979f169c0eaSGlenn Lagasse /*
2980a63c99a2SToomas Soome * Function: be_get_platform
2981a63c99a2SToomas Soome * Description:
2982a63c99a2SToomas Soome * Returns the platfom name
2983a63c99a2SToomas Soome * Parameters:
2984a63c99a2SToomas Soome * none
2985a63c99a2SToomas Soome * Returns:
2986a63c99a2SToomas Soome * NULL - the platform name returned by sysinfo() was too
2987a63c99a2SToomas Soome * long for local variables
2988a63c99a2SToomas Soome * char * - pointer to a string containing the platform name
2989a63c99a2SToomas Soome * Scope:
2990a63c99a2SToomas Soome * Semi-private (library wide use only)
2991a63c99a2SToomas Soome */
2992a63c99a2SToomas Soome char *
be_get_platform(void)2993a63c99a2SToomas Soome be_get_platform(void)
2994a63c99a2SToomas Soome {
2995a63c99a2SToomas Soome int i;
2996a63c99a2SToomas Soome static char default_inst[ARCH_LENGTH] = "";
2997a63c99a2SToomas Soome
2998a63c99a2SToomas Soome if (default_inst[0] == '\0') {
2999a63c99a2SToomas Soome i = sysinfo(SI_PLATFORM, default_inst, ARCH_LENGTH);
3000a63c99a2SToomas Soome if (i < 0 || i > ARCH_LENGTH)
3001a63c99a2SToomas Soome return (NULL);
3002a63c99a2SToomas Soome }
3003a63c99a2SToomas Soome return (default_inst);
3004a63c99a2SToomas Soome }
3005a63c99a2SToomas Soome
3006a63c99a2SToomas Soome /*
3007f169c0eaSGlenn Lagasse * Function: be_run_cmd
3008f169c0eaSGlenn Lagasse * Description:
3009f169c0eaSGlenn Lagasse * Runs a command in a separate subprocess. Splits out stdout from stderr
3010f169c0eaSGlenn Lagasse * and sends each to its own buffer. Buffers must be pre-allocated and
3011f169c0eaSGlenn Lagasse * passed in as arguments. Buffer sizes are also passed in as arguments.
3012f169c0eaSGlenn Lagasse *
3013f169c0eaSGlenn Lagasse * Notes / caveats:
3014f169c0eaSGlenn Lagasse * - Command being run is assumed to not have any stdout or stderr
3015f169c0eaSGlenn Lagasse * redirection.
3016f169c0eaSGlenn Lagasse * - Commands which emit total stderr output of greater than PIPE_BUF
3017f169c0eaSGlenn Lagasse * bytes can hang. For such commands, a different implementation
3018f169c0eaSGlenn Lagasse * which uses poll(2) must be used.
3019f169c0eaSGlenn Lagasse * - stdout_buf can be NULL. In this case, stdout_bufsize is ignored, and
3020f169c0eaSGlenn Lagasse * the stream which would have gone to it is sent to the bit
3021f169c0eaSGlenn Lagasse * bucket.
3022f169c0eaSGlenn Lagasse * - stderr_buf cannot be NULL.
3023f169c0eaSGlenn Lagasse * - Only subprocess errors are appended to the stderr_buf. Errors
3024f169c0eaSGlenn Lagasse * running the command are reported through be_print_err().
3025f169c0eaSGlenn Lagasse * - Data which would overflow its respective buffer is sent to the bit
3026f169c0eaSGlenn Lagasse * bucket.
3027f169c0eaSGlenn Lagasse *
3028f169c0eaSGlenn Lagasse * Parameters:
3029f169c0eaSGlenn Lagasse * command: command to run. Assumed not to have embedded stdout
3030f169c0eaSGlenn Lagasse * or stderr redirection. May have stdin redirection,
3031f169c0eaSGlenn Lagasse * however.
3032f169c0eaSGlenn Lagasse * stderr_buf: buffer returning subprocess stderr data. Errors
3033f169c0eaSGlenn Lagasse * reported by this function are reported through
3034f169c0eaSGlenn Lagasse * be_print_err().
3035f169c0eaSGlenn Lagasse * stderr_bufsize: size of stderr_buf
3036f169c0eaSGlenn Lagasse * stdout_buf: buffer returning subprocess stdout data.
3037f169c0eaSGlenn Lagasse * stdout_bufsize: size of stdout_buf
3038f169c0eaSGlenn Lagasse * Returns:
3039f169c0eaSGlenn Lagasse * BE_SUCCESS - The command ran successfully without returning
3040f169c0eaSGlenn Lagasse * errors.
3041f169c0eaSGlenn Lagasse * BE_ERR_EXTCMD
3042f169c0eaSGlenn Lagasse * - The command could not be run.
3043f169c0eaSGlenn Lagasse * - The command terminated with error status.
3044f169c0eaSGlenn Lagasse * - There were errors extracting or returning subprocess
3045f169c0eaSGlenn Lagasse * data.
3046f169c0eaSGlenn Lagasse * BE_ERR_NOMEM - The command exceeds the command buffer size.
3047f169c0eaSGlenn Lagasse * BE_ERR_INVAL - An invalid argument was specified.
3048f169c0eaSGlenn Lagasse * Scope:
3049f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
3050f169c0eaSGlenn Lagasse */
3051f169c0eaSGlenn Lagasse int
be_run_cmd(char * command,char * stderr_buf,int stderr_bufsize,char * stdout_buf,int stdout_bufsize)3052f169c0eaSGlenn Lagasse be_run_cmd(char *command, char *stderr_buf, int stderr_bufsize,
3053f169c0eaSGlenn Lagasse char *stdout_buf, int stdout_bufsize)
3054f169c0eaSGlenn Lagasse {
3055f169c0eaSGlenn Lagasse char *temp_filename = strdup(tmpnam(NULL));
3056f169c0eaSGlenn Lagasse FILE *stdout_str = NULL;
3057f169c0eaSGlenn Lagasse FILE *stderr_str = NULL;
3058f169c0eaSGlenn Lagasse char cmdline[BUFSIZ];
3059f169c0eaSGlenn Lagasse char oneline[BUFSIZ];
3060f169c0eaSGlenn Lagasse int exit_status;
3061f169c0eaSGlenn Lagasse int rval = BE_SUCCESS;
3062f169c0eaSGlenn Lagasse
3063f169c0eaSGlenn Lagasse if ((command == NULL) || (stderr_buf == NULL) ||
3064f169c0eaSGlenn Lagasse (stderr_bufsize <= 0) || (stdout_bufsize < 0) ||
3065f169c0eaSGlenn Lagasse ((stdout_buf != NULL) ^ (stdout_bufsize != 0))) {
3066f169c0eaSGlenn Lagasse return (BE_ERR_INVAL);
3067f169c0eaSGlenn Lagasse }
3068f169c0eaSGlenn Lagasse
3069f169c0eaSGlenn Lagasse /* Set up command so popen returns stderr, not stdout */
3070f169c0eaSGlenn Lagasse if (snprintf(cmdline, BUFSIZ, "%s 2> %s", command,
3071f169c0eaSGlenn Lagasse temp_filename) >= BUFSIZ) {
3072f169c0eaSGlenn Lagasse rval = BE_ERR_NOMEM;
3073f169c0eaSGlenn Lagasse goto cleanup;
3074f169c0eaSGlenn Lagasse }
3075f169c0eaSGlenn Lagasse
3076f169c0eaSGlenn Lagasse /* Set up the fifo that will make stderr available. */
3077f169c0eaSGlenn Lagasse if (mkfifo(temp_filename, 0600) != 0) {
3078f169c0eaSGlenn Lagasse (void) be_print_err(gettext("be_run_cmd: mkfifo: %s\n"),
3079f169c0eaSGlenn Lagasse strerror(errno));
3080f169c0eaSGlenn Lagasse rval = BE_ERR_EXTCMD;
3081f169c0eaSGlenn Lagasse goto cleanup;
3082f169c0eaSGlenn Lagasse }
3083f169c0eaSGlenn Lagasse
3084f169c0eaSGlenn Lagasse if ((stdout_str = popen(cmdline, "r")) == NULL) {
3085f169c0eaSGlenn Lagasse (void) be_print_err(gettext("be_run_cmd: popen: %s\n"),
3086f169c0eaSGlenn Lagasse strerror(errno));
3087f169c0eaSGlenn Lagasse rval = BE_ERR_EXTCMD;
3088f169c0eaSGlenn Lagasse goto cleanup;
3089f169c0eaSGlenn Lagasse }
3090f169c0eaSGlenn Lagasse
3091f169c0eaSGlenn Lagasse if ((stderr_str = fopen(temp_filename, "r")) == NULL) {
3092f169c0eaSGlenn Lagasse (void) be_print_err(gettext("be_run_cmd: fopen: %s\n"),
3093f169c0eaSGlenn Lagasse strerror(errno));
3094f169c0eaSGlenn Lagasse (void) pclose(stdout_str);
3095f169c0eaSGlenn Lagasse rval = BE_ERR_EXTCMD;
3096f169c0eaSGlenn Lagasse goto cleanup;
3097f169c0eaSGlenn Lagasse }
3098f169c0eaSGlenn Lagasse
3099f169c0eaSGlenn Lagasse /* Read stdout first, as it usually outputs more than stderr. */
3100f169c0eaSGlenn Lagasse oneline[BUFSIZ-1] = '\0';
3101f169c0eaSGlenn Lagasse while (fgets(oneline, BUFSIZ-1, stdout_str) != NULL) {
3102f169c0eaSGlenn Lagasse if (stdout_str != NULL) {
3103f169c0eaSGlenn Lagasse (void) strlcat(stdout_buf, oneline, stdout_bufsize);
3104f169c0eaSGlenn Lagasse }
3105f169c0eaSGlenn Lagasse }
3106f169c0eaSGlenn Lagasse
3107f169c0eaSGlenn Lagasse while (fgets(oneline, BUFSIZ-1, stderr_str) != NULL) {
3108f169c0eaSGlenn Lagasse (void) strlcat(stderr_buf, oneline, stderr_bufsize);
3109f169c0eaSGlenn Lagasse }
3110f169c0eaSGlenn Lagasse
3111f169c0eaSGlenn Lagasse /* Close pipe, get exit status. */
3112f169c0eaSGlenn Lagasse if ((exit_status = pclose(stdout_str)) == -1) {
3113f169c0eaSGlenn Lagasse (void) be_print_err(gettext("be_run_cmd: pclose: %s\n"),
3114f169c0eaSGlenn Lagasse strerror(errno));
3115f169c0eaSGlenn Lagasse rval = BE_ERR_EXTCMD;
3116f169c0eaSGlenn Lagasse } else if (WIFEXITED(exit_status)) {
3117f169c0eaSGlenn Lagasse exit_status = (int)((char)WEXITSTATUS(exit_status));
3118a63c99a2SToomas Soome /*
3119a63c99a2SToomas Soome * error code BC_NOUPDT means more recent version
3120a63c99a2SToomas Soome * is installed
3121a63c99a2SToomas Soome */
3122a63c99a2SToomas Soome if (exit_status != BC_SUCCESS && exit_status != BC_NOUPDT) {
3123f169c0eaSGlenn Lagasse (void) snprintf(oneline, BUFSIZ, gettext("be_run_cmd: "
3124f169c0eaSGlenn Lagasse "command terminated with error status: %d\n"),
3125f169c0eaSGlenn Lagasse exit_status);
3126f169c0eaSGlenn Lagasse (void) strlcat(stderr_buf, oneline, stderr_bufsize);
3127f169c0eaSGlenn Lagasse rval = BE_ERR_EXTCMD;
3128f169c0eaSGlenn Lagasse }
3129f169c0eaSGlenn Lagasse } else {
3130f169c0eaSGlenn Lagasse (void) snprintf(oneline, BUFSIZ, gettext("be_run_cmd: command "
3131f169c0eaSGlenn Lagasse "terminated on signal: %s\n"),
3132f169c0eaSGlenn Lagasse strsignal(WTERMSIG(exit_status)));
3133f169c0eaSGlenn Lagasse (void) strlcat(stderr_buf, oneline, stderr_bufsize);
3134f169c0eaSGlenn Lagasse rval = BE_ERR_EXTCMD;
3135f169c0eaSGlenn Lagasse }
3136f169c0eaSGlenn Lagasse
3137f169c0eaSGlenn Lagasse cleanup:
3138f169c0eaSGlenn Lagasse (void) unlink(temp_filename);
3139f169c0eaSGlenn Lagasse (void) free(temp_filename);
3140f169c0eaSGlenn Lagasse
3141f169c0eaSGlenn Lagasse return (rval);
3142f169c0eaSGlenn Lagasse }
3143f169c0eaSGlenn Lagasse
3144f169c0eaSGlenn Lagasse /* ******************************************************************** */
3145f169c0eaSGlenn Lagasse /* Private Functions */
3146f169c0eaSGlenn Lagasse /* ******************************************************************** */
3147f169c0eaSGlenn Lagasse
3148f169c0eaSGlenn Lagasse /*
3149f169c0eaSGlenn Lagasse * Function: update_dataset
3150f169c0eaSGlenn Lagasse * Description: This function takes a dataset name and replaces the zpool
3151f169c0eaSGlenn Lagasse * and be_name components of the dataset with the new be_name
3152f169c0eaSGlenn Lagasse * zpool passed in.
3153f169c0eaSGlenn Lagasse * Parameters:
3154f169c0eaSGlenn Lagasse * dataset - name of dataset
3155f169c0eaSGlenn Lagasse * dataset_len - lenth of buffer in which dataset is passed in.
3156f169c0eaSGlenn Lagasse * be_name - name of new BE name to update to.
3157f169c0eaSGlenn Lagasse * old_rc_loc - dataset under which the root container dataset
3158f169c0eaSGlenn Lagasse * for the old BE lives.
3159f169c0eaSGlenn Lagasse * new_rc_loc - dataset under which the root container dataset
3160f169c0eaSGlenn Lagasse * for the new BE lives.
3161f169c0eaSGlenn Lagasse * Returns:
3162f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
3163f169c0eaSGlenn Lagasse * be_errno_t - Failure
3164f169c0eaSGlenn Lagasse * Scope:
3165f169c0eaSGlenn Lagasse * Private
3166f169c0eaSGlenn Lagasse */
3167f169c0eaSGlenn Lagasse static int
update_dataset(char * dataset,int dataset_len,char * be_name,char * old_rc_loc,char * new_rc_loc)3168f169c0eaSGlenn Lagasse update_dataset(char *dataset, int dataset_len, char *be_name,
3169f169c0eaSGlenn Lagasse char *old_rc_loc, char *new_rc_loc)
3170f169c0eaSGlenn Lagasse {
3171f169c0eaSGlenn Lagasse char *ds = NULL;
3172f169c0eaSGlenn Lagasse char *sub_ds = NULL;
3173f169c0eaSGlenn Lagasse
3174f169c0eaSGlenn Lagasse /* Tear off the BE container dataset */
3175f169c0eaSGlenn Lagasse if ((ds = be_make_name_from_ds(dataset, old_rc_loc)) == NULL) {
3176f169c0eaSGlenn Lagasse return (BE_ERR_INVAL);
3177f169c0eaSGlenn Lagasse }
3178f169c0eaSGlenn Lagasse
3179f169c0eaSGlenn Lagasse /* Get dataset name relative to BE root, if there is one */
3180f169c0eaSGlenn Lagasse sub_ds = strchr(ds, '/');
3181f169c0eaSGlenn Lagasse
3182f169c0eaSGlenn Lagasse /* Generate the BE root dataset name */
3183f169c0eaSGlenn Lagasse be_make_root_ds(new_rc_loc, be_name, dataset, dataset_len);
3184f169c0eaSGlenn Lagasse
3185f169c0eaSGlenn Lagasse /* If a subordinate dataset name was found, append it */
3186f169c0eaSGlenn Lagasse if (sub_ds != NULL)
3187f169c0eaSGlenn Lagasse (void) strlcat(dataset, sub_ds, dataset_len);
3188f169c0eaSGlenn Lagasse
3189f169c0eaSGlenn Lagasse free(ds);
3190f169c0eaSGlenn Lagasse return (BE_SUCCESS);
3191f169c0eaSGlenn Lagasse }
3192f169c0eaSGlenn Lagasse
3193f169c0eaSGlenn Lagasse /*
3194f169c0eaSGlenn Lagasse * Function: _update_vfstab
3195f169c0eaSGlenn Lagasse * Description: This function updates a vfstab file to reflect the new
3196f169c0eaSGlenn Lagasse * root container dataset location and be_name for all
3197f169c0eaSGlenn Lagasse * entries listed in the be_fs_list_data_t structure passed in.
3198f169c0eaSGlenn Lagasse * Parameters:
3199f169c0eaSGlenn Lagasse * vfstab - vfstab file to modify
3200f169c0eaSGlenn Lagasse * be_name - name of BE to update.
3201f169c0eaSGlenn Lagasse * old_rc_loc - dataset under which the root container dataset
3202f169c0eaSGlenn Lagasse * of the old BE resides in.
3203f169c0eaSGlenn Lagasse * new_rc_loc - dataset under which the root container dataset
3204f169c0eaSGlenn Lagasse * of the new BE resides in.
3205f169c0eaSGlenn Lagasse * fld - be_fs_list_data_t pointer providing the list of
3206f169c0eaSGlenn Lagasse * file systems to look for in vfstab.
3207f169c0eaSGlenn Lagasse * Returns:
3208f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
3209f169c0eaSGlenn Lagasse * be_errno_t - Failure
3210f169c0eaSGlenn Lagasse * Scope:
3211f169c0eaSGlenn Lagasse * Private
3212f169c0eaSGlenn Lagasse */
3213f169c0eaSGlenn Lagasse static int
_update_vfstab(char * vfstab,char * be_name,char * old_rc_loc,char * new_rc_loc,be_fs_list_data_t * fld)3214f169c0eaSGlenn Lagasse _update_vfstab(char *vfstab, char *be_name, char *old_rc_loc,
3215f169c0eaSGlenn Lagasse char *new_rc_loc, be_fs_list_data_t *fld)
3216f169c0eaSGlenn Lagasse {
3217f169c0eaSGlenn Lagasse struct vfstab vp;
3218f169c0eaSGlenn Lagasse char *tmp_vfstab = NULL;
3219f169c0eaSGlenn Lagasse char comments_buf[BUFSIZ];
3220f169c0eaSGlenn Lagasse FILE *comments = NULL;
3221f169c0eaSGlenn Lagasse FILE *vfs_ents = NULL;
3222f169c0eaSGlenn Lagasse FILE *tfile = NULL;
3223f169c0eaSGlenn Lagasse struct stat sb;
3224f169c0eaSGlenn Lagasse char dev[MAXPATHLEN];
3225f169c0eaSGlenn Lagasse char *c;
3226f169c0eaSGlenn Lagasse int fd;
3227f169c0eaSGlenn Lagasse int ret = BE_SUCCESS, err = 0;
3228f169c0eaSGlenn Lagasse int i;
3229f169c0eaSGlenn Lagasse int tmp_vfstab_len = 0;
3230f169c0eaSGlenn Lagasse
3231f169c0eaSGlenn Lagasse errno = 0;
3232f169c0eaSGlenn Lagasse
3233f169c0eaSGlenn Lagasse /*
3234f169c0eaSGlenn Lagasse * Open vfstab for reading twice. First is for comments,
3235f169c0eaSGlenn Lagasse * second is for actual entries.
3236f169c0eaSGlenn Lagasse */
3237f169c0eaSGlenn Lagasse if ((comments = fopen(vfstab, "r")) == NULL ||
3238f169c0eaSGlenn Lagasse (vfs_ents = fopen(vfstab, "r")) == NULL) {
3239f169c0eaSGlenn Lagasse err = errno;
3240f169c0eaSGlenn Lagasse be_print_err(gettext("_update_vfstab: "
3241f169c0eaSGlenn Lagasse "failed to open vfstab (%s): %s\n"), vfstab,
3242f169c0eaSGlenn Lagasse strerror(err));
3243f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
3244f169c0eaSGlenn Lagasse goto cleanup;
3245f169c0eaSGlenn Lagasse }
3246f169c0eaSGlenn Lagasse
3247f169c0eaSGlenn Lagasse /* Grab the stats of the original vfstab file */
3248f169c0eaSGlenn Lagasse if (stat(vfstab, &sb) != 0) {
3249f169c0eaSGlenn Lagasse err = errno;
3250f169c0eaSGlenn Lagasse be_print_err(gettext("_update_vfstab: "
3251f169c0eaSGlenn Lagasse "failed to stat file %s: %s\n"), vfstab,
3252f169c0eaSGlenn Lagasse strerror(err));
3253f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
3254f169c0eaSGlenn Lagasse goto cleanup;
3255f169c0eaSGlenn Lagasse }
3256f169c0eaSGlenn Lagasse
3257f169c0eaSGlenn Lagasse /* Create tmp file for modified vfstab */
3258f169c0eaSGlenn Lagasse if ((tmp_vfstab = (char *)malloc(strlen(vfstab) + 7))
3259f169c0eaSGlenn Lagasse == NULL) {
3260f169c0eaSGlenn Lagasse be_print_err(gettext("_update_vfstab: "
3261f169c0eaSGlenn Lagasse "malloc failed\n"));
3262f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM;
3263f169c0eaSGlenn Lagasse goto cleanup;
3264f169c0eaSGlenn Lagasse }
3265f169c0eaSGlenn Lagasse tmp_vfstab_len = strlen(vfstab) + 7;
3266f169c0eaSGlenn Lagasse (void) memset(tmp_vfstab, 0, tmp_vfstab_len);
3267f169c0eaSGlenn Lagasse (void) strlcpy(tmp_vfstab, vfstab, tmp_vfstab_len);
3268f169c0eaSGlenn Lagasse (void) strlcat(tmp_vfstab, "XXXXXX", tmp_vfstab_len);
3269f169c0eaSGlenn Lagasse if ((fd = mkstemp(tmp_vfstab)) == -1) {
3270f169c0eaSGlenn Lagasse err = errno;
3271f169c0eaSGlenn Lagasse be_print_err(gettext("_update_vfstab: "
3272f169c0eaSGlenn Lagasse "mkstemp failed: %s\n"), strerror(err));
3273f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
3274f169c0eaSGlenn Lagasse goto cleanup;
3275f169c0eaSGlenn Lagasse }
3276f169c0eaSGlenn Lagasse if ((tfile = fdopen(fd, "w")) == NULL) {
3277f169c0eaSGlenn Lagasse err = errno;
3278f169c0eaSGlenn Lagasse be_print_err(gettext("_update_vfstab: "
3279f169c0eaSGlenn Lagasse "could not open file for write\n"));
3280f169c0eaSGlenn Lagasse (void) close(fd);
3281f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
3282f169c0eaSGlenn Lagasse goto cleanup;
3283f169c0eaSGlenn Lagasse }
3284f169c0eaSGlenn Lagasse
3285f169c0eaSGlenn Lagasse while (fgets(comments_buf, BUFSIZ, comments)) {
3286f169c0eaSGlenn Lagasse for (c = comments_buf; *c != '\0' && isspace(*c); c++)
3287f169c0eaSGlenn Lagasse ;
3288f169c0eaSGlenn Lagasse if (*c == '\0') {
3289f169c0eaSGlenn Lagasse continue;
3290f169c0eaSGlenn Lagasse } else if (*c == '#') {
3291f169c0eaSGlenn Lagasse /*
3292f169c0eaSGlenn Lagasse * If line is a comment line, just put
3293f169c0eaSGlenn Lagasse * it through to the tmp vfstab.
3294f169c0eaSGlenn Lagasse */
3295f169c0eaSGlenn Lagasse (void) fputs(comments_buf, tfile);
3296f169c0eaSGlenn Lagasse } else {
3297f169c0eaSGlenn Lagasse /*
3298f169c0eaSGlenn Lagasse * Else line is a vfstab entry, grab it
3299f169c0eaSGlenn Lagasse * into a vfstab struct.
3300f169c0eaSGlenn Lagasse */
3301f169c0eaSGlenn Lagasse if (getvfsent(vfs_ents, &vp) != 0) {
3302f169c0eaSGlenn Lagasse err = errno;
3303f169c0eaSGlenn Lagasse be_print_err(gettext("_update_vfstab: "
3304f169c0eaSGlenn Lagasse "getvfsent failed: %s\n"), strerror(err));
3305f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
3306f169c0eaSGlenn Lagasse goto cleanup;
3307f169c0eaSGlenn Lagasse }
3308f169c0eaSGlenn Lagasse
3309f169c0eaSGlenn Lagasse if (vp.vfs_special == NULL || vp.vfs_mountp == NULL) {
3310f169c0eaSGlenn Lagasse (void) putvfsent(tfile, &vp);
3311f169c0eaSGlenn Lagasse continue;
3312f169c0eaSGlenn Lagasse }
3313f169c0eaSGlenn Lagasse
3314f169c0eaSGlenn Lagasse /*
3315f169c0eaSGlenn Lagasse * If the entry is one of the entries in the list
3316f169c0eaSGlenn Lagasse * of file systems to update, modify it's device
3317f169c0eaSGlenn Lagasse * field to be correct for this BE.
3318f169c0eaSGlenn Lagasse */
3319f169c0eaSGlenn Lagasse for (i = 0; i < fld->fs_num; i++) {
3320f169c0eaSGlenn Lagasse if (strcmp(vp.vfs_special, fld->fs_list[i])
3321f169c0eaSGlenn Lagasse == 0) {
3322f169c0eaSGlenn Lagasse /*
3323f169c0eaSGlenn Lagasse * Found entry that needs an update.
3324f169c0eaSGlenn Lagasse * Replace the root container dataset
3325f169c0eaSGlenn Lagasse * location and be_name in the
3326f169c0eaSGlenn Lagasse * entry's device.
3327f169c0eaSGlenn Lagasse */
3328f169c0eaSGlenn Lagasse (void) strlcpy(dev, vp.vfs_special,
3329f169c0eaSGlenn Lagasse sizeof (dev));
3330f169c0eaSGlenn Lagasse
3331f169c0eaSGlenn Lagasse if ((ret = update_dataset(dev,
3332f169c0eaSGlenn Lagasse sizeof (dev), be_name, old_rc_loc,
3333f169c0eaSGlenn Lagasse new_rc_loc)) != 0) {
3334f169c0eaSGlenn Lagasse be_print_err(
3335f169c0eaSGlenn Lagasse gettext("_update_vfstab: "
3336f169c0eaSGlenn Lagasse "Failed to update device "
3337f169c0eaSGlenn Lagasse "field for vfstab entry "
3338f169c0eaSGlenn Lagasse "%s\n"), fld->fs_list[i]);
3339f169c0eaSGlenn Lagasse goto cleanup;
3340f169c0eaSGlenn Lagasse }
3341f169c0eaSGlenn Lagasse
3342f169c0eaSGlenn Lagasse vp.vfs_special = dev;
3343f169c0eaSGlenn Lagasse break;
3344f169c0eaSGlenn Lagasse }
3345f169c0eaSGlenn Lagasse }
3346f169c0eaSGlenn Lagasse
3347f169c0eaSGlenn Lagasse /* Put entry through to tmp vfstab */
3348f169c0eaSGlenn Lagasse (void) putvfsent(tfile, &vp);
3349f169c0eaSGlenn Lagasse }
3350f169c0eaSGlenn Lagasse }
3351f169c0eaSGlenn Lagasse
3352f169c0eaSGlenn Lagasse (void) fclose(comments);
3353f169c0eaSGlenn Lagasse comments = NULL;
3354f169c0eaSGlenn Lagasse (void) fclose(vfs_ents);
3355f169c0eaSGlenn Lagasse vfs_ents = NULL;
3356f169c0eaSGlenn Lagasse (void) fclose(tfile);
3357f169c0eaSGlenn Lagasse tfile = NULL;
3358f169c0eaSGlenn Lagasse
3359f169c0eaSGlenn Lagasse /* Copy tmp vfstab into place */
3360f169c0eaSGlenn Lagasse if (rename(tmp_vfstab, vfstab) != 0) {
3361f169c0eaSGlenn Lagasse err = errno;
3362f169c0eaSGlenn Lagasse be_print_err(gettext("_update_vfstab: "
3363f169c0eaSGlenn Lagasse "failed to rename file %s to %s: %s\n"), tmp_vfstab,
3364f169c0eaSGlenn Lagasse vfstab, strerror(err));
3365f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
3366f169c0eaSGlenn Lagasse goto cleanup;
3367f169c0eaSGlenn Lagasse }
3368f169c0eaSGlenn Lagasse
3369f169c0eaSGlenn Lagasse /* Set the perms and ownership of the updated file */
3370f169c0eaSGlenn Lagasse if (chmod(vfstab, sb.st_mode) != 0) {
3371f169c0eaSGlenn Lagasse err = errno;
3372f169c0eaSGlenn Lagasse be_print_err(gettext("_update_vfstab: "
3373f169c0eaSGlenn Lagasse "failed to chmod %s: %s\n"), vfstab, strerror(err));
3374f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
3375f169c0eaSGlenn Lagasse goto cleanup;
3376f169c0eaSGlenn Lagasse }
3377f169c0eaSGlenn Lagasse if (chown(vfstab, sb.st_uid, sb.st_gid) != 0) {
3378f169c0eaSGlenn Lagasse err = errno;
3379f169c0eaSGlenn Lagasse be_print_err(gettext("_update_vfstab: "
3380f169c0eaSGlenn Lagasse "failed to chown %s: %s\n"), vfstab, strerror(err));
3381f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
3382f169c0eaSGlenn Lagasse goto cleanup;
3383f169c0eaSGlenn Lagasse }
3384f169c0eaSGlenn Lagasse
3385f169c0eaSGlenn Lagasse cleanup:
3386f169c0eaSGlenn Lagasse if (comments != NULL)
3387f169c0eaSGlenn Lagasse (void) fclose(comments);
3388f169c0eaSGlenn Lagasse if (vfs_ents != NULL)
3389f169c0eaSGlenn Lagasse (void) fclose(vfs_ents);
3390f169c0eaSGlenn Lagasse (void) unlink(tmp_vfstab);
3391f169c0eaSGlenn Lagasse (void) free(tmp_vfstab);
3392f169c0eaSGlenn Lagasse if (tfile != NULL)
3393f169c0eaSGlenn Lagasse (void) fclose(tfile);
3394f169c0eaSGlenn Lagasse
3395f169c0eaSGlenn Lagasse return (ret);
3396f169c0eaSGlenn Lagasse }
3397f169c0eaSGlenn Lagasse
3398f169c0eaSGlenn Lagasse
3399f169c0eaSGlenn Lagasse /*
3400f169c0eaSGlenn Lagasse * Function: be_get_auto_name
3401f169c0eaSGlenn Lagasse * Description: Generate an auto name constructed based on the BE name
3402f169c0eaSGlenn Lagasse * of the original BE or zone BE being cloned.
3403f169c0eaSGlenn Lagasse * Parameters:
3404f169c0eaSGlenn Lagasse * obe_name - name of the original BE or zone BE being cloned.
3405f169c0eaSGlenn Lagasse * container_ds - container dataset for the zone.
3406f169c0eaSGlenn Lagasse * Note: if zone_be is false this should be
3407f169c0eaSGlenn Lagasse * NULL.
3408f169c0eaSGlenn Lagasse * zone_be - flag that indicates if we are operating on a zone BE.
3409f169c0eaSGlenn Lagasse * Returns:
3410f169c0eaSGlenn Lagasse * Success - pointer to auto generated BE name. The name
3411f169c0eaSGlenn Lagasse * is allocated in heap storage so the caller is
3412f169c0eaSGlenn Lagasse * responsible for free'ing the name.
3413f169c0eaSGlenn Lagasse * Failure - NULL
3414f169c0eaSGlenn Lagasse * Scope:
3415f169c0eaSGlenn Lagasse * Private
3416f169c0eaSGlenn Lagasse */
3417f169c0eaSGlenn Lagasse static char *
be_get_auto_name(char * obe_name,char * be_container_ds,boolean_t zone_be)3418f169c0eaSGlenn Lagasse be_get_auto_name(char *obe_name, char *be_container_ds, boolean_t zone_be)
3419f169c0eaSGlenn Lagasse {
3420f169c0eaSGlenn Lagasse be_node_list_t *be_nodes = NULL;
3421f169c0eaSGlenn Lagasse be_node_list_t *cur_be = NULL;
3422f169c0eaSGlenn Lagasse char auto_be_name[MAXPATHLEN];
3423f169c0eaSGlenn Lagasse char base_be_name[MAXPATHLEN];
3424f169c0eaSGlenn Lagasse char cur_be_name[MAXPATHLEN];
3425f169c0eaSGlenn Lagasse char *num_str = NULL;
3426f169c0eaSGlenn Lagasse char *c = NULL;
3427f169c0eaSGlenn Lagasse int num = 0;
3428f169c0eaSGlenn Lagasse int cur_num = 0;
3429f169c0eaSGlenn Lagasse
3430f169c0eaSGlenn Lagasse errno = 0;
3431f169c0eaSGlenn Lagasse
3432f169c0eaSGlenn Lagasse /*
3433f169c0eaSGlenn Lagasse * Check if obe_name is already in an auto BE name format.
3434f169c0eaSGlenn Lagasse * If it is, then strip off the increment number to get the
3435f169c0eaSGlenn Lagasse * base name.
3436f169c0eaSGlenn Lagasse */
3437f169c0eaSGlenn Lagasse (void) strlcpy(base_be_name, obe_name, sizeof (base_be_name));
3438f169c0eaSGlenn Lagasse
3439f169c0eaSGlenn Lagasse if ((num_str = strrchr(base_be_name, BE_AUTO_NAME_DELIM))
3440f169c0eaSGlenn Lagasse != NULL) {
3441f169c0eaSGlenn Lagasse /* Make sure remaining string is all digits */
3442f169c0eaSGlenn Lagasse c = num_str + 1;
3443f169c0eaSGlenn Lagasse while (c[0] != '\0' && isdigit(c[0]))
3444f169c0eaSGlenn Lagasse c++;
3445f169c0eaSGlenn Lagasse /*
3446f169c0eaSGlenn Lagasse * If we're now at the end of the string strip off the
3447f169c0eaSGlenn Lagasse * increment number.
3448f169c0eaSGlenn Lagasse */
3449f169c0eaSGlenn Lagasse if (c[0] == '\0')
3450f169c0eaSGlenn Lagasse num_str[0] = '\0';
3451f169c0eaSGlenn Lagasse }
3452f169c0eaSGlenn Lagasse
3453f169c0eaSGlenn Lagasse if (zone_be) {
3454f169c0eaSGlenn Lagasse if (be_container_ds == NULL)
3455f169c0eaSGlenn Lagasse return (NULL);
3456f169c0eaSGlenn Lagasse if (be_get_zone_be_list(obe_name, be_container_ds,
3457f169c0eaSGlenn Lagasse &be_nodes) != BE_SUCCESS) {
3458f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_auto_name: "
3459f169c0eaSGlenn Lagasse "be_get_zone_be_list failed\n"));
3460f169c0eaSGlenn Lagasse return (NULL);
3461f169c0eaSGlenn Lagasse }
3462*4fef13f1SAndy Fiddaman } else if (_be_list(NULL, &be_nodes, BE_LIST_DEFAULT) != BE_SUCCESS) {
3463f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_auto_name: be_list failed\n"));
3464f169c0eaSGlenn Lagasse return (NULL);
3465f169c0eaSGlenn Lagasse }
3466f169c0eaSGlenn Lagasse
3467f169c0eaSGlenn Lagasse for (cur_be = be_nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
3468f169c0eaSGlenn Lagasse (void) strlcpy(cur_be_name, cur_be->be_node_name,
3469f169c0eaSGlenn Lagasse sizeof (cur_be_name));
3470f169c0eaSGlenn Lagasse
3471f169c0eaSGlenn Lagasse /* If cur_be_name doesn't match at least base be name, skip. */
3472f169c0eaSGlenn Lagasse if (strncmp(cur_be_name, base_be_name, strlen(base_be_name))
3473f169c0eaSGlenn Lagasse != 0)
3474f169c0eaSGlenn Lagasse continue;
3475f169c0eaSGlenn Lagasse
3476f169c0eaSGlenn Lagasse /* Get the string following the base be name */
3477f169c0eaSGlenn Lagasse num_str = cur_be_name + strlen(base_be_name);
3478f169c0eaSGlenn Lagasse
3479f169c0eaSGlenn Lagasse /*
3480f169c0eaSGlenn Lagasse * If nothing follows the base be name, this cur_be_name
3481f169c0eaSGlenn Lagasse * is the BE named with the base be name, skip.
3482f169c0eaSGlenn Lagasse */
3483f169c0eaSGlenn Lagasse if (num_str == NULL || num_str[0] == '\0')
3484f169c0eaSGlenn Lagasse continue;
3485f169c0eaSGlenn Lagasse
3486f169c0eaSGlenn Lagasse /*
3487f169c0eaSGlenn Lagasse * Remove the name delimiter. If its not there,
3488f169c0eaSGlenn Lagasse * cur_be_name isn't part of this BE name stream, skip.
3489f169c0eaSGlenn Lagasse */
3490f169c0eaSGlenn Lagasse if (num_str[0] == BE_AUTO_NAME_DELIM)
3491f169c0eaSGlenn Lagasse num_str++;
3492f169c0eaSGlenn Lagasse else
3493f169c0eaSGlenn Lagasse continue;
3494f169c0eaSGlenn Lagasse
3495f169c0eaSGlenn Lagasse /* Make sure remaining string is all digits */
3496f169c0eaSGlenn Lagasse c = num_str;
3497f169c0eaSGlenn Lagasse while (c[0] != '\0' && isdigit(c[0]))
3498f169c0eaSGlenn Lagasse c++;
3499f169c0eaSGlenn Lagasse if (c[0] != '\0')
3500f169c0eaSGlenn Lagasse continue;
3501f169c0eaSGlenn Lagasse
3502f169c0eaSGlenn Lagasse /* Convert the number string to an int */
3503f169c0eaSGlenn Lagasse cur_num = atoi(num_str);
3504f169c0eaSGlenn Lagasse
3505f169c0eaSGlenn Lagasse /*
3506f169c0eaSGlenn Lagasse * If failed to convert the string, skip it. If its too
3507f169c0eaSGlenn Lagasse * long to be converted to an int, we wouldn't auto generate
3508f169c0eaSGlenn Lagasse * this number anyway so there couldn't be a conflict.
3509f169c0eaSGlenn Lagasse * We treat it as a manually created BE name.
3510f169c0eaSGlenn Lagasse */
3511f169c0eaSGlenn Lagasse if (cur_num == 0 && errno == EINVAL)
3512f169c0eaSGlenn Lagasse continue;
3513f169c0eaSGlenn Lagasse
3514f169c0eaSGlenn Lagasse /*
3515f169c0eaSGlenn Lagasse * Compare current number to current max number,
3516f169c0eaSGlenn Lagasse * take higher of the two.
3517f169c0eaSGlenn Lagasse */
3518f169c0eaSGlenn Lagasse if (cur_num > num)
3519f169c0eaSGlenn Lagasse num = cur_num;
3520f169c0eaSGlenn Lagasse }
3521f169c0eaSGlenn Lagasse
3522f169c0eaSGlenn Lagasse /*
3523f169c0eaSGlenn Lagasse * Store off a copy of 'num' incase we need it later. If incrementing
3524f169c0eaSGlenn Lagasse * 'num' causes it to roll over, this means 'num' is the largest
3525f169c0eaSGlenn Lagasse * positive int possible; we'll need it later in the loop to determine
3526f169c0eaSGlenn Lagasse * if we've exhausted all possible increment numbers. We store it in
3527f169c0eaSGlenn Lagasse * 'cur_num'.
3528f169c0eaSGlenn Lagasse */
3529f169c0eaSGlenn Lagasse cur_num = num;
3530f169c0eaSGlenn Lagasse
3531f169c0eaSGlenn Lagasse /* Increment 'num' to get new auto BE name number */
3532f169c0eaSGlenn Lagasse if (++num <= 0) {
3533f169c0eaSGlenn Lagasse int ret = 0;
3534f169c0eaSGlenn Lagasse
3535f169c0eaSGlenn Lagasse /*
3536f169c0eaSGlenn Lagasse * Since incrementing 'num' caused it to rollover, start
3537f169c0eaSGlenn Lagasse * over at 0 and find the first available number.
3538f169c0eaSGlenn Lagasse */
3539f169c0eaSGlenn Lagasse for (num = 0; num < cur_num; num++) {
3540f169c0eaSGlenn Lagasse
3541f169c0eaSGlenn Lagasse (void) snprintf(cur_be_name, sizeof (cur_be_name),
3542f169c0eaSGlenn Lagasse "%s%c%d", base_be_name, BE_AUTO_NAME_DELIM, num);
3543f169c0eaSGlenn Lagasse
3544f169c0eaSGlenn Lagasse ret = zpool_iter(g_zfs, be_exists_callback,
3545f169c0eaSGlenn Lagasse cur_be_name);
3546f169c0eaSGlenn Lagasse
3547f169c0eaSGlenn Lagasse if (ret == 0) {
3548f169c0eaSGlenn Lagasse /*
3549f169c0eaSGlenn Lagasse * BE name doesn't exist, break out
3550f169c0eaSGlenn Lagasse * to use 'num'.
3551f169c0eaSGlenn Lagasse */
3552f169c0eaSGlenn Lagasse break;
3553f169c0eaSGlenn Lagasse } else if (ret == 1) {
3554f169c0eaSGlenn Lagasse /* BE name exists, continue looking */
3555f169c0eaSGlenn Lagasse continue;
3556f169c0eaSGlenn Lagasse } else {
3557f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_auto_name: "
3558f169c0eaSGlenn Lagasse "zpool_iter failed: %s\n"),
3559f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
3560f169c0eaSGlenn Lagasse be_free_list(be_nodes);
3561f169c0eaSGlenn Lagasse return (NULL);
3562f169c0eaSGlenn Lagasse }
3563f169c0eaSGlenn Lagasse }
3564f169c0eaSGlenn Lagasse
3565f169c0eaSGlenn Lagasse /*
3566f169c0eaSGlenn Lagasse * If 'num' equals 'cur_num', we've exhausted all possible
3567f169c0eaSGlenn Lagasse * auto BE names for this base BE name.
3568f169c0eaSGlenn Lagasse */
3569f169c0eaSGlenn Lagasse if (num == cur_num) {
3570f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_auto_name: "
3571f169c0eaSGlenn Lagasse "No more available auto BE names for base "
3572f169c0eaSGlenn Lagasse "BE name %s\n"), base_be_name);
3573f169c0eaSGlenn Lagasse be_free_list(be_nodes);
3574f169c0eaSGlenn Lagasse return (NULL);
3575f169c0eaSGlenn Lagasse }
3576f169c0eaSGlenn Lagasse }
3577f169c0eaSGlenn Lagasse
3578f169c0eaSGlenn Lagasse be_free_list(be_nodes);
3579f169c0eaSGlenn Lagasse
3580f169c0eaSGlenn Lagasse /*
3581f169c0eaSGlenn Lagasse * Generate string for auto BE name.
3582f169c0eaSGlenn Lagasse */
3583f169c0eaSGlenn Lagasse (void) snprintf(auto_be_name, sizeof (auto_be_name), "%s%c%d",
3584f169c0eaSGlenn Lagasse base_be_name, BE_AUTO_NAME_DELIM, num);
3585f169c0eaSGlenn Lagasse
3586f169c0eaSGlenn Lagasse if ((c = strdup(auto_be_name)) == NULL) {
3587f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_auto_name: "
3588f169c0eaSGlenn Lagasse "memory allocation failed\n"));
3589f169c0eaSGlenn Lagasse return (NULL);
3590f169c0eaSGlenn Lagasse }
3591f169c0eaSGlenn Lagasse
3592f169c0eaSGlenn Lagasse return (c);
3593f169c0eaSGlenn Lagasse }
3594f169c0eaSGlenn Lagasse
3595f169c0eaSGlenn Lagasse /*
35966b1d07a4SAlexander Eremin * Function: be_get_console_prop
35976b1d07a4SAlexander Eremin * Description: Determine console device.
35986b1d07a4SAlexander Eremin * Returns:
35996b1d07a4SAlexander Eremin * Success - pointer to console setting.
36006b1d07a4SAlexander Eremin * Failure - NULL
36016b1d07a4SAlexander Eremin * Scope:
36026b1d07a4SAlexander Eremin * Private
36036b1d07a4SAlexander Eremin */
36046b1d07a4SAlexander Eremin static char *
be_get_console_prop(void)36056b1d07a4SAlexander Eremin be_get_console_prop(void)
36066b1d07a4SAlexander Eremin {
36076b1d07a4SAlexander Eremin di_node_t dn;
36086b1d07a4SAlexander Eremin char *console = NULL;
36096b1d07a4SAlexander Eremin
36106b1d07a4SAlexander Eremin if ((dn = di_init("/", DINFOPROP)) == DI_NODE_NIL) {
36116b1d07a4SAlexander Eremin be_print_err(gettext("be_get_console_prop: "
36126b1d07a4SAlexander Eremin "di_init() failed\n"));
36136b1d07a4SAlexander Eremin return (NULL);
36146b1d07a4SAlexander Eremin }
36156b1d07a4SAlexander Eremin
36166b1d07a4SAlexander Eremin if (di_prop_lookup_strings(DDI_DEV_T_ANY, dn,
36176b1d07a4SAlexander Eremin "console", &console) != -1) {
36186b1d07a4SAlexander Eremin di_fini(dn);
36196b1d07a4SAlexander Eremin return (console);
36206b1d07a4SAlexander Eremin }
36216b1d07a4SAlexander Eremin
36226b1d07a4SAlexander Eremin if (console == NULL) {
36236b1d07a4SAlexander Eremin if (di_prop_lookup_strings(DDI_DEV_T_ANY, dn,
36246b1d07a4SAlexander Eremin "output-device", &console) != -1) {
36256b1d07a4SAlexander Eremin di_fini(dn);
36266b1d07a4SAlexander Eremin if (strncmp(console, "screen", strlen("screen")) == 0)
36276b1d07a4SAlexander Eremin console = BE_DEFAULT_CONSOLE;
36286b1d07a4SAlexander Eremin }
36296b1d07a4SAlexander Eremin }
36306b1d07a4SAlexander Eremin
36316b1d07a4SAlexander Eremin /*
36326b1d07a4SAlexander Eremin * Default console to text
36336b1d07a4SAlexander Eremin */
36346b1d07a4SAlexander Eremin if (console == NULL) {
36356b1d07a4SAlexander Eremin console = BE_DEFAULT_CONSOLE;
36366b1d07a4SAlexander Eremin }
36376b1d07a4SAlexander Eremin
36386b1d07a4SAlexander Eremin return (console);
36396b1d07a4SAlexander Eremin }
36406b1d07a4SAlexander Eremin
36416b1d07a4SAlexander Eremin /*
3642f169c0eaSGlenn Lagasse * Function: be_create_menu
3643f169c0eaSGlenn Lagasse * Description:
3644f169c0eaSGlenn Lagasse * This function is used if no menu.lst file exists. In
3645f169c0eaSGlenn Lagasse * this case a new file is created and if needed default
3646f169c0eaSGlenn Lagasse * lines are added to the file.
3647f169c0eaSGlenn Lagasse * Parameters:
3648f169c0eaSGlenn Lagasse * pool - The name of the pool the menu.lst file is on
3649f169c0eaSGlenn Lagasse * menu_file - The name of the file we're creating.
3650f169c0eaSGlenn Lagasse * menu_fp - A pointer to the file pointer of the file we
3651f169c0eaSGlenn Lagasse * created. This is also used to pass back the file
3652f169c0eaSGlenn Lagasse * pointer to the newly created file.
3653f169c0eaSGlenn Lagasse * mode - the original mode used for the failed attempt to
3654f169c0eaSGlenn Lagasse * non-existent file.
3655f169c0eaSGlenn Lagasse * Returns:
3656f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
3657f169c0eaSGlenn Lagasse * be_errno_t - Failure
3658f169c0eaSGlenn Lagasse * Scope:
3659f169c0eaSGlenn Lagasse * Private
3660f169c0eaSGlenn Lagasse */
3661f169c0eaSGlenn Lagasse static int
be_create_menu(char * pool,char * menu_file,FILE ** menu_fp,char * mode)3662f169c0eaSGlenn Lagasse be_create_menu(
3663f169c0eaSGlenn Lagasse char *pool,
3664f169c0eaSGlenn Lagasse char *menu_file,
3665f169c0eaSGlenn Lagasse FILE **menu_fp,
3666f169c0eaSGlenn Lagasse char *mode)
3667f169c0eaSGlenn Lagasse {
3668f169c0eaSGlenn Lagasse be_node_list_t *be_nodes = NULL;
3669f169c0eaSGlenn Lagasse char *menu_path = NULL;
3670f169c0eaSGlenn Lagasse char *be_rpool = NULL;
3671f169c0eaSGlenn Lagasse char *be_name = NULL;
36726b1d07a4SAlexander Eremin char *console = NULL;
3673f169c0eaSGlenn Lagasse errno = 0;
3674f169c0eaSGlenn Lagasse
3675f169c0eaSGlenn Lagasse if (menu_file == NULL || menu_fp == NULL || mode == NULL)
3676f169c0eaSGlenn Lagasse return (BE_ERR_INVAL);
3677f169c0eaSGlenn Lagasse
3678f169c0eaSGlenn Lagasse menu_path = strdup(menu_file);
3679f169c0eaSGlenn Lagasse if (menu_path == NULL)
3680f169c0eaSGlenn Lagasse return (BE_ERR_NOMEM);
3681f169c0eaSGlenn Lagasse
3682f169c0eaSGlenn Lagasse (void) dirname(menu_path);
3683f169c0eaSGlenn Lagasse if (*menu_path == '.') {
3684f169c0eaSGlenn Lagasse free(menu_path);
3685f169c0eaSGlenn Lagasse return (BE_ERR_BAD_MENU_PATH);
3686f169c0eaSGlenn Lagasse }
3687f169c0eaSGlenn Lagasse if (mkdirp(menu_path,
3688f169c0eaSGlenn Lagasse S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1 &&
3689f169c0eaSGlenn Lagasse errno != EEXIST) {
3690f169c0eaSGlenn Lagasse free(menu_path);
3691f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_menu: Failed to create the %s "
3692f169c0eaSGlenn Lagasse "directory: %s\n"), menu_path, strerror(errno));
3693f169c0eaSGlenn Lagasse return (errno_to_be_err(errno));
3694f169c0eaSGlenn Lagasse }
3695f169c0eaSGlenn Lagasse free(menu_path);
3696f169c0eaSGlenn Lagasse
3697f169c0eaSGlenn Lagasse /*
3698f169c0eaSGlenn Lagasse * Check to see if this system supports grub
3699f169c0eaSGlenn Lagasse */
3700f169c0eaSGlenn Lagasse if (be_has_grub()) {
3701f169c0eaSGlenn Lagasse /*
3702f169c0eaSGlenn Lagasse * The grub menu is missing so we need to create it
3703f169c0eaSGlenn Lagasse * and fill in the first few lines.
3704f169c0eaSGlenn Lagasse */
37056b1d07a4SAlexander Eremin FILE *temp_fp = fopen(menu_file, "a+");
37066b1d07a4SAlexander Eremin if (temp_fp == NULL) {
37076b1d07a4SAlexander Eremin *menu_fp = NULL;
37086b1d07a4SAlexander Eremin return (errno_to_be_err(errno));
3709f169c0eaSGlenn Lagasse }
37106b1d07a4SAlexander Eremin
37116b1d07a4SAlexander Eremin if ((console = be_get_console_prop()) != NULL) {
37126b1d07a4SAlexander Eremin
37136b1d07a4SAlexander Eremin /*
37146b1d07a4SAlexander Eremin * If console is redirected to serial line,
37156b1d07a4SAlexander Eremin * GRUB splash screen will not be enabled.
37166b1d07a4SAlexander Eremin */
37176b1d07a4SAlexander Eremin if (strncmp(console, "text", strlen("text")) == 0 ||
37186b1d07a4SAlexander Eremin strncmp(console, "graphics",
37196b1d07a4SAlexander Eremin strlen("graphics")) == 0) {
37206b1d07a4SAlexander Eremin
37216b1d07a4SAlexander Eremin (void) fprintf(temp_fp, "%s\n", BE_GRUB_SPLASH);
37226b1d07a4SAlexander Eremin (void) fprintf(temp_fp, "%s\n",
37236b1d07a4SAlexander Eremin BE_GRUB_FOREGROUND);
37246b1d07a4SAlexander Eremin (void) fprintf(temp_fp, "%s\n",
37256b1d07a4SAlexander Eremin BE_GRUB_BACKGROUND);
37266b1d07a4SAlexander Eremin (void) fprintf(temp_fp, "%s\n",
37276b1d07a4SAlexander Eremin BE_GRUB_DEFAULT);
37286b1d07a4SAlexander Eremin } else {
37296b1d07a4SAlexander Eremin be_print_err(gettext("be_create_menu: "
37306b1d07a4SAlexander Eremin "console on serial line, "
37316b1d07a4SAlexander Eremin "GRUB splash image will be disabled\n"));
37326b1d07a4SAlexander Eremin }
37336b1d07a4SAlexander Eremin }
37346b1d07a4SAlexander Eremin
37356b1d07a4SAlexander Eremin (void) fprintf(temp_fp, "timeout 30\n");
37366b1d07a4SAlexander Eremin (void) fclose(temp_fp);
37376b1d07a4SAlexander Eremin
3738f169c0eaSGlenn Lagasse } else {
3739f169c0eaSGlenn Lagasse /*
3740f169c0eaSGlenn Lagasse * The menu file doesn't exist so we need to create a
3741f169c0eaSGlenn Lagasse * blank file.
3742f169c0eaSGlenn Lagasse */
3743f169c0eaSGlenn Lagasse FILE *temp_fp = fopen(menu_file, "w+");
3744f169c0eaSGlenn Lagasse if (temp_fp == NULL) {
3745f169c0eaSGlenn Lagasse *menu_fp = NULL;
3746f169c0eaSGlenn Lagasse return (errno_to_be_err(errno));
3747f169c0eaSGlenn Lagasse }
3748f169c0eaSGlenn Lagasse (void) fclose(temp_fp);
3749f169c0eaSGlenn Lagasse }
3750f169c0eaSGlenn Lagasse
3751f169c0eaSGlenn Lagasse /*
3752f169c0eaSGlenn Lagasse * Now we need to add all the BE's back into the the file.
3753f169c0eaSGlenn Lagasse */
3754*4fef13f1SAndy Fiddaman if (_be_list(NULL, &be_nodes, BE_LIST_DEFAULT) == BE_SUCCESS) {
3755f169c0eaSGlenn Lagasse while (be_nodes != NULL) {
3756f169c0eaSGlenn Lagasse if (strcmp(pool, be_nodes->be_rpool) == 0) {
3757f169c0eaSGlenn Lagasse (void) be_append_menu(be_nodes->be_node_name,
3758f169c0eaSGlenn Lagasse be_nodes->be_rpool, NULL, NULL, NULL);
3759f169c0eaSGlenn Lagasse }
3760f169c0eaSGlenn Lagasse if (be_nodes->be_active_on_boot) {
3761f169c0eaSGlenn Lagasse be_rpool = strdup(be_nodes->be_rpool);
3762f169c0eaSGlenn Lagasse be_name = strdup(be_nodes->be_node_name);
3763f169c0eaSGlenn Lagasse }
3764f169c0eaSGlenn Lagasse
3765f169c0eaSGlenn Lagasse be_nodes = be_nodes->be_next_node;
3766f169c0eaSGlenn Lagasse }
3767f169c0eaSGlenn Lagasse }
3768f169c0eaSGlenn Lagasse be_free_list(be_nodes);
3769f169c0eaSGlenn Lagasse
3770f169c0eaSGlenn Lagasse /*
3771f169c0eaSGlenn Lagasse * Check to see if this system supports grub
3772f169c0eaSGlenn Lagasse */
3773f169c0eaSGlenn Lagasse if (be_has_grub()) {
3774f169c0eaSGlenn Lagasse int err = be_change_grub_default(be_name, be_rpool);
3775f169c0eaSGlenn Lagasse if (err != BE_SUCCESS)
3776f169c0eaSGlenn Lagasse return (err);
3777f169c0eaSGlenn Lagasse }
3778f169c0eaSGlenn Lagasse *menu_fp = fopen(menu_file, mode);
3779f169c0eaSGlenn Lagasse if (*menu_fp == NULL)
3780f169c0eaSGlenn Lagasse return (errno_to_be_err(errno));
3781f169c0eaSGlenn Lagasse
3782f169c0eaSGlenn Lagasse return (BE_SUCCESS);
3783f169c0eaSGlenn Lagasse }
3784f169c0eaSGlenn Lagasse
3785f169c0eaSGlenn Lagasse /*
3786f169c0eaSGlenn Lagasse * Function: be_open_menu
3787f169c0eaSGlenn Lagasse * Description:
3788f169c0eaSGlenn Lagasse * This function is used it open the menu.lst file. If this
3789f169c0eaSGlenn Lagasse * file does not exist be_create_menu is called to create it
3790f169c0eaSGlenn Lagasse * and the open file pointer is returned. If the file does
3791f169c0eaSGlenn Lagasse * exist it is simply opened using the mode passed in.
3792f169c0eaSGlenn Lagasse * Parameters:
3793f169c0eaSGlenn Lagasse * pool - The name of the pool the menu.lst file is on
3794f169c0eaSGlenn Lagasse * menu_file - The name of the file we're opening.
3795f169c0eaSGlenn Lagasse * menu_fp - A pointer to the file pointer of the file we're
3796f169c0eaSGlenn Lagasse * opening. This is also used to pass back the file
3797f169c0eaSGlenn Lagasse * pointer.
3798f169c0eaSGlenn Lagasse * mode - the original mode to be used for opening the menu.lst
3799f169c0eaSGlenn Lagasse * file.
3800f169c0eaSGlenn Lagasse * create_menu - If this is true and the menu.lst file does not
3801f169c0eaSGlenn Lagasse * exist we will attempt to re-create it. However
3802f169c0eaSGlenn Lagasse * if it's false the error returned from the fopen
3803f169c0eaSGlenn Lagasse * will be returned.
3804f169c0eaSGlenn Lagasse * Returns:
3805f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
3806f169c0eaSGlenn Lagasse * be_errno_t - Failure
3807f169c0eaSGlenn Lagasse * Scope:
3808f169c0eaSGlenn Lagasse * Private
3809f169c0eaSGlenn Lagasse */
3810f169c0eaSGlenn Lagasse static int
be_open_menu(char * pool,char * menu_file,FILE ** menu_fp,char * mode,boolean_t create_menu)3811f169c0eaSGlenn Lagasse be_open_menu(
3812f169c0eaSGlenn Lagasse char *pool,
3813f169c0eaSGlenn Lagasse char *menu_file,
3814f169c0eaSGlenn Lagasse FILE **menu_fp,
3815f169c0eaSGlenn Lagasse char *mode,
3816f169c0eaSGlenn Lagasse boolean_t create_menu)
3817f169c0eaSGlenn Lagasse {
3818f169c0eaSGlenn Lagasse int err = 0;
3819f169c0eaSGlenn Lagasse boolean_t set_print = B_FALSE;
3820f169c0eaSGlenn Lagasse
3821f169c0eaSGlenn Lagasse *menu_fp = fopen(menu_file, mode);
3822f169c0eaSGlenn Lagasse err = errno;
3823f169c0eaSGlenn Lagasse if (*menu_fp == NULL) {
3824f169c0eaSGlenn Lagasse if (err == ENOENT && create_menu) {
3825f169c0eaSGlenn Lagasse be_print_err(gettext("be_open_menu: menu.lst "
3826f169c0eaSGlenn Lagasse "file %s does not exist,\n"), menu_file);
3827f169c0eaSGlenn Lagasse if (!do_print) {
3828f169c0eaSGlenn Lagasse set_print = B_TRUE;
3829f169c0eaSGlenn Lagasse do_print = B_TRUE;
3830f169c0eaSGlenn Lagasse }
3831f169c0eaSGlenn Lagasse be_print_err(gettext("WARNING: menu.lst "
3832f169c0eaSGlenn Lagasse "file %s does not exist,\n generating "
3833f169c0eaSGlenn Lagasse "a new menu.lst file\n"), menu_file);
3834f169c0eaSGlenn Lagasse if (set_print)
3835f169c0eaSGlenn Lagasse do_print = B_FALSE;
3836f169c0eaSGlenn Lagasse err = 0;
3837de1ab35cSAlexander Eremin if ((err = be_create_menu(pool, menu_file,
3838f169c0eaSGlenn Lagasse menu_fp, mode)) == ENOENT)
3839f169c0eaSGlenn Lagasse return (BE_ERR_NO_MENU);
3840f169c0eaSGlenn Lagasse else if (err != BE_SUCCESS)
3841f169c0eaSGlenn Lagasse return (err);
3842f169c0eaSGlenn Lagasse else if (*menu_fp == NULL)
3843f169c0eaSGlenn Lagasse return (BE_ERR_NO_MENU);
3844f169c0eaSGlenn Lagasse } else {
3845f169c0eaSGlenn Lagasse be_print_err(gettext("be_open_menu: failed "
3846f169c0eaSGlenn Lagasse "to open menu.lst file %s\n"), menu_file);
3847f169c0eaSGlenn Lagasse if (err == ENOENT)
3848f169c0eaSGlenn Lagasse return (BE_ERR_NO_MENU);
3849f169c0eaSGlenn Lagasse else
3850f169c0eaSGlenn Lagasse return (errno_to_be_err(err));
3851f169c0eaSGlenn Lagasse }
3852f169c0eaSGlenn Lagasse }
3853f169c0eaSGlenn Lagasse return (BE_SUCCESS);
3854f169c0eaSGlenn Lagasse }
3855