1 /* $NetBSD: installboot.c,v 1.7 2002/04/30 14:21:17 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.7 2002/04/30 14:21:17 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 <stdint.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <unistd.h> 55 56 #include "installboot.h" 57 58 int main(int, char *[]); 59 static int getmachine(ib_params *, const char *, const char *); 60 static int getfstype(ib_params *, const char *, const char *); 61 static void usage(void); 62 63 static ib_params installboot_params; 64 65 int 66 main(int argc, char *argv[]) 67 { 68 struct utsname utsname; 69 ib_params *params; 70 unsigned long lval; 71 int ch, rv, mode; 72 char *p; 73 const char *op; 74 75 setprogname(argv[0]); 76 params = &installboot_params; 77 memset(params, 0, sizeof(*params)); 78 if ((p = getenv("MACHINE")) != NULL) 79 if (! getmachine(params, p, "$MACHINE")) 80 exit(1); 81 82 while ((ch = getopt(argc, argv, "b:cm:no:t:v")) != -1) { 83 switch (ch) { 84 85 case 'b': 86 if (*optarg == '\0') 87 goto badblock; 88 lval = strtoul(optarg, &p, 0); 89 if (lval > UINT32_MAX || *p != '\0') { 90 badblock: 91 errx(1, "Invalid block number `%s'", optarg); 92 } 93 params->startblock = (uint32_t)lval; 94 params->flags |= IB_STARTBLOCK; 95 break; 96 97 case 'c': 98 params->flags |= IB_CLEAR; 99 break; 100 101 case 'm': 102 if (! getmachine(params, optarg, "-m")) 103 exit(1); 104 break; 105 106 case 'n': 107 params->flags |= IB_NOWRITE; 108 break; 109 110 case 'o': 111 if (params->machine == NULL) 112 errx(1, 113 "Machine needs to be specified before -o"); 114 while ((p = strsep(&optarg, ",")) != NULL) { 115 if (*p == '\0') 116 errx(1, "Empty `-o' option"); 117 if (! params->machine->parseopt(params, p)) 118 exit(1); 119 } 120 break; 121 122 case 't': 123 if (! getfstype(params, optarg, "-t")) 124 exit(1); 125 break; 126 127 case 'v': 128 params->flags |= IB_VERBOSE; 129 break; 130 131 case '?': 132 default: 133 usage(); 134 /* NOTREACHED */ 135 136 } 137 } 138 argc -= optind; 139 argv += optind; 140 141 if (((params->flags & IB_CLEAR) != 0 && argc != 1) || 142 ((params->flags & IB_CLEAR) == 0 && (argc < 2 || argc > 3))) 143 usage(); 144 145 /* set missing defaults */ 146 if (params->machine == NULL) { 147 if (uname(&utsname) == -1) 148 err(1, "Determine uname"); 149 if (! getmachine(params, utsname.machine, "uname()")) 150 exit(1); 151 } 152 153 params->filesystem = argv[0]; 154 if (params->flags & IB_NOWRITE) { 155 op = "only"; 156 mode = O_RDONLY; 157 } else { 158 op = "write"; 159 mode = O_RDWR; 160 } 161 if ((params->fsfd = open(params->filesystem, mode, 0600)) == -1) 162 err(1, "Opening file system `%s' read-%s", 163 params->filesystem, op); 164 if (params->fstype != NULL) { 165 if (! params->fstype->match(params)) 166 err(1, "File system `%s' is not of type %s", 167 params->filesystem, params->fstype->name); 168 } else { 169 params->fstype = &fstypes[0]; 170 while (params->fstype->name != NULL && 171 ! params->fstype->match(params)) 172 params->fstype++; 173 if (params->fstype->name == NULL) 174 errx(1, "File system `%s' is of an unknown type", 175 params->filesystem); 176 } 177 178 if (argc >= 2) { 179 params->stage1 = argv[1]; 180 if ((params->s1fd = open(params->stage1, O_RDONLY, 0600)) 181 == -1) 182 err(1, "Opening primary bootstrap `%s'", 183 params->stage1); 184 } 185 if (argc == 3) { 186 params->stage2 = argv[2]; 187 } 188 assert(params->machine != NULL); 189 190 if (params->flags & IB_VERBOSE) { 191 printf("File system: %s\n", params->filesystem); 192 printf("Primary bootstrap: %s\n", 193 (params->flags & IB_CLEAR) ? "(to be cleared)" 194 : params->stage1); 195 if (params->stage2 != NULL) 196 printf("Secondary bootstrap: %s\n", params->stage2); 197 } 198 199 if (params->flags & IB_CLEAR) { 200 op = "Clear"; 201 rv = params->machine->clearboot(params); 202 } else { 203 op = "Set"; 204 rv = params->machine->setboot(params); 205 } 206 if (rv == 0) 207 errx(1, "%s bootstrap operation failed", op); 208 209 if (fsync(params->fsfd) == -1) 210 err(1, "Synchronising file system `%s'", params->filesystem); 211 if (close(params->fsfd) == -1) 212 err(1, "Closing file system `%s'", params->filesystem); 213 if (argc == 2) 214 if (close(params->s1fd) == -1) 215 err(1, "Closing primary bootstrap `%s'", 216 params->stage1); 217 218 exit(0); 219 /* NOTREACHED */ 220 } 221 222 int 223 parseoptionflag(ib_params *params, const char *option, ib_flags wantflags) 224 { 225 struct { 226 const char *name; 227 ib_flags flag; 228 } flags[] = { 229 { "alphasum", IB_ALPHASUM }, 230 { "append", IB_APPEND }, 231 { "sunsum", IB_SUNSUM }, 232 { NULL, 0 }, 233 }; 234 235 int i; 236 237 assert(params != NULL); 238 assert(option != NULL); 239 240 for (i = 0; flags[i].name != NULL; i++) { 241 if ((strcmp(flags[i].name, option) == 0) && 242 (wantflags & flags[i].flag)) { 243 params->flags |= flags[i].flag; 244 return (1); 245 } 246 } 247 return (0); 248 } 249 250 int 251 no_parseopt(ib_params *params, const char *option) 252 { 253 254 assert(params != NULL); 255 assert(option != NULL); 256 257 /* all options are unsupported */ 258 warnx("Unsupported -o option `%s'", option); 259 return (0); 260 } 261 262 int 263 no_setboot(ib_params *params) 264 { 265 266 assert(params != NULL); 267 268 /* bootstrap installation is not supported */ 269 warnx("%s: bootstrap installation is not supported", 270 params->machine->name); 271 return (0); 272 } 273 274 int 275 no_clearboot(ib_params *params) 276 { 277 278 assert(params != NULL); 279 280 /* bootstrap removal is not supported */ 281 warnx("%s: bootstrap removal is not supported", 282 params->machine->name); 283 return (0); 284 } 285 286 287 static int 288 getmachine(ib_params *param, const char *mach, const char *provider) 289 { 290 int i; 291 292 assert(param != NULL); 293 assert(mach != NULL); 294 assert(provider != NULL); 295 296 for (i = 0; machines[i].name != NULL; i++) { 297 if (strcmp(machines[i].name, mach) == 0) { 298 param->machine = &machines[i]; 299 return (1); 300 } 301 } 302 warnx("Invalid machine `%s' from %s", mach, provider); 303 warnx("Supported machines are:"); 304 #define MACHS_PER_LINE 10 305 for (i = 0; machines[i].name != NULL; i++) { 306 fputs((i % MACHS_PER_LINE) ? ", " : "\t", stderr); 307 fputs(machines[i].name, stderr); 308 if ((i % MACHS_PER_LINE) == (MACHS_PER_LINE - 1)) 309 fputs("\n", stderr); 310 } 311 if ((i % MACHS_PER_LINE) != 0) 312 fputs("\n", stderr); 313 return (0); 314 } 315 316 static int 317 getfstype(ib_params *param, const char *fstype, const char *provider) 318 { 319 int i; 320 321 assert(param != NULL); 322 assert(fstype != NULL); 323 assert(provider != NULL); 324 325 for (i = 0; fstypes[i].name != NULL; i++) { 326 if (strcmp(fstypes[i].name, fstype) == 0) { 327 param->fstype = &fstypes[i]; 328 return (1); 329 } 330 } 331 warnx("Invalid file system type `%s' from %s", fstype, provider); 332 warnx("Supported file system types are:"); 333 #define FSTYPES_PER_LINE 10 334 for (i = 0; fstypes[i].name != NULL; i++) { 335 fputs((i % FSTYPES_PER_LINE) ? ", " : "\t", stderr); 336 fputs(fstypes[i].name, stderr); 337 if ((i % FSTYPES_PER_LINE) == (FSTYPES_PER_LINE - 1)) 338 fputs("\n", stderr); 339 } 340 if ((i % FSTYPES_PER_LINE) != 0) 341 fputs("\n", stderr); 342 return (0); 343 } 344 345 static void 346 usage(void) 347 { 348 const char *prog; 349 350 prog = getprogname(); 351 fprintf(stderr, 352 "Usage: %s [-nv] [-m machine] [-o options] [-t fstype]\n" 353 "\t\t [-b block] filesystem primary [secondary]\n" 354 "Usage: %s -c [-nv] [-m machine] [-o options] [-t fstype] filesystem\n", 355 prog, prog); 356 exit(1); 357 } 358