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