1 /* $NetBSD: installboot.c,v 1.9 2013/06/27 21:23:21 christos 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(void); 55 static void do_list(const char *); 56 static void do_remove(const char *, const char *); 57 static void do_install(const char *, const char *, const char *); 58 static int mipsvh_cksum(struct mips_volheader *); 59 static void read_volheader(const char *, struct mips_volheader *); 60 static void write_volheader(const char *, struct mips_volheader *); 61 static struct mips_voldir *voldir_findfile(struct mips_volheader *, 62 const char *, int); 63 64 int verbose, nowrite; 65 66 static void 67 usage(void) 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(const char *disk) 129 { 130 struct mips_volheader vh; 131 struct mips_voldir *vdp; 132 int i; 133 134 read_volheader(disk, &vh); 135 136 printf("Slot\t LBN\tLength\tFilename\n"); 137 printf("------------------------------------------\n"); 138 for (i=0, vdp=vh.vh_voldir; i<MIPS_NVOLDIR; i++, vdp++) 139 if (vdp->vd_len) 140 printf("%2d:\t%5d\t%6d\t%s\n", i, vdp->vd_lba, 141 vdp->vd_len, vdp->vd_name); 142 } 143 144 static void 145 do_remove(const char *disk, const char *filename) 146 { 147 struct mips_volheader vh; 148 struct mips_voldir *vdp; 149 150 read_volheader(disk, &vh); 151 vdp = voldir_findfile(&vh, filename, 0); 152 if (vdp == NULL) 153 FATAL("%s: file not found", disk); 154 155 memset(vdp, 0, sizeof(*vdp)); 156 157 /* Update volume header */ 158 write_volheader(disk, &vh); 159 } 160 161 static void 162 do_install(const char *disk, const char *bootstrap, const char *bootname) 163 { 164 struct stat bootstrapsb; 165 struct mips_volheader vh; 166 struct mips_voldir *vdp; 167 int fd; 168 char *boot_code; 169 size_t boot_size; 170 ssize_t len; 171 172 /* Open the input file and check it out */ 173 if ((fd = open(bootstrap, O_RDONLY)) == -1) 174 FATALIO("open %s", bootstrap); 175 if (fstat(fd, &bootstrapsb) == -1) 176 FATALIO("fstat %s", bootstrap); 177 if (!S_ISREG(bootstrapsb.st_mode)) 178 FATAL("%s must be a regular file", bootstrap); 179 180 boot_size = roundup(bootstrapsb.st_size, DEV_BSIZE); 181 182 if (boot_size > 8192-1024) 183 FATAL("bootstrap program too large (%d bytes)", boot_size); 184 185 boot_code = malloc(boot_size); 186 if (boot_code == NULL) 187 FATAL("malloc %d bytes failed", boot_size); 188 memset(boot_code, 0, boot_size); 189 190 /* read the file into the buffer */ 191 len = read(fd, boot_code, bootstrapsb.st_size); 192 if (len == -1) 193 FATALIO("read %s", bootstrap); 194 else if (len != bootstrapsb.st_size) 195 FATAL("read %s: short read", bootstrap); 196 (void)close(fd); 197 198 read_volheader(disk, &vh); 199 200 vdp = voldir_findfile(&vh, bootname, 1); 201 if (vdp == NULL) 202 FATAL("%s: volume directory full", disk); 203 204 strcpy(vdp->vd_name, bootname); 205 vdp->vd_lba = BOOTBLOCK_NUMBER; 206 vdp->vd_len = bootstrapsb.st_size; 207 208 if (nowrite) { 209 if (verbose) 210 fprintf(stderr, "not writing\n"); 211 return; 212 } 213 214 if (verbose) 215 fprintf(stderr, "writing bootstrap (%d bytes at logical block %d)\n", 216 boot_size, 2); 217 218 /* Write bootstrap */ 219 if ((fd = open(disk, O_WRONLY)) == -1) 220 FATALIO("open %s", bootstrap); 221 len = pwrite(fd, boot_code, boot_size, BOOTBLOCK_OFFSET); 222 free(boot_code); 223 if (len == -1) 224 FATAL("write %s", disk); 225 if (len != boot_size) 226 FATAL("write %s: short write", disk); 227 (void) close(fd); 228 229 /* Update volume header */ 230 write_volheader(disk, &vh); 231 } 232 233 static void 234 read_volheader(const char *disk, struct mips_volheader *vhp) 235 { 236 int vfd; 237 ssize_t len; 238 239 if ((vfd = open(disk, O_RDONLY)) == -1) 240 FATALIO("open %s", disk); 241 242 len = pread(vfd, vhp, sizeof(*vhp), MIPS_VHSECTOR*DEV_BSIZE); 243 244 (void) close(vfd); 245 246 if (len == -1) 247 FATALIO("read %s", disk); 248 if (len != sizeof(*vhp)) 249 FATAL("read %s: short read", disk); 250 251 /* Check volume header magic */ 252 if (vhp->vh_magic != MIPS_VHMAGIC) 253 FATAL("%s: no volume header", disk); 254 255 /* check volume header checksum */ 256 if (mipsvh_cksum(vhp)) 257 FATAL("%s: volume header corrupted", disk); 258 } 259 260 static void 261 write_volheader(const char *disk, struct mips_volheader *vhp) 262 { 263 int vfd; 264 ssize_t len; 265 266 /* update volume header checksum */ 267 vhp->vh_cksum = 0; 268 vhp->vh_cksum = -mipsvh_cksum(vhp); 269 270 if ((vfd = open(disk, O_WRONLY)) == -1) 271 FATALIO("open %s", disk); 272 273 if (verbose) 274 fprintf(stderr, "%s: writing volume header\n", disk); 275 276 len = pwrite(vfd, vhp, sizeof(*vhp), MIPS_VHSECTOR*512); /* XXX */ 277 if (len == -1) 278 FATALIO("write %s", disk); 279 if (len != sizeof(*vhp)) 280 FATAL("write %s: short write", disk); 281 282 (void) close(vfd); 283 } 284 285 /* 286 * Compute checksum for MIPS disk volume header 287 * 288 * Mips volume header checksum is the 32bit 2's complement sum 289 * of the entire volume header structure 290 */ 291 int 292 mipsvh_cksum(struct mips_volheader *vhp) 293 { 294 int i, *ptr; 295 int cksum = 0; 296 297 ptr = (int *)vhp; 298 i = sizeof(*vhp) / sizeof(*ptr); 299 while (i--) 300 cksum += *ptr++; 301 return cksum; 302 } 303 304 305 /* 306 * Locate the volume directory slot that matches a filename 307 * 308 * If the file entry cannot be found and create is non-zero the next 309 * empty slot is returned, otherwise return NULL 310 */ 311 static struct mips_voldir * 312 voldir_findfile(struct mips_volheader *vhp, const char *file, int create) 313 /* create: return unused entry if not found */ 314 { 315 struct mips_voldir *vdp = vhp->vh_voldir; 316 int i; 317 318 for (i=0; i<MIPS_NVOLDIR; i++, vdp++) { 319 if (strcmp(vdp->vd_name, file) == 0) 320 return vdp; 321 } 322 if (create) { 323 vdp = vhp->vh_voldir; 324 for (i=0; i<MIPS_NVOLDIR; i++, vdp++) 325 if (vdp->vd_len == 0) 326 return vdp; 327 } 328 return NULL; 329 } 330