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