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