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