1/* $NetBSD: installboot.c,v 1.5 2006/09/23 20:10:14 pavel 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 48int nflag = 0, vflag = 0, fflag = 0, merging = 0; 49int floppy = 0; 50char rawname[PATH_MAX]; 51off_t bboffset = 0; 52size_t bootprogsize; 53size_t blocksize; 54const char *progname; 55const char *bootprog; 56char *target; 57char template[] = _PATH_TMP "/installbootXXXXXX"; 58u_int8_t bootblock[MAXBBSIZE]; 59struct disklabel label; 60 61void usage(void) __attribute((__noreturn__)); 62int checkbootprog(const char *); 63int checktargetdev(const char *); 64int checkparttype(const char *, int); 65 66void 67usage(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 75int 76checkbootprog(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 89int 90checktargetdev(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 (!S_ISCHR(st.st_mode)) 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 113int 114checkparttype(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 (!S_ISCHR(st.st_mode)) 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((const char *)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 (lp->d_npartitions > MAXPARTITIONS || 163 dkcksum(lp) != 0) 164 /* there is no valid label */ 165 memset(&label, 0, sizeof(struct disklabel)); 166 } 167 168 return 0; 169} 170 171int 172main(int argc, char *argv[]) 173{ 174 int c; 175 int fd; 176 177 progname = argv[0]; 178 179 while ((c = getopt(argc, argv, "nvf")) != -1) { 180 switch (c) { 181 case 'n': 182 nflag = 1; 183 break; 184 case 'v': 185 vflag = 1; 186 break; 187 case 'f': 188 fflag = 1; 189 break; 190 default: 191 usage(); 192 /* NOTREACHED */ 193 } 194 } 195 argc -= optind; 196 argv += optind; 197 198 if (argc != 2) 199 usage(); 200 bootprog = argv[0]; 201 target = argv[1]; 202 203 if (checkbootprog(bootprog) < 0) 204 errx(1, "aborting"); 205 if (checktargetdev(target) < 0) 206 errx(1, "aborting"); 207 208 if (checkparttype(target, fflag)) 209 errx(1, "aborting"); 210 if (merging && blocksize > bboffset && !floppy) 211 bboffset = blocksize; 212 if (bootprogsize > MAXBBSIZE - bboffset) 213 errx(1, "%s: boot block too big", bootprog); 214 215 /* Read the boot program */ 216 fd = open(bootprog, O_RDONLY); 217 if (fd < 0) 218 err(1, "opening %s", bootprog); 219 if (read(fd, bootblock + bboffset, bootprogsize) != bootprogsize) 220 err(1, "reading %s", bootprog); 221 close(fd); 222 if (merging) 223 memcpy(bootblock + LABELBYTEOFFSET, &label, sizeof(label)); 224 225 /* Write the boot block (+ disklabel if necessary) */ 226 if (nflag) { 227 target = template; 228 229 fd = mkstemp(target); 230 if (fd < 0) 231 err(1, "opening the output file"); 232 } else { 233 int writable = 1; 234 235 fd = open(target, O_WRONLY); 236 if (fd < 0) 237 err(1, "opening the disk"); 238 if (merging && ioctl(fd, DIOCWLABEL, &writable) < 0) 239 err(1, "opening the disk"); 240 } 241 bootprogsize = howmany(bootprogsize+bboffset, blocksize) * blocksize; 242 if (write(fd, bootblock, bootprogsize) != bootprogsize) { 243 warn("writing the label"); 244 if (!nflag && merging) { 245 int writable = 0; 246 ioctl(fd, DIOCWLABEL, &writable); 247 } 248 exit(1); 249 } 250 251 if (!nflag && merging) { 252 int writable = 0; 253 ioctl(fd, DIOCWLABEL, &writable); 254 } 255 close(fd); 256 257 if (nflag) 258 fprintf(stderr, "The bootblock is kept in %s\n", target); 259 else 260 fprintf(stderr, "Do not forget to copy /usr/mdec/boot" 261 " to the root directory of %s.\n", target); 262 263 return 0; 264} 265