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