1 /* $NetBSD: installboot.c,v 1.10 2016/01/21 16:58:36 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 free(boot_code); 212 return; 213 } 214 215 if (verbose) 216 fprintf(stderr, "writing bootstrap (%d bytes at logical block %d)\n", 217 boot_size, 2); 218 219 /* Write bootstrap */ 220 if ((fd = open(disk, O_WRONLY)) == -1) 221 FATALIO("open %s", bootstrap); 222 len = pwrite(fd, boot_code, boot_size, BOOTBLOCK_OFFSET); 223 free(boot_code); 224 if (len == -1) 225 FATAL("write %s", disk); 226 if (len != boot_size) 227 FATAL("write %s: short write", disk); 228 (void) close(fd); 229 230 /* Update volume header */ 231 write_volheader(disk, &vh); 232 } 233 234 static void 235 read_volheader(const char *disk, struct mips_volheader *vhp) 236 { 237 int vfd; 238 ssize_t len; 239 240 if ((vfd = open(disk, O_RDONLY)) == -1) 241 FATALIO("open %s", disk); 242 243 len = pread(vfd, vhp, sizeof(*vhp), MIPS_VHSECTOR*DEV_BSIZE); 244 245 (void) close(vfd); 246 247 if (len == -1) 248 FATALIO("read %s", disk); 249 if (len != sizeof(*vhp)) 250 FATAL("read %s: short read", disk); 251 252 /* Check volume header magic */ 253 if (vhp->vh_magic != MIPS_VHMAGIC) 254 FATAL("%s: no volume header", disk); 255 256 /* check volume header checksum */ 257 if (mipsvh_cksum(vhp)) 258 FATAL("%s: volume header corrupted", disk); 259 } 260 261 static void 262 write_volheader(const char *disk, struct mips_volheader *vhp) 263 { 264 int vfd; 265 ssize_t len; 266 267 /* update volume header checksum */ 268 vhp->vh_cksum = 0; 269 vhp->vh_cksum = -mipsvh_cksum(vhp); 270 271 if ((vfd = open(disk, O_WRONLY)) == -1) 272 FATALIO("open %s", disk); 273 274 if (verbose) 275 fprintf(stderr, "%s: writing volume header\n", disk); 276 277 len = pwrite(vfd, vhp, sizeof(*vhp), MIPS_VHSECTOR*512); /* XXX */ 278 if (len == -1) 279 FATALIO("write %s", disk); 280 if (len != sizeof(*vhp)) 281 FATAL("write %s: short write", disk); 282 283 (void) close(vfd); 284 } 285 286 /* 287 * Compute checksum for MIPS disk volume header 288 * 289 * Mips volume header checksum is the 32bit 2's complement sum 290 * of the entire volume header structure 291 */ 292 int 293 mipsvh_cksum(struct mips_volheader *vhp) 294 { 295 int i, *ptr; 296 int cksum = 0; 297 298 ptr = (int *)vhp; 299 i = sizeof(*vhp) / sizeof(*ptr); 300 while (i--) 301 cksum += *ptr++; 302 return cksum; 303 } 304 305 306 /* 307 * Locate the volume directory slot that matches a filename 308 * 309 * If the file entry cannot be found and create is non-zero the next 310 * empty slot is returned, otherwise return NULL 311 */ 312 static struct mips_voldir * 313 voldir_findfile(struct mips_volheader *vhp, const char *file, int create) 314 /* create: return unused entry if not found */ 315 { 316 struct mips_voldir *vdp = vhp->vh_voldir; 317 int i; 318 319 for (i=0; i<MIPS_NVOLDIR; i++, vdp++) { 320 if (strcmp(vdp->vd_name, file) == 0) 321 return vdp; 322 } 323 if (create) { 324 vdp = vhp->vh_voldir; 325 for (i=0; i<MIPS_NVOLDIR; i++, vdp++) 326 if (vdp->vd_len == 0) 327 return vdp; 328 } 329 return NULL; 330 } 331