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