xref: /openbsd-src/sys/arch/octeon/stand/rdboot/disk.c (revision 8a9ff49d785dfa0d133f66af715b210bca964cdb)
1*8a9ff49dSkettenis /*	$OpenBSD: disk.c,v 1.3 2023/10/20 18:53:12 kettenis Exp $	*/
23a62b615Svisa 
33a62b615Svisa /*
43a62b615Svisa  * Copyright (c) 2019 Visa Hankala
53a62b615Svisa  *
63a62b615Svisa  * Permission to use, copy, modify, and/or distribute this software for any
73a62b615Svisa  * purpose with or without fee is hereby granted, provided that the above
83a62b615Svisa  * copyright notice and this permission notice appear in all copies.
93a62b615Svisa  *
103a62b615Svisa  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
113a62b615Svisa  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
123a62b615Svisa  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
133a62b615Svisa  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
143a62b615Svisa  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
153a62b615Svisa  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
163a62b615Svisa  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
173a62b615Svisa  */
183a62b615Svisa 
193a62b615Svisa #include <sys/types.h>
203a62b615Svisa #include <sys/param.h>
213a62b615Svisa #include <sys/disklabel.h>
223a62b615Svisa #include <sys/dkio.h>
233a62b615Svisa #include <sys/ioctl.h>
243a62b615Svisa #include <sys/mount.h>
253a62b615Svisa #include <sys/stat.h>
263a62b615Svisa #include <sys/sysctl.h>
273a62b615Svisa 
283a62b615Svisa #include <err.h>
293a62b615Svisa #include <errno.h>
303a62b615Svisa #include <fcntl.h>
313a62b615Svisa #include <stdio.h>
323a62b615Svisa #include <stdlib.h>
333a62b615Svisa #include <string.h>
343a62b615Svisa #include <unistd.h>
353a62b615Svisa #include <util.h>
363a62b615Svisa 
373a62b615Svisa #include "cmd.h"
383a62b615Svisa 
393a62b615Svisa int	disk_proberoot(const char *);
403a62b615Svisa 
413a62b615Svisa int mounted = 0;
423a62b615Svisa int rdroot = -1;		/* fd that points to the root of the ramdisk */
433a62b615Svisa 
443a62b615Svisa void
disk_init(void)453a62b615Svisa disk_init(void)
463a62b615Svisa {
473a62b615Svisa 	char rootdevs[1024];
483a62b615Svisa 	char *devname, *disknames, *ptr;
493a62b615Svisa 	size_t size;
503a62b615Svisa 	int mib[2];
513a62b615Svisa 
523a62b615Svisa 	rdroot = open("/", O_RDONLY);
533a62b615Svisa 	if (rdroot == -1)
543a62b615Svisa 		err(1, "failed to open root directory fd");
553a62b615Svisa 
563a62b615Svisa 	if (strlen(cmd.bootdev) != 0)
573a62b615Svisa 		return;
583a62b615Svisa 
593a62b615Svisa 	mib[0] = CTL_HW;
603a62b615Svisa 	mib[1] = HW_DISKNAMES;
613a62b615Svisa 	size = 0;
623a62b615Svisa 	if (sysctl(mib, 2, NULL, &size, NULL, 0) == -1) {
633a62b615Svisa 		fprintf(stderr, "%s: cannot get hw.disknames: %s\n", __func__,
643a62b615Svisa 		    strerror(errno));
653a62b615Svisa 		return;
663a62b615Svisa 	}
673a62b615Svisa 	disknames = malloc(size);
683a62b615Svisa 	if (disknames == NULL) {
693a62b615Svisa 		fprintf(stderr, "%s: out of memory\n", __func__);
703a62b615Svisa 		return;
713a62b615Svisa 	}
723a62b615Svisa 	if (sysctl(mib, 2, disknames, &size, NULL, 0) == -1) {
733a62b615Svisa 		fprintf(stderr, "%s: cannot get hw.disknames: %s\n", __func__,
743a62b615Svisa 		    strerror(errno));
753a62b615Svisa 		free(disknames);
763a62b615Svisa 		return;
773a62b615Svisa 	}
783a62b615Svisa 
793a62b615Svisa 	printf("probing disks\n");
803a62b615Svisa 	rootdevs[0] = '\0';
813a62b615Svisa 	ptr = disknames;
823a62b615Svisa 	while ((devname = strsep(&ptr, ",")) != NULL) {
833a62b615Svisa 		char *duid;
843a62b615Svisa 
853a62b615Svisa 		duid = strchr(devname, ':');
863a62b615Svisa 		if (duid == NULL)
873a62b615Svisa 			continue;
883a62b615Svisa 		*duid++ = '\0';
893a62b615Svisa 
903a62b615Svisa 		/* Disk without a duid cannot be a root device. */
913a62b615Svisa 		if (strlen(duid) == 0)
923a62b615Svisa 			continue;
933a62b615Svisa 
943a62b615Svisa 		if (disk_proberoot(devname)) {
953a62b615Svisa 			if (strlen(cmd.bootdev) == 0) {
963a62b615Svisa 				snprintf(cmd.bootdev, sizeof(cmd.bootdev),
973a62b615Svisa 				    "%sa", devname);
983a62b615Svisa 			}
993a62b615Svisa 			(void)strlcat(rootdevs, " ", sizeof(rootdevs));
1003a62b615Svisa 			(void)strlcat(rootdevs, devname, sizeof(rootdevs));
1013a62b615Svisa 		}
1023a62b615Svisa 	}
1033a62b615Svisa 	if (strlen(rootdevs) != 0)
1043a62b615Svisa 		printf("available root devices:%s\n", rootdevs);
1053a62b615Svisa 	else
1063a62b615Svisa 		printf("no root devices found\n");
1073a62b615Svisa }
1083a62b615Svisa 
1093a62b615Svisa int
disk_proberoot(const char * devname)1103a62b615Svisa disk_proberoot(const char *devname)
1113a62b615Svisa {
1123a62b615Svisa 	static const char *const names[] = {
1133a62b615Svisa 		"bin", "dev", "etc", "home", "mnt", "root", "sbin", "tmp",
1143a62b615Svisa 		"usr", "var", NULL
1153a62b615Svisa 	};
1163a62b615Svisa 	struct ufs_args ffs_args;
1173a62b615Svisa 	struct stat st;
1183a62b615Svisa 	char path[32];
1193a62b615Svisa 	int i, is_root = 1;
1203a62b615Svisa 
1213a62b615Svisa 	snprintf(path, sizeof(path), "/dev/%sa", devname);
1223a62b615Svisa 	memset(&ffs_args, 0, sizeof(ffs_args));
1233a62b615Svisa 	ffs_args.fspec = path;
1243a62b615Svisa 	if (mount(MOUNT_FFS, "/mnt", MNT_RDONLY, &ffs_args) == -1)
1253a62b615Svisa 		return 0;
1263a62b615Svisa 	for (i = 0; names[i] != NULL; i++) {
1273a62b615Svisa 		snprintf(path, sizeof(path), "/mnt/%s", names[i]);
1283a62b615Svisa 		if (stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) {
1293a62b615Svisa 			is_root = 0;
1303a62b615Svisa 			break;
1313a62b615Svisa 		}
1323a62b615Svisa 	}
1333a62b615Svisa 	(void)unmount("/mnt", 0);
1343a62b615Svisa 
1353a62b615Svisa 	return is_root;
1363a62b615Svisa }
1373a62b615Svisa 
1383a62b615Svisa const char *
disk_open(const char * path)1393a62b615Svisa disk_open(const char *path)
1403a62b615Svisa {
1413a62b615Svisa 	struct ufs_args ffs_args;
1423a62b615Svisa 	struct disklabel label;
1433a62b615Svisa 	char devname[32];
1443a62b615Svisa 	char *devpath;
1453a62b615Svisa 	const char *ptr;
1463a62b615Svisa 	int fd;
1473a62b615Svisa 
1483a62b615Svisa 	if (mounted) {
1493a62b615Svisa 		fprintf(stderr, "%s: cannot nest\n", __func__);
1503a62b615Svisa 		return NULL;
1513a62b615Svisa 	}
1523a62b615Svisa 
1533a62b615Svisa 	ptr = strchr(path, ':');
1543a62b615Svisa 	if (ptr != NULL) {
1553a62b615Svisa 		snprintf(devname, sizeof(devname), "%.*s",
1563a62b615Svisa 		    (int)(ptr - path), path);
1573a62b615Svisa 		ptr++;	/* skip ':' */
1583a62b615Svisa 	} else {
1593a62b615Svisa 		strlcpy(devname, cmd.bootdev, sizeof(devname));
1603a62b615Svisa 		ptr = path;
1613a62b615Svisa 	}
1623a62b615Svisa 	if (strlen(devname) == 0) {
1633a62b615Svisa 		fprintf(stderr, "no device specified\n");
1643a62b615Svisa 		return NULL;
1653a62b615Svisa 	}
1663a62b615Svisa 
1673a62b615Svisa 	cmd.hasduid = 0;
1683a62b615Svisa 	fd = opendev(devname, O_RDONLY, OPENDEV_BLCK, &devpath);
1693a62b615Svisa 	if (fd != -1) {
1703a62b615Svisa 		if (ioctl(fd, DIOCGDINFO, &label) != -1) {
1713a62b615Svisa 			memcpy(cmd.bootduid, label.d_uid, 8);
1723a62b615Svisa 			cmd.hasduid = 1;
1733a62b615Svisa 		}
1743a62b615Svisa 		close(fd);
1753a62b615Svisa 	} else {
1763a62b615Svisa 		fprintf(stderr, "failed to open device %s: %s\n", devname,
1773a62b615Svisa 		    strerror(errno));
1783a62b615Svisa 		return NULL;
1793a62b615Svisa 	}
1803a62b615Svisa 
1813a62b615Svisa 	memset(&ffs_args, 0, sizeof(ffs_args));
1823a62b615Svisa 	ffs_args.fspec = devpath;
183*8a9ff49dSkettenis 	if (mount(MOUNT_FFS, "/mnt", MNT_NOATIME, &ffs_args) == -1) {
184*8a9ff49dSkettenis 		if (mount(MOUNT_FFS, "/mnt", MNT_RDONLY, &ffs_args) == -1) {
1853a62b615Svisa 			fprintf(stderr, "failed to mount %s: %s\n", devpath,
1863a62b615Svisa 			    strerror(errno));
1873a62b615Svisa 			return NULL;
1883a62b615Svisa 		}
189*8a9ff49dSkettenis 		fprintf(stderr, "%s: mounted read-only\n", devpath);
190*8a9ff49dSkettenis 	}
1913a62b615Svisa 	if (chroot("/mnt") == -1) {
1923a62b615Svisa 		fprintf(stderr, "failed to chroot: %s\n", strerror(errno));
1933a62b615Svisa 		(void)unmount("/mnt", 0);
1943a62b615Svisa 		return NULL;
1953a62b615Svisa 	}
1963a62b615Svisa 	mounted = 1;
1973a62b615Svisa 
1983a62b615Svisa 	return ptr;
1993a62b615Svisa }
2003a62b615Svisa 
2013a62b615Svisa void
disk_close(void)2023a62b615Svisa disk_close(void)
2033a62b615Svisa {
2043a62b615Svisa 	if (mounted) {
2053a62b615Svisa 		(void)fchdir(rdroot);
2063a62b615Svisa 		(void)chroot(".");
2073a62b615Svisa 		mounted = 0;
2083a62b615Svisa 		(void)unmount("/mnt", 0);
2093a62b615Svisa 	}
2103a62b615Svisa }
211