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