1 1.6 tsutsui /* $NetBSD: installboot.c,v 1.6 2012/10/14 16:20:04 tsutsui Exp $ */ 2 1.1 minoura 3 1.1 minoura /* 4 1.1 minoura * Copyright (c) 2001 Minoura Makoto 5 1.1 minoura * All rights reserved. 6 1.1 minoura * 7 1.1 minoura * Redistribution and use in source and binary forms, with or without 8 1.1 minoura * modification, are permitted provided that the following conditions 9 1.1 minoura * are met: 10 1.1 minoura * 1. Redistributions of source code must retain the above copyright 11 1.1 minoura * notice, this list of conditions and the following disclaimer. 12 1.1 minoura * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 minoura * notice, this list of conditions and the following disclaimer in the 14 1.1 minoura * documentation and/or other materials provided with the distribution. 15 1.1 minoura * 16 1.1 minoura * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.1 minoura * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 minoura * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 minoura * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 minoura * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 minoura * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 minoura * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 minoura * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 minoura * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 minoura * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 minoura * SUCH DAMAGE. 27 1.1 minoura */ 28 1.1 minoura 29 1.1 minoura #include <stdio.h> 30 1.1 minoura #include <stdlib.h> 31 1.1 minoura #include <string.h> 32 1.1 minoura #include <unistd.h> 33 1.1 minoura #include <fcntl.h> 34 1.1 minoura #include <paths.h> 35 1.1 minoura #include <err.h> 36 1.1 minoura #include <sys/param.h> 37 1.1 minoura #include <sys/disklabel.h> 38 1.1 minoura #include <sys/ioctl.h> 39 1.1 minoura #include <sys/stat.h> 40 1.1 minoura #include <ufs/ufs/dinode.h> 41 1.1 minoura #include <ufs/ffs/fs.h> 42 1.1 minoura 43 1.1 minoura #include "dkcksum.h" 44 1.1 minoura 45 1.1 minoura #define MAXBBSIZE BBSIZE 46 1.1 minoura #define LABELBYTEOFFSET (LABELSECTOR*512+LABELOFFSET) 47 1.1 minoura 48 1.1 minoura int nflag = 0, vflag = 0, fflag = 0, merging = 0; 49 1.1 minoura int floppy = 0; 50 1.1 minoura char rawname[PATH_MAX]; 51 1.1 minoura off_t bboffset = 0; 52 1.1 minoura size_t bootprogsize; 53 1.1 minoura size_t blocksize; 54 1.1 minoura const char *progname; 55 1.1 minoura const char *bootprog; 56 1.1 minoura char *target; 57 1.1 minoura char template[] = _PATH_TMP "/installbootXXXXXX"; 58 1.1 minoura u_int8_t bootblock[MAXBBSIZE]; 59 1.1 minoura struct disklabel label; 60 1.1 minoura 61 1.1 minoura void usage(void) __attribute((__noreturn__)); 62 1.1 minoura int checkbootprog(const char *); 63 1.1 minoura int checktargetdev(const char *); 64 1.1 minoura int checkparttype(const char *, int); 65 1.1 minoura 66 1.1 minoura void 67 1.1 minoura usage(void) 68 1.1 minoura { 69 1.1 minoura fprintf(stderr, "usage: %s [-nvf] /usr/mdec/xxboot_ufs /dev/rxx?a\n", 70 1.1 minoura progname); 71 1.1 minoura exit(1); 72 1.1 minoura /* NOTREACHED */ 73 1.1 minoura } 74 1.1 minoura 75 1.1 minoura int 76 1.1 minoura checkbootprog(const char *name) 77 1.1 minoura { 78 1.1 minoura struct stat st; 79 1.1 minoura 80 1.1 minoura if (access(name, R_OK) < 0) 81 1.1 minoura err(1, "%s", name); 82 1.1 minoura if (stat(name, &st) < 0) 83 1.1 minoura err(1, "%s", name); 84 1.1 minoura bootprogsize = st.st_size; 85 1.1 minoura 86 1.1 minoura return 0; 87 1.1 minoura } 88 1.1 minoura 89 1.1 minoura int 90 1.1 minoura checktargetdev(const char *name) 91 1.1 minoura { 92 1.1 minoura struct stat st; 93 1.1 minoura 94 1.1 minoura if (access(name, W_OK) < 0) 95 1.1 minoura err(1, "%s", name); 96 1.1 minoura if (stat(name, &st) < 0) 97 1.1 minoura err(1, "%s", name); 98 1.5 pavel if (!S_ISCHR(st.st_mode)) 99 1.1 minoura errx(1, "%s: not a character special device", name); 100 1.1 minoura if (DISKPART(st.st_rdev) > MAXPARTITIONS) 101 1.1 minoura errx(1, "%s: invalid device", name); 102 1.1 minoura strcpy(rawname, name); 103 1.2 minoura if (strncmp(name + strlen(name) - 4, "fd", 2) == 0) 104 1.1 minoura floppy = 1; 105 1.2 minoura else 106 1.1 minoura rawname[strlen(name) - 1] = RAW_PART+'a'; 107 1.1 minoura if (!floppy && DISKPART(st.st_rdev) == RAW_PART) 108 1.1 minoura errx(1, "%s is the raw device", name); 109 1.1 minoura 110 1.1 minoura return 0; 111 1.1 minoura } 112 1.1 minoura 113 1.1 minoura int 114 1.1 minoura checkparttype(const char *name, int force) 115 1.1 minoura { 116 1.1 minoura struct stat st; 117 1.1 minoura int fd, part; 118 1.1 minoura 119 1.1 minoura fd = open(rawname, O_RDONLY | O_EXLOCK); 120 1.1 minoura if (fd < 0) 121 1.1 minoura err(1, "opening %s", name); 122 1.1 minoura if (stat(name, &st) < 0) 123 1.1 minoura err(1, "%s", name); 124 1.5 pavel if (!S_ISCHR(st.st_mode)) 125 1.1 minoura errx(1, "%s: not a character special device", name); 126 1.1 minoura part = DISKPART(st.st_rdev); 127 1.1 minoura if (ioctl(fd, DIOCGDINFO, &label) < 0) 128 1.1 minoura err(1, "%s: reading disklabel", name); 129 1.1 minoura if (part >= label.d_npartitions) 130 1.1 minoura errx(1, "%s: invalid partition", name); 131 1.1 minoura blocksize = label.d_secsize; 132 1.1 minoura if (blocksize < 512) 133 1.1 minoura blocksize = 512; 134 1.1 minoura if (blocksize > MAXBBSIZE) 135 1.1 minoura errx(1, "%s: blocksize too large", name); 136 1.1 minoura if (read(fd, bootblock, blocksize) != blocksize) 137 1.1 minoura errx(1, "%s: reading the mark", name); 138 1.1 minoura close(fd); 139 1.4 mhitch if (strncmp((const char *)bootblock, "X68SCSI1", 8) != 0) 140 1.1 minoura floppy = 1; /* XXX: or unformated */ 141 1.1 minoura 142 1.1 minoura if (!force && !floppy) { 143 1.1 minoura if (label.d_partitions[part].p_fstype != FS_BSDFFS 144 1.1 minoura && label.d_partitions[part].p_fstype != FS_BSDLFS) 145 1.1 minoura errx(1, "%s: invalid partition type", name); 146 1.1 minoura if ((label.d_partitions[part].p_offset * blocksize < 32768) && 147 1.1 minoura label.d_partitions[part].p_offset != 0) 148 1.1 minoura errx(1, "%s: cannot make the partition bootable", 149 1.1 minoura name); 150 1.1 minoura } 151 1.1 minoura if (floppy) 152 1.1 minoura merging = 1; 153 1.1 minoura else if (label.d_partitions[part].p_offset == 0) { 154 1.1 minoura merging = 1; 155 1.1 minoura bboffset = 1024; /* adjusted below */ 156 1.1 minoura } 157 1.1 minoura if (merging) { 158 1.1 minoura struct disklabel *lp; 159 1.1 minoura 160 1.1 minoura lp = (struct disklabel *) &bootblock[LABELBYTEOFFSET]; 161 1.1 minoura memcpy(&label, lp, sizeof(struct disklabel)); 162 1.6 tsutsui if (lp->d_npartitions > MAXPARTITIONS || 163 1.6 tsutsui dkcksum(lp) != 0) 164 1.1 minoura /* there is no valid label */ 165 1.1 minoura memset(&label, 0, sizeof(struct disklabel)); 166 1.1 minoura } 167 1.1 minoura 168 1.1 minoura return 0; 169 1.1 minoura } 170 1.1 minoura 171 1.1 minoura int 172 1.1 minoura main(int argc, char *argv[]) 173 1.1 minoura { 174 1.1 minoura int c; 175 1.1 minoura int fd; 176 1.1 minoura 177 1.1 minoura progname = argv[0]; 178 1.1 minoura 179 1.1 minoura while ((c = getopt(argc, argv, "nvf")) != -1) { 180 1.1 minoura switch (c) { 181 1.1 minoura case 'n': 182 1.1 minoura nflag = 1; 183 1.1 minoura break; 184 1.1 minoura case 'v': 185 1.1 minoura vflag = 1; 186 1.1 minoura break; 187 1.1 minoura case 'f': 188 1.1 minoura fflag = 1; 189 1.1 minoura break; 190 1.1 minoura default: 191 1.1 minoura usage(); 192 1.1 minoura /* NOTREACHED */ 193 1.1 minoura } 194 1.1 minoura } 195 1.1 minoura argc -= optind; 196 1.1 minoura argv += optind; 197 1.1 minoura 198 1.1 minoura if (argc != 2) 199 1.1 minoura usage(); 200 1.1 minoura bootprog = argv[0]; 201 1.1 minoura target = argv[1]; 202 1.1 minoura 203 1.1 minoura if (checkbootprog(bootprog) < 0) 204 1.1 minoura errx(1, "aborting"); 205 1.1 minoura if (checktargetdev(target) < 0) 206 1.1 minoura errx(1, "aborting"); 207 1.1 minoura 208 1.1 minoura if (checkparttype(target, fflag)) 209 1.1 minoura errx(1, "aborting"); 210 1.3 minoura if (merging && blocksize > bboffset && !floppy) 211 1.1 minoura bboffset = blocksize; 212 1.1 minoura if (bootprogsize > MAXBBSIZE - bboffset) 213 1.1 minoura errx(1, "%s: boot block too big", bootprog); 214 1.1 minoura 215 1.1 minoura /* Read the boot program */ 216 1.1 minoura fd = open(bootprog, O_RDONLY); 217 1.1 minoura if (fd < 0) 218 1.1 minoura err(1, "opening %s", bootprog); 219 1.1 minoura if (read(fd, bootblock + bboffset, bootprogsize) != bootprogsize) 220 1.1 minoura err(1, "reading %s", bootprog); 221 1.1 minoura close(fd); 222 1.1 minoura if (merging) 223 1.1 minoura memcpy(bootblock + LABELBYTEOFFSET, &label, sizeof(label)); 224 1.1 minoura 225 1.1 minoura /* Write the boot block (+ disklabel if necessary) */ 226 1.1 minoura if (nflag) { 227 1.1 minoura target = template; 228 1.1 minoura 229 1.1 minoura fd = mkstemp(target); 230 1.1 minoura if (fd < 0) 231 1.1 minoura err(1, "opening the output file"); 232 1.1 minoura } else { 233 1.1 minoura int writable = 1; 234 1.1 minoura 235 1.1 minoura fd = open(target, O_WRONLY); 236 1.1 minoura if (fd < 0) 237 1.1 minoura err(1, "opening the disk"); 238 1.1 minoura if (merging && ioctl(fd, DIOCWLABEL, &writable) < 0) 239 1.1 minoura err(1, "opening the disk"); 240 1.1 minoura } 241 1.1 minoura bootprogsize = howmany(bootprogsize+bboffset, blocksize) * blocksize; 242 1.1 minoura if (write(fd, bootblock, bootprogsize) != bootprogsize) { 243 1.1 minoura warn("writing the label"); 244 1.1 minoura if (!nflag && merging) { 245 1.1 minoura int writable = 0; 246 1.1 minoura ioctl(fd, DIOCWLABEL, &writable); 247 1.1 minoura } 248 1.1 minoura exit(1); 249 1.1 minoura } 250 1.1 minoura 251 1.1 minoura if (!nflag && merging) { 252 1.1 minoura int writable = 0; 253 1.1 minoura ioctl(fd, DIOCWLABEL, &writable); 254 1.1 minoura } 255 1.1 minoura close(fd); 256 1.1 minoura 257 1.1 minoura if (nflag) 258 1.1 minoura fprintf(stderr, "The bootblock is kept in %s\n", target); 259 1.1 minoura else 260 1.1 minoura fprintf(stderr, "Do not forget to copy /usr/mdec/boot" 261 1.1 minoura " to the root directory of %s.\n", target); 262 1.1 minoura 263 1.1 minoura return 0; 264 1.1 minoura } 265