installboot.c revision 1.1.2.2 1 /* $NetBSD: installboot.c,v 1.1.2.2 2000/11/20 20:14:14 bouyer Exp $ */
2
3 /*
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Wayne Knowles
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <assert.h>
40 #include <err.h>
41 #include <fcntl.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <unistd.h>
46
47 #include <sys/param.h>
48 #include <sys/stat.h>
49 #include <sys/disklabel.h>
50
51
52 #define VERBOSE(msg) if (verbose) \
53 fprintf(stderr, msg)
54 #define FATAL(a1,a2) errx(EXIT_FAILURE, a1, a2)
55 #define FATALIO(a1,a2) err(EXIT_FAILURE, a1, a2)
56
57 #define BOOTBLOCK_NUMBER 2
58 #define BOOTBLOCK_OFFSET BOOTBLOCK_NUMBER*DEV_BSIZE
59 #define DEFAULT_BOOTFILE "boot"
60
61 static void usage __P((void));
62 static void do_list __P((const char *));
63 static void do_remove __P((const char *, const char *));
64 static void do_install __P((const char *, const char *, const char *));
65 static int mipsvh_cksum __P((struct mips_volheader *));
66 static void read_volheader __P((const char *, struct mips_volheader *));
67 static void write_volheader __P((const char *, struct mips_volheader *));
68 static struct mips_voldir *voldir_findfile __P((struct mips_volheader *,
69 const char *, int));
70
71 int verbose, nowrite;
72
73 static void
74 usage()
75 {
76 extern char *__progname;
77
78 fprintf(stderr, "usage:\n");
79 fprintf(stderr, "\t%s [-nv] disk bootstrap [name]\n", __progname);
80 fprintf(stderr, "\t%s -r [-nv] disk [name]\n", __progname);
81 fprintf(stderr, "\t%s -l [-nv] disk\n", __progname);
82 exit(EXIT_FAILURE);
83 }
84
85 int
86 main(int argc, char *argv[])
87 {
88 const char *disk;
89 int c, rflag, lflag;
90
91 rflag = lflag = verbose = nowrite = 0;
92
93 while ((c = getopt(argc, argv, "lnrv")) != -1) {
94 switch (c) {
95 case 'l':
96 /* List volume directory contents */
97 lflag = 1;
98 break;
99 case 'n':
100 /* Disable write of boot sectors */
101 nowrite = 1;
102 break;
103 case 'r':
104 /* Clear any existing boot block */
105 rflag = 1;
106 break;
107 case 'v':
108 /* Verbose output */
109 verbose = 1;
110 break;
111 default:
112 usage();
113 }
114 }
115
116 argc -= optind;
117 argv += optind;
118
119 if ((lflag && rflag) || argc < 1 || (lflag && argc != 1) ||
120 (rflag && argc > 3) || argc > 4)
121 usage();
122
123 disk = argv[0];
124
125 if (lflag)
126 do_list(disk);
127 else if (rflag)
128 do_remove(disk, argc==2?argv[1]:DEFAULT_BOOTFILE);
129 else
130 do_install(disk, argv[1], argc==3?argv[2]:DEFAULT_BOOTFILE);
131
132 exit(EXIT_SUCCESS);
133 }
134
135 static void
136 do_list(disk)
137 const char *disk;
138 {
139 struct mips_volheader vh;
140 struct mips_voldir *vdp;
141 int i;
142
143 read_volheader(disk, &vh);
144
145 printf("Slot\t LBN\tLength\tFilename\n");
146 printf("------------------------------------------\n");
147 for (i=0, vdp=vh.vh_voldir; i<MIPS_NVOLDIR; i++, vdp++)
148 if (vdp->vd_len)
149 printf("%2d:\t%5d\t%6d\t%s\n", i, vdp->vd_lba,
150 vdp->vd_len, vdp->vd_name);
151 }
152
153 static void
154 do_remove(disk, filename)
155 const char *disk;
156 const char *filename;
157 {
158 struct mips_volheader vh;
159 struct mips_voldir *vdp;
160
161 read_volheader(disk, &vh);
162 vdp = voldir_findfile(&vh, filename, 0);
163 if (vdp == NULL)
164 FATAL("%s: file not found", disk);
165
166 bzero(vdp, sizeof(*vdp));
167
168 /* Update volume header */
169 write_volheader(disk, &vh);
170 }
171
172 static void
173 do_install(disk, bootstrap, bootname)
174 const char *disk;
175 const char *bootstrap;
176 const char *bootname;
177 {
178 struct stat bootstrapsb;
179 struct mips_volheader vh;
180 struct mips_voldir *vdp;
181 int fd;
182 char *boot_code;
183 size_t boot_size;
184 ssize_t len;
185
186 /* Open the input file and check it out */
187 if ((fd = open(bootstrap, O_RDONLY)) == -1)
188 FATALIO("open %s", bootstrap);
189 if (fstat(fd, &bootstrapsb) == -1)
190 FATALIO("fstat %s", bootstrap);
191 if (!S_ISREG(bootstrapsb.st_mode))
192 FATAL("%s must be a regular file", bootstrap);
193
194 boot_size = roundup(bootstrapsb.st_size, DEV_BSIZE);
195
196 if (boot_size > 8192-1024)
197 FATAL("bootstrap program too large (%d bytes)", boot_size);
198
199 boot_code = malloc(boot_size);
200 if (boot_code == NULL)
201 FATAL("malloc %d bytes failed", boot_size);
202 bzero(boot_code, boot_size);
203
204 /* read the file into the buffer */
205 len = read(fd, boot_code, bootstrapsb.st_size);
206 if (len == -1)
207 FATALIO("read %s", bootstrap);
208 else if (len != bootstrapsb.st_size)
209 FATAL("read %s: short read", bootstrap);
210 (void)close(fd);
211
212 read_volheader(disk, &vh);
213
214 vdp = voldir_findfile(&vh, bootname, 1);
215 if (vdp == NULL)
216 FATAL("%s: volume directory full", disk);
217
218 strcpy(vdp->vd_name, bootname);
219 vdp->vd_lba = BOOTBLOCK_NUMBER;
220 vdp->vd_len = bootstrapsb.st_size;
221
222 if (nowrite) {
223 if (verbose)
224 fprintf(stderr, "not writing\n");
225 return;
226 }
227
228 if (verbose)
229 fprintf(stderr, "writing bootstrap (%d bytes at logical block %d)\n",
230 boot_size, 2);
231
232 /* Write bootstrap */
233 if ((fd = open(disk, O_WRONLY)) == -1)
234 FATALIO("open %s", bootstrap);
235 len = pwrite(fd, boot_code, boot_size, BOOTBLOCK_OFFSET);
236 if (len == -1)
237 FATAL("write %s", disk);
238 if (len != boot_size)
239 FATAL("write %s: short write", disk);
240 (void) close(fd);
241
242 /* Update volume header */
243 write_volheader(disk, &vh);
244 }
245
246 static void
247 read_volheader(disk, vhp)
248 const char *disk;
249 struct mips_volheader *vhp;
250 {
251 int vfd;
252 ssize_t len;
253
254 if ((vfd = open(disk, O_RDONLY)) == -1)
255 FATALIO("open %s", disk);
256
257 len = pread(vfd, vhp, sizeof(*vhp), MIPS_VHSECTOR*DEV_BSIZE);
258
259 (void) close(vfd);
260
261 if (len == -1)
262 FATALIO("read %s", disk);
263 if (len != sizeof(*vhp))
264 FATAL("read %s: short read", disk);
265
266 /* Check volume header magic */
267 if (vhp->vh_magic != MIPS_VHMAGIC)
268 FATAL("%s: no volume header", disk);
269
270 /* check volume header checksum */
271 if (mipsvh_cksum(vhp))
272 FATAL("%s: volume header corrupted", disk);
273 }
274
275 static void
276 write_volheader(disk, vhp)
277 const char *disk;
278 struct mips_volheader *vhp;
279 {
280 int vfd;
281 ssize_t len;
282
283 /* update volume header checksum */
284 vhp->vh_cksum = 0;
285 vhp->vh_cksum = -mipsvh_cksum(vhp);
286
287 if ((vfd = open(disk, O_WRONLY)) == -1)
288 FATALIO("open %s", disk);
289
290 if (verbose)
291 fprintf(stderr, "%s: writing volume header\n", disk);
292
293 len = pwrite(vfd, vhp, sizeof(*vhp), MIPS_VHSECTOR*512); /* XXX */
294 if (len == -1)
295 FATALIO("write %s", disk);
296 if (len != sizeof(*vhp))
297 FATAL("write %s: short write", disk);
298
299 (void) close(vfd);
300 }
301
302 /*
303 * Compute checksum for MIPS disk volume header
304 *
305 * Mips volume header checksum is the 32bit 2's complement sum
306 * of the entire volume header structure
307 */
308 int
309 mipsvh_cksum(vhp)
310 struct mips_volheader *vhp;
311 {
312 int i, *ptr;
313 int cksum = 0;
314
315 ptr = (int *)vhp;
316 i = sizeof(*vhp) / sizeof(*ptr);
317 while (i--)
318 cksum += *ptr++;
319 return cksum;
320 }
321
322
323 /*
324 * Locate the volume directory slot that matches a filename
325 *
326 * If the file entry cannot be found and create is non-zero the next
327 * empty slot is returned, otherwise return NULL
328 */
329 static struct mips_voldir *
330 voldir_findfile(vhp, file, create)
331 struct mips_volheader *vhp;
332 const char *file;
333 int create; /* return unused entry if not found */
334 {
335 struct mips_voldir *vdp = vhp->vh_voldir;
336 int i;
337
338 for (i=0; i<MIPS_NVOLDIR; i++, vdp++) {
339 if (strcmp(vdp->vd_name, file) == 0)
340 return vdp;
341 }
342 if (create) {
343 vdp = vhp->vh_voldir;
344 for (i=0; i<MIPS_NVOLDIR; i++, vdp++)
345 if (vdp->vd_len == 0)
346 return vdp;
347 }
348 return NULL;
349 }
350