1*acd6e620Skn /* $OpenBSD: powerpc64_installboot.c,v 1.9 2023/04/26 18:04:21 kn Exp $ */
2c25120afSkettenis
3c25120afSkettenis /*
4c25120afSkettenis * Copyright (c) 2011 Joel Sing <jsing@openbsd.org>
5c25120afSkettenis * Copyright (c) 2010 Otto Moerbeek <otto@openbsd.org>
6c25120afSkettenis * Copyright (c) 2003 Tom Cosgrove <tom.cosgrove@arches-consulting.com>
7c25120afSkettenis * Copyright (c) 1997 Michael Shalayeff
8c25120afSkettenis * Copyright (c) 1994 Paul Kranenburg
9c25120afSkettenis * All rights reserved.
10c25120afSkettenis *
11c25120afSkettenis * Redistribution and use in source and binary forms, with or without
12c25120afSkettenis * modification, are permitted provided that the following conditions
13c25120afSkettenis * are met:
14c25120afSkettenis * 1. Redistributions of source code must retain the above copyright
15c25120afSkettenis * notice, this list of conditions and the following disclaimer.
16c25120afSkettenis * 2. Redistributions in binary form must reproduce the above copyright
17c25120afSkettenis * notice, this list of conditions and the following disclaimer in the
18c25120afSkettenis * documentation and/or other materials provided with the distribution.
19c25120afSkettenis * 3. All advertising materials mentioning features or use of this software
20c25120afSkettenis * must display the following acknowledgement:
21c25120afSkettenis * This product includes software developed by Paul Kranenburg.
22c25120afSkettenis * 4. The name of the author may not be used to endorse or promote products
23c25120afSkettenis * derived from this software without specific prior written permission
24c25120afSkettenis *
25c25120afSkettenis * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26c25120afSkettenis * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27c25120afSkettenis * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28c25120afSkettenis * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29c25120afSkettenis * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30c25120afSkettenis * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31c25120afSkettenis * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32c25120afSkettenis * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33c25120afSkettenis * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34c25120afSkettenis * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35c25120afSkettenis */
36c25120afSkettenis
37c25120afSkettenis #include <sys/param.h> /* DEV_BSIZE */
38c25120afSkettenis #include <sys/disklabel.h>
39c25120afSkettenis #include <sys/dkio.h>
40c25120afSkettenis #include <sys/ioctl.h>
41c25120afSkettenis #include <sys/mount.h>
42c25120afSkettenis #include <sys/stat.h>
43c25120afSkettenis
44c25120afSkettenis #include <err.h>
45c25120afSkettenis #include <errno.h>
46c25120afSkettenis #include <fcntl.h>
47c25120afSkettenis #include <stdlib.h>
48c25120afSkettenis #include <stdio.h>
49c25120afSkettenis #include <string.h>
50c25120afSkettenis #include <unistd.h>
51c25120afSkettenis #include <util.h>
52c25120afSkettenis #include <endian.h>
53c25120afSkettenis
54c25120afSkettenis #include "installboot.h"
55c25120afSkettenis
56c3e1bf61Skettenis static int create_filesystem(struct disklabel *, char);
57c25120afSkettenis static void write_filesystem(struct disklabel *, char);
58c25120afSkettenis static int findmbrfat(int, struct disklabel *);
59c25120afSkettenis
6045126b27Sderaadt char duid[20];
6145126b27Sderaadt
62c25120afSkettenis void
md_init(void)63c25120afSkettenis md_init(void)
64c25120afSkettenis {
65ed13161dSkn stages = 1;
66ed13161dSkn stage1 = "/usr/mdec/boot";
67c25120afSkettenis }
68c25120afSkettenis
69c25120afSkettenis void
md_loadboot(void)70c25120afSkettenis md_loadboot(void)
71c25120afSkettenis {
72c25120afSkettenis }
73c25120afSkettenis
74c25120afSkettenis void
md_prepareboot(int devfd,char * dev)75c3e1bf61Skettenis md_prepareboot(int devfd, char *dev)
76c3e1bf61Skettenis {
77c3e1bf61Skettenis struct disklabel dl;
78c3e1bf61Skettenis int part;
79c3e1bf61Skettenis
80c3e1bf61Skettenis /* Get and check disklabel. */
81c3e1bf61Skettenis if (ioctl(devfd, DIOCGDINFO, &dl) == -1)
82c3e1bf61Skettenis err(1, "disklabel: %s", dev);
83c3e1bf61Skettenis if (dl.d_magic != DISKMAGIC)
84c3e1bf61Skettenis errx(1, "bad disklabel magic=0x%08x", dl.d_magic);
85c3e1bf61Skettenis
86c3e1bf61Skettenis /* Warn on unknown disklabel types. */
87c3e1bf61Skettenis if (dl.d_type == 0)
88c3e1bf61Skettenis warnx("disklabel type unknown");
89c3e1bf61Skettenis
90c3e1bf61Skettenis part = findmbrfat(devfd, &dl);
91c3e1bf61Skettenis if (part != -1) {
9214cbb8d0Skn create_filesystem(&dl, (char)part);
9314cbb8d0Skn return;
94c3e1bf61Skettenis }
95c3e1bf61Skettenis }
96c3e1bf61Skettenis
97c3e1bf61Skettenis void
md_installboot(int devfd,char * dev)98c25120afSkettenis md_installboot(int devfd, char *dev)
99c25120afSkettenis {
100c25120afSkettenis struct disklabel dl;
101c25120afSkettenis int part;
102c25120afSkettenis
103c25120afSkettenis /* Get and check disklabel. */
104c25120afSkettenis if (ioctl(devfd, DIOCGDINFO, &dl) == -1)
105c25120afSkettenis err(1, "disklabel: %s", dev);
106c25120afSkettenis if (dl.d_magic != DISKMAGIC)
107c25120afSkettenis errx(1, "bad disklabel magic=0x%08x", dl.d_magic);
108c25120afSkettenis
10945126b27Sderaadt snprintf(duid, sizeof duid,
11045126b27Sderaadt "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
11145126b27Sderaadt dl.d_uid[0], dl.d_uid[1], dl.d_uid[2], dl.d_uid[3],
11245126b27Sderaadt dl.d_uid[4], dl.d_uid[5], dl.d_uid[6], dl.d_uid[7]);
11345126b27Sderaadt
114c25120afSkettenis /* Warn on unknown disklabel types. */
115c25120afSkettenis if (dl.d_type == 0)
116c25120afSkettenis warnx("disklabel type unknown");
117c25120afSkettenis
118c25120afSkettenis part = findmbrfat(devfd, &dl);
119c25120afSkettenis if (part != -1) {
120c25120afSkettenis write_filesystem(&dl, (char)part);
121c25120afSkettenis return;
122c25120afSkettenis }
123c25120afSkettenis }
124c25120afSkettenis
125c3e1bf61Skettenis static int
create_filesystem(struct disklabel * dl,char part)126c3e1bf61Skettenis create_filesystem(struct disklabel *dl, char part)
127c3e1bf61Skettenis {
1287a17f38cSkrw static const char *newfsfmt = "/sbin/newfs -t msdos %s >/dev/null";
129c3e1bf61Skettenis struct msdosfs_args args;
130c3e1bf61Skettenis char cmd[60];
131c3e1bf61Skettenis int rslt;
132c3e1bf61Skettenis
133*acd6e620Skn /* Newfs <duid>.<part> as msdos filesystem. */
134c3e1bf61Skettenis memset(&args, 0, sizeof(args));
135c3e1bf61Skettenis rslt = asprintf(&args.fspec,
136c3e1bf61Skettenis "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c",
137c3e1bf61Skettenis dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3],
138c3e1bf61Skettenis dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7],
139c3e1bf61Skettenis part);
140c3e1bf61Skettenis if (rslt == -1) {
141c3e1bf61Skettenis warn("bad special device");
142c3e1bf61Skettenis return rslt;
143c3e1bf61Skettenis }
144c3e1bf61Skettenis
145c3e1bf61Skettenis rslt = snprintf(cmd, sizeof(cmd), newfsfmt, args.fspec);
146c3e1bf61Skettenis if (rslt >= sizeof(cmd)) {
147c3e1bf61Skettenis warnx("can't build newfs command");
148993e4236Skrw free(args.fspec);
149c3e1bf61Skettenis rslt = -1;
150c3e1bf61Skettenis return rslt;
151c3e1bf61Skettenis }
152c3e1bf61Skettenis
153c3e1bf61Skettenis if (verbose)
154c3e1bf61Skettenis fprintf(stderr, "%s %s\n",
155c3e1bf61Skettenis (nowrite ? "would newfs" : "newfsing"), args.fspec);
156c3e1bf61Skettenis if (!nowrite) {
157c3e1bf61Skettenis rslt = system(cmd);
158c3e1bf61Skettenis if (rslt == -1) {
159c3e1bf61Skettenis warn("system('%s') failed", cmd);
160993e4236Skrw free(args.fspec);
161c3e1bf61Skettenis return rslt;
162c3e1bf61Skettenis }
163c3e1bf61Skettenis }
164c3e1bf61Skettenis
165993e4236Skrw free(args.fspec);
166c3e1bf61Skettenis return 0;
167c3e1bf61Skettenis }
168c25120afSkettenis
169c25120afSkettenis static void
write_filesystem(struct disklabel * dl,char part)170c25120afSkettenis write_filesystem(struct disklabel *dl, char part)
171c25120afSkettenis {
1727a17f38cSkrw static const char *fsckfmt = "/sbin/fsck -t msdos %s >/dev/null";
17345126b27Sderaadt struct msdosfs_args args;
174c25120afSkettenis char cmd[60];
17545126b27Sderaadt char dir[PATH_MAX];
176c25120afSkettenis char dst[PATH_MAX];
177ed13161dSkn size_t mntlen;
178c25120afSkettenis int rslt;
179c25120afSkettenis
180c25120afSkettenis /* Create directory for temporary mount point. */
18145126b27Sderaadt strlcpy(dir, "/tmp/installboot.XXXXXXXXXX", sizeof(dst));
18245126b27Sderaadt if (mkdtemp(dir) == NULL)
183c25120afSkettenis err(1, "mkdtemp('%s') failed", dst);
18445126b27Sderaadt mntlen = strlen(dir);
185c25120afSkettenis
186c25120afSkettenis /* Mount <duid>.<part> as msdos filesystem. */
187c25120afSkettenis memset(&args, 0, sizeof(args));
188c25120afSkettenis rslt = asprintf(&args.fspec,
189c25120afSkettenis "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c",
190c25120afSkettenis dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3],
191c25120afSkettenis dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7],
192c25120afSkettenis part);
193c25120afSkettenis if (rslt == -1) {
194c25120afSkettenis warn("bad special device");
195c25120afSkettenis goto rmdir;
196c25120afSkettenis }
197c25120afSkettenis
198c25120afSkettenis args.export_info.ex_root = -2;
199c25120afSkettenis args.export_info.ex_flags = 0;
20045126b27Sderaadt args.flags = MSDOSFSMNT_LONGNAME;
201c25120afSkettenis
20245126b27Sderaadt if (mount(MOUNT_MSDOS, dir, 0, &args) == -1) {
203c25120afSkettenis /* Try fsck'ing it. */
204c25120afSkettenis rslt = snprintf(cmd, sizeof(cmd), fsckfmt, args.fspec);
205c25120afSkettenis if (rslt >= sizeof(cmd)) {
206c25120afSkettenis warnx("can't build fsck command");
207c25120afSkettenis rslt = -1;
208c25120afSkettenis goto rmdir;
209c25120afSkettenis }
210c25120afSkettenis rslt = system(cmd);
211c25120afSkettenis if (rslt == -1) {
212c25120afSkettenis warn("system('%s') failed", cmd);
213c25120afSkettenis goto rmdir;
214c25120afSkettenis }
21545126b27Sderaadt if (mount(MOUNT_MSDOS, dir, 0, &args) == -1) {
216c25120afSkettenis /* Try newfs'ing it. */
217c3e1bf61Skettenis rslt = create_filesystem(dl, part);
218c3e1bf61Skettenis if (rslt == -1)
219c25120afSkettenis goto rmdir;
22045126b27Sderaadt rslt = mount(MOUNT_MSDOS, dir, 0, &args);
221c25120afSkettenis if (rslt == -1) {
222c25120afSkettenis warn("unable to mount MSDOS partition");
223c25120afSkettenis goto rmdir;
224c25120afSkettenis }
225c25120afSkettenis }
226c25120afSkettenis }
227c25120afSkettenis
228c25120afSkettenis /*
229c25120afSkettenis * Copy /usr/mdec/boot to /mnt/boot.
230c25120afSkettenis */
23145126b27Sderaadt strlcpy(dst, dir, sizeof dst);
232c25120afSkettenis if (strlcat(dst, "/boot", sizeof(dst)) >= sizeof(dst)) {
233c25120afSkettenis rslt = -1;
234c25120afSkettenis warn("unable to build /boot path");
235c25120afSkettenis goto umount;
236c25120afSkettenis }
237c25120afSkettenis if (verbose)
238c25120afSkettenis fprintf(stderr, "%s %s to %s\n",
239ed13161dSkn (nowrite ? "would copy" : "copying"), stage1, dst);
240c25120afSkettenis if (!nowrite) {
241ed13161dSkn rslt = filecopy(stage1, dst);
242c25120afSkettenis if (rslt == -1)
243c25120afSkettenis goto umount;
244c25120afSkettenis }
245c25120afSkettenis
24645126b27Sderaadt /*
24745126b27Sderaadt * Create grub.cfg
24845126b27Sderaadt */
24945126b27Sderaadt strlcpy(dst, dir, sizeof dst);
25045126b27Sderaadt if (strlcat(dst, "/grub.cfg", sizeof(dst)) >= sizeof(dst)) {
25145126b27Sderaadt rslt = -1;
25245126b27Sderaadt warn("unable to build /grub.cfg path");
25345126b27Sderaadt goto umount;
25445126b27Sderaadt }
25545126b27Sderaadt if (verbose)
25645126b27Sderaadt fprintf(stderr, "%s %s\n",
25745126b27Sderaadt (nowrite ? "would create" : "creating"), dst);
25845126b27Sderaadt if (!nowrite) {
25945126b27Sderaadt FILE *f;
26045126b27Sderaadt
26145126b27Sderaadt f = fopen(dst, "w+");
26245126b27Sderaadt if (f == NULL)
26345126b27Sderaadt goto umount;
26445126b27Sderaadt fprintf(f,
26545126b27Sderaadt "menuentry \"OpenBSD\" {\n"
26645126b27Sderaadt "\tlinux /boot bootduid=%s\n"
26745126b27Sderaadt "\tinitrd /boot\n"
26845126b27Sderaadt "}\n", duid);
26945126b27Sderaadt fclose(f);
27045126b27Sderaadt }
27145126b27Sderaadt
272c25120afSkettenis rslt = 0;
273c25120afSkettenis
274c25120afSkettenis umount:
27545126b27Sderaadt dir[mntlen] = '\0';
27645126b27Sderaadt if (unmount(dir, MNT_FORCE) == -1)
27745126b27Sderaadt err(1, "unmount('%s') failed", dir);
278c25120afSkettenis
279c25120afSkettenis rmdir:
280c25120afSkettenis free(args.fspec);
281c25120afSkettenis dst[mntlen] = '\0';
28245126b27Sderaadt if (rmdir(dir) == -1)
28345126b27Sderaadt err(1, "rmdir('%s') failed", dir);
284c25120afSkettenis
285c25120afSkettenis if (rslt == -1)
286c25120afSkettenis exit(1);
287c25120afSkettenis }
288c25120afSkettenis
289c25120afSkettenis int
findmbrfat(int devfd,struct disklabel * dl)290c25120afSkettenis findmbrfat(int devfd, struct disklabel *dl)
291c25120afSkettenis {
292c25120afSkettenis struct dos_partition dp[NDOSPART];
293c25120afSkettenis ssize_t len;
294c25120afSkettenis u_int64_t start = 0;
295c25120afSkettenis int i;
296c25120afSkettenis u_int8_t *secbuf;
297c25120afSkettenis
298c25120afSkettenis if ((secbuf = malloc(dl->d_secsize)) == NULL)
299c25120afSkettenis err(1, NULL);
300c25120afSkettenis
301c25120afSkettenis /* Read MBR. */
302c25120afSkettenis len = pread(devfd, secbuf, dl->d_secsize, 0);
303c25120afSkettenis if (len != dl->d_secsize)
304c25120afSkettenis err(4, "can't read mbr");
305c25120afSkettenis memcpy(dp, &secbuf[DOSPARTOFF], sizeof(dp));
306c25120afSkettenis
307c25120afSkettenis for (i = 0; i < NDOSPART; i++) {
308c25120afSkettenis if (dp[i].dp_typ == DOSPTYP_UNUSED)
309c25120afSkettenis continue;
310c25120afSkettenis if (dp[i].dp_typ == DOSPTYP_FAT16L ||
311c25120afSkettenis dp[i].dp_typ == DOSPTYP_FAT32L ||
312c25120afSkettenis dp[i].dp_typ == DOSPTYP_FAT16B)
313c25120afSkettenis start = letoh32(dp[i].dp_start);
314c25120afSkettenis }
315c25120afSkettenis
316c25120afSkettenis free(secbuf);
317c25120afSkettenis
318c25120afSkettenis if (start) {
319c25120afSkettenis for (i = 0; i < MAXPARTITIONS; i++) {
320c25120afSkettenis if (DL_GETPSIZE(&dl->d_partitions[i]) > 0 &&
321c25120afSkettenis DL_GETPOFFSET(&dl->d_partitions[i]) == start)
322c25120afSkettenis return ('a' + i);
323c25120afSkettenis }
324c25120afSkettenis }
325c25120afSkettenis
326c25120afSkettenis return (-1);
327c25120afSkettenis }
328