1*acd6e620Skn /* $OpenBSD: octeon_installboot.c,v 1.11 2023/04/26 18:04:21 kn Exp $ */
2a284d5afSderaadt
3a284d5afSderaadt /*
4a284d5afSderaadt * Copyright (c) 2011 Joel Sing <jsing@openbsd.org>
5a284d5afSderaadt * Copyright (c) 2010 Otto Moerbeek <otto@openbsd.org>
6a284d5afSderaadt * Copyright (c) 2003 Tom Cosgrove <tom.cosgrove@arches-consulting.com>
7a284d5afSderaadt * Copyright (c) 1997 Michael Shalayeff
8a284d5afSderaadt * Copyright (c) 1994 Paul Kranenburg
9a284d5afSderaadt * All rights reserved.
10a284d5afSderaadt *
11a284d5afSderaadt * Redistribution and use in source and binary forms, with or without
12a284d5afSderaadt * modification, are permitted provided that the following conditions
13a284d5afSderaadt * are met:
14a284d5afSderaadt * 1. Redistributions of source code must retain the above copyright
15a284d5afSderaadt * notice, this list of conditions and the following disclaimer.
16a284d5afSderaadt * 2. Redistributions in binary form must reproduce the above copyright
17a284d5afSderaadt * notice, this list of conditions and the following disclaimer in the
18a284d5afSderaadt * documentation and/or other materials provided with the distribution.
19a284d5afSderaadt * 3. All advertising materials mentioning features or use of this software
20a284d5afSderaadt * must display the following acknowledgement:
21a284d5afSderaadt * This product includes software developed by Paul Kranenburg.
22a284d5afSderaadt * 4. The name of the author may not be used to endorse or promote products
23a284d5afSderaadt * derived from this software without specific prior written permission
24a284d5afSderaadt *
25a284d5afSderaadt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26a284d5afSderaadt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27a284d5afSderaadt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28a284d5afSderaadt * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29a284d5afSderaadt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30a284d5afSderaadt * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31a284d5afSderaadt * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32a284d5afSderaadt * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33a284d5afSderaadt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34a284d5afSderaadt * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35a284d5afSderaadt */
36a284d5afSderaadt
37a284d5afSderaadt #include <sys/param.h> /* DEV_BSIZE */
38a284d5afSderaadt #include <sys/disklabel.h>
39a284d5afSderaadt #include <sys/dkio.h>
40a284d5afSderaadt #include <sys/ioctl.h>
41a284d5afSderaadt #include <sys/mount.h>
42a284d5afSderaadt #include <sys/stat.h>
43a284d5afSderaadt
44a284d5afSderaadt #include <err.h>
45a284d5afSderaadt #include <errno.h>
46a284d5afSderaadt #include <fcntl.h>
47a284d5afSderaadt #include <stdlib.h>
48a284d5afSderaadt #include <stdio.h>
49a284d5afSderaadt #include <string.h>
50a284d5afSderaadt #include <unistd.h>
51a284d5afSderaadt #include <util.h>
52a284d5afSderaadt #include <endian.h>
53a284d5afSderaadt
54a284d5afSderaadt #include "installboot.h"
55a284d5afSderaadt
56c3e1bf61Skettenis static int create_filesystem(struct disklabel *, char);
57a284d5afSderaadt static void write_filesystem(struct disklabel *, char);
58a284d5afSderaadt static int findmbrfat(int, struct disklabel *);
59a284d5afSderaadt
60a284d5afSderaadt void
md_init(void)61a284d5afSderaadt md_init(void)
62a284d5afSderaadt {
63b8f3f2d0Skn stages = 1;
64b8f3f2d0Skn stage1 = "/usr/mdec/boot";
65a284d5afSderaadt }
66a284d5afSderaadt
67a284d5afSderaadt void
md_loadboot(void)68a284d5afSderaadt md_loadboot(void)
69a284d5afSderaadt {
70a284d5afSderaadt }
71a284d5afSderaadt
72a284d5afSderaadt void
md_prepareboot(int devfd,char * dev)73c3e1bf61Skettenis md_prepareboot(int devfd, char *dev)
74c3e1bf61Skettenis {
75c3e1bf61Skettenis struct disklabel dl;
76c3e1bf61Skettenis int part;
77c3e1bf61Skettenis
78c3e1bf61Skettenis /* Get and check disklabel. */
79c3e1bf61Skettenis if (ioctl(devfd, DIOCGDINFO, &dl) == -1)
80c3e1bf61Skettenis err(1, "disklabel: %s", dev);
81c3e1bf61Skettenis if (dl.d_magic != DISKMAGIC)
82c3e1bf61Skettenis errx(1, "bad disklabel magic=0x%08x", dl.d_magic);
83c3e1bf61Skettenis
84c3e1bf61Skettenis /* Warn on unknown disklabel types. */
85c3e1bf61Skettenis if (dl.d_type == 0)
86c3e1bf61Skettenis warnx("disklabel type unknown");
87c3e1bf61Skettenis
88c3e1bf61Skettenis part = findmbrfat(devfd, &dl);
89c3e1bf61Skettenis if (part != -1) {
9014cbb8d0Skn create_filesystem(&dl, (char)part);
9114cbb8d0Skn return;
92c3e1bf61Skettenis }
93c3e1bf61Skettenis }
94c3e1bf61Skettenis
95c3e1bf61Skettenis void
md_installboot(int devfd,char * dev)96a284d5afSderaadt md_installboot(int devfd, char *dev)
97a284d5afSderaadt {
98a284d5afSderaadt struct disklabel dl;
99a284d5afSderaadt int part;
100a284d5afSderaadt
101a284d5afSderaadt /* Get and check disklabel. */
102a284d5afSderaadt if (ioctl(devfd, DIOCGDINFO, &dl) == -1)
103a284d5afSderaadt err(1, "disklabel: %s", dev);
104a284d5afSderaadt if (dl.d_magic != DISKMAGIC)
105a284d5afSderaadt errx(1, "bad disklabel magic=0x%08x", dl.d_magic);
106a284d5afSderaadt
107a284d5afSderaadt /* Warn on unknown disklabel types. */
108a284d5afSderaadt if (dl.d_type == 0)
109a284d5afSderaadt warnx("disklabel type unknown");
110a284d5afSderaadt
111a284d5afSderaadt part = findmbrfat(devfd, &dl);
112a284d5afSderaadt if (part != -1) {
113a284d5afSderaadt write_filesystem(&dl, (char)part);
114a284d5afSderaadt return;
115a284d5afSderaadt }
116a284d5afSderaadt }
117a284d5afSderaadt
118c3e1bf61Skettenis static int
create_filesystem(struct disklabel * dl,char part)119c3e1bf61Skettenis create_filesystem(struct disklabel *dl, char part)
120c3e1bf61Skettenis {
1217a17f38cSkrw static const char *newfsfmt = "/sbin/newfs -t msdos %s >/dev/null";
122c3e1bf61Skettenis struct msdosfs_args args;
123c3e1bf61Skettenis char cmd[60];
124c3e1bf61Skettenis int rslt;
125c3e1bf61Skettenis
126*acd6e620Skn /* Newfs <duid>.<part> as msdos filesystem. */
127c3e1bf61Skettenis memset(&args, 0, sizeof(args));
128c3e1bf61Skettenis rslt = asprintf(&args.fspec,
129c3e1bf61Skettenis "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c",
130c3e1bf61Skettenis dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3],
131c3e1bf61Skettenis dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7],
132c3e1bf61Skettenis part);
133c3e1bf61Skettenis if (rslt == -1) {
134c3e1bf61Skettenis warn("bad special device");
135c3e1bf61Skettenis return rslt;
136c3e1bf61Skettenis }
137c3e1bf61Skettenis
138c3e1bf61Skettenis rslt = snprintf(cmd, sizeof(cmd), newfsfmt, args.fspec);
139c3e1bf61Skettenis if (rslt >= sizeof(cmd)) {
140c3e1bf61Skettenis warnx("can't build newfs command");
141993e4236Skrw free(args.fspec);
142c3e1bf61Skettenis rslt = -1;
143c3e1bf61Skettenis return rslt;
144c3e1bf61Skettenis }
145c3e1bf61Skettenis
146c3e1bf61Skettenis if (verbose)
147c3e1bf61Skettenis fprintf(stderr, "%s %s\n",
148c3e1bf61Skettenis (nowrite ? "would newfs" : "newfsing"), args.fspec);
149c3e1bf61Skettenis if (!nowrite) {
150c3e1bf61Skettenis rslt = system(cmd);
151c3e1bf61Skettenis if (rslt == -1) {
152c3e1bf61Skettenis warn("system('%s') failed", cmd);
153993e4236Skrw free(args.fspec);
154c3e1bf61Skettenis return rslt;
155c3e1bf61Skettenis }
156c3e1bf61Skettenis }
157c3e1bf61Skettenis
158993e4236Skrw free(args.fspec);
159c3e1bf61Skettenis return 0;
160c3e1bf61Skettenis }
161a284d5afSderaadt
162a284d5afSderaadt static void
write_filesystem(struct disklabel * dl,char part)163a284d5afSderaadt write_filesystem(struct disklabel *dl, char part)
164a284d5afSderaadt {
1657a17f38cSkrw static char *fsckfmt = "/sbin/fsck -t msdos %s >/dev/null";
166a1ee4d86Sderaadt struct msdosfs_args args;
167a284d5afSderaadt char cmd[60];
168a284d5afSderaadt char dst[PATH_MAX];
1696c99b301Skrw size_t mntlen;
170a284d5afSderaadt int rslt;
171a284d5afSderaadt
172a284d5afSderaadt /* Create directory for temporary mount point. */
173a284d5afSderaadt strlcpy(dst, "/tmp/installboot.XXXXXXXXXX", sizeof(dst));
174a284d5afSderaadt if (mkdtemp(dst) == NULL)
175a284d5afSderaadt err(1, "mkdtemp('%s') failed", dst);
176a284d5afSderaadt mntlen = strlen(dst);
177a284d5afSderaadt
178a284d5afSderaadt /* Mount <duid>.<part> as msdos filesystem. */
179a284d5afSderaadt memset(&args, 0, sizeof(args));
180a284d5afSderaadt rslt = asprintf(&args.fspec,
181a284d5afSderaadt "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c",
182a284d5afSderaadt dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3],
183a284d5afSderaadt dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7],
184a284d5afSderaadt part);
185a284d5afSderaadt if (rslt == -1) {
186a284d5afSderaadt warn("bad special device");
187a284d5afSderaadt goto rmdir;
188a284d5afSderaadt }
189a284d5afSderaadt
190a284d5afSderaadt args.export_info.ex_root = -2;
191a284d5afSderaadt args.export_info.ex_flags = 0;
192d160f728Sderaadt args.flags = MSDOSFSMNT_LONGNAME;
193a284d5afSderaadt
194a284d5afSderaadt if (mount(MOUNT_MSDOS, dst, 0, &args) == -1) {
195a284d5afSderaadt /* Try fsck'ing it. */
196a284d5afSderaadt rslt = snprintf(cmd, sizeof(cmd), fsckfmt, args.fspec);
197a284d5afSderaadt if (rslt >= sizeof(cmd)) {
198a284d5afSderaadt warnx("can't build fsck command");
199a284d5afSderaadt rslt = -1;
200a284d5afSderaadt goto rmdir;
201a284d5afSderaadt }
202a284d5afSderaadt rslt = system(cmd);
203a284d5afSderaadt if (rslt == -1) {
204a284d5afSderaadt warn("system('%s') failed", cmd);
205a284d5afSderaadt goto rmdir;
206a284d5afSderaadt }
207a284d5afSderaadt if (mount(MOUNT_MSDOS, dst, 0, &args) == -1) {
208a284d5afSderaadt /* Try newfs'ing it. */
209c3e1bf61Skettenis rslt = create_filesystem(dl, part);
210c3e1bf61Skettenis if (rslt == -1)
211a284d5afSderaadt goto rmdir;
212a284d5afSderaadt rslt = mount(MOUNT_MSDOS, dst, 0, &args);
213a284d5afSderaadt if (rslt == -1) {
214a284d5afSderaadt warn("unable to mount MSDOS partition");
215a284d5afSderaadt goto rmdir;
216a284d5afSderaadt }
217a284d5afSderaadt }
218a284d5afSderaadt }
219a284d5afSderaadt
220a284d5afSderaadt /*
221a284d5afSderaadt * Copy /usr/mdec/boot to /mnt/boot.
222a284d5afSderaadt */
223a284d5afSderaadt if (strlcat(dst, "/boot", sizeof(dst)) >= sizeof(dst)) {
224a284d5afSderaadt rslt = -1;
225a284d5afSderaadt warn("unable to build /boot path");
226a284d5afSderaadt goto umount;
227a284d5afSderaadt }
228a284d5afSderaadt if (verbose)
229a284d5afSderaadt fprintf(stderr, "%s %s to %s\n",
230b8f3f2d0Skn (nowrite ? "would copy" : "copying"), stage1, dst);
231a284d5afSderaadt if (!nowrite) {
232b8f3f2d0Skn rslt = filecopy(stage1, dst);
233a284d5afSderaadt if (rslt == -1)
234a284d5afSderaadt goto umount;
235a284d5afSderaadt }
236a284d5afSderaadt
237a284d5afSderaadt rslt = 0;
238a284d5afSderaadt
239a284d5afSderaadt umount:
240a284d5afSderaadt dst[mntlen] = '\0';
241a284d5afSderaadt if (unmount(dst, MNT_FORCE) == -1)
242a284d5afSderaadt err(1, "unmount('%s') failed", dst);
243a284d5afSderaadt
244a284d5afSderaadt rmdir:
245a284d5afSderaadt free(args.fspec);
246a284d5afSderaadt dst[mntlen] = '\0';
247a284d5afSderaadt if (rmdir(dst) == -1)
248a284d5afSderaadt err(1, "rmdir('%s') failed", dst);
249a284d5afSderaadt
250a284d5afSderaadt if (rslt == -1)
251a284d5afSderaadt exit(1);
252a284d5afSderaadt }
253a284d5afSderaadt
254a284d5afSderaadt int
findmbrfat(int devfd,struct disklabel * dl)255a284d5afSderaadt findmbrfat(int devfd, struct disklabel *dl)
256a284d5afSderaadt {
257a284d5afSderaadt struct dos_partition dp[NDOSPART];
258a284d5afSderaadt ssize_t len;
259a284d5afSderaadt u_int64_t start = 0;
260a284d5afSderaadt int i;
261a284d5afSderaadt u_int8_t *secbuf;
262a284d5afSderaadt
263a284d5afSderaadt if ((secbuf = malloc(dl->d_secsize)) == NULL)
264a284d5afSderaadt err(1, NULL);
265a284d5afSderaadt
266a284d5afSderaadt /* Read MBR. */
267a284d5afSderaadt len = pread(devfd, secbuf, dl->d_secsize, 0);
268a284d5afSderaadt if (len != dl->d_secsize)
269a284d5afSderaadt err(4, "can't read mbr");
270a284d5afSderaadt memcpy(dp, &secbuf[DOSPARTOFF], sizeof(dp));
271a284d5afSderaadt
272a284d5afSderaadt for (i = 0; i < NDOSPART; i++) {
273a284d5afSderaadt if (dp[i].dp_typ == DOSPTYP_UNUSED)
274a284d5afSderaadt continue;
275a284d5afSderaadt if (dp[i].dp_typ == DOSPTYP_FAT16L ||
276a284d5afSderaadt dp[i].dp_typ == DOSPTYP_FAT32L ||
277a284d5afSderaadt dp[i].dp_typ == DOSPTYP_FAT16B)
278a284d5afSderaadt start = letoh32(dp[i].dp_start);
279a284d5afSderaadt }
280a284d5afSderaadt
281a284d5afSderaadt free(secbuf);
282a284d5afSderaadt
283a284d5afSderaadt if (start) {
284a284d5afSderaadt for (i = 0; i < MAXPARTITIONS; i++) {
285a284d5afSderaadt if (DL_GETPSIZE(&dl->d_partitions[i]) > 0 &&
286a284d5afSderaadt DL_GETPOFFSET(&dl->d_partitions[i]) == start)
287a284d5afSderaadt return ('a' + i);
288a284d5afSderaadt }
289a284d5afSderaadt }
290a284d5afSderaadt
291a284d5afSderaadt return (-1);
292a284d5afSderaadt }
293