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