xref: /openbsd-src/usr.sbin/installboot/octeon_installboot.c (revision acd6e620916954483f14fb19e66715b2f7385d74)
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