installboot.c revision 1.4 1 1.4 mhitch /* $NetBSD: installboot.c,v 1.4 2006/08/04 02:21:19 mhitch 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.1 minoura if ((st.st_mode & S_IFCHR) == 0)
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.1 minoura if ((st.st_mode & S_IFCHR) == 0)
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.1 minoura if (dkcksum(lp) != 0)
163 1.1 minoura /* there is no valid label */
164 1.1 minoura memset(&label, 0, sizeof(struct disklabel));
165 1.1 minoura }
166 1.1 minoura
167 1.1 minoura return 0;
168 1.1 minoura }
169 1.1 minoura
170 1.1 minoura int
171 1.1 minoura main(int argc, char *argv[])
172 1.1 minoura {
173 1.1 minoura int c;
174 1.1 minoura int fd;
175 1.1 minoura
176 1.1 minoura progname = argv[0];
177 1.1 minoura
178 1.1 minoura while ((c = getopt(argc, argv, "nvf")) != -1) {
179 1.1 minoura switch (c) {
180 1.1 minoura case 'n':
181 1.1 minoura nflag = 1;
182 1.1 minoura break;
183 1.1 minoura case 'v':
184 1.1 minoura vflag = 1;
185 1.1 minoura break;
186 1.1 minoura case 'f':
187 1.1 minoura fflag = 1;
188 1.1 minoura break;
189 1.1 minoura default:
190 1.1 minoura usage();
191 1.1 minoura /* NOTREACHED */
192 1.1 minoura }
193 1.1 minoura }
194 1.1 minoura argc -= optind;
195 1.1 minoura argv += optind;
196 1.1 minoura
197 1.1 minoura if (argc != 2)
198 1.1 minoura usage();
199 1.1 minoura bootprog = argv[0];
200 1.1 minoura target = argv[1];
201 1.1 minoura
202 1.1 minoura if (checkbootprog(bootprog) < 0)
203 1.1 minoura errx(1, "aborting");
204 1.1 minoura if (checktargetdev(target) < 0)
205 1.1 minoura errx(1, "aborting");
206 1.1 minoura
207 1.1 minoura if (checkparttype(target, fflag))
208 1.1 minoura errx(1, "aborting");
209 1.3 minoura if (merging && blocksize > bboffset && !floppy)
210 1.1 minoura bboffset = blocksize;
211 1.1 minoura if (bootprogsize > MAXBBSIZE - bboffset)
212 1.1 minoura errx(1, "%s: boot block too big", bootprog);
213 1.1 minoura
214 1.1 minoura /* Read the boot program */
215 1.1 minoura fd = open(bootprog, O_RDONLY);
216 1.1 minoura if (fd < 0)
217 1.1 minoura err(1, "opening %s", bootprog);
218 1.1 minoura if (read(fd, bootblock + bboffset, bootprogsize) != bootprogsize)
219 1.1 minoura err(1, "reading %s", bootprog);
220 1.1 minoura close(fd);
221 1.1 minoura if (merging)
222 1.1 minoura memcpy(bootblock + LABELBYTEOFFSET, &label, sizeof(label));
223 1.1 minoura
224 1.1 minoura /* Write the boot block (+ disklabel if necessary) */
225 1.1 minoura if (nflag) {
226 1.1 minoura target = template;
227 1.1 minoura
228 1.1 minoura fd = mkstemp(target);
229 1.1 minoura if (fd < 0)
230 1.1 minoura err(1, "opening the output file");
231 1.1 minoura } else {
232 1.1 minoura int writable = 1;
233 1.1 minoura
234 1.1 minoura fd = open(target, O_WRONLY);
235 1.1 minoura if (fd < 0)
236 1.1 minoura err(1, "opening the disk");
237 1.1 minoura if (merging && ioctl(fd, DIOCWLABEL, &writable) < 0)
238 1.1 minoura err(1, "opening the disk");
239 1.1 minoura }
240 1.1 minoura bootprogsize = howmany(bootprogsize+bboffset, blocksize) * blocksize;
241 1.1 minoura if (write(fd, bootblock, bootprogsize) != bootprogsize) {
242 1.1 minoura warn("writing the label");
243 1.1 minoura if (!nflag && merging) {
244 1.1 minoura int writable = 0;
245 1.1 minoura ioctl(fd, DIOCWLABEL, &writable);
246 1.1 minoura }
247 1.1 minoura exit(1);
248 1.1 minoura }
249 1.1 minoura
250 1.1 minoura if (!nflag && merging) {
251 1.1 minoura int writable = 0;
252 1.1 minoura ioctl(fd, DIOCWLABEL, &writable);
253 1.1 minoura }
254 1.1 minoura close(fd);
255 1.1 minoura
256 1.1 minoura if (nflag)
257 1.1 minoura fprintf(stderr, "The bootblock is kept in %s\n", target);
258 1.1 minoura else
259 1.1 minoura fprintf(stderr, "Do not forget to copy /usr/mdec/boot"
260 1.1 minoura " to the root directory of %s.\n", target);
261 1.1 minoura
262 1.1 minoura return 0;
263 1.1 minoura }
264