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