1*9160SSherry.Moore@Sun.COM /*
2*9160SSherry.Moore@Sun.COM  * CDDL HEADER START
3*9160SSherry.Moore@Sun.COM  *
4*9160SSherry.Moore@Sun.COM  * The contents of this file are subject to the terms of the
5*9160SSherry.Moore@Sun.COM  * Common Development and Distribution License (the "License").
6*9160SSherry.Moore@Sun.COM  * You may not use this file except in compliance with the License.
7*9160SSherry.Moore@Sun.COM  *
8*9160SSherry.Moore@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*9160SSherry.Moore@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*9160SSherry.Moore@Sun.COM  * See the License for the specific language governing permissions
11*9160SSherry.Moore@Sun.COM  * and limitations under the License.
12*9160SSherry.Moore@Sun.COM  *
13*9160SSherry.Moore@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*9160SSherry.Moore@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*9160SSherry.Moore@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*9160SSherry.Moore@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*9160SSherry.Moore@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*9160SSherry.Moore@Sun.COM  *
19*9160SSherry.Moore@Sun.COM  * CDDL HEADER END
20*9160SSherry.Moore@Sun.COM  */
21*9160SSherry.Moore@Sun.COM /*
22*9160SSherry.Moore@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*9160SSherry.Moore@Sun.COM  * Use is subject to license terms.
24*9160SSherry.Moore@Sun.COM  */
25*9160SSherry.Moore@Sun.COM 
26*9160SSherry.Moore@Sun.COM /*
27*9160SSherry.Moore@Sun.COM  * This file contains all the functions that manipualte the file
28*9160SSherry.Moore@Sun.COM  * system where the GRUB menu resides.
29*9160SSherry.Moore@Sun.COM  */
30*9160SSherry.Moore@Sun.COM #include <stdio.h>
31*9160SSherry.Moore@Sun.COM #include <errno.h>
32*9160SSherry.Moore@Sun.COM #include <stdlib.h>
33*9160SSherry.Moore@Sun.COM #include <strings.h>
34*9160SSherry.Moore@Sun.COM #include <unistd.h>
35*9160SSherry.Moore@Sun.COM #include <fcntl.h>
36*9160SSherry.Moore@Sun.COM #include <assert.h>
37*9160SSherry.Moore@Sun.COM #include <sys/types.h>
38*9160SSherry.Moore@Sun.COM #include <sys/stat.h>
39*9160SSherry.Moore@Sun.COM #include <sys/mount.h>
40*9160SSherry.Moore@Sun.COM #include <sys/mntent.h>
41*9160SSherry.Moore@Sun.COM #include <sys/mnttab.h>
42*9160SSherry.Moore@Sun.COM #include <sys/fs/ufs_mount.h>
43*9160SSherry.Moore@Sun.COM #include <sys/dktp/fdisk.h>
44*9160SSherry.Moore@Sun.COM #include <libfstyp.h>
45*9160SSherry.Moore@Sun.COM 
46*9160SSherry.Moore@Sun.COM #include "libgrub_impl.h"
47*9160SSherry.Moore@Sun.COM 
48*9160SSherry.Moore@Sun.COM static int
49*9160SSherry.Moore@Sun.COM slice_match(const char *physpath, int slice)
50*9160SSherry.Moore@Sun.COM {
51*9160SSherry.Moore@Sun.COM 	const char *pos;
52*9160SSherry.Moore@Sun.COM 
53*9160SSherry.Moore@Sun.COM 	return ((pos = strrchr(physpath, slice)) == NULL ||
54*9160SSherry.Moore@Sun.COM 	    pos[1] != 0 || pos[-1] != ':');
55*9160SSherry.Moore@Sun.COM }
56*9160SSherry.Moore@Sun.COM 
57*9160SSherry.Moore@Sun.COM /*
58*9160SSherry.Moore@Sun.COM  * Returns zero if path contains ufs
59*9160SSherry.Moore@Sun.COM  */
60*9160SSherry.Moore@Sun.COM static int
61*9160SSherry.Moore@Sun.COM slice_ufs(const char *path)
62*9160SSherry.Moore@Sun.COM {
63*9160SSherry.Moore@Sun.COM 	int fd, ret;
64*9160SSherry.Moore@Sun.COM 	const char *id;
65*9160SSherry.Moore@Sun.COM 	fstyp_handle_t hdl;
66*9160SSherry.Moore@Sun.COM 
67*9160SSherry.Moore@Sun.COM 	fd = open(path, O_RDONLY);
68*9160SSherry.Moore@Sun.COM 	if ((ret = fstyp_init(fd, 0, NULL, &hdl)) == 0) {
69*9160SSherry.Moore@Sun.COM 		ret = fstyp_ident(hdl, "ufs", &id);
70*9160SSherry.Moore@Sun.COM 		fstyp_fini(hdl);
71*9160SSherry.Moore@Sun.COM 	}
72*9160SSherry.Moore@Sun.COM 	(void) close(fd);
73*9160SSherry.Moore@Sun.COM 	return (ret);
74*9160SSherry.Moore@Sun.COM }
75*9160SSherry.Moore@Sun.COM 
76*9160SSherry.Moore@Sun.COM 
77*9160SSherry.Moore@Sun.COM static int
78*9160SSherry.Moore@Sun.COM get_sol_prtnum(const char *physpath)
79*9160SSherry.Moore@Sun.COM {
80*9160SSherry.Moore@Sun.COM 	int i, fd;
81*9160SSherry.Moore@Sun.COM 	char *pos;
82*9160SSherry.Moore@Sun.COM 	size_t sz;
83*9160SSherry.Moore@Sun.COM 	struct mboot *mb;
84*9160SSherry.Moore@Sun.COM 	struct ipart *ipart;
85*9160SSherry.Moore@Sun.COM 	char boot_sect[512];
86*9160SSherry.Moore@Sun.COM 	char rdev[MAXNAMELEN];
87*9160SSherry.Moore@Sun.COM 
88*9160SSherry.Moore@Sun.COM 	(void) snprintf(rdev, sizeof (rdev), "/devices%s,raw", physpath);
89*9160SSherry.Moore@Sun.COM 
90*9160SSherry.Moore@Sun.COM 	if ((pos = strrchr(rdev, ':')) == NULL)
91*9160SSherry.Moore@Sun.COM 		return (PRTNUM_INVALID);
92*9160SSherry.Moore@Sun.COM 
93*9160SSherry.Moore@Sun.COM 	pos[1] = SLCNUM_WHOLE_DISK;
94*9160SSherry.Moore@Sun.COM 
95*9160SSherry.Moore@Sun.COM 	fd = open(rdev, O_RDONLY);
96*9160SSherry.Moore@Sun.COM 	sz = read(fd, boot_sect, sizeof (boot_sect));
97*9160SSherry.Moore@Sun.COM 	(void) close(fd);
98*9160SSherry.Moore@Sun.COM 
99*9160SSherry.Moore@Sun.COM 	if (sz != sizeof (boot_sect))
100*9160SSherry.Moore@Sun.COM 		return (PRTNUM_INVALID);
101*9160SSherry.Moore@Sun.COM 
102*9160SSherry.Moore@Sun.COM 	/* parse fdisk table */
103*9160SSherry.Moore@Sun.COM 	mb = (struct mboot *)(uintptr_t)boot_sect;
104*9160SSherry.Moore@Sun.COM 	ipart = (struct ipart *)(uintptr_t)mb->parts;
105*9160SSherry.Moore@Sun.COM 	for (i = 0; i < FD_NUMPART; ++i) {
106*9160SSherry.Moore@Sun.COM 		if (ipart[i].systid == SUNIXOS || ipart[i].systid == SUNIXOS2)
107*9160SSherry.Moore@Sun.COM 			return (i);
108*9160SSherry.Moore@Sun.COM 	}
109*9160SSherry.Moore@Sun.COM 	return (PRTNUM_INVALID);
110*9160SSherry.Moore@Sun.COM }
111*9160SSherry.Moore@Sun.COM 
112*9160SSherry.Moore@Sun.COM /*
113*9160SSherry.Moore@Sun.COM  * Get physpath, topfs and bootfs for ZFS root dataset.
114*9160SSherry.Moore@Sun.COM  * Return 0 on success, non-zero (not errno) on failure.
115*9160SSherry.Moore@Sun.COM  */
116*9160SSherry.Moore@Sun.COM static int
117*9160SSherry.Moore@Sun.COM get_zfs_root(zfs_handle_t *zfh, grub_fs_t *fs, grub_root_t *root)
118*9160SSherry.Moore@Sun.COM {
119*9160SSherry.Moore@Sun.COM 	int ret;
120*9160SSherry.Moore@Sun.COM 	zpool_handle_t *zph;
121*9160SSherry.Moore@Sun.COM 	const char *name;
122*9160SSherry.Moore@Sun.COM 
123*9160SSherry.Moore@Sun.COM 	if (zfs_get_type(zfh) != ZFS_TYPE_FILESYSTEM ||
124*9160SSherry.Moore@Sun.COM 	    (name = zfs_get_name(zfh)) == NULL ||
125*9160SSherry.Moore@Sun.COM 	    (zph = zpool_open(fs->gf_lzfh, name)) == NULL)
126*9160SSherry.Moore@Sun.COM 		return (-1);
127*9160SSherry.Moore@Sun.COM 
128*9160SSherry.Moore@Sun.COM 	if ((ret = zpool_get_physpath(zph, root->gr_physpath,
129*9160SSherry.Moore@Sun.COM 	    sizeof (root->gr_physpath))) == 0 &&
130*9160SSherry.Moore@Sun.COM 	    (ret = zpool_get_prop(zph, ZPOOL_PROP_BOOTFS,
131*9160SSherry.Moore@Sun.COM 	    root->gr_fs[GRBM_ZFS_BOOTFS].gfs_dev,
132*9160SSherry.Moore@Sun.COM 	    sizeof (root->gr_fs[GRBM_ZFS_BOOTFS].gfs_dev), NULL)) == 0) {
133*9160SSherry.Moore@Sun.COM 
134*9160SSherry.Moore@Sun.COM 		(void) strlcpy(root->gr_fs[GRBM_ZFS_TOPFS].gfs_dev, name,
135*9160SSherry.Moore@Sun.COM 		    sizeof (root->gr_fs[GRBM_ZFS_TOPFS].gfs_dev));
136*9160SSherry.Moore@Sun.COM 		(void) grub_fsd_get_mountp(root->gr_fs + GRBM_ZFS_BOOTFS,
137*9160SSherry.Moore@Sun.COM 		    MNTTYPE_ZFS);
138*9160SSherry.Moore@Sun.COM 		(void) grub_fsd_get_mountp(root->gr_fs + GRBM_ZFS_TOPFS,
139*9160SSherry.Moore@Sun.COM 		    MNTTYPE_ZFS);
140*9160SSherry.Moore@Sun.COM 	}
141*9160SSherry.Moore@Sun.COM 
142*9160SSherry.Moore@Sun.COM 	zpool_close(zph);
143*9160SSherry.Moore@Sun.COM 	return (ret);
144*9160SSherry.Moore@Sun.COM }
145*9160SSherry.Moore@Sun.COM 
146*9160SSherry.Moore@Sun.COM /*
147*9160SSherry.Moore@Sun.COM  * On entry physpath parameter supposed to contain:
148*9160SSherry.Moore@Sun.COM  * <disk_physpath>[<space><disk_physpath>]*.
149*9160SSherry.Moore@Sun.COM  * Retireives first <disk_physpath> that matches both partition and slice.
150*9160SSherry.Moore@Sun.COM  * If any partition and slice is acceptable, first <disk_physpath> is returned.
151*9160SSherry.Moore@Sun.COM  */
152*9160SSherry.Moore@Sun.COM static int
153*9160SSherry.Moore@Sun.COM get_one_physpath(char *physpath, uint_t prtnum, uint_t slcnum)
154*9160SSherry.Moore@Sun.COM {
155*9160SSherry.Moore@Sun.COM 	int ret;
156*9160SSherry.Moore@Sun.COM 	char *tmp, *tok;
157*9160SSherry.Moore@Sun.COM 
158*9160SSherry.Moore@Sun.COM 	if (!IS_SLCNUM_VALID(slcnum) && !IS_PRTNUM_VALID(prtnum)) {
159*9160SSherry.Moore@Sun.COM 		(void) strtok(physpath, " ");
160*9160SSherry.Moore@Sun.COM 		return (0);
161*9160SSherry.Moore@Sun.COM 	}
162*9160SSherry.Moore@Sun.COM 
163*9160SSherry.Moore@Sun.COM 	if ((tmp = strdup(physpath)) == NULL)
164*9160SSherry.Moore@Sun.COM 		return (errno);
165*9160SSherry.Moore@Sun.COM 
166*9160SSherry.Moore@Sun.COM 	ret = ENODEV;
167*9160SSherry.Moore@Sun.COM 	for (tok = strtok(tmp, " "); tok != NULL; tok = strtok(NULL, " ")) {
168*9160SSherry.Moore@Sun.COM 		if ((ret = (slice_match(tok, slcnum) != 0 ||
169*9160SSherry.Moore@Sun.COM 		    get_sol_prtnum(tok) != prtnum)) == 0) {
170*9160SSherry.Moore@Sun.COM 			(void) strcpy(physpath, tok);
171*9160SSherry.Moore@Sun.COM 			break;
172*9160SSherry.Moore@Sun.COM 		}
173*9160SSherry.Moore@Sun.COM 	}
174*9160SSherry.Moore@Sun.COM 
175*9160SSherry.Moore@Sun.COM 	free(tmp);
176*9160SSherry.Moore@Sun.COM 	return (ret);
177*9160SSherry.Moore@Sun.COM }
178*9160SSherry.Moore@Sun.COM 
179*9160SSherry.Moore@Sun.COM static int
180*9160SSherry.Moore@Sun.COM zfs_bootsign(zfs_handle_t *zfh, void *data)
181*9160SSherry.Moore@Sun.COM {
182*9160SSherry.Moore@Sun.COM 	grub_barg_t *barg;
183*9160SSherry.Moore@Sun.COM 	grub_menu_t *menu;
184*9160SSherry.Moore@Sun.COM 	struct stat st;
185*9160SSherry.Moore@Sun.COM 	char path[MAXPATHLEN];
186*9160SSherry.Moore@Sun.COM 
187*9160SSherry.Moore@Sun.COM 	barg = (grub_barg_t *)data;
188*9160SSherry.Moore@Sun.COM 	menu = barg->gb_entry->ge_menu;
189*9160SSherry.Moore@Sun.COM 
190*9160SSherry.Moore@Sun.COM 	do {
191*9160SSherry.Moore@Sun.COM 		if (get_zfs_root(zfh, &menu->gm_fs, &barg->gb_root) != 0 ||
192*9160SSherry.Moore@Sun.COM 		    get_one_physpath(barg->gb_root.gr_physpath, barg->gb_prtnum,
193*9160SSherry.Moore@Sun.COM 		    barg->gb_slcnum) != 0)
194*9160SSherry.Moore@Sun.COM 			break;
195*9160SSherry.Moore@Sun.COM 
196*9160SSherry.Moore@Sun.COM 		/*
197*9160SSherry.Moore@Sun.COM 		 * if top zfs dataset is not mounted, mount it now
198*9160SSherry.Moore@Sun.COM 		 */
199*9160SSherry.Moore@Sun.COM 		if (barg->gb_root.gr_fs[GRBM_ZFS_TOPFS].gfs_mountp[0] == 0) {
200*9160SSherry.Moore@Sun.COM 			if (grub_fsd_mount_tmp(barg->gb_root.gr_fs +
201*9160SSherry.Moore@Sun.COM 			    GRBM_ZFS_TOPFS, MNTTYPE_ZFS) != 0)
202*9160SSherry.Moore@Sun.COM 				break;
203*9160SSherry.Moore@Sun.COM 		}
204*9160SSherry.Moore@Sun.COM 
205*9160SSherry.Moore@Sun.COM 		/* check that bootsign exists and it is a regular file */
206*9160SSherry.Moore@Sun.COM 		(void) snprintf(path, sizeof (path), "%s%s",
207*9160SSherry.Moore@Sun.COM 		    barg->gb_root.gr_fs[GRBM_ZFS_TOPFS].gfs_mountp,
208*9160SSherry.Moore@Sun.COM 		    barg->gb_bootsign);
209*9160SSherry.Moore@Sun.COM 
210*9160SSherry.Moore@Sun.COM 		if (lstat(path, &st) != 0 || S_ISREG(st.st_mode) == 0 ||
211*9160SSherry.Moore@Sun.COM 		    (st.st_mode & S_IRUSR) == 0)
212*9160SSherry.Moore@Sun.COM 			break;
213*9160SSherry.Moore@Sun.COM 
214*9160SSherry.Moore@Sun.COM 		(void) strlcpy(barg->gb_root.gr_fstyp, MNTTYPE_ZFS,
215*9160SSherry.Moore@Sun.COM 		    sizeof (barg->gb_root.gr_fstyp));
216*9160SSherry.Moore@Sun.COM 		barg->gb_walkret = 0;
217*9160SSherry.Moore@Sun.COM 	/* LINTED: E_CONSTANT_CONDITION */
218*9160SSherry.Moore@Sun.COM 	} while (0);
219*9160SSherry.Moore@Sun.COM 
220*9160SSherry.Moore@Sun.COM 	grub_fsd_umount_tmp(barg->gb_root.gr_fs + GRBM_ZFS_TOPFS);
221*9160SSherry.Moore@Sun.COM 	zfs_close(zfh);
222*9160SSherry.Moore@Sun.COM 
223*9160SSherry.Moore@Sun.COM 	/* return non-zero to terminate the walk */
224*9160SSherry.Moore@Sun.COM 	return (barg->gb_walkret == 0);
225*9160SSherry.Moore@Sun.COM }
226*9160SSherry.Moore@Sun.COM 
227*9160SSherry.Moore@Sun.COM static int
228*9160SSherry.Moore@Sun.COM get_devlink(di_devlink_t dl, void *arg)
229*9160SSherry.Moore@Sun.COM {
230*9160SSherry.Moore@Sun.COM 	const char *path;
231*9160SSherry.Moore@Sun.COM 	grub_barg_t *barg;
232*9160SSherry.Moore@Sun.COM 
233*9160SSherry.Moore@Sun.COM 	barg = (grub_barg_t *)arg;
234*9160SSherry.Moore@Sun.COM 	if ((path = di_devlink_path(dl)) != NULL)
235*9160SSherry.Moore@Sun.COM 		(void) strlcpy(barg->gb_root.gr_fs[GRBM_UFS].gfs_dev, path,
236*9160SSherry.Moore@Sun.COM 		    sizeof (barg->gb_root.gr_fs[GRBM_UFS].gfs_dev));
237*9160SSherry.Moore@Sun.COM 	return (DI_WALK_TERMINATE);
238*9160SSherry.Moore@Sun.COM }
239*9160SSherry.Moore@Sun.COM 
240*9160SSherry.Moore@Sun.COM static int
241*9160SSherry.Moore@Sun.COM ufs_bootsign_check(grub_barg_t *barg)
242*9160SSherry.Moore@Sun.COM {
243*9160SSherry.Moore@Sun.COM 	int ret;
244*9160SSherry.Moore@Sun.COM 	struct stat st;
245*9160SSherry.Moore@Sun.COM 	grub_menu_t *mp;
246*9160SSherry.Moore@Sun.COM 	char path[MAXPATHLEN];
247*9160SSherry.Moore@Sun.COM 
248*9160SSherry.Moore@Sun.COM 	mp = barg->gb_entry->ge_menu;
249*9160SSherry.Moore@Sun.COM 
250*9160SSherry.Moore@Sun.COM 	/* get /dev/dsk link */
251*9160SSherry.Moore@Sun.COM 	if (di_devlink_walk(mp->gm_fs.gf_dvlh, "^dsk/",
252*9160SSherry.Moore@Sun.COM 	    barg->gb_root.gr_physpath, DI_PRIMARY_LINK, barg, get_devlink) != 0)
253*9160SSherry.Moore@Sun.COM 		return (errno);
254*9160SSherry.Moore@Sun.COM 	/*
255*9160SSherry.Moore@Sun.COM 	 * if disk is not mounted, mount it now
256*9160SSherry.Moore@Sun.COM 	 */
257*9160SSherry.Moore@Sun.COM 	if (grub_fsd_get_mountp(barg->gb_root.gr_fs + GRBM_UFS,
258*9160SSherry.Moore@Sun.COM 	    MNTTYPE_UFS) != 0) {
259*9160SSherry.Moore@Sun.COM 		if ((ret =
260*9160SSherry.Moore@Sun.COM 		    slice_ufs(barg->gb_root.gr_fs[GRBM_UFS].gfs_dev)) != 0 ||
261*9160SSherry.Moore@Sun.COM 		    (ret = grub_fsd_mount_tmp(barg->gb_root.gr_fs + GRBM_UFS,
262*9160SSherry.Moore@Sun.COM 		    MNTTYPE_UFS)) != 0)
263*9160SSherry.Moore@Sun.COM 			return (ret);
264*9160SSherry.Moore@Sun.COM 	}
265*9160SSherry.Moore@Sun.COM 
266*9160SSherry.Moore@Sun.COM 	(void) snprintf(path, sizeof (path), "%s%s",
267*9160SSherry.Moore@Sun.COM 	    barg->gb_root.gr_fs[GRBM_UFS].gfs_mountp, barg->gb_bootsign);
268*9160SSherry.Moore@Sun.COM 
269*9160SSherry.Moore@Sun.COM 	if (lstat(path, &st) == 0 && S_ISREG(st.st_mode) &&
270*9160SSherry.Moore@Sun.COM 	    (st.st_mode & S_IRUSR) != 0) {
271*9160SSherry.Moore@Sun.COM 		barg->gb_walkret = 0;
272*9160SSherry.Moore@Sun.COM 		(void) strlcpy(barg->gb_root.gr_fstyp, MNTTYPE_UFS,
273*9160SSherry.Moore@Sun.COM 		    sizeof (barg->gb_root.gr_fstyp));
274*9160SSherry.Moore@Sun.COM 	}
275*9160SSherry.Moore@Sun.COM 
276*9160SSherry.Moore@Sun.COM 	grub_fsd_umount_tmp(barg->gb_root.gr_fs + GRBM_UFS);
277*9160SSherry.Moore@Sun.COM 	return (barg->gb_walkret);
278*9160SSherry.Moore@Sun.COM }
279*9160SSherry.Moore@Sun.COM 
280*9160SSherry.Moore@Sun.COM static int
281*9160SSherry.Moore@Sun.COM ufs_bootsign(di_node_t node, di_minor_t minor, void *arg)
282*9160SSherry.Moore@Sun.COM {
283*9160SSherry.Moore@Sun.COM 	uint_t prtnum;
284*9160SSherry.Moore@Sun.COM 	char *name, *path;
285*9160SSherry.Moore@Sun.COM 	grub_barg_t *barg;
286*9160SSherry.Moore@Sun.COM 
287*9160SSherry.Moore@Sun.COM 	barg = (grub_barg_t *)arg;
288*9160SSherry.Moore@Sun.COM 
289*9160SSherry.Moore@Sun.COM 	if (di_minor_spectype(minor) != S_IFBLK)
290*9160SSherry.Moore@Sun.COM 		return (DI_WALK_CONTINUE);
291*9160SSherry.Moore@Sun.COM 
292*9160SSherry.Moore@Sun.COM 	name = di_minor_name(minor);
293*9160SSherry.Moore@Sun.COM 	if (name[0] != barg->gb_slcnum || name[1] != 0)
294*9160SSherry.Moore@Sun.COM 		return (DI_WALK_CONTINUE);
295*9160SSherry.Moore@Sun.COM 
296*9160SSherry.Moore@Sun.COM 	path = di_devfs_path(node);
297*9160SSherry.Moore@Sun.COM 	(void) snprintf(barg->gb_root.gr_physpath,
298*9160SSherry.Moore@Sun.COM 	    sizeof (barg->gb_root.gr_physpath), "%s:%c", path, barg->gb_slcnum);
299*9160SSherry.Moore@Sun.COM 	di_devfs_path_free(path);
300*9160SSherry.Moore@Sun.COM 
301*9160SSherry.Moore@Sun.COM 	prtnum = get_sol_prtnum(barg->gb_root.gr_physpath);
302*9160SSherry.Moore@Sun.COM 	if (!IS_PRTNUM_VALID(prtnum))
303*9160SSherry.Moore@Sun.COM 		return (DI_WALK_CONTINUE);
304*9160SSherry.Moore@Sun.COM 
305*9160SSherry.Moore@Sun.COM 	/*
306*9160SSherry.Moore@Sun.COM 	 * check only specified partition, slice
307*9160SSherry.Moore@Sun.COM 	 */
308*9160SSherry.Moore@Sun.COM 
309*9160SSherry.Moore@Sun.COM 	if (IS_PRTNUM_VALID(barg->gb_prtnum)) {
310*9160SSherry.Moore@Sun.COM 		if (prtnum != barg->gb_prtnum || ufs_bootsign_check(barg) != 0)
311*9160SSherry.Moore@Sun.COM 			return (DI_WALK_CONTINUE);
312*9160SSherry.Moore@Sun.COM 		return (DI_WALK_TERMINATE);
313*9160SSherry.Moore@Sun.COM 	}
314*9160SSherry.Moore@Sun.COM 
315*9160SSherry.Moore@Sun.COM 	/*
316*9160SSherry.Moore@Sun.COM 	 * Walk through all slices in found solaris partition
317*9160SSherry.Moore@Sun.COM 	 */
318*9160SSherry.Moore@Sun.COM 
319*9160SSherry.Moore@Sun.COM 	barg->gb_prtnum = prtnum;
320*9160SSherry.Moore@Sun.COM 	minor = DI_MINOR_NIL;
321*9160SSherry.Moore@Sun.COM 
322*9160SSherry.Moore@Sun.COM 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
323*9160SSherry.Moore@Sun.COM 
324*9160SSherry.Moore@Sun.COM 		if (di_minor_spectype(minor) != S_IFBLK)
325*9160SSherry.Moore@Sun.COM 			continue;
326*9160SSherry.Moore@Sun.COM 
327*9160SSherry.Moore@Sun.COM 		name = di_minor_name(minor);
328*9160SSherry.Moore@Sun.COM 		if (!IS_SLCNUM_VALID(name[0]) || name[1] != 0)
329*9160SSherry.Moore@Sun.COM 			continue;
330*9160SSherry.Moore@Sun.COM 
331*9160SSherry.Moore@Sun.COM 		barg->gb_slcnum = name[0];
332*9160SSherry.Moore@Sun.COM 		path = strrchr(barg->gb_root.gr_physpath, ':');
333*9160SSherry.Moore@Sun.COM 		path[1] = barg->gb_slcnum;
334*9160SSherry.Moore@Sun.COM 
335*9160SSherry.Moore@Sun.COM 		if (ufs_bootsign_check(barg) == 0)
336*9160SSherry.Moore@Sun.COM 			return (DI_WALK_TERMINATE);
337*9160SSherry.Moore@Sun.COM 	}
338*9160SSherry.Moore@Sun.COM 
339*9160SSherry.Moore@Sun.COM 	barg->gb_prtnum = (uint_t)PRTNUM_INVALID;
340*9160SSherry.Moore@Sun.COM 	barg->gb_slcnum = (uint_t)SLCNUM_WHOLE_DISK;
341*9160SSherry.Moore@Sun.COM 	return (DI_WALK_CONTINUE);
342*9160SSherry.Moore@Sun.COM }
343*9160SSherry.Moore@Sun.COM 
344*9160SSherry.Moore@Sun.COM /*
345*9160SSherry.Moore@Sun.COM  * Differs from what GRUB is doing: GRUB searchs through all disks seen by bios
346*9160SSherry.Moore@Sun.COM  * for bootsign, if bootsign is found on ufs slice GRUB sets it as a root,
347*9160SSherry.Moore@Sun.COM  * if on zfs, then GRUB uses zfs slice as root only if bootsign wasn't found
348*9160SSherry.Moore@Sun.COM  * on other slices.
349*9160SSherry.Moore@Sun.COM  * That function first searches through all top datasets of active zpools,
350*9160SSherry.Moore@Sun.COM  * then if bootsign still not found walks through all disks and tries to
351*9160SSherry.Moore@Sun.COM  * find ufs slice with the bootsign.
352*9160SSherry.Moore@Sun.COM  */
353*9160SSherry.Moore@Sun.COM int
354*9160SSherry.Moore@Sun.COM grub_find_bootsign(grub_barg_t *barg)
355*9160SSherry.Moore@Sun.COM {
356*9160SSherry.Moore@Sun.COM 	grub_menu_t *mp;
357*9160SSherry.Moore@Sun.COM 	mp = barg->gb_entry->ge_menu;
358*9160SSherry.Moore@Sun.COM 
359*9160SSherry.Moore@Sun.COM 	/* try to find bootsign over zfs pools */
360*9160SSherry.Moore@Sun.COM 	barg->gb_walkret = EG_BOOTSIGN;
361*9160SSherry.Moore@Sun.COM 	(void) zfs_iter_root(mp->gm_fs.gf_lzfh, zfs_bootsign, barg);
362*9160SSherry.Moore@Sun.COM 
363*9160SSherry.Moore@Sun.COM 	/* try ufs now */
364*9160SSherry.Moore@Sun.COM 	if (barg->gb_walkret != 0 && di_walk_minor(mp->gm_fs.gf_diroot,
365*9160SSherry.Moore@Sun.COM 	    DDI_NT_BLOCK, 0, barg, ufs_bootsign) != 0)
366*9160SSherry.Moore@Sun.COM 		return (errno);
367*9160SSherry.Moore@Sun.COM 
368*9160SSherry.Moore@Sun.COM 	return (barg->gb_walkret);
369*9160SSherry.Moore@Sun.COM }
370*9160SSherry.Moore@Sun.COM 
371*9160SSherry.Moore@Sun.COM /*
372*9160SSherry.Moore@Sun.COM  * Get current root file system.
373*9160SSherry.Moore@Sun.COM  * Return 0 on success, errno code on failure.
374*9160SSherry.Moore@Sun.COM  */
375*9160SSherry.Moore@Sun.COM int
376*9160SSherry.Moore@Sun.COM grub_current_root(grub_fs_t *fs, grub_root_t *root)
377*9160SSherry.Moore@Sun.COM {
378*9160SSherry.Moore@Sun.COM 	int rc = 0;
379*9160SSherry.Moore@Sun.COM 	FILE *fp = NULL;
380*9160SSherry.Moore@Sun.COM 	char *name = NULL;
381*9160SSherry.Moore@Sun.COM 	zfs_handle_t *zfh = NULL;
382*9160SSherry.Moore@Sun.COM 	struct mnttab mp = {0};
383*9160SSherry.Moore@Sun.COM 	struct mnttab mpref = {0};
384*9160SSherry.Moore@Sun.COM 	char buf[MAXNAMELEN] = {0};
385*9160SSherry.Moore@Sun.COM 
386*9160SSherry.Moore@Sun.COM 	mpref.mnt_mountp = "/";
387*9160SSherry.Moore@Sun.COM 
388*9160SSherry.Moore@Sun.COM 	if ((fp = fopen(MNTTAB, "r")) == NULL)
389*9160SSherry.Moore@Sun.COM 		return (errno);
390*9160SSherry.Moore@Sun.COM 
391*9160SSherry.Moore@Sun.COM 	/*
392*9160SSherry.Moore@Sun.COM 	 * getmntany returns non-zero for failure, and sets errno
393*9160SSherry.Moore@Sun.COM 	 */
394*9160SSherry.Moore@Sun.COM 	rc = getmntany(fp, &mp, &mpref);
395*9160SSherry.Moore@Sun.COM 	if (rc != 0)
396*9160SSherry.Moore@Sun.COM 		rc = errno;
397*9160SSherry.Moore@Sun.COM 
398*9160SSherry.Moore@Sun.COM 	(void) fclose(fp);
399*9160SSherry.Moore@Sun.COM 
400*9160SSherry.Moore@Sun.COM 	if (rc != 0)
401*9160SSherry.Moore@Sun.COM 		return (rc);
402*9160SSherry.Moore@Sun.COM 
403*9160SSherry.Moore@Sun.COM 	(void) strlcpy(root->gr_fstyp, mp.mnt_fstype, sizeof (root->gr_fstyp));
404*9160SSherry.Moore@Sun.COM 
405*9160SSherry.Moore@Sun.COM 	if (strcmp(root->gr_fstyp, MNTTYPE_ZFS) == 0) {
406*9160SSherry.Moore@Sun.COM 
407*9160SSherry.Moore@Sun.COM 		(void) strlcpy(buf, mp.mnt_special, sizeof (buf));
408*9160SSherry.Moore@Sun.COM 		if ((name = strtok(buf, "/")) == NULL)
409*9160SSherry.Moore@Sun.COM 			return (EG_CURROOT);
410*9160SSherry.Moore@Sun.COM 
411*9160SSherry.Moore@Sun.COM 		if ((zfh = zfs_open(fs->gf_lzfh, name, ZFS_TYPE_FILESYSTEM)) ==
412*9160SSherry.Moore@Sun.COM 		    NULL)
413*9160SSherry.Moore@Sun.COM 			return (EG_OPENZFS);
414*9160SSherry.Moore@Sun.COM 
415*9160SSherry.Moore@Sun.COM 		/*
416*9160SSherry.Moore@Sun.COM 		 * get_zfs_root returns non-zero on failure, not
417*9160SSherry.Moore@Sun.COM 		 * errno.
418*9160SSherry.Moore@Sun.COM 		 */
419*9160SSherry.Moore@Sun.COM 		if (get_zfs_root(zfh, fs, root))
420*9160SSherry.Moore@Sun.COM 			rc = EG_CURROOT;
421*9160SSherry.Moore@Sun.COM 
422*9160SSherry.Moore@Sun.COM 		zfs_close(zfh);
423*9160SSherry.Moore@Sun.COM 
424*9160SSherry.Moore@Sun.COM 	} else if (strcmp(mp.mnt_fstype, MNTTYPE_UFS) == 0) {
425*9160SSherry.Moore@Sun.COM 		(void) strlcpy(root->gr_fs[GRBM_UFS].gfs_dev, mp.mnt_special,
426*9160SSherry.Moore@Sun.COM 		    sizeof (root->gr_fs[GRBM_UFS].gfs_dev));
427*9160SSherry.Moore@Sun.COM 		(void) strlcpy(root->gr_fs[GRBM_UFS].gfs_mountp, mp.mnt_mountp,
428*9160SSherry.Moore@Sun.COM 		    sizeof (root->gr_fs[GRBM_UFS].gfs_mountp));
429*9160SSherry.Moore@Sun.COM 	} else {
430*9160SSherry.Moore@Sun.COM 		rc = EG_UNKNOWNFS;
431*9160SSherry.Moore@Sun.COM 	}
432*9160SSherry.Moore@Sun.COM 
433*9160SSherry.Moore@Sun.COM 	return (rc);
434*9160SSherry.Moore@Sun.COM }
435*9160SSherry.Moore@Sun.COM 
436*9160SSherry.Moore@Sun.COM grub_fsdesc_t *
437*9160SSherry.Moore@Sun.COM grub_get_rootfsd(const grub_root_t *root)
438*9160SSherry.Moore@Sun.COM {
439*9160SSherry.Moore@Sun.COM 	grub_fsdesc_t *fsd = NULL;
440*9160SSherry.Moore@Sun.COM 
441*9160SSherry.Moore@Sun.COM 	assert(root);
442*9160SSherry.Moore@Sun.COM 	if (strcmp(MNTTYPE_UFS, root->gr_fstyp) == 0)
443*9160SSherry.Moore@Sun.COM 		fsd = (grub_fsdesc_t *)root->gr_fs + GRBM_UFS;
444*9160SSherry.Moore@Sun.COM 	else if (strcmp(MNTTYPE_ZFS, root->gr_fstyp) == 0)
445*9160SSherry.Moore@Sun.COM 		fsd = (grub_fsdesc_t *)root->gr_fs + GRBM_ZFS_BOOTFS;
446*9160SSherry.Moore@Sun.COM 
447*9160SSherry.Moore@Sun.COM 	return (fsd);
448*9160SSherry.Moore@Sun.COM }
449*9160SSherry.Moore@Sun.COM 
450*9160SSherry.Moore@Sun.COM /*
451*9160SSherry.Moore@Sun.COM  * Gets file systems mount point if any.
452*9160SSherry.Moore@Sun.COM  * Return 0 if filesystem is mounted, errno on failure.
453*9160SSherry.Moore@Sun.COM  */
454*9160SSherry.Moore@Sun.COM int
455*9160SSherry.Moore@Sun.COM grub_fsd_get_mountp(grub_fsdesc_t *fsd, char *fstyp)
456*9160SSherry.Moore@Sun.COM {
457*9160SSherry.Moore@Sun.COM 	int rc;
458*9160SSherry.Moore@Sun.COM 	FILE *fp = NULL;
459*9160SSherry.Moore@Sun.COM 	struct mnttab mp = {0};
460*9160SSherry.Moore@Sun.COM 	struct mnttab mpref = {0};
461*9160SSherry.Moore@Sun.COM 
462*9160SSherry.Moore@Sun.COM 	fsd->gfs_mountp[0] = 0;
463*9160SSherry.Moore@Sun.COM 
464*9160SSherry.Moore@Sun.COM 	if ((fp = fopen(MNTTAB, "r")) == NULL)
465*9160SSherry.Moore@Sun.COM 		return (errno);
466*9160SSherry.Moore@Sun.COM 
467*9160SSherry.Moore@Sun.COM 	mpref.mnt_special = fsd->gfs_dev;
468*9160SSherry.Moore@Sun.COM 	mpref.mnt_fstype = fstyp;
469*9160SSherry.Moore@Sun.COM 
470*9160SSherry.Moore@Sun.COM 	if ((rc = getmntany(fp, &mp, &mpref)) == 0)
471*9160SSherry.Moore@Sun.COM 		(void) strlcpy(fsd->gfs_mountp, mp.mnt_mountp,
472*9160SSherry.Moore@Sun.COM 		    sizeof (fsd->gfs_mountp));
473*9160SSherry.Moore@Sun.COM 	else
474*9160SSherry.Moore@Sun.COM 		rc = EG_GETMNTTAB;
475*9160SSherry.Moore@Sun.COM 
476*9160SSherry.Moore@Sun.COM 	(void) fclose(fp);
477*9160SSherry.Moore@Sun.COM 	return (rc);
478*9160SSherry.Moore@Sun.COM }
479*9160SSherry.Moore@Sun.COM 
480*9160SSherry.Moore@Sun.COM static const char tmp_mountp[] = "/tmp/.libgrubmgmt.%s.XXXXXX";
481*9160SSherry.Moore@Sun.COM 
482*9160SSherry.Moore@Sun.COM /*
483*9160SSherry.Moore@Sun.COM  * Mount file system at tmp_mountp.
484*9160SSherry.Moore@Sun.COM  * Return 0 on success, errno on failure.
485*9160SSherry.Moore@Sun.COM  */
486*9160SSherry.Moore@Sun.COM int
487*9160SSherry.Moore@Sun.COM grub_fsd_mount_tmp(grub_fsdesc_t *fsd, const char *fstyp)
488*9160SSherry.Moore@Sun.COM {
489*9160SSherry.Moore@Sun.COM 	const char *pos;
490*9160SSherry.Moore@Sun.COM 	void *data = NULL;
491*9160SSherry.Moore@Sun.COM 	int dtsz = 0;
492*9160SSherry.Moore@Sun.COM 	struct ufs_args ufs_args = {UFSMNT_LARGEFILES};
493*9160SSherry.Moore@Sun.COM 	char mntopts[MNT_LINE_MAX] = "";
494*9160SSherry.Moore@Sun.COM 	int rc = 0;
495*9160SSherry.Moore@Sun.COM 
496*9160SSherry.Moore@Sun.COM 	assert(fsd);
497*9160SSherry.Moore@Sun.COM 	assert(!fsd->gfs_is_tmp_mounted);
498*9160SSherry.Moore@Sun.COM 
499*9160SSherry.Moore@Sun.COM 	fsd->gfs_mountp[0] = 0;
500*9160SSherry.Moore@Sun.COM 
501*9160SSherry.Moore@Sun.COM 	if (strcmp(fstyp, MNTTYPE_UFS) == 0) {
502*9160SSherry.Moore@Sun.COM 		(void) strlcpy(mntopts, MNTOPT_LARGEFILES, sizeof (mntopts));
503*9160SSherry.Moore@Sun.COM 		data = &ufs_args;
504*9160SSherry.Moore@Sun.COM 		dtsz = sizeof (ufs_args);
505*9160SSherry.Moore@Sun.COM 	} else if (strcmp(fstyp, MNTTYPE_ZFS) != 0) {
506*9160SSherry.Moore@Sun.COM 		return (EG_UNKNOWNFS);
507*9160SSherry.Moore@Sun.COM 	}
508*9160SSherry.Moore@Sun.COM 
509*9160SSherry.Moore@Sun.COM 	/* construct name for temporary mount point */
510*9160SSherry.Moore@Sun.COM 	pos = strrchr(fsd->gfs_dev, '/');
511*9160SSherry.Moore@Sun.COM 	pos = (pos == NULL) ? fsd->gfs_dev : pos + 1;
512*9160SSherry.Moore@Sun.COM 
513*9160SSherry.Moore@Sun.COM 	(void) snprintf(fsd->gfs_mountp, sizeof (fsd->gfs_mountp),
514*9160SSherry.Moore@Sun.COM 	    tmp_mountp, pos);
515*9160SSherry.Moore@Sun.COM 	if (mkdtemp(fsd->gfs_mountp) != NULL) {
516*9160SSherry.Moore@Sun.COM 		if ((rc = mount(fsd->gfs_dev, fsd->gfs_mountp,
517*9160SSherry.Moore@Sun.COM 		    MS_DATA | MS_OPTIONSTR | MS_RDONLY,
518*9160SSherry.Moore@Sun.COM 		    fstyp, data, dtsz, mntopts, sizeof (mntopts))) != 0) {
519*9160SSherry.Moore@Sun.COM 			/*
520*9160SSherry.Moore@Sun.COM 			 * mount failed, collect errno and remove temp dir
521*9160SSherry.Moore@Sun.COM 			 */
522*9160SSherry.Moore@Sun.COM 			rc = errno;
523*9160SSherry.Moore@Sun.COM 			(void) rmdir(fsd->gfs_mountp);
524*9160SSherry.Moore@Sun.COM 		}
525*9160SSherry.Moore@Sun.COM 	} else {
526*9160SSherry.Moore@Sun.COM 		rc = errno;
527*9160SSherry.Moore@Sun.COM 	}
528*9160SSherry.Moore@Sun.COM 
529*9160SSherry.Moore@Sun.COM 	if (rc != 0)
530*9160SSherry.Moore@Sun.COM 		fsd->gfs_mountp[0] = 0;
531*9160SSherry.Moore@Sun.COM 
532*9160SSherry.Moore@Sun.COM 	/*
533*9160SSherry.Moore@Sun.COM 	 * Note that valid values for gfs_is_tmp_mounted are 0,1.
534*9160SSherry.Moore@Sun.COM 	 * Any other value indicates that something bad happened.
535*9160SSherry.Moore@Sun.COM 	 * Probably grub_fsd_umount_tmp() wasn't called or didn't
536*9160SSherry.Moore@Sun.COM 	 * work as expected.
537*9160SSherry.Moore@Sun.COM 	 */
538*9160SSherry.Moore@Sun.COM 	fsd->gfs_is_tmp_mounted += (rc == 0);
539*9160SSherry.Moore@Sun.COM 	return (rc);
540*9160SSherry.Moore@Sun.COM }
541*9160SSherry.Moore@Sun.COM 
542*9160SSherry.Moore@Sun.COM /*
543*9160SSherry.Moore@Sun.COM  * Unmount file system at tmp_mountp.
544*9160SSherry.Moore@Sun.COM  */
545*9160SSherry.Moore@Sun.COM void
546*9160SSherry.Moore@Sun.COM grub_fsd_umount_tmp(grub_fsdesc_t *fsd)
547*9160SSherry.Moore@Sun.COM {
548*9160SSherry.Moore@Sun.COM 	if (fsd == NULL)
549*9160SSherry.Moore@Sun.COM 		return;
550*9160SSherry.Moore@Sun.COM 
551*9160SSherry.Moore@Sun.COM 	if (fsd->gfs_is_tmp_mounted) {
552*9160SSherry.Moore@Sun.COM 		if (fsd->gfs_mountp[0] != 0) {
553*9160SSherry.Moore@Sun.COM 			(void) umount2(fsd->gfs_mountp, 0);
554*9160SSherry.Moore@Sun.COM 			(void) rmdir(fsd->gfs_mountp);
555*9160SSherry.Moore@Sun.COM 			fsd->gfs_mountp[0] = 0;
556*9160SSherry.Moore@Sun.COM 		}
557*9160SSherry.Moore@Sun.COM 		fsd->gfs_is_tmp_mounted = 0;
558*9160SSherry.Moore@Sun.COM 	}
559*9160SSherry.Moore@Sun.COM }
560