1 /* $NetBSD: installboot.c,v 1.1 2000/09/26 10:00:19 wdk Exp $ */ 2 3 /* 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Wayne Knowles 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 <assert.h> 40 #include <err.h> 41 #include <fcntl.h> 42 #include <stdlib.h> 43 #include <stdio.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #include <sys/param.h> 48 #include <sys/stat.h> 49 #include <sys/disklabel.h> 50 51 52 #define VERBOSE(msg) if (verbose) \ 53 fprintf(stderr, msg) 54 #define FATAL(a1,a2) errx(EXIT_FAILURE, a1, a2) 55 #define FATALIO(a1,a2) err(EXIT_FAILURE, a1, a2) 56 57 #define BOOTBLOCK_NUMBER 2 58 #define BOOTBLOCK_OFFSET BOOTBLOCK_NUMBER*DEV_BSIZE 59 #define DEFAULT_BOOTFILE "boot" 60 61 static void usage __P((void)); 62 static void do_list __P((const char *)); 63 static void do_remove __P((const char *, const char *)); 64 static void do_install __P((const char *, const char *, const char *)); 65 static int mipsvh_cksum __P((struct mips_volheader *)); 66 static void read_volheader __P((const char *, struct mips_volheader *)); 67 static void write_volheader __P((const char *, struct mips_volheader *)); 68 static struct mips_voldir *voldir_findfile __P((struct mips_volheader *, 69 const char *, int)); 70 71 int verbose, nowrite; 72 73 static void 74 usage() 75 { 76 extern char *__progname; 77 78 fprintf(stderr, "usage:\n"); 79 fprintf(stderr, "\t%s [-nv] disk bootstrap [name]\n", __progname); 80 fprintf(stderr, "\t%s -r [-nv] disk [name]\n", __progname); 81 fprintf(stderr, "\t%s -l [-nv] disk\n", __progname); 82 exit(EXIT_FAILURE); 83 } 84 85 int 86 main(int argc, char *argv[]) 87 { 88 const char *disk; 89 int c, rflag, lflag; 90 91 rflag = lflag = verbose = nowrite = 0; 92 93 while ((c = getopt(argc, argv, "lnrv")) != -1) { 94 switch (c) { 95 case 'l': 96 /* List volume directory contents */ 97 lflag = 1; 98 break; 99 case 'n': 100 /* Disable write of boot sectors */ 101 nowrite = 1; 102 break; 103 case 'r': 104 /* Clear any existing boot block */ 105 rflag = 1; 106 break; 107 case 'v': 108 /* Verbose output */ 109 verbose = 1; 110 break; 111 default: 112 usage(); 113 } 114 } 115 116 argc -= optind; 117 argv += optind; 118 119 if ((lflag && rflag) || argc < 1 || (lflag && argc != 1) || 120 (rflag && argc > 3) || argc > 4) 121 usage(); 122 123 disk = argv[0]; 124 125 if (lflag) 126 do_list(disk); 127 else if (rflag) 128 do_remove(disk, argc==2?argv[1]:DEFAULT_BOOTFILE); 129 else 130 do_install(disk, argv[1], argc==3?argv[2]:DEFAULT_BOOTFILE); 131 132 exit(EXIT_SUCCESS); 133 } 134 135 static void 136 do_list(disk) 137 const char *disk; 138 { 139 struct mips_volheader vh; 140 struct mips_voldir *vdp; 141 int i; 142 143 read_volheader(disk, &vh); 144 145 printf("Slot\t LBN\tLength\tFilename\n"); 146 printf("------------------------------------------\n"); 147 for (i=0, vdp=vh.vh_voldir; i<MIPS_NVOLDIR; i++, vdp++) 148 if (vdp->vd_len) 149 printf("%2d:\t%5d\t%6d\t%s\n", i, vdp->vd_lba, 150 vdp->vd_len, vdp->vd_name); 151 } 152 153 static void 154 do_remove(disk, filename) 155 const char *disk; 156 const char *filename; 157 { 158 struct mips_volheader vh; 159 struct mips_voldir *vdp; 160 161 read_volheader(disk, &vh); 162 vdp = voldir_findfile(&vh, filename, 0); 163 if (vdp == NULL) 164 FATAL("%s: file not found", disk); 165 166 bzero(vdp, sizeof(*vdp)); 167 168 /* Update volume header */ 169 write_volheader(disk, &vh); 170 } 171 172 static void 173 do_install(disk, bootstrap, bootname) 174 const char *disk; 175 const char *bootstrap; 176 const char *bootname; 177 { 178 struct stat bootstrapsb; 179 struct mips_volheader vh; 180 struct mips_voldir *vdp; 181 int fd; 182 char *boot_code; 183 size_t boot_size; 184 ssize_t len; 185 186 /* Open the input file and check it out */ 187 if ((fd = open(bootstrap, O_RDONLY)) == -1) 188 FATALIO("open %s", bootstrap); 189 if (fstat(fd, &bootstrapsb) == -1) 190 FATALIO("fstat %s", bootstrap); 191 if (!S_ISREG(bootstrapsb.st_mode)) 192 FATAL("%s must be a regular file", bootstrap); 193 194 boot_size = roundup(bootstrapsb.st_size, DEV_BSIZE); 195 196 if (boot_size > 8192-1024) 197 FATAL("bootstrap program too large (%d bytes)", boot_size); 198 199 boot_code = malloc(boot_size); 200 if (boot_code == NULL) 201 FATAL("malloc %d bytes failed", boot_size); 202 bzero(boot_code, boot_size); 203 204 /* read the file into the buffer */ 205 len = read(fd, boot_code, bootstrapsb.st_size); 206 if (len == -1) 207 FATALIO("read %s", bootstrap); 208 else if (len != bootstrapsb.st_size) 209 FATAL("read %s: short read", bootstrap); 210 (void)close(fd); 211 212 read_volheader(disk, &vh); 213 214 vdp = voldir_findfile(&vh, bootname, 1); 215 if (vdp == NULL) 216 FATAL("%s: volume directory full", disk); 217 218 strcpy(vdp->vd_name, bootname); 219 vdp->vd_lba = BOOTBLOCK_NUMBER; 220 vdp->vd_len = bootstrapsb.st_size; 221 222 if (nowrite) { 223 if (verbose) 224 fprintf(stderr, "not writing\n"); 225 return; 226 } 227 228 if (verbose) 229 fprintf(stderr, "writing bootstrap (%d bytes at logical block %d)\n", 230 boot_size, 2); 231 232 /* Write bootstrap */ 233 if ((fd = open(disk, O_WRONLY)) == -1) 234 FATALIO("open %s", bootstrap); 235 len = pwrite(fd, boot_code, boot_size, BOOTBLOCK_OFFSET); 236 if (len == -1) 237 FATAL("write %s", disk); 238 if (len != boot_size) 239 FATAL("write %s: short write", disk); 240 (void) close(fd); 241 242 /* Update volume header */ 243 write_volheader(disk, &vh); 244 } 245 246 static void 247 read_volheader(disk, vhp) 248 const char *disk; 249 struct mips_volheader *vhp; 250 { 251 int vfd; 252 ssize_t len; 253 254 if ((vfd = open(disk, O_RDONLY)) == -1) 255 FATALIO("open %s", disk); 256 257 len = pread(vfd, vhp, sizeof(*vhp), MIPS_VHSECTOR*DEV_BSIZE); 258 259 (void) close(vfd); 260 261 if (len == -1) 262 FATALIO("read %s", disk); 263 if (len != sizeof(*vhp)) 264 FATAL("read %s: short read", disk); 265 266 /* Check volume header magic */ 267 if (vhp->vh_magic != MIPS_VHMAGIC) 268 FATAL("%s: no volume header", disk); 269 270 /* check volume header checksum */ 271 if (mipsvh_cksum(vhp)) 272 FATAL("%s: volume header corrupted", disk); 273 } 274 275 static void 276 write_volheader(disk, vhp) 277 const char *disk; 278 struct mips_volheader *vhp; 279 { 280 int vfd; 281 ssize_t len; 282 283 /* update volume header checksum */ 284 vhp->vh_cksum = 0; 285 vhp->vh_cksum = -mipsvh_cksum(vhp); 286 287 if ((vfd = open(disk, O_WRONLY)) == -1) 288 FATALIO("open %s", disk); 289 290 if (verbose) 291 fprintf(stderr, "%s: writing volume header\n", disk); 292 293 len = pwrite(vfd, vhp, sizeof(*vhp), MIPS_VHSECTOR*512); /* XXX */ 294 if (len == -1) 295 FATALIO("write %s", disk); 296 if (len != sizeof(*vhp)) 297 FATAL("write %s: short write", disk); 298 299 (void) close(vfd); 300 } 301 302 /* 303 * Compute checksum for MIPS disk volume header 304 * 305 * Mips volume header checksum is the 32bit 2's complement sum 306 * of the entire volume header structure 307 */ 308 int 309 mipsvh_cksum(vhp) 310 struct mips_volheader *vhp; 311 { 312 int i, *ptr; 313 int cksum = 0; 314 315 ptr = (int *)vhp; 316 i = sizeof(*vhp) / sizeof(*ptr); 317 while (i--) 318 cksum += *ptr++; 319 return cksum; 320 } 321 322 323 /* 324 * Locate the volume directory slot that matches a filename 325 * 326 * If the file entry cannot be found and create is non-zero the next 327 * empty slot is returned, otherwise return NULL 328 */ 329 static struct mips_voldir * 330 voldir_findfile(vhp, file, create) 331 struct mips_volheader *vhp; 332 const char *file; 333 int create; /* return unused entry if not found */ 334 { 335 struct mips_voldir *vdp = vhp->vh_voldir; 336 int i; 337 338 for (i=0; i<MIPS_NVOLDIR; i++, vdp++) { 339 if (strcmp(vdp->vd_name, file) == 0) 340 return vdp; 341 } 342 if (create) { 343 vdp = vhp->vh_voldir; 344 for (i=0; i<MIPS_NVOLDIR; i++, vdp++) 345 if (vdp->vd_len == 0) 346 return vdp; 347 } 348 return NULL; 349 } 350