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