installboot.c revision 1.1 1 1.1 minoura /* $NetBSD: installboot.c,v 1.1 2001/11/24 16:26:56 minoura 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 #if 0
79 1.1 minoura struct stat st;
80 1.1 minoura
81 1.1 minoura if (access(name, R_OK) < 0)
82 1.1 minoura err(1, "%s", name);
83 1.1 minoura if (stat(name, &st) < 0)
84 1.1 minoura err(1, "%s", name);
85 1.1 minoura bootprogsize = st.st_size;
86 1.1 minoura
87 1.1 minoura return 0;
88 1.1 minoura #else
89 1.1 minoura int fd;
90 1.1 minoura
91 1.1 minoura if (access(name, R_OK) < 0)
92 1.1 minoura err(1, "%s", name);
93 1.1 minoura fd = open(name, O_RDONLY);
94 1.1 minoura if (fd < 0)
95 1.1 minoura err(1, "%s", name);
96 1.1 minoura bootprogsize = lseek(fd, 0, SEEK_END);
97 1.1 minoura close(fd);
98 1.1 minoura
99 1.1 minoura return 0;
100 1.1 minoura #endif
101 1.1 minoura }
102 1.1 minoura
103 1.1 minoura int
104 1.1 minoura checktargetdev(const char *name)
105 1.1 minoura {
106 1.1 minoura struct stat st;
107 1.1 minoura
108 1.1 minoura if (access(name, W_OK) < 0)
109 1.1 minoura err(1, "%s", name);
110 1.1 minoura if (stat(name, &st) < 0)
111 1.1 minoura err(1, "%s", name);
112 1.1 minoura if ((st.st_mode & S_IFCHR) == 0)
113 1.1 minoura errx(1, "%s: not a character special device", name);
114 1.1 minoura if (DISKPART(st.st_rdev) > MAXPARTITIONS)
115 1.1 minoura errx(1, "%s: invalid device", name);
116 1.1 minoura strcpy(rawname, name);
117 1.1 minoura if (strncmp(name + strlen(name) - 4, "fd", 2) == 1) {
118 1.1 minoura printf("floppy\n"); /* XXX */
119 1.1 minoura floppy = 1;
120 1.1 minoura } else {
121 1.1 minoura printf("not floppy\n");
122 1.1 minoura rawname[strlen(name) - 1] = RAW_PART+'a';
123 1.1 minoura }
124 1.1 minoura if (!floppy && DISKPART(st.st_rdev) == RAW_PART)
125 1.1 minoura errx(1, "%s is the raw device", name);
126 1.1 minoura
127 1.1 minoura return 0;
128 1.1 minoura }
129 1.1 minoura
130 1.1 minoura int
131 1.1 minoura checkparttype(const char *name, int force)
132 1.1 minoura {
133 1.1 minoura struct stat st;
134 1.1 minoura int fd, part;
135 1.1 minoura
136 1.1 minoura fd = open(rawname, O_RDONLY | O_EXLOCK);
137 1.1 minoura if (fd < 0)
138 1.1 minoura err(1, "opening %s", name);
139 1.1 minoura if (stat(name, &st) < 0)
140 1.1 minoura err(1, "%s", name);
141 1.1 minoura if ((st.st_mode & S_IFCHR) == 0)
142 1.1 minoura errx(1, "%s: not a character special device", name);
143 1.1 minoura part = DISKPART(st.st_rdev);
144 1.1 minoura if (ioctl(fd, DIOCGDINFO, &label) < 0)
145 1.1 minoura err(1, "%s: reading disklabel", name);
146 1.1 minoura if (part >= label.d_npartitions)
147 1.1 minoura errx(1, "%s: invalid partition", name);
148 1.1 minoura blocksize = label.d_secsize;
149 1.1 minoura if (blocksize < 512)
150 1.1 minoura blocksize = 512;
151 1.1 minoura if (blocksize > MAXBBSIZE)
152 1.1 minoura errx(1, "%s: blocksize too large", name);
153 1.1 minoura if (read(fd, bootblock, blocksize) != blocksize)
154 1.1 minoura errx(1, "%s: reading the mark", name);
155 1.1 minoura close(fd);
156 1.1 minoura if (strncmp(bootblock, "X68SCSI1", 8) != 0)
157 1.1 minoura floppy = 1; /* XXX: or unformated */
158 1.1 minoura
159 1.1 minoura if (!force && !floppy) {
160 1.1 minoura if (label.d_partitions[part].p_fstype != FS_BSDFFS
161 1.1 minoura && label.d_partitions[part].p_fstype != FS_BSDLFS)
162 1.1 minoura errx(1, "%s: invalid partition type", name);
163 1.1 minoura if ((label.d_partitions[part].p_offset * blocksize < 32768) &&
164 1.1 minoura label.d_partitions[part].p_offset != 0)
165 1.1 minoura errx(1, "%s: cannot make the partition bootable",
166 1.1 minoura name);
167 1.1 minoura }
168 1.1 minoura if (floppy)
169 1.1 minoura merging = 1;
170 1.1 minoura else if (label.d_partitions[part].p_offset == 0) {
171 1.1 minoura merging = 1;
172 1.1 minoura bboffset = 1024; /* adjusted below */
173 1.1 minoura }
174 1.1 minoura if (merging) {
175 1.1 minoura struct disklabel *lp;
176 1.1 minoura
177 1.1 minoura lp = (struct disklabel *) &bootblock[LABELBYTEOFFSET];
178 1.1 minoura memcpy(&label, lp, sizeof(struct disklabel));
179 1.1 minoura if (dkcksum(lp) != 0)
180 1.1 minoura /* there is no valid label */
181 1.1 minoura memset(&label, 0, sizeof(struct disklabel));
182 1.1 minoura }
183 1.1 minoura
184 1.1 minoura return 0;
185 1.1 minoura }
186 1.1 minoura
187 1.1 minoura int
188 1.1 minoura main(int argc, char *argv[])
189 1.1 minoura {
190 1.1 minoura int c;
191 1.1 minoura int fd;
192 1.1 minoura
193 1.1 minoura progname = argv[0];
194 1.1 minoura
195 1.1 minoura while ((c = getopt(argc, argv, "nvf")) != -1) {
196 1.1 minoura switch (c) {
197 1.1 minoura case 'n':
198 1.1 minoura nflag = 1;
199 1.1 minoura break;
200 1.1 minoura case 'v':
201 1.1 minoura vflag = 1;
202 1.1 minoura break;
203 1.1 minoura case 'f':
204 1.1 minoura fflag = 1;
205 1.1 minoura break;
206 1.1 minoura default:
207 1.1 minoura usage();
208 1.1 minoura /* NOTREACHED */
209 1.1 minoura }
210 1.1 minoura }
211 1.1 minoura argc -= optind;
212 1.1 minoura argv += optind;
213 1.1 minoura
214 1.1 minoura if (argc != 2)
215 1.1 minoura usage();
216 1.1 minoura bootprog = argv[0];
217 1.1 minoura target = argv[1];
218 1.1 minoura
219 1.1 minoura if (checkbootprog(bootprog) < 0)
220 1.1 minoura errx(1, "aborting");
221 1.1 minoura if (checktargetdev(target) < 0)
222 1.1 minoura errx(1, "aborting");
223 1.1 minoura
224 1.1 minoura if (checkparttype(target, fflag))
225 1.1 minoura errx(1, "aborting");
226 1.1 minoura if (merging && blocksize > bboffset)
227 1.1 minoura bboffset = blocksize;
228 1.1 minoura if (bootprogsize > MAXBBSIZE - bboffset)
229 1.1 minoura errx(1, "%s: boot block too big", bootprog);
230 1.1 minoura
231 1.1 minoura /* Read the boot program */
232 1.1 minoura fd = open(bootprog, O_RDONLY);
233 1.1 minoura if (fd < 0)
234 1.1 minoura err(1, "opening %s", bootprog);
235 1.1 minoura if (read(fd, bootblock + bboffset, bootprogsize) != bootprogsize)
236 1.1 minoura err(1, "reading %s", bootprog);
237 1.1 minoura close(fd);
238 1.1 minoura if (merging)
239 1.1 minoura memcpy(bootblock + LABELBYTEOFFSET, &label, sizeof(label));
240 1.1 minoura
241 1.1 minoura /* Write the boot block (+ disklabel if necessary) */
242 1.1 minoura if (nflag) {
243 1.1 minoura target = template;
244 1.1 minoura
245 1.1 minoura fd = mkstemp(target);
246 1.1 minoura if (fd < 0)
247 1.1 minoura err(1, "opening the output file");
248 1.1 minoura } else {
249 1.1 minoura int writable = 1;
250 1.1 minoura
251 1.1 minoura fd = open(target, O_WRONLY);
252 1.1 minoura if (fd < 0)
253 1.1 minoura err(1, "opening the disk");
254 1.1 minoura if (merging && ioctl(fd, DIOCWLABEL, &writable) < 0)
255 1.1 minoura err(1, "opening the disk");
256 1.1 minoura }
257 1.1 minoura bootprogsize = howmany(bootprogsize+bboffset, blocksize) * blocksize;
258 1.1 minoura if (write(fd, bootblock, bootprogsize) != bootprogsize) {
259 1.1 minoura warn("writing the label");
260 1.1 minoura if (!nflag && merging) {
261 1.1 minoura int writable = 0;
262 1.1 minoura ioctl(fd, DIOCWLABEL, &writable);
263 1.1 minoura }
264 1.1 minoura exit(1);
265 1.1 minoura }
266 1.1 minoura
267 1.1 minoura if (!nflag && merging) {
268 1.1 minoura int writable = 0;
269 1.1 minoura ioctl(fd, DIOCWLABEL, &writable);
270 1.1 minoura }
271 1.1 minoura close(fd);
272 1.1 minoura
273 1.1 minoura if (nflag)
274 1.1 minoura fprintf(stderr, "The bootblock is kept in %s\n", target);
275 1.1 minoura else
276 1.1 minoura fprintf(stderr, "Do not forget to copy /usr/mdec/boot"
277 1.1 minoura " to the root directory of %s.\n", target);
278 1.1 minoura
279 1.1 minoura return 0;
280 1.1 minoura }
281