1 /* $NetBSD: installboot.c,v 1.10 2002/05/20 14:38:38 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.10 2002/05/20 14:38:38 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 const char *prefix; 314 int i; 315 316 if (param != NULL && mach != NULL && provider != NULL) { 317 for (i = 0; machines[i].name != NULL; i++) { 318 if (strcmp(machines[i].name, mach) == 0) { 319 param->machine = &machines[i]; 320 return (1); 321 } 322 } 323 warnx("Invalid machine `%s' from %s", mach, provider); 324 } 325 warnx("Supported machines are:"); 326 #define MACHS_PER_LINE 9 327 prefix=""; 328 for (i = 0; machines[i].name != NULL; i++) { 329 if (i == 0) 330 prefix="\t"; 331 else if (i % MACHS_PER_LINE) 332 prefix=", "; 333 else 334 prefix=",\n\t"; 335 fprintf(stderr, "%s%s", prefix, machines[i].name); 336 } 337 fputs("\n", stderr); 338 return (0); 339 } 340 341 static int 342 getfstype(ib_params *param, const char *fstype, const char *provider) 343 { 344 const char *prefix; 345 int i; 346 347 if (param != NULL && fstype != NULL && provider != NULL) { 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", 355 fstype, provider); 356 } 357 warnx("Supported file system types are:"); 358 #define FSTYPES_PER_LINE 9 359 prefix=""; 360 for (i = 0; fstypes[i].name != NULL; i++) { 361 if (i == 0) 362 prefix="\t"; 363 else if (i % FSTYPES_PER_LINE) 364 prefix=", "; 365 else 366 prefix=",\n\t"; 367 fprintf(stderr, "%s%s", prefix, fstypes[i].name); 368 } 369 fputs("\n", stderr); 370 return (0); 371 } 372 373 static void 374 usage(void) 375 { 376 const char *prog; 377 378 prog = getprogname(); 379 fprintf(stderr, 380 "Usage: %s [-nv] [-m machine] [-o options] [-t fstype]\n" 381 "\t\t [-b s1start] [-B s2start] filesystem primary [secondary]\n" 382 "Usage: %s -c [-nv] [-m machine] [-o options] [-t fstype] filesystem\n", 383 prog, prog); 384 getmachine(NULL, NULL, NULL); 385 getfstype(NULL, NULL, NULL); 386 exit(1); 387 } 388