1 /*	$OpenBSD: loongson_installboot.c,v 1.4 2021/07/20 14:51:56 kettenis 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
60 md_init(void)
61 {
62 }
63 
64 void
65 md_loadboot(void)
66 {
67 }
68 
69 void
70 md_prepareboot(int devfd, char *dev)
71 {
72 }
73 
74 void
75 md_installboot(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 		write_filesystem(&dl, (char)part);
93 		return;
94 	}
95 }
96 
97 
98 static void
99 write_filesystem(struct disklabel *dl, char part)
100 {
101 	static char *fsckfmt = "/sbin/fsck_ext2fs %s >/dev/null";
102 	static char *newfsfmt ="/sbin/newfs_ext2fs %s >/dev/null";
103 	struct ufs_args args;
104 	char cmd[60];
105 	char dst[PATH_MAX];
106 	char *src;
107 	size_t mntlen, pathlen, srclen;
108 	int rslt;
109 
110 	src = NULL;
111 
112 	/* Create directory for temporary mount point. */
113 	strlcpy(dst, "/tmp/installboot.XXXXXXXXXX", sizeof(dst));
114 	if (mkdtemp(dst) == NULL)
115 		err(1, "mkdtemp('%s') failed", dst);
116 	mntlen = strlen(dst);
117 
118 	/* Mount <duid>.<part> as ext2fs filesystem. */
119 	memset(&args, 0, sizeof(args));
120 	rslt = asprintf(&args.fspec,
121 	    "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c",
122             dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3],
123             dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7],
124 	    part);
125 	if (rslt == -1) {
126 		warn("bad special device");
127 		goto rmdir;
128 	}
129 
130 	args.export_info.ex_root = -2;
131 	args.export_info.ex_flags = 0;
132 
133 	if (mount(MOUNT_EXT2FS, dst, 0, &args) == -1) {
134 		/* Try fsck'ing it. */
135 		rslt = snprintf(cmd, sizeof(cmd), fsckfmt, args.fspec);
136 		if (rslt >= sizeof(cmd)) {
137 			warnx("can't build fsck command");
138 			rslt = -1;
139 			goto rmdir;
140 		}
141 		rslt = system(cmd);
142 		if (rslt == -1) {
143 			warn("system('%s') failed", cmd);
144 			goto rmdir;
145 		}
146 		if (mount(MOUNT_EXT2FS, dst, 0, &args) == -1) {
147 			/* Try newfs'ing it. */
148 			rslt = snprintf(cmd, sizeof(cmd), newfsfmt,
149 			    args.fspec);
150 			if (rslt >= sizeof(cmd)) {
151 				warnx("can't build newfs command");
152 				rslt = -1;
153 				goto rmdir;
154 			}
155 			rslt = system(cmd);
156 			if (rslt == -1) {
157 				warn("system('%s') failed", cmd);
158 				goto rmdir;
159 			}
160 			rslt = mount(MOUNT_EXT2FS, dst, 0, &args);
161 			if (rslt == -1) {
162 				warn("unable to mount ext2fs partition");
163 				goto rmdir;
164 			}
165 		}
166 	}
167 
168 	/* Create "/boot" directory in <duid>.<part>. */
169 	if (strlcat(dst, "/boot", sizeof(dst)) >= sizeof(dst)) {
170 		rslt = -1;
171 		warn("unable to build /boot directory");
172 		goto umount;
173 	}
174 	rslt = mkdir(dst, 0755);
175 	if (rslt == -1 && errno != EEXIST) {
176 		warn("mkdir('%s') failed", dst);
177 		goto umount;
178 	}
179 
180 	/*
181 	 * Copy /usr/mdec/boot to /boot/boot.
182 	 */
183 	pathlen = strlen(dst);
184 	if (strlcat(dst, "/boot", sizeof(dst)) >= sizeof(dst)) {
185 		rslt = -1;
186 		warn("unable to build /boot path");
187 		goto umount;
188 	}
189 	src = fileprefix(root, "/usr/mdec/boot");
190 	if (src == NULL) {
191 		rslt = -1;
192 		goto umount;
193 	}
194 	srclen = strlen(src);
195 	if (verbose)
196 		fprintf(stderr, "%s %s to %s\n",
197 		    (nowrite ? "would copy" : "copying"), src, dst);
198 	if (!nowrite) {
199 		rslt = filecopy(src, dst);
200 		if (rslt == -1)
201 			goto umount;
202 	}
203 
204 	rslt = 0;
205 
206 umount:
207 	dst[mntlen] = '\0';
208 	if (unmount(dst, MNT_FORCE) == -1)
209 		err(1, "unmount('%s') failed", dst);
210 
211 rmdir:
212 	free(args.fspec);
213 	dst[mntlen] = '\0';
214 	if (rmdir(dst) == -1)
215 		err(1, "rmdir('%s') failed", dst);
216 
217 	free(src);
218 
219 	if (rslt == -1)
220 		exit(1);
221 }
222 
223 int
224 findmbrfat(int devfd, struct disklabel *dl)
225 {
226 	struct dos_partition	 dp[NDOSPART];
227 	ssize_t			 len;
228 	u_int64_t		 start = 0;
229 	int			 i;
230 	u_int8_t		*secbuf;
231 
232 	if ((secbuf = malloc(dl->d_secsize)) == NULL)
233 		err(1, NULL);
234 
235 	/* Read MBR. */
236 	len = pread(devfd, secbuf, dl->d_secsize, 0);
237 	if (len != dl->d_secsize)
238 		err(4, "can't read mbr");
239 	memcpy(dp, &secbuf[DOSPARTOFF], sizeof(dp));
240 
241 	for (i = 0; i < NDOSPART; i++) {
242 		if (dp[i].dp_typ == DOSPTYP_UNUSED)
243 			continue;
244 		if (dp[i].dp_typ == DOSPTYP_LINUX)
245 			start = dp[i].dp_start;
246 	}
247 
248 	free(secbuf);
249 
250 	if (start) {
251 		for (i = 0; i < MAXPARTITIONS; i++) {
252 			if (DL_GETPSIZE(&dl->d_partitions[i]) > 0 &&
253 			    DL_GETPOFFSET(&dl->d_partitions[i]) == start)
254 				return ('a' + i);
255 		}
256 	}
257 
258 	return (-1);
259 }
260