1 /* $NetBSD: installboot.c,v 1.39 2015/07/25 10:37:22 mlelstv Exp $ */
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn of Wasabi Systems.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
36 #include <sys/cdefs.h>
38 __RCSID("$NetBSD: installboot.c,v 1.39 2015/07/25 10:37:22 mlelstv Exp $");
41 #include <sys/param.h>
42 #include <sys/ioctl.h>
43 #include <sys/utsname.h>
54 #if !HAVE_NBTOOL_CONFIG_H
58 #include "installboot.h"
60 static void getmachine(ib_params
*, const char *, const char *);
61 static void getfstype(ib_params
*, const char *, const char *);
62 static void parseoptions(ib_params
*, const char *);
63 __dead
static void usage(void);
64 static void options_usage(void);
65 static void machine_usage(void);
66 static void fstype_usage(void);
68 static ib_params installboot_params
;
70 #define OFFSET(field) offsetof(ib_params, field)
72 const char *name
; /* Name of option */
73 ib_flags flag
; /* Corresponding IB_xxx flag */
74 enum { /* Type of option value... */
75 OPT_BOOL
, /* no value */
76 OPT_INT
, /* numeric value */
77 OPT_WORD
, /* space/tab/, terminated */
78 OPT_STRING
/* null terminated */
80 int offset
; /* of field in ib_params */
82 { "alphasum", IB_ALPHASUM
, OPT_BOOL
, 0 },
83 { "append", IB_APPEND
, OPT_BOOL
, 0 },
84 { "command", IB_COMMAND
, OPT_STRING
, OFFSET(command
) },
85 { "console", IB_CONSOLE
, OPT_WORD
, OFFSET(console
) },
86 { "ioaddr", IB_CONSADDR
, OPT_INT
, OFFSET(consaddr
) },
87 { "keymap", IB_KEYMAP
, OPT_WORD
, OFFSET(keymap
) },
88 { "password", IB_PASSWORD
, OPT_WORD
, OFFSET(password
) },
89 { "resetvideo", IB_RESETVIDEO
, OPT_BOOL
, 0 },
90 { "speed", IB_CONSPEED
, OPT_INT
, OFFSET(conspeed
) },
91 { "sunsum", IB_SUNSUM
, OPT_BOOL
, 0 },
92 { "timeout", IB_TIMEOUT
, OPT_INT
, OFFSET(timeout
) },
93 { "modules", IB_MODULES
, OPT_BOOL
, 0 },
94 { "bootconf", IB_BOOTCONF
, OPT_BOOL
, 0 },
98 #define OPTION(params, type, opt) (*(type *)((char *)(params) + (opt)->offset))
100 #define DFL_SECSIZE 512 /* Don't use DEV_BSIZE. It's host's value. */
103 main(int argc
, char *argv
[])
105 struct utsname utsname
;
111 ib_flags unsupported_flags
;
112 #if !HAVE_NBTOOL_CONFIG_H && !defined(__minix)
113 char specname
[MAXPATHLEN
];
114 char rawname
[MAXPATHLEN
];
115 const char *special
, *raw
;
119 /* XXX Temp stuff for MINIX until fdisk is ported */
120 if ((4 <= argc
&& argc
<= 6) && isoption(argv
[1], "-master")) {
121 install_master(argv
[2], argv
[3], argv
+ 4);
124 #endif /* defined(__minix) */
126 setprogname(argv
[0]);
127 params
= &installboot_params
;
128 memset(params
, 0, sizeof(*params
));
131 if ((p
= getenv("MACHINE")) != NULL
)
132 getmachine(params
, p
, "$MACHINE");
134 while ((ch
= getopt(argc
, argv
, "b:B:cefm:no:t:v")) != -1) {
141 lval
= strtoul(optarg
, &p
, 0);
142 if (lval
> UINT32_MAX
|| *p
!= '\0') {
144 errx(1, "Invalid block number `%s'", optarg
);
147 params
->s1start
= (uint32_t)lval
;
148 params
->flags
|= IB_STAGE1START
;
150 params
->s2start
= (uint32_t)lval
;
151 params
->flags
|= IB_STAGE2START
;
156 params
->flags
|= IB_CLEAR
;
160 params
->flags
|= IB_EDIT
;
164 params
->flags
|= IB_FORCE
;
168 getmachine(params
, optarg
, "-m");
172 params
->flags
|= IB_NOWRITE
;
176 parseoptions(params
, optarg
);
180 getfstype(params
, optarg
, "-t");
184 params
->flags
|= IB_VERBOSE
;
197 if (params
->flags
& IB_CLEAR
&& params
->flags
& IB_EDIT
)
199 if (argc
< 1 || argc
+ 2 * !!(params
->flags
& (IB_CLEAR
| IB_EDIT
)) > 3)
202 /* set missing defaults */
203 if (params
->machine
== NULL
) {
204 if (uname(&utsname
) == -1)
205 err(1, "Determine uname");
206 getmachine(params
, utsname
.machine
, "uname()");
209 /* Check that options are supported by this system */
210 unsupported_flags
= params
->flags
& ~params
->machine
->valid_flags
;
211 unsupported_flags
&= ~(IB_VERBOSE
| IB_NOWRITE
| IB_CLEAR
| IB_EDIT
213 if (unsupported_flags
!= 0) {
215 for (ndx
= 0; options
[ndx
].name
!= NULL
; ndx
++) {
216 if (unsupported_flags
& options
[ndx
].flag
) {
217 unsupported_flags
&= ~options
[ndx
].flag
;
218 warnx("`-o %s' is not supported for %s",
219 options
[ndx
].name
, params
->machine
->name
);
222 if (unsupported_flags
& IB_STAGE1START
)
223 warnx("`-b bno' is not supported for %s",
224 params
->machine
->name
);
225 if (unsupported_flags
& IB_STAGE2START
)
226 warnx("`-B bno' is not supported for %s",
227 params
->machine
->name
);
228 unsupported_flags
&= ~(IB_STAGE1START
| IB_STAGE2START
);
229 if (unsupported_flags
!= 0)
230 warnx("Unknown unsupported flag %#x (coding error!)",
234 /* and some illegal combinations */
235 if (params
->flags
& IB_STAGE1START
&& params
->flags
& IB_APPEND
) {
236 warnx("Can't use `-b bno' with `-o append'");
239 if (params
->flags
& IB_CLEAR
&&
240 params
->flags
& (IB_STAGE1START
| IB_STAGE2START
| IB_APPEND
)) {
241 warnx("Can't use `-b bno', `-B bno' or `-o append' with `-c'");
246 params
->stage2
= argv
[2];
249 #if !HAVE_NBTOOL_CONFIG_H && !defined(__minix)
250 special
= getfsspecname(specname
, sizeof(specname
), argv
[0]);
252 err(1, "%s: %s", argv
[0], specname
);
253 raw
= getdiskrawname(rawname
, sizeof(rawname
), special
);
256 params
->filesystem
= special
;
258 params
->filesystem
= argv
[0];
261 if (params
->flags
& IB_NOWRITE
) {
269 if (minixfs3_is_minix_partition(params
)) {
270 /* Old setups has just 1 sector for bootblock,
271 * but bootxx_minixfs is ~8Kb, so we require new setups
272 * to have 32 sectors before the first subpartition.
273 * This prevents from overwriting FS on old setups.
275 if (!minixfs3_has_bootblock_space(params
)) {
276 err(1, "No space for bootxx, you should have 32 sectors"
277 " before the first subpartition on %s",
281 #endif /* defined(__minix) */
282 /* XXX should be specified via option */
283 params
->sectorsize
= DFL_SECSIZE
;
284 if ((params
->fsfd
= open(params
->filesystem
, mode
, 0600)) == -1)
285 err(1, "Opening file system `%s' read-%s",
286 params
->filesystem
, op
);
287 if (fstat(params
->fsfd
, ¶ms
->fsstat
) == -1)
288 err(1, "Examining file system `%s'", params
->filesystem
);
289 if (params
->fstype
!= NULL
) {
290 if (! params
->fstype
->match(params
))
291 errx(1, "File system `%s' is not of type %s",
292 params
->filesystem
, params
->fstype
->name
);
294 if (params
->stage2
!= NULL
) {
295 params
->fstype
= &fstypes
[0];
296 while (params
->fstype
->name
!= NULL
&&
297 !params
->fstype
->match(params
))
299 if (params
->fstype
->name
== NULL
)
300 errx(1, "File system `%s' is of an unknown type",
306 if ((params
->s1fd
= open(argv
[1], O_RDONLY
, 0600)) == -1)
307 err(1, "Opening primary bootstrap `%s'", argv
[1]);
308 if (fstat(params
->s1fd
, ¶ms
->s1stat
) == -1)
309 err(1, "Examining primary bootstrap `%s'", argv
[1]);
310 if (!S_ISREG(params
->s1stat
.st_mode
))
311 errx(1, "`%s' must be a regular file", argv
[1]);
312 params
->stage1
= argv
[1];
314 assert(params
->machine
!= NULL
);
316 if (params
->flags
& IB_VERBOSE
) {
317 printf("File system: %s\n", params
->filesystem
);
319 printf("File system type: %s (blocksize %u, "
321 params
->fstype
->name
, params
->fstype
->blocksize
,
322 params
->fstype
->needswap
);
323 if (!(params
->flags
& IB_EDIT
))
324 printf("Primary bootstrap: %s\n",
325 (params
->flags
& IB_CLEAR
) ? "(to be cleared)"
326 : params
->stage1
? params
->stage1
: "(none)" );
327 if (params
->stage2
!= NULL
)
328 printf("Secondary bootstrap: %s\n", params
->stage2
);
331 if (params
->flags
& IB_EDIT
) {
333 rv
= params
->machine
->editboot(params
);
334 } else if (params
->flags
& IB_CLEAR
) {
336 rv
= params
->machine
->clearboot(params
);
339 errx(EXIT_FAILURE
, "Please specify the primary "
342 rv
= params
->machine
->setboot(params
);
345 errx(1, "%s bootstrap operation failed", op
);
347 if (S_ISREG(params
->fsstat
.st_mode
)) {
348 if (fsync(params
->fsfd
) == -1)
349 err(1, "Synchronising file system `%s'",
352 /* Sync filesystems (to clean in-memory superblock?) */
355 if (close(params
->fsfd
) == -1)
356 err(1, "Closing file system `%s'", params
->filesystem
);
358 if (close(params
->s1fd
) == -1)
359 err(1, "Closing primary bootstrap `%s'",
367 parseoptions(ib_params
*params
, const char *option
)
370 const struct option
*opt
;
374 assert(params
!= NULL
);
375 assert(option
!= NULL
);
377 for (;; option
+= len
) {
378 option
+= strspn(option
, ", \t");
381 len
= strcspn(option
, "=,");
382 for (opt
= options
; opt
->name
!= NULL
; opt
++) {
383 if (memcmp(option
, opt
->name
, len
) == 0
384 && opt
->name
[len
] == 0)
387 if (opt
->name
== NULL
) {
388 len
= strcspn(option
, ",");
389 warnx("Unknown option `-o %.*s'", len
, option
);
392 params
->flags
|= opt
->flag
;
393 if (opt
->type
== OPT_BOOL
) {
394 if (option
[len
] != '=')
396 warnx("Option `%s' must not have a value", opt
->name
);
399 if (option
[len
] != '=') {
400 warnx("Option `%s' must have a value", opt
->name
);
404 len
= strcspn(option
, ",");
407 len
= strlen(option
);
414 OPTION(params
, char *, opt
) = cp
;
417 val
= strtoul(option
, &cp
, 0);
418 if (cp
> option
+ len
|| (*cp
!= 0 && *cp
!= ','))
422 OPTION(params
, int, opt
) = (int)val
;
425 errx(1, "Internal error: option `%s' has invalid type %d",
426 opt
->name
, opt
->type
);
428 warnx("Invalid option value `%s=%.*s'", opt
->name
, len
, option
);
441 warnx("Valid options are:");
443 for (ndx
= 0; options
[ndx
].name
!= 0; ndx
++) {
444 fprintf(stderr
, "%s%s", pfx
, options
[ndx
].name
);
445 switch (options
[ndx
].type
) {
447 fprintf(stderr
, "=number");
450 fprintf(stderr
, "=word");
453 fprintf(stderr
, "=string");
463 fprintf(stderr
, "\n");
467 no_setboot(ib_params
*params
)
470 assert(params
!= NULL
);
472 warnx("%s: bootstrap installation is not supported",
473 params
->machine
->name
);
478 no_clearboot(ib_params
*params
)
481 assert(params
!= NULL
);
483 warnx("%s: bootstrap removal is not supported",
484 params
->machine
->name
);
489 no_editboot(ib_params
*params
)
492 assert(params
!= NULL
);
494 warnx("%s: bootstrap editing is not supported",
495 params
->machine
->name
);
501 getmachine(ib_params
*param
, const char *mach
, const char *provider
)
505 assert(param
!= NULL
);
506 assert(mach
!= NULL
);
507 assert(provider
!= NULL
);
509 for (i
= 0; machines
[i
] != NULL
; i
++) {
510 if (machines
[i
]->name
== NULL
)
512 if (strcmp(machines
[i
]->name
, mach
) == 0) {
513 param
->machine
= machines
[i
];
517 warnx("Invalid machine `%s' from %s", mach
, provider
);
533 if (ioctl(fileno(stderr
), TIOCGWINSZ
, &win
) == 0 && win
.ws_col
> 0)
537 warnx("Supported machines are:");
540 for (i
= 0; machines
[i
] != NULL
; i
++) {
541 name
= machines
[i
]->name
;
545 if (col
+ len
> wincol
) {
549 col
+= fprintf(stderr
, "%s%s", prefix
, name
);
556 getfstype(ib_params
*param
, const char *fstype
, const char *provider
)
560 assert(param
!= NULL
);
561 assert(fstype
!= NULL
);
562 assert(provider
!= NULL
);
564 for (i
= 0; fstypes
[i
].name
!= NULL
; i
++) {
565 if (strcmp(fstypes
[i
].name
, fstype
) == 0) {
566 param
->fstype
= &fstypes
[i
];
570 warnx("Invalid file system type `%s' from %s", fstype
, provider
);
582 warnx("Supported file system types are:");
583 #define FSTYPES_PER_LINE 9
585 for (i
= 0; fstypes
[i
].name
!= NULL
; i
++) {
586 if (i
&& (i
% FSTYPES_PER_LINE
) == 0)
588 fprintf(stderr
, "%s%s", prefix
, fstypes
[i
].name
);
600 prog
= getprogname();
602 "usage: %s [-fnv] [-B s2bno] [-b s1bno] [-m machine] [-o options]\n"
603 "\t\t [-t fstype] filesystem primary [secondary]\n"
604 "usage: %s -c [-fnv] [-m machine] [-o options] [-t fstype] filesystem\n"
605 "usage: %s -e [-fnv] [-m machine] [-o options] bootstrap\n",