xref: /netbsd-src/sbin/apmlabel/apmlabel.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: apmlabel.c,v 1.2 2011/08/27 16:10:51 joerg Exp $	*/
2 
3 /*
4  * Copyright (C) 1998 Wolfgang Solfrank.
5  * Copyright (C) 1998 TooLs GmbH.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by TooLs GmbH.
19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 #ifndef lint
36 __RCSID("$NetBSD: apmlabel.c,v 1.2 2011/08/27 16:10:51 joerg Exp $");
37 #endif /* not lint */
38 
39 #include <stdio.h>
40 #include <err.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <limits.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <util.h>
48 
49 #include <sys/param.h>
50 #define FSTYPENAMES
51 #include <sys/disklabel.h>
52 #include <sys/bootblock.h>
53 #include <sys/ioctl.h>
54 
55 #include "dkcksum.h"
56 #include "extern.h"
57 
58 __dead static void	usage(void);
59 static void	getlabel(int);
60 static void	setlabel(int, int);
61 static int	getparts(int, int);
62 static struct apple_drvr_map *convert_drvr_map(unsigned char *);
63 static struct apple_part_map_entry *convert_part_map_entry(unsigned char *);
64 
65 static struct disklabel label;
66 
67 static void
68 getlabel(int sd)
69 {
70 
71 	if (ioctl(sd, DIOCGDINFO, &label) < 0) {
72 		perror("get label");
73 		exit(1);
74 	}
75 	/*
76 	 * Some ports seem to not set the number of partitions
77 	 * correctly, albeit they seem to set the raw partition ok!
78 	 */
79 	if (label.d_npartitions <= getrawpartition())
80 		label.d_npartitions = getrawpartition() + 1;
81 }
82 
83 static void
84 setlabel(int sd, int doraw)
85 {
86 	int one = 1;
87 
88 	label.d_checksum = 0;
89 	label.d_checksum = dkcksum(&label);
90 	if (ioctl(sd, doraw ? DIOCWDINFO : DIOCSDINFO, &label) < 0) {
91 		perror("set label");
92 		exit(1);
93 	}
94 	if (!doraw)
95 		/* If we haven't written to the disk, don't discard on close */
96 		ioctl(sd, DIOCKLABEL, &one);
97 
98 }
99 
100 static int
101 getparts(int sd, int verbose)
102 {
103 	unsigned char		buf[DEV_BSIZE];
104 	struct apple_drvr_map	*drvr;
105 	struct apple_part_map_entry *part;
106 	struct partition	npe;
107 	uint16_t		blksize, blkcnt, partcnt;
108 	int			i, j, unused, changed;
109 	uint64_t		temp;
110 
111 	changed = 0;
112 
113 	if (lseek(sd, 0, SEEK_SET) == -1) {
114 		perror("seek drvr map");
115 		exit(1);
116 	}
117 	if ((i=read(sd, buf, sizeof(buf))) != DEV_BSIZE) {
118 		perror("read drvr map");
119 		exit(1);
120 	}
121 	drvr = convert_drvr_map(buf);
122 
123 	if (drvr->sbSig != APPLE_DRVR_MAP_MAGIC)
124 		return (changed);
125 	blksize = drvr->sbBlockSize;
126 	blkcnt = drvr->sbBlkCount;
127 
128 	partcnt = 1;
129 
130 	for (i = 0; i < partcnt; i++) {
131 		if (lseek(sd, (i+1)*blksize, SEEK_SET) == -1) {
132 			perror("seek part");
133 			exit(1);
134 		}
135 		if (read(sd, buf, sizeof(buf)) != DEV_BSIZE) {
136 			perror("read part");
137 			exit(1);
138 		}
139 
140 		part = convert_part_map_entry(buf);
141 
142 		if (part->pmSig != APPLE_PART_MAP_ENTRY_MAGIC)
143 			return (changed);
144 		if (i == 0)
145 			partcnt = part->pmMapBlkCnt;
146 		/* XXX: consistency checks? */
147 
148 		memset((void *)&npe, 0, sizeof(npe));
149 
150 		if (strcasecmp((char *)part->pmPartType,
151 			APPLE_PART_TYPE_MAC) == 0
152 		    || strcasecmp((char *)part->pmPartType, "Apple_HFSX") == 0)
153 			npe.p_fstype = FS_HFS;
154 		else if (strcasecmp((char *)part->pmPartType,
155 			     "Apple_UFS") == 0) {
156 			npe.p_fstype = FS_APPLEUFS;
157 			npe.p_size = 16384;	/* XXX */
158 			npe.p_fsize = 1024;
159 			npe.p_frag = 8;
160 			npe.p_cpg = 16;
161 		}
162 		else
163 			continue;
164 
165 		temp = (uint64_t)part->pmDataCnt * (uint64_t)blksize;
166 		if (temp % label.d_secsize != 0) {
167 		    warnx("partition size not multiple of sector size"
168 			  ", skipping");
169 		    continue;
170 		}
171 		npe.p_size = temp / label.d_secsize;
172 		temp = (uint64_t)(part->pmPyPartStart + part->pmLgDataStart)
173 		    * (uint64_t)blksize;
174 		if (temp % label.d_secsize != 0) {
175 		    warnx("partition offset not multiple of sector size"
176 			  ", skipping");
177 		    continue;
178 		}
179 		npe.p_offset = temp / label.d_secsize;
180 
181 				/* find existing entry, or first free slot */
182 		unused = -1;	/* flag as no free slot */
183 		if (verbose)
184 			printf(
185 			    "Found %s partition; size %u (%u MB), offset %u\n",
186 			    fstypenames[npe.p_fstype],
187 			    npe.p_size, npe.p_size / 2048, npe.p_offset);
188 		for (j = 0; j < label.d_npartitions; j++) {
189 			struct partition *lpe;
190 
191 			if (j == RAW_PART)
192 				continue;
193 			lpe = &label.d_partitions[j];
194 			if (lpe->p_size == npe.p_size &&
195 			    lpe->p_offset == npe.p_offset
196 #ifdef notyet
197 			    && (lpe->p_fstype == npe.p_fstype ||
198 			     lpe->p_fstype == FS_UNUSED) */
199 #endif
200 			     ) {
201 				if (verbose)
202 					printf(
203 			    "  skipping existing %s partition at slot %c.\n",
204 					    fstypenames[lpe->p_fstype],
205 					    j + 'a');
206 				unused = -2;	/* flag as existing */
207 				break;
208 			}
209 			if (unused == -1 && lpe->p_size == 0 &&
210 			    lpe->p_fstype == FS_UNUSED)
211 				unused = j;
212 		}
213 		if (unused == -2)
214 			continue;	/* entry exists, skip... */
215 		if (unused == -1) {
216 			if (label.d_npartitions < MAXPARTITIONS) {
217 				unused = label.d_npartitions;
218 				label.d_npartitions++;
219 			} else {
220 				printf(
221 				"  WARNING: no slots free for %s partition.\n",
222 				    fstypenames[npe.p_fstype]);
223 				continue;
224 			}
225 		}
226 
227 		if (verbose)
228 			printf("  adding %s partition to slot %c.\n",
229 			    fstypenames[npe.p_fstype], unused + 'a');
230 		changed++;
231 		label.d_partitions[unused] = npe;
232 	}
233 
234 	return (changed);
235 }
236 
237 static struct apple_drvr_map *
238 convert_drvr_map(unsigned char *buf)
239 {
240 	struct apple_drvr_map *drvr;
241 	int i;
242 
243 	drvr = (struct apple_drvr_map *)buf;
244 
245 	BE16TOH(drvr->sbSig);
246 	BE16TOH(drvr->sbBlockSize);
247 	BE32TOH(drvr->sbBlkCount);
248 	BE16TOH(drvr->sbDevType);
249 	BE16TOH(drvr->sbDevID);
250 	BE32TOH(drvr->sbData);
251 	BE16TOH(drvr->sbDrvrCount);
252 	for (i=0; i<APPLE_DRVR_MAP_MAX_DESCRIPTORS; i++) {
253 		BE32TOH(drvr->sb_dd[i].descBlock);
254 		BE16TOH(drvr->sb_dd[i].descSize);
255 		BE16TOH(drvr->sb_dd[i].descType);
256 	}
257 
258 	return drvr;
259 }
260 
261 static struct apple_part_map_entry *
262 convert_part_map_entry(unsigned char *buf)
263 {
264 	struct apple_part_map_entry *part;
265 
266 	part = (struct apple_part_map_entry *)buf;
267 
268 	BE16TOH(part->pmSig);
269 	BE16TOH(part->pmSigPad);
270 	BE32TOH(part->pmMapBlkCnt);
271 	BE32TOH(part->pmPyPartStart);
272 	BE32TOH(part->pmPartBlkCnt);
273 	BE32TOH(part->pmLgDataStart);
274 	BE32TOH(part->pmDataCnt);
275 	BE32TOH(part->pmPartStatus);
276 	BE32TOH(part->pmLgBootStart);
277 	BE32TOH(part->pmBootSize);
278 	BE32TOH(part->pmBootLoad);
279 	BE32TOH(part->pmBootLoad2);
280 	BE32TOH(part->pmBootEntry);
281 	BE32TOH(part->pmBootEntry2);
282 	BE32TOH(part->pmBootCksum);
283 
284 	return part;
285 }
286 
287 static void
288 usage(void)
289 {
290 	fprintf(stderr, "usage: %s [-fqrw] rawdisk\n",
291 	    getprogname());
292 	exit(1);
293 }
294 
295 
296 int
297 main(int argc, char **argv)
298 {
299 	int	sd, ch, changed;
300 	char	name[MAXPATHLEN];
301 	int	force;			/* force label update */
302 	int	raw;			/* update on-disk label as well */
303 	int	verbose;		/* verbose output */
304 	int	write_it;		/* update in-core label if changed */
305 
306 	force = 0;
307 	raw = 0;
308 	verbose = 1;
309 	write_it = 0;
310 	while ((ch = getopt(argc, argv, "fqrw")) != -1) {
311 		switch (ch) {
312 		case 'f':
313 			force = 1;
314 			break;
315 		case 'q':
316 			verbose = 0;
317 			break;
318 		case 'r':
319 			raw = 1;
320 			break;
321 		case 'w':
322 			write_it = 1;
323 			break;
324 		default:
325 			usage();
326 		}
327 	}
328 	argc -= optind;
329 	argv += optind;
330 	if (argc != 1)
331 		usage();
332 
333 	if ((sd = opendisk(argv[0], write_it ? O_RDWR : O_RDONLY, name,
334 	    (size_t)MAXPATHLEN, 1)) < 0) {
335 		perror(argv[0]);
336 		exit(1);
337 	}
338 	getlabel(sd);
339 	changed = getparts(sd, verbose);
340 
341 	if (verbose) {
342 		putchar('\n');
343 		showpartitions(stdout, &label, 0);
344 		putchar('\n');
345 	}
346 	if (write_it) {
347 		if (! changed && ! force)
348 			printf("No change; not updating disk label.\n");
349 		else {
350 			if (verbose)
351 				printf("Updating in-core %sdisk label.\n",
352 				    raw ? "and on-disk " : "");
353 			setlabel(sd, raw);
354 		}
355 	} else {
356 		printf("Not updating disk label.\n");
357 	}
358 	close(sd);
359 	return (0);
360 }
361