installboot.c revision 1.9 1 /* $NetBSD: installboot.c,v 1.9 2002/05/15 02:18:22 lukem Exp $ */
2
3 /*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn of Wasabi Systems.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 #if defined(__RCSID) && !defined(__lint)
41 __RCSID("$NetBSD: installboot.c,v 1.9 2002/05/15 02:18:22 lukem Exp $");
42 #endif /* !__lint */
43
44 #include <sys/utsname.h>
45
46 #include <assert.h>
47 #include <err.h>
48 #include <fcntl.h>
49 #include <limits.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54
55 #include "installboot.h"
56
57 int main(int, char *[]);
58 static int getmachine(ib_params *, const char *, const char *);
59 static int getfstype(ib_params *, const char *, const char *);
60 static void usage(void);
61
62 static ib_params installboot_params;
63
64 int
65 main(int argc, char *argv[])
66 {
67 struct utsname utsname;
68 ib_params *params;
69 unsigned long lval;
70 int ch, rv, mode;
71 char *p;
72 const char *op;
73
74 setprogname(argv[0]);
75 params = &installboot_params;
76 memset(params, 0, sizeof(*params));
77 params->fsfd = -1;
78 params->s1fd = -1;
79 if ((p = getenv("MACHINE")) != NULL)
80 if (! getmachine(params, p, "$MACHINE"))
81 exit(1);
82
83 while ((ch = getopt(argc, argv, "b:B:cm:no:t:v")) != -1) {
84 switch (ch) {
85
86 case 'b':
87 case 'B':
88 if (*optarg == '\0')
89 goto badblock;
90 lval = strtoul(optarg, &p, 0);
91 if (lval > UINT32_MAX || *p != '\0') {
92 badblock:
93 errx(1, "Invalid block number `%s'", optarg);
94 }
95 if (ch == 'b') {
96 params->s1start = (uint32_t)lval;
97 params->flags |= IB_STAGE1START;
98 } else {
99 params->s2start = (uint32_t)lval;
100 params->flags |= IB_STAGE2START;
101 }
102 break;
103
104 case 'c':
105 params->flags |= IB_CLEAR;
106 break;
107
108 case 'm':
109 if (! getmachine(params, optarg, "-m"))
110 exit(1);
111 break;
112
113 case 'n':
114 params->flags |= IB_NOWRITE;
115 break;
116
117 case 'o':
118 if (params->machine == NULL)
119 errx(1,
120 "Machine needs to be specified before -o");
121 while ((p = strsep(&optarg, ",")) != NULL) {
122 if (*p == '\0')
123 errx(1, "Empty `-o' option");
124 if (! params->machine->parseopt(params, p))
125 exit(1);
126 }
127 break;
128
129 case 't':
130 if (! getfstype(params, optarg, "-t"))
131 exit(1);
132 break;
133
134 case 'v':
135 params->flags |= IB_VERBOSE;
136 break;
137
138 case '?':
139 default:
140 usage();
141 /* NOTREACHED */
142
143 }
144 }
145 argc -= optind;
146 argv += optind;
147
148 if (((params->flags & IB_CLEAR) != 0 && argc != 1) ||
149 ((params->flags & IB_CLEAR) == 0 && (argc < 2 || argc > 3)))
150 usage();
151
152 /* set missing defaults */
153 if (params->machine == NULL) {
154 if (uname(&utsname) == -1)
155 err(1, "Determine uname");
156 if (! getmachine(params, utsname.machine, "uname()"))
157 exit(1);
158 }
159
160 params->filesystem = argv[0];
161 if (params->flags & IB_NOWRITE) {
162 op = "only";
163 mode = O_RDONLY;
164 } else {
165 op = "write";
166 mode = O_RDWR;
167 }
168 if ((params->fsfd = open(params->filesystem, mode, 0600)) == -1)
169 err(1, "Opening file system `%s' read-%s",
170 params->filesystem, op);
171 if (fstat(params->fsfd, ¶ms->fsstat) == -1)
172 err(1, "Examining file system `%s'", params->filesystem);
173 if (params->fstype != NULL) {
174 if (! params->fstype->match(params))
175 err(1, "File system `%s' is not of type %s",
176 params->filesystem, params->fstype->name);
177 } else {
178 params->fstype = &fstypes[0];
179 while (params->fstype->name != NULL &&
180 ! params->fstype->match(params))
181 params->fstype++;
182 if (params->fstype->name == NULL)
183 errx(1, "File system `%s' is of an unknown type",
184 params->filesystem);
185 }
186
187 if (argc >= 2) {
188 params->stage1 = argv[1];
189 if ((params->s1fd = open(params->stage1, O_RDONLY, 0600))
190 == -1)
191 err(1, "Opening primary bootstrap `%s'",
192 params->stage1);
193 if (fstat(params->s1fd, ¶ms->s1stat) == -1)
194 err(1, "Examining primary bootstrap `%s'",
195 params->stage1);
196 if (!S_ISREG(params->s1stat.st_mode))
197 err(1, "`%s' must be a regular file", params->stage1);
198 }
199 if (argc == 3) {
200 params->stage2 = argv[2];
201 }
202 assert(params->machine != NULL);
203
204 if (params->flags & IB_VERBOSE) {
205 printf("File system: %s\n", params->filesystem);
206 printf("File system type: %s (blocksize %u, needswap %d)\n",
207 params->fstype->name,
208 params->fstype->blocksize, params->fstype->needswap);
209 printf("Primary bootstrap: %s\n",
210 (params->flags & IB_CLEAR) ? "(to be cleared)"
211 : params->stage1);
212 if (params->stage2 != NULL)
213 printf("Secondary bootstrap: %s\n", params->stage2);
214 }
215
216 if (params->flags & IB_CLEAR) {
217 op = "Clear";
218 rv = params->machine->clearboot(params);
219 } else {
220 op = "Set";
221 rv = params->machine->setboot(params);
222 }
223 if (rv == 0)
224 errx(1, "%s bootstrap operation failed", op);
225
226 if (S_ISREG(params->fsstat.st_mode)) {
227 if (fsync(params->fsfd) == -1)
228 err(1, "Synchronising file system `%s'",
229 params->filesystem);
230 } else {
231 /* Sync filesystems (to clean in-memory superblock?) */
232 sync();
233 }
234 if (close(params->fsfd) == -1)
235 err(1, "Closing file system `%s'", params->filesystem);
236 if (argc == 2)
237 if (close(params->s1fd) == -1)
238 err(1, "Closing primary bootstrap `%s'",
239 params->stage1);
240
241 exit(0);
242 /* NOTREACHED */
243 }
244
245 int
246 parseoptionflag(ib_params *params, const char *option, ib_flags wantflags)
247 {
248 struct {
249 const char *name;
250 ib_flags flag;
251 } flags[] = {
252 { "alphasum", IB_ALPHASUM },
253 { "append", IB_APPEND },
254 { "sunsum", IB_SUNSUM },
255 { NULL, 0 },
256 };
257
258 int i;
259
260 assert(params != NULL);
261 assert(option != NULL);
262
263 for (i = 0; flags[i].name != NULL; i++) {
264 if ((strcmp(flags[i].name, option) == 0) &&
265 (wantflags & flags[i].flag)) {
266 params->flags |= flags[i].flag;
267 return (1);
268 }
269 }
270 return (0);
271 }
272
273 int
274 no_parseopt(ib_params *params, const char *option)
275 {
276
277 assert(params != NULL);
278 assert(option != NULL);
279
280 /* all options are unsupported */
281 warnx("Unsupported -o option `%s'", option);
282 return (0);
283 }
284
285 int
286 no_setboot(ib_params *params)
287 {
288
289 assert(params != NULL);
290
291 /* bootstrap installation is not supported */
292 warnx("%s: bootstrap installation is not supported",
293 params->machine->name);
294 return (0);
295 }
296
297 int
298 no_clearboot(ib_params *params)
299 {
300
301 assert(params != NULL);
302
303 /* bootstrap removal is not supported */
304 warnx("%s: bootstrap removal is not supported",
305 params->machine->name);
306 return (0);
307 }
308
309
310 static int
311 getmachine(ib_params *param, const char *mach, const char *provider)
312 {
313 int i;
314
315 assert(param != NULL);
316 assert(mach != NULL);
317 assert(provider != NULL);
318
319 for (i = 0; machines[i].name != NULL; i++) {
320 if (strcmp(machines[i].name, mach) == 0) {
321 param->machine = &machines[i];
322 return (1);
323 }
324 }
325 warnx("Invalid machine `%s' from %s", mach, provider);
326 warnx("Supported machines are:");
327 #define MACHS_PER_LINE 10
328 for (i = 0; machines[i].name != NULL; i++) {
329 fputs((i % MACHS_PER_LINE) ? ", " : "\t", stderr);
330 fputs(machines[i].name, stderr);
331 if ((i % MACHS_PER_LINE) == (MACHS_PER_LINE - 1))
332 fputs("\n", stderr);
333 }
334 if ((i % MACHS_PER_LINE) != 0)
335 fputs("\n", stderr);
336 return (0);
337 }
338
339 static int
340 getfstype(ib_params *param, const char *fstype, const char *provider)
341 {
342 int i;
343
344 assert(param != NULL);
345 assert(fstype != NULL);
346 assert(provider != NULL);
347
348 for (i = 0; fstypes[i].name != NULL; i++) {
349 if (strcmp(fstypes[i].name, fstype) == 0) {
350 param->fstype = &fstypes[i];
351 return (1);
352 }
353 }
354 warnx("Invalid file system type `%s' from %s", fstype, provider);
355 warnx("Supported file system types are:");
356 #define FSTYPES_PER_LINE 10
357 for (i = 0; fstypes[i].name != NULL; i++) {
358 fputs((i % FSTYPES_PER_LINE) ? ", " : "\t", stderr);
359 fputs(fstypes[i].name, stderr);
360 if ((i % FSTYPES_PER_LINE) == (FSTYPES_PER_LINE - 1))
361 fputs("\n", stderr);
362 }
363 if ((i % FSTYPES_PER_LINE) != 0)
364 fputs("\n", stderr);
365 return (0);
366 }
367
368 static void
369 usage(void)
370 {
371 const char *prog;
372
373 prog = getprogname();
374 fprintf(stderr,
375 "Usage: %s [-nv] [-m machine] [-o options] [-t fstype]\n"
376 "\t\t [-b s1start] [-B s2start] filesystem primary [secondary]\n"
377 "Usage: %s -c [-nv] [-m machine] [-o options] [-t fstype] filesystem\n",
378 prog, prog);
379 exit(1);
380 }
381