apmlabel.c revision 1.3 1 1.3 christos /* $NetBSD: apmlabel.c,v 1.3 2013/10/19 01:09:58 christos 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.3 christos __RCSID("$NetBSD: apmlabel.c,v 1.3 2013/10/19 01:09:58 christos 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.3 christos uint16_t blksize, 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
127 1.1 dillo partcnt = 1;
128 1.1 dillo
129 1.1 dillo for (i = 0; i < partcnt; i++) {
130 1.1 dillo if (lseek(sd, (i+1)*blksize, SEEK_SET) == -1) {
131 1.1 dillo perror("seek part");
132 1.1 dillo exit(1);
133 1.1 dillo }
134 1.1 dillo if (read(sd, buf, sizeof(buf)) != DEV_BSIZE) {
135 1.1 dillo perror("read part");
136 1.1 dillo exit(1);
137 1.1 dillo }
138 1.1 dillo
139 1.1 dillo part = convert_part_map_entry(buf);
140 1.1 dillo
141 1.1 dillo if (part->pmSig != APPLE_PART_MAP_ENTRY_MAGIC)
142 1.1 dillo return (changed);
143 1.1 dillo if (i == 0)
144 1.1 dillo partcnt = part->pmMapBlkCnt;
145 1.1 dillo /* XXX: consistency checks? */
146 1.1 dillo
147 1.1 dillo memset((void *)&npe, 0, sizeof(npe));
148 1.1 dillo
149 1.1 dillo if (strcasecmp((char *)part->pmPartType,
150 1.1 dillo APPLE_PART_TYPE_MAC) == 0
151 1.1 dillo || strcasecmp((char *)part->pmPartType, "Apple_HFSX") == 0)
152 1.1 dillo npe.p_fstype = FS_HFS;
153 1.1 dillo else if (strcasecmp((char *)part->pmPartType,
154 1.1 dillo "Apple_UFS") == 0) {
155 1.1 dillo npe.p_fstype = FS_APPLEUFS;
156 1.1 dillo npe.p_size = 16384; /* XXX */
157 1.1 dillo npe.p_fsize = 1024;
158 1.1 dillo npe.p_frag = 8;
159 1.1 dillo npe.p_cpg = 16;
160 1.1 dillo }
161 1.1 dillo else
162 1.1 dillo continue;
163 1.1 dillo
164 1.1 dillo temp = (uint64_t)part->pmDataCnt * (uint64_t)blksize;
165 1.1 dillo if (temp % label.d_secsize != 0) {
166 1.1 dillo warnx("partition size not multiple of sector size"
167 1.1 dillo ", skipping");
168 1.1 dillo continue;
169 1.1 dillo }
170 1.1 dillo npe.p_size = temp / label.d_secsize;
171 1.1 dillo temp = (uint64_t)(part->pmPyPartStart + part->pmLgDataStart)
172 1.1 dillo * (uint64_t)blksize;
173 1.1 dillo if (temp % label.d_secsize != 0) {
174 1.1 dillo warnx("partition offset not multiple of sector size"
175 1.1 dillo ", skipping");
176 1.1 dillo continue;
177 1.1 dillo }
178 1.1 dillo npe.p_offset = temp / label.d_secsize;
179 1.1 dillo
180 1.1 dillo /* find existing entry, or first free slot */
181 1.1 dillo unused = -1; /* flag as no free slot */
182 1.1 dillo if (verbose)
183 1.1 dillo printf(
184 1.1 dillo "Found %s partition; size %u (%u MB), offset %u\n",
185 1.1 dillo fstypenames[npe.p_fstype],
186 1.1 dillo npe.p_size, npe.p_size / 2048, npe.p_offset);
187 1.1 dillo for (j = 0; j < label.d_npartitions; j++) {
188 1.1 dillo struct partition *lpe;
189 1.1 dillo
190 1.1 dillo if (j == RAW_PART)
191 1.1 dillo continue;
192 1.1 dillo lpe = &label.d_partitions[j];
193 1.1 dillo if (lpe->p_size == npe.p_size &&
194 1.1 dillo lpe->p_offset == npe.p_offset
195 1.1 dillo #ifdef notyet
196 1.1 dillo && (lpe->p_fstype == npe.p_fstype ||
197 1.1 dillo lpe->p_fstype == FS_UNUSED) */
198 1.1 dillo #endif
199 1.1 dillo ) {
200 1.1 dillo if (verbose)
201 1.1 dillo printf(
202 1.1 dillo " skipping existing %s partition at slot %c.\n",
203 1.1 dillo fstypenames[lpe->p_fstype],
204 1.1 dillo j + 'a');
205 1.1 dillo unused = -2; /* flag as existing */
206 1.1 dillo break;
207 1.1 dillo }
208 1.1 dillo if (unused == -1 && lpe->p_size == 0 &&
209 1.1 dillo lpe->p_fstype == FS_UNUSED)
210 1.1 dillo unused = j;
211 1.1 dillo }
212 1.1 dillo if (unused == -2)
213 1.1 dillo continue; /* entry exists, skip... */
214 1.1 dillo if (unused == -1) {
215 1.1 dillo if (label.d_npartitions < MAXPARTITIONS) {
216 1.1 dillo unused = label.d_npartitions;
217 1.1 dillo label.d_npartitions++;
218 1.1 dillo } else {
219 1.1 dillo printf(
220 1.1 dillo " WARNING: no slots free for %s partition.\n",
221 1.1 dillo fstypenames[npe.p_fstype]);
222 1.1 dillo continue;
223 1.1 dillo }
224 1.1 dillo }
225 1.1 dillo
226 1.1 dillo if (verbose)
227 1.1 dillo printf(" adding %s partition to slot %c.\n",
228 1.1 dillo fstypenames[npe.p_fstype], unused + 'a');
229 1.1 dillo changed++;
230 1.1 dillo label.d_partitions[unused] = npe;
231 1.1 dillo }
232 1.1 dillo
233 1.1 dillo return (changed);
234 1.1 dillo }
235 1.1 dillo
236 1.2 joerg static struct apple_drvr_map *
237 1.1 dillo convert_drvr_map(unsigned char *buf)
238 1.1 dillo {
239 1.1 dillo struct apple_drvr_map *drvr;
240 1.1 dillo int i;
241 1.1 dillo
242 1.1 dillo drvr = (struct apple_drvr_map *)buf;
243 1.1 dillo
244 1.1 dillo BE16TOH(drvr->sbSig);
245 1.1 dillo BE16TOH(drvr->sbBlockSize);
246 1.1 dillo BE32TOH(drvr->sbBlkCount);
247 1.1 dillo BE16TOH(drvr->sbDevType);
248 1.1 dillo BE16TOH(drvr->sbDevID);
249 1.1 dillo BE32TOH(drvr->sbData);
250 1.1 dillo BE16TOH(drvr->sbDrvrCount);
251 1.1 dillo for (i=0; i<APPLE_DRVR_MAP_MAX_DESCRIPTORS; i++) {
252 1.1 dillo BE32TOH(drvr->sb_dd[i].descBlock);
253 1.1 dillo BE16TOH(drvr->sb_dd[i].descSize);
254 1.1 dillo BE16TOH(drvr->sb_dd[i].descType);
255 1.1 dillo }
256 1.1 dillo
257 1.1 dillo return drvr;
258 1.1 dillo }
259 1.1 dillo
260 1.2 joerg static struct apple_part_map_entry *
261 1.1 dillo convert_part_map_entry(unsigned char *buf)
262 1.1 dillo {
263 1.1 dillo struct apple_part_map_entry *part;
264 1.1 dillo
265 1.1 dillo part = (struct apple_part_map_entry *)buf;
266 1.1 dillo
267 1.1 dillo BE16TOH(part->pmSig);
268 1.1 dillo BE16TOH(part->pmSigPad);
269 1.1 dillo BE32TOH(part->pmMapBlkCnt);
270 1.1 dillo BE32TOH(part->pmPyPartStart);
271 1.1 dillo BE32TOH(part->pmPartBlkCnt);
272 1.1 dillo BE32TOH(part->pmLgDataStart);
273 1.1 dillo BE32TOH(part->pmDataCnt);
274 1.1 dillo BE32TOH(part->pmPartStatus);
275 1.1 dillo BE32TOH(part->pmLgBootStart);
276 1.1 dillo BE32TOH(part->pmBootSize);
277 1.1 dillo BE32TOH(part->pmBootLoad);
278 1.1 dillo BE32TOH(part->pmBootLoad2);
279 1.1 dillo BE32TOH(part->pmBootEntry);
280 1.1 dillo BE32TOH(part->pmBootEntry2);
281 1.1 dillo BE32TOH(part->pmBootCksum);
282 1.1 dillo
283 1.1 dillo return part;
284 1.1 dillo }
285 1.1 dillo
286 1.2 joerg static void
287 1.1 dillo usage(void)
288 1.1 dillo {
289 1.1 dillo fprintf(stderr, "usage: %s [-fqrw] rawdisk\n",
290 1.1 dillo getprogname());
291 1.1 dillo exit(1);
292 1.1 dillo }
293 1.1 dillo
294 1.1 dillo
295 1.1 dillo int
296 1.1 dillo main(int argc, char **argv)
297 1.1 dillo {
298 1.1 dillo int sd, ch, changed;
299 1.1 dillo char name[MAXPATHLEN];
300 1.1 dillo int force; /* force label update */
301 1.1 dillo int raw; /* update on-disk label as well */
302 1.1 dillo int verbose; /* verbose output */
303 1.1 dillo int write_it; /* update in-core label if changed */
304 1.1 dillo
305 1.1 dillo force = 0;
306 1.1 dillo raw = 0;
307 1.1 dillo verbose = 1;
308 1.1 dillo write_it = 0;
309 1.1 dillo while ((ch = getopt(argc, argv, "fqrw")) != -1) {
310 1.1 dillo switch (ch) {
311 1.1 dillo case 'f':
312 1.1 dillo force = 1;
313 1.1 dillo break;
314 1.1 dillo case 'q':
315 1.1 dillo verbose = 0;
316 1.1 dillo break;
317 1.1 dillo case 'r':
318 1.1 dillo raw = 1;
319 1.1 dillo break;
320 1.1 dillo case 'w':
321 1.1 dillo write_it = 1;
322 1.1 dillo break;
323 1.1 dillo default:
324 1.1 dillo usage();
325 1.1 dillo }
326 1.1 dillo }
327 1.1 dillo argc -= optind;
328 1.1 dillo argv += optind;
329 1.1 dillo if (argc != 1)
330 1.1 dillo usage();
331 1.1 dillo
332 1.1 dillo if ((sd = opendisk(argv[0], write_it ? O_RDWR : O_RDONLY, name,
333 1.1 dillo (size_t)MAXPATHLEN, 1)) < 0) {
334 1.1 dillo perror(argv[0]);
335 1.1 dillo exit(1);
336 1.1 dillo }
337 1.1 dillo getlabel(sd);
338 1.1 dillo changed = getparts(sd, verbose);
339 1.1 dillo
340 1.1 dillo if (verbose) {
341 1.1 dillo putchar('\n');
342 1.1 dillo showpartitions(stdout, &label, 0);
343 1.1 dillo putchar('\n');
344 1.1 dillo }
345 1.1 dillo if (write_it) {
346 1.1 dillo if (! changed && ! force)
347 1.1 dillo printf("No change; not updating disk label.\n");
348 1.1 dillo else {
349 1.1 dillo if (verbose)
350 1.1 dillo printf("Updating in-core %sdisk label.\n",
351 1.1 dillo raw ? "and on-disk " : "");
352 1.1 dillo setlabel(sd, raw);
353 1.1 dillo }
354 1.1 dillo } else {
355 1.1 dillo printf("Not updating disk label.\n");
356 1.1 dillo }
357 1.1 dillo close(sd);
358 1.1 dillo return (0);
359 1.1 dillo }
360