xref: /openbsd-src/usr.sbin/installboot/octeon_installboot.c (revision 4e1ee0786f11cc571bd0be17d38e46f635c719fc)
1 /*	$OpenBSD: octeon_installboot.c,v 1.4 2021/07/20 14:51:56 kettenis 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 void
61 md_init(void)
62 {
63 }
64 
65 void
66 md_loadboot(void)
67 {
68 }
69 
70 void
71 md_prepareboot(int devfd, char *dev)
72 {
73 	struct disklabel dl;
74 	int part;
75 
76 	/* Get and check disklabel. */
77 	if (ioctl(devfd, DIOCGDINFO, &dl) == -1)
78 		err(1, "disklabel: %s", dev);
79 	if (dl.d_magic != DISKMAGIC)
80 		errx(1, "bad disklabel magic=0x%08x", dl.d_magic);
81 
82 	/* Warn on unknown disklabel types. */
83 	if (dl.d_type == 0)
84 		warnx("disklabel type unknown");
85 
86 	part = findmbrfat(devfd, &dl);
87 	if (part != -1) {
88 		create_filesystem(&dl, (char)part);
89 		return;
90 	}
91 }
92 
93 void
94 md_installboot(int devfd, char *dev)
95 {
96 	struct disklabel dl;
97 	int part;
98 
99 	/* Get and check disklabel. */
100 	if (ioctl(devfd, DIOCGDINFO, &dl) == -1)
101 		err(1, "disklabel: %s", dev);
102 	if (dl.d_magic != DISKMAGIC)
103 		errx(1, "bad disklabel magic=0x%08x", dl.d_magic);
104 
105 	/* Warn on unknown disklabel types. */
106 	if (dl.d_type == 0)
107 		warnx("disklabel type unknown");
108 
109 	part = findmbrfat(devfd, &dl);
110 	if (part != -1) {
111 		write_filesystem(&dl, (char)part);
112 		return;
113 	}
114 }
115 
116 static int
117 create_filesystem(struct disklabel *dl, char part)
118 {
119 	static char *newfsfmt ="/sbin/newfs_msdos %s >/dev/null";
120 	struct msdosfs_args args;
121 	char cmd[60];
122 	int rslt;
123 
124 	/* Mount <duid>.<part> as msdos filesystem. */
125 	memset(&args, 0, sizeof(args));
126 	rslt = asprintf(&args.fspec,
127 	    "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c",
128             dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3],
129             dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7],
130 	    part);
131 	if (rslt == -1) {
132 		warn("bad special device");
133 		return rslt;
134 	}
135 
136 	rslt = snprintf(cmd, sizeof(cmd), newfsfmt, args.fspec);
137 	if (rslt >= sizeof(cmd)) {
138 		warnx("can't build newfs command");
139 		rslt = -1;
140 		return rslt;
141 	}
142 
143 	if (verbose)
144 		fprintf(stderr, "%s %s\n",
145 		    (nowrite ? "would newfs" : "newfsing"), args.fspec);
146 	if (!nowrite) {
147 		rslt = system(cmd);
148 		if (rslt == -1) {
149 			warn("system('%s') failed", cmd);
150 			return rslt;
151 		}
152 	}
153 
154 	return 0;
155 }
156 
157 static void
158 write_filesystem(struct disklabel *dl, char part)
159 {
160 	static char *fsckfmt = "/sbin/fsck_msdos %s >/dev/null";
161 	struct msdosfs_args args;
162 	char cmd[60];
163 	char dst[PATH_MAX];
164 	char *src;
165 	size_t mntlen, pathlen, srclen;
166 	int rslt;
167 
168 	src = NULL;
169 
170 	/* Create directory for temporary mount point. */
171 	strlcpy(dst, "/tmp/installboot.XXXXXXXXXX", sizeof(dst));
172 	if (mkdtemp(dst) == NULL)
173 		err(1, "mkdtemp('%s') failed", dst);
174 	mntlen = strlen(dst);
175 
176 	/* Mount <duid>.<part> as msdos filesystem. */
177 	memset(&args, 0, sizeof(args));
178 	rslt = asprintf(&args.fspec,
179 	    "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c",
180             dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3],
181             dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7],
182 	    part);
183 	if (rslt == -1) {
184 		warn("bad special device");
185 		goto rmdir;
186 	}
187 
188 	args.export_info.ex_root = -2;
189 	args.export_info.ex_flags = 0;
190 	args.flags = MSDOSFSMNT_LONGNAME;
191 
192 	if (mount(MOUNT_MSDOS, dst, 0, &args) == -1) {
193 		/* Try fsck'ing it. */
194 		rslt = snprintf(cmd, sizeof(cmd), fsckfmt, args.fspec);
195 		if (rslt >= sizeof(cmd)) {
196 			warnx("can't build fsck command");
197 			rslt = -1;
198 			goto rmdir;
199 		}
200 		rslt = system(cmd);
201 		if (rslt == -1) {
202 			warn("system('%s') failed", cmd);
203 			goto rmdir;
204 		}
205 		if (mount(MOUNT_MSDOS, dst, 0, &args) == -1) {
206 			/* Try newfs'ing it. */
207 			rslt = create_filesystem(dl, part);
208 			if (rslt == -1)
209 				goto rmdir;
210 			rslt = mount(MOUNT_MSDOS, dst, 0, &args);
211 			if (rslt == -1) {
212 				warn("unable to mount MSDOS partition");
213 				goto rmdir;
214 			}
215 		}
216 	}
217 
218 	/*
219 	 * Copy /usr/mdec/boot to /mnt/boot.
220 	 */
221 	pathlen = strlen(dst);
222 	if (strlcat(dst, "/boot", sizeof(dst)) >= sizeof(dst)) {
223 		rslt = -1;
224 		warn("unable to build /boot path");
225 		goto umount;
226 	}
227 	src = fileprefix(root, "/usr/mdec/boot");
228 	if (src == NULL) {
229 		rslt = -1;
230 		goto umount;
231 	}
232 	srclen = strlen(src);
233 	if (verbose)
234 		fprintf(stderr, "%s %s to %s\n",
235 		    (nowrite ? "would copy" : "copying"), src, dst);
236 	if (!nowrite) {
237 		rslt = filecopy(src, dst);
238 		if (rslt == -1)
239 			goto umount;
240 	}
241 
242 	rslt = 0;
243 
244 umount:
245 	dst[mntlen] = '\0';
246 	if (unmount(dst, MNT_FORCE) == -1)
247 		err(1, "unmount('%s') failed", dst);
248 
249 rmdir:
250 	free(args.fspec);
251 	dst[mntlen] = '\0';
252 	if (rmdir(dst) == -1)
253 		err(1, "rmdir('%s') failed", dst);
254 
255 	free(src);
256 
257 	if (rslt == -1)
258 		exit(1);
259 }
260 
261 int
262 findmbrfat(int devfd, struct disklabel *dl)
263 {
264 	struct dos_partition	 dp[NDOSPART];
265 	ssize_t			 len;
266 	u_int64_t		 start = 0;
267 	int			 i;
268 	u_int8_t		*secbuf;
269 
270 	if ((secbuf = malloc(dl->d_secsize)) == NULL)
271 		err(1, NULL);
272 
273 	/* Read MBR. */
274 	len = pread(devfd, secbuf, dl->d_secsize, 0);
275 	if (len != dl->d_secsize)
276 		err(4, "can't read mbr");
277 	memcpy(dp, &secbuf[DOSPARTOFF], sizeof(dp));
278 
279 	for (i = 0; i < NDOSPART; i++) {
280 		if (dp[i].dp_typ == DOSPTYP_UNUSED)
281 			continue;
282 		if (dp[i].dp_typ == DOSPTYP_FAT16L ||
283 		    dp[i].dp_typ == DOSPTYP_FAT32L ||
284 		    dp[i].dp_typ == DOSPTYP_FAT16B)
285 			start = letoh32(dp[i].dp_start);
286 	}
287 
288 	free(secbuf);
289 
290 	if (start) {
291 		for (i = 0; i < MAXPARTITIONS; i++) {
292 			if (DL_GETPSIZE(&dl->d_partitions[i]) > 0 &&
293 			    DL_GETPOFFSET(&dl->d_partitions[i]) == start)
294 				return ('a' + i);
295 		}
296 	}
297 
298 	return (-1);
299 }
300