xref: /openbsd-src/usr.sbin/mksuncd/mksuncd.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: mksuncd.c,v 1.2 2010/02/25 17:15:42 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 2001 Jason L. Wright (jason@thought.net)
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 ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * WARNING! WARNING!
31  * This program is not type safe (it assumes sparc type sizes) and not
32  * endian safe (assumes sparc endianness).
33  * WARNING! WARNING!
34  */
35 
36 /*
37  * Copyright (c) 1992, 1993
38  *	The Regents of the University of California.  All rights reserved.
39  *
40  * This software was developed by the Computer Systems Engineering group
41  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
42  * contributed to Berkeley.
43  *
44  * All advertising materials mentioning features or use of this software
45  * must display the following acknowledgement:
46  *	This product includes software developed by the University of
47  *	California, Lawrence Berkeley Laboratory.
48  *
49  * Redistribution and use in source and binary forms, with or without
50  * modification, are permitted provided that the following conditions
51  * are met:
52  * 1. Redistributions of source code must retain the above copyright
53  *    notice, this list of conditions and the following disclaimer.
54  * 2. Redistributions in binary form must reproduce the above copyright
55  *    notice, this list of conditions and the following disclaimer in the
56  *    documentation and/or other materials provided with the distribution.
57  * 3. Neither the name of the University nor the names of its contributors
58  *    may be used to endorse or promote products derived from this software
59  *    without specific prior written permission.
60  *
61  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
62  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
63  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
65  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
66  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
67  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
68  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
69  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
70  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
71  * SUCH DAMAGE.
72  *
73  *	@(#)sun_disklabel.h	8.1 (Berkeley) 6/11/93
74  */
75 
76 #include <stdio.h>
77 #include <sys/types.h>
78 #include <sys/stat.h>
79 #include <unistd.h>
80 #include <fcntl.h>
81 #include <err.h>
82 #include <string.h>
83 
84 /*
85  * SunOS disk label layout (only relevant portions discovered here).
86  * JLW XXX should get these definitions from elsewhere, oh well.
87  */
88 
89 #define	SUN_DKMAGIC	55998
90 
91 /* partition info */
92 struct sun_dkpart {
93 	int	sdkp_cyloffset;		/* starting cylinder */
94 	int	sdkp_nsectors;		/* number of sectors */
95 };
96 
97 struct sun_disklabel {			/* total size = 512 bytes */
98 	char	sl_text[128];
99 	char	sl_xxx1[292];
100 #define sl_bsdlabel	sl_xxx1		/* Embedded OpenBSD label */
101 	u_short sl_rpm;			/* rotational speed */
102 	u_short	sl_pcylinders;		/* number of physical cyls */
103 #define	sl_pcyl	 sl_pcylinders		/* XXX: old sun3 */
104 	u_short sl_sparespercyl;	/* spare sectors per cylinder */
105 	char	sl_xxx3[4];
106 	u_short sl_interleave;		/* interleave factor */
107 	u_short	sl_ncylinders;		/* data cylinders */
108 	u_short	sl_acylinders;		/* alternate cylinders */
109 	u_short	sl_ntracks;		/* tracks per cylinder */
110 	u_short	sl_nsectors;		/* sectors per track */
111 	char	sl_xxx4[4];
112 	struct sun_dkpart sl_part[8];	/* partition layout */
113 	u_short	sl_magic;		/* == SUN_DKMAGIC */
114 	u_short	sl_cksum;		/* xor checksum of all shorts */
115 };
116 
117 int expand_file(int, off_t);
118 void usage(void);
119 int adjust_base(int, struct sun_disklabel *);
120 int get_label(int, struct sun_disklabel *);
121 int append_osfile(int, int);
122 off_t cylindersize(int, struct sun_disklabel *);
123 int adjust_label(int, struct sun_disklabel *, int, off_t, off_t);
124 
125 int
126 expand_file(int f, off_t len)
127 {
128 	char buf[1024];
129 	off_t i;
130 
131 	if (lseek(f, 0, SEEK_END) == -1)
132 		return (-1);
133 	bzero(buf, sizeof(buf));
134 	while (len) {
135 		i = (sizeof(buf) < len) ? sizeof(buf) : len;
136 		if (write(f, buf, i) != i)
137 			return (-1);
138 		len -= i;
139 	}
140 	return (0);
141 }
142 
143 void
144 usage(void)
145 {
146 	fprintf(stderr, "usage: mksuncd partition isoimage bootimage\n");
147 }
148 
149 /*
150  * Adjust size of base to meet a cylinder boundary.
151  */
152 int
153 adjust_base(int f, struct sun_disklabel *slp)
154 {
155 	struct stat st;
156 	off_t sz;
157 
158 	if (lseek(f, 0, SEEK_END) == -1)
159 		err(1, "lseek");
160 
161 	if (fstat(f, &st) == -1)
162 		err(1, "fstat");
163 
164 	sz = ((off_t)slp->sl_nsectors) *
165 	    ((off_t)slp->sl_ntracks) * ((off_t)512);
166 
167 	if ((st.st_size % sz) != 0) {
168 		if (expand_file(f, sz - (st.st_size % sz)))
169 			err(1, "expand_file");
170 	}
171 
172 	return (0);
173 }
174 
175 int
176 get_label(int f, struct sun_disklabel *slp)
177 {
178 	int r;
179 
180 	if (lseek(f, 0, SEEK_SET) == -1)
181 		err(1, "lseek");
182 
183 	r = read(f, slp, sizeof(*slp));
184 	if (r == -1)
185 		err(1, "read");
186 	if (r != sizeof(*slp))
187 		errx(1, "short read");
188 
189 	if (slp->sl_ntracks == 0 || slp->sl_ncylinders == 0 ||
190 	    slp->sl_nsectors == 0)
191 		errx(1, "bogus disklabel");
192 
193 	return (0);
194 }
195 
196 int
197 main(int argc, char **argv)
198 {
199 	struct sun_disklabel sl;
200 	int part, bf, of;
201 	off_t cylstart, cylsize;
202 
203 	if (argc != 4) {
204 		usage();
205 		return (1);
206 	}
207 
208 	if (argv[1] == NULL || strlen(argv[1]) != 1 ||
209 	    (argv[1][0] < 'a' || argv[1][0] > 'h')) {
210 		usage();
211 		return (1);
212 	}
213 	part = argv[1][0] - 'a';
214 
215 	if (argv[2] == NULL || argv[3] == NULL) {
216 		usage();
217 		return (1);
218 	}
219 
220 	bf = open(argv[2], O_RDWR);
221 	if (bf == -1)
222 		err(1, "open");
223 
224 	of = open(argv[3], O_RDONLY);
225 	if (of == -1)
226 		err(1, "open");
227 
228 	if (get_label(bf, &sl))
229 		return (1);
230 
231 	if (adjust_base(bf, &sl))
232 		return (1);
233 
234 	cylstart = cylindersize(bf, &sl);
235 	cylsize = cylindersize(of, &sl);
236 
237 	if (append_osfile(bf, of))
238 		return (1);
239 
240 	if (adjust_base(bf, &sl))
241 		return (1);
242 
243 	if (adjust_label(bf, &sl, part, cylstart, cylsize))
244 		return (1);
245 
246 	close(bf);
247 	close(of);
248 
249 	return (0);
250 }
251 
252 /*
253  * Put our entry into the disklabel, recompute label checksum, and
254  * write it back to the disk.
255  */
256 int
257 adjust_label(int f, struct sun_disklabel *slp, int part, off_t start, off_t size)
258 {
259 	u_short sum = 0, *sp;
260 	int i;
261 
262 	if (start > 65535)
263 		errx(1, "start too large! %lld", (long long)start);
264 	if (part < 0 || part > 8)
265 		errx(1, "invalid partition: %d", part);
266 	slp->sl_part[part].sdkp_cyloffset = start;
267 	slp->sl_part[part].sdkp_nsectors =
268 	    size * slp->sl_nsectors * slp->sl_ntracks;
269 
270 	slp->sl_cksum = 0;
271 	sp = (u_short *)slp;
272 	for (i = 0; i < sizeof(*slp)/sizeof(u_short); i++) {
273 		sum ^= *sp;
274 		sp++;
275 	}
276 	slp->sl_cksum = sum;
277 
278 	if (lseek(f, 0, SEEK_SET) == -1)
279 		return (-1);
280 
281 	i = write(f, slp, sizeof(*slp));
282 	if (i < 0)
283 		err(1, "write modified label");
284 	if (i != sizeof(*slp))
285 		errx(1, "short write modified label");
286 	return (0);
287 }
288 
289 int
290 append_osfile(int outf, int inf)
291 {
292 	char buf[512];
293 	int r, len;
294 
295 	while (1) {
296 		len = read(inf, buf, sizeof(buf));
297 		if (len < 0)
298 			err(1, "read osfile");
299 		if (len == 0)
300 			return (0);
301 
302 		r = write(outf, buf, len);
303 		if (r < 0)
304 			err(1, "write basefile");
305 		if (r != len)
306 			errx(1, "short write basefile");
307 	}
308 }
309 
310 off_t
311 cylindersize(int f, struct sun_disklabel *slp)
312 {
313 	struct stat st;
314 	off_t sz, r;
315 
316 	if (fstat(f, &st) == -1)
317 		err(1, "fstat");
318 
319 	sz = ((off_t)slp->sl_nsectors) *
320 	    ((off_t)slp->sl_ntracks) * ((off_t)512);
321 
322 	r = st.st_size / sz;
323 
324 	if ((st.st_size % sz) == 0)
325 		return (r);
326 	return (r + 1);
327 }
328