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 
56 static void	write_filesystem(struct disklabel *, char);
57 static int	findmbrfat(int, struct disklabel *);
58 
59 void
md_init(void)60 md_init(void)
61 {
62 	stages = 1;
63 	stage1 = "/usr/mdec/boot";
64 }
65 
66 void
md_loadboot(void)67 md_loadboot(void)
68 {
69 }
70 
71 void
md_prepareboot(int devfd,char * dev)72 md_prepareboot(int devfd, char *dev)
73 {
74 }
75 
76 void
md_installboot(int devfd,char * dev)77 md_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 
100 static void
write_filesystem(struct disklabel * dl,char part)101 write_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 
198 umount:
199 	dst[mntlen] = '\0';
200 	if (unmount(dst, MNT_FORCE) == -1)
201 		err(1, "unmount('%s') failed", dst);
202 
203 rmdir:
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 
213 int
findmbrfat(int devfd,struct disklabel * dl)214 findmbrfat(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