xref: /openbsd-src/sys/arch/powerpc64/stand/rdboot/disk.c (revision 1a98aacbe5b16fbc9d44ae470c7928a7f5277549)
1*1a98aacbSkettenis /*	$OpenBSD: disk.c,v 1.4 2023/10/18 22:44:42 kettenis Exp $	*/
2a79842c9Skettenis 
3a79842c9Skettenis /*
4a79842c9Skettenis  * Copyright (c) 2019 Visa Hankala
5a79842c9Skettenis  *
6a79842c9Skettenis  * Permission to use, copy, modify, and/or distribute this software for any
7a79842c9Skettenis  * purpose with or without fee is hereby granted, provided that the above
8a79842c9Skettenis  * copyright notice and this permission notice appear in all copies.
9a79842c9Skettenis  *
10a79842c9Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11a79842c9Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12a79842c9Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13a79842c9Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14a79842c9Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15a79842c9Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16a79842c9Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a79842c9Skettenis  */
18a79842c9Skettenis 
19a79842c9Skettenis #include <sys/types.h>
20a79842c9Skettenis #include <sys/param.h>
21a79842c9Skettenis #include <sys/disklabel.h>
22a79842c9Skettenis #include <sys/dkio.h>
23a79842c9Skettenis #include <sys/ioctl.h>
24a79842c9Skettenis #include <sys/mount.h>
25a79842c9Skettenis #include <sys/stat.h>
26a79842c9Skettenis #include <sys/sysctl.h>
27a79842c9Skettenis 
28a79842c9Skettenis #include <err.h>
29a79842c9Skettenis #include <errno.h>
30a79842c9Skettenis #include <fcntl.h>
31a79842c9Skettenis #include <stdio.h>
32a79842c9Skettenis #include <stdlib.h>
33a79842c9Skettenis #include <string.h>
34a79842c9Skettenis #include <unistd.h>
35a79842c9Skettenis #include <util.h>
36a79842c9Skettenis 
37a79842c9Skettenis #include "cmd.h"
38a79842c9Skettenis 
39a79842c9Skettenis int	disk_proberoot(const char *);
40a79842c9Skettenis 
41a79842c9Skettenis int mounted = 0;
42a79842c9Skettenis int rdroot = -1;		/* fd that points to the root of the ramdisk */
43a79842c9Skettenis 
44f0d7b389Skettenis const u_char zeroduid[8];
45f0d7b389Skettenis 
46a79842c9Skettenis void
disk_init(void)47a79842c9Skettenis disk_init(void)
48a79842c9Skettenis {
49a79842c9Skettenis 	char rootdevs[1024];
50ad5cc052Skettenis 	char bootduid[17];
51a79842c9Skettenis 	char *devname, *disknames, *ptr;
52a79842c9Skettenis 	size_t size;
53a79842c9Skettenis 	int mib[2];
54a79842c9Skettenis 
55a79842c9Skettenis 	rdroot = open("/", O_RDONLY);
56a79842c9Skettenis 	if (rdroot == -1)
57a79842c9Skettenis 		err(1, "failed to open root directory fd");
58a79842c9Skettenis 
59a79842c9Skettenis 	if (strlen(cmd.bootdev) != 0)
60a79842c9Skettenis 		return;
61a79842c9Skettenis 
62a79842c9Skettenis 	mib[0] = CTL_HW;
63a79842c9Skettenis 	mib[1] = HW_DISKNAMES;
64a79842c9Skettenis 	size = 0;
65a79842c9Skettenis 	if (sysctl(mib, 2, NULL, &size, NULL, 0) == -1) {
66a79842c9Skettenis 		fprintf(stderr, "%s: cannot get hw.disknames: %s\n", __func__,
67a79842c9Skettenis 		    strerror(errno));
68a79842c9Skettenis 		return;
69a79842c9Skettenis 	}
70a79842c9Skettenis 	disknames = malloc(size);
71a79842c9Skettenis 	if (disknames == NULL) {
72a79842c9Skettenis 		fprintf(stderr, "%s: out of memory\n", __func__);
73a79842c9Skettenis 		return;
74a79842c9Skettenis 	}
75a79842c9Skettenis 	if (sysctl(mib, 2, disknames, &size, NULL, 0) == -1) {
76a79842c9Skettenis 		fprintf(stderr, "%s: cannot get hw.disknames: %s\n", __func__,
77a79842c9Skettenis 		    strerror(errno));
78a79842c9Skettenis 		free(disknames);
79a79842c9Skettenis 		return;
80a79842c9Skettenis 	}
81a79842c9Skettenis 
82ad5cc052Skettenis 	snprintf(bootduid, sizeof(bootduid),
83ad5cc052Skettenis 	    "%02x%02x%02x%02x%02x%02x%02x%02x", cmd.bootduid[0],
84ad5cc052Skettenis 	    cmd.bootduid[1], cmd.bootduid[2], cmd.bootduid[3], cmd.bootduid[4],
85ad5cc052Skettenis 	    cmd.bootduid[5], cmd.bootduid[6], cmd.bootduid[7]);
86ad5cc052Skettenis 
87a79842c9Skettenis 	printf("probing disks\n");
88a79842c9Skettenis 	rootdevs[0] = '\0';
89a79842c9Skettenis 	ptr = disknames;
90a79842c9Skettenis 	while ((devname = strsep(&ptr, ",")) != NULL) {
91a79842c9Skettenis 		char *duid;
92a79842c9Skettenis 
93a79842c9Skettenis 		duid = strchr(devname, ':');
94a79842c9Skettenis 		if (duid == NULL)
95a79842c9Skettenis 			continue;
96a79842c9Skettenis 		*duid++ = '\0';
97a79842c9Skettenis 
98a79842c9Skettenis 		/* Disk without a duid cannot be a root device. */
99a79842c9Skettenis 		if (strlen(duid) == 0)
100a79842c9Skettenis 			continue;
101a79842c9Skettenis 
102ad5cc052Skettenis 		/* If we have a bootduid match, nail it down! */
103ad5cc052Skettenis 		if (strcmp(duid, bootduid) == 0) {
104ad5cc052Skettenis 			snprintf(cmd.bootdev, sizeof(cmd.bootdev),
105ad5cc052Skettenis 			    "%sa", devname);
106ad5cc052Skettenis 		}
107ad5cc052Skettenis 
108ad5cc052Skettenis 		/* Otherwise pick the first potential root disk. */
109a79842c9Skettenis 		if (disk_proberoot(devname)) {
110f0d7b389Skettenis 			if (memcmp(cmd.bootduid, zeroduid, 8) == 0) {
111a79842c9Skettenis 				snprintf(cmd.bootdev, sizeof(cmd.bootdev),
112a79842c9Skettenis 				    "%sa", devname);
113a79842c9Skettenis 			}
114a79842c9Skettenis 			(void)strlcat(rootdevs, " ", sizeof(rootdevs));
115a79842c9Skettenis 			(void)strlcat(rootdevs, devname, sizeof(rootdevs));
116a79842c9Skettenis 		}
117a79842c9Skettenis 	}
118a79842c9Skettenis 	if (strlen(rootdevs) != 0)
119a79842c9Skettenis 		printf("available root devices:%s\n", rootdevs);
120a79842c9Skettenis 	else
121a79842c9Skettenis 		printf("no root devices found\n");
122a79842c9Skettenis }
123a79842c9Skettenis 
124a79842c9Skettenis int
disk_proberoot(const char * devname)125a79842c9Skettenis disk_proberoot(const char *devname)
126a79842c9Skettenis {
127a79842c9Skettenis 	static const char *const names[] = {
128a79842c9Skettenis 		"bin", "dev", "etc", "home", "mnt", "root", "sbin", "tmp",
129a79842c9Skettenis 		"usr", "var", NULL
130a79842c9Skettenis 	};
131a79842c9Skettenis 	struct ufs_args ffs_args;
132a79842c9Skettenis 	struct stat st;
133a79842c9Skettenis 	char path[32];
134a79842c9Skettenis 	int i, is_root = 1;
135a79842c9Skettenis 
136a79842c9Skettenis 	snprintf(path, sizeof(path), "/dev/%sa", devname);
137a79842c9Skettenis 	memset(&ffs_args, 0, sizeof(ffs_args));
138a79842c9Skettenis 	ffs_args.fspec = path;
139a79842c9Skettenis 	if (mount(MOUNT_FFS, "/mnt", MNT_RDONLY, &ffs_args) == -1)
140a79842c9Skettenis 		return 0;
141a79842c9Skettenis 	for (i = 0; names[i] != NULL; i++) {
142a79842c9Skettenis 		snprintf(path, sizeof(path), "/mnt/%s", names[i]);
143a79842c9Skettenis 		if (stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) {
144a79842c9Skettenis 			is_root = 0;
145a79842c9Skettenis 			break;
146a79842c9Skettenis 		}
147a79842c9Skettenis 	}
148a79842c9Skettenis 	(void)unmount("/mnt", 0);
149a79842c9Skettenis 
150a79842c9Skettenis 	return is_root;
151a79842c9Skettenis }
152a79842c9Skettenis 
153a79842c9Skettenis const char *
disk_open(const char * path)154a79842c9Skettenis disk_open(const char *path)
155a79842c9Skettenis {
156a79842c9Skettenis 	struct ufs_args ffs_args;
157a79842c9Skettenis 	struct disklabel label;
158a79842c9Skettenis 	char devname[32];
159a79842c9Skettenis 	char *devpath;
160a79842c9Skettenis 	const char *ptr;
161a79842c9Skettenis 	int fd;
162a79842c9Skettenis 
163a79842c9Skettenis 	if (mounted) {
164a79842c9Skettenis 		fprintf(stderr, "%s: cannot nest\n", __func__);
165a79842c9Skettenis 		return NULL;
166a79842c9Skettenis 	}
167a79842c9Skettenis 
168a79842c9Skettenis 	ptr = strchr(path, ':');
169a79842c9Skettenis 	if (ptr != NULL) {
170a79842c9Skettenis 		snprintf(devname, sizeof(devname), "%.*s",
171a79842c9Skettenis 		    (int)(ptr - path), path);
172a79842c9Skettenis 		ptr++;	/* skip ':' */
173a79842c9Skettenis 	} else {
174a79842c9Skettenis 		strlcpy(devname, cmd.bootdev, sizeof(devname));
175a79842c9Skettenis 		ptr = path;
176a79842c9Skettenis 	}
177a79842c9Skettenis 	if (strlen(devname) == 0) {
178a79842c9Skettenis 		fprintf(stderr, "no device specified\n");
179a79842c9Skettenis 		return NULL;
180a79842c9Skettenis 	}
181a79842c9Skettenis 
182a79842c9Skettenis 	cmd.hasduid = 0;
183a79842c9Skettenis 	fd = opendev(devname, O_RDONLY, OPENDEV_BLCK, &devpath);
184a79842c9Skettenis 	if (fd != -1) {
185a79842c9Skettenis 		if (ioctl(fd, DIOCGDINFO, &label) != -1) {
186a79842c9Skettenis 			memcpy(cmd.bootduid, label.d_uid, 8);
187a79842c9Skettenis 			cmd.hasduid = 1;
188a79842c9Skettenis 		}
189a79842c9Skettenis 		close(fd);
190a79842c9Skettenis 	} else {
191a79842c9Skettenis 		fprintf(stderr, "failed to open device %s: %s\n", devname,
192a79842c9Skettenis 		    strerror(errno));
193a79842c9Skettenis 		return NULL;
194a79842c9Skettenis 	}
195a79842c9Skettenis 
196a79842c9Skettenis 	memset(&ffs_args, 0, sizeof(ffs_args));
197a79842c9Skettenis 	ffs_args.fspec = devpath;
198*1a98aacbSkettenis 	if (mount(MOUNT_FFS, "/mnt", MNT_NOATIME, &ffs_args) == -1) {
199*1a98aacbSkettenis 		if (mount(MOUNT_FFS, "/mnt", MNT_RDONLY, &ffs_args) == -1) {
200a79842c9Skettenis 			fprintf(stderr, "failed to mount %s: %s\n", devpath,
201a79842c9Skettenis 			    strerror(errno));
202a79842c9Skettenis 			return NULL;
203a79842c9Skettenis 		}
204*1a98aacbSkettenis 		fprintf(stderr, "%s: mounted read-only\n", devpath);
205*1a98aacbSkettenis 	}
206a79842c9Skettenis 	if (chroot("/mnt") == -1) {
207a79842c9Skettenis 		fprintf(stderr, "failed to chroot: %s\n", strerror(errno));
208a79842c9Skettenis 		(void)unmount("/mnt", 0);
209a79842c9Skettenis 		return NULL;
210a79842c9Skettenis 	}
211a79842c9Skettenis 	mounted = 1;
212a79842c9Skettenis 
213a79842c9Skettenis 	return ptr;
214a79842c9Skettenis }
215a79842c9Skettenis 
216a79842c9Skettenis void
disk_close(void)217a79842c9Skettenis disk_close(void)
218a79842c9Skettenis {
219a79842c9Skettenis 	if (mounted) {
220a79842c9Skettenis 		(void)fchdir(rdroot);
221a79842c9Skettenis 		(void)chroot(".");
222a79842c9Skettenis 		mounted = 0;
223a79842c9Skettenis 		(void)unmount("/mnt", 0);
224a79842c9Skettenis 	}
225a79842c9Skettenis }
226