apmlabel.c revision 1.1 1 1.1 dillo /* $NetBSD: apmlabel.c,v 1.1 2007/03/05 23:06:53 dillo 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.1 dillo __RCSID("$NetBSD: apmlabel.c,v 1.1 2007/03/05 23:06:53 dillo 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.1 dillo int main(int, char **);
59 1.1 dillo void usage(void);
60 1.1 dillo void getlabel(int);
61 1.1 dillo void setlabel(int, int);
62 1.1 dillo int getparts(int, int);
63 1.1 dillo struct apple_drvr_map *convert_drvr_map(unsigned char *);
64 1.1 dillo struct apple_part_map_entry *convert_part_map_entry(unsigned char *);
65 1.1 dillo
66 1.1 dillo struct disklabel label;
67 1.1 dillo
68 1.1 dillo void
69 1.1 dillo getlabel(int sd)
70 1.1 dillo {
71 1.1 dillo
72 1.1 dillo if (ioctl(sd, DIOCGDINFO, &label) < 0) {
73 1.1 dillo perror("get label");
74 1.1 dillo exit(1);
75 1.1 dillo }
76 1.1 dillo /*
77 1.1 dillo * Some ports seem to not set the number of partitions
78 1.1 dillo * correctly, albeit they seem to set the raw partition ok!
79 1.1 dillo */
80 1.1 dillo if (label.d_npartitions <= getrawpartition())
81 1.1 dillo label.d_npartitions = getrawpartition() + 1;
82 1.1 dillo }
83 1.1 dillo
84 1.1 dillo void
85 1.1 dillo setlabel(int sd, int doraw)
86 1.1 dillo {
87 1.1 dillo int one = 1;
88 1.1 dillo
89 1.1 dillo label.d_checksum = 0;
90 1.1 dillo label.d_checksum = dkcksum(&label);
91 1.1 dillo if (ioctl(sd, doraw ? DIOCWDINFO : DIOCSDINFO, &label) < 0) {
92 1.1 dillo perror("set label");
93 1.1 dillo exit(1);
94 1.1 dillo }
95 1.1 dillo if (!doraw)
96 1.1 dillo /* If we haven't written to the disk, don't discard on close */
97 1.1 dillo ioctl(sd, DIOCKLABEL, &one);
98 1.1 dillo
99 1.1 dillo }
100 1.1 dillo
101 1.1 dillo int
102 1.1 dillo getparts(int sd, int verbose)
103 1.1 dillo {
104 1.1 dillo unsigned char buf[DEV_BSIZE];
105 1.1 dillo struct apple_drvr_map *drvr;
106 1.1 dillo struct apple_part_map_entry *part;
107 1.1 dillo struct partition npe;
108 1.1 dillo uint16_t blksize, blkcnt, partcnt;
109 1.1 dillo int i, j, unused, changed;
110 1.1 dillo uint64_t temp;
111 1.1 dillo
112 1.1 dillo changed = 0;
113 1.1 dillo
114 1.1 dillo if (lseek(sd, 0, SEEK_SET) == -1) {
115 1.1 dillo perror("seek drvr map");
116 1.1 dillo exit(1);
117 1.1 dillo }
118 1.1 dillo if ((i=read(sd, buf, sizeof(buf))) != DEV_BSIZE) {
119 1.1 dillo perror("read drvr map");
120 1.1 dillo exit(1);
121 1.1 dillo }
122 1.1 dillo drvr = convert_drvr_map(buf);
123 1.1 dillo
124 1.1 dillo if (drvr->sbSig != APPLE_DRVR_MAP_MAGIC)
125 1.1 dillo return (changed);
126 1.1 dillo blksize = drvr->sbBlockSize;
127 1.1 dillo blkcnt = drvr->sbBlkCount;
128 1.1 dillo
129 1.1 dillo partcnt = 1;
130 1.1 dillo
131 1.1 dillo for (i = 0; i < partcnt; i++) {
132 1.1 dillo if (lseek(sd, (i+1)*blksize, SEEK_SET) == -1) {
133 1.1 dillo perror("seek part");
134 1.1 dillo exit(1);
135 1.1 dillo }
136 1.1 dillo if (read(sd, buf, sizeof(buf)) != DEV_BSIZE) {
137 1.1 dillo perror("read part");
138 1.1 dillo exit(1);
139 1.1 dillo }
140 1.1 dillo
141 1.1 dillo part = convert_part_map_entry(buf);
142 1.1 dillo
143 1.1 dillo if (part->pmSig != APPLE_PART_MAP_ENTRY_MAGIC)
144 1.1 dillo return (changed);
145 1.1 dillo if (i == 0)
146 1.1 dillo partcnt = part->pmMapBlkCnt;
147 1.1 dillo /* XXX: consistency checks? */
148 1.1 dillo
149 1.1 dillo memset((void *)&npe, 0, sizeof(npe));
150 1.1 dillo
151 1.1 dillo if (strcasecmp((char *)part->pmPartType,
152 1.1 dillo APPLE_PART_TYPE_MAC) == 0
153 1.1 dillo || strcasecmp((char *)part->pmPartType, "Apple_HFSX") == 0)
154 1.1 dillo npe.p_fstype = FS_HFS;
155 1.1 dillo else if (strcasecmp((char *)part->pmPartType,
156 1.1 dillo "Apple_UFS") == 0) {
157 1.1 dillo npe.p_fstype = FS_APPLEUFS;
158 1.1 dillo npe.p_size = 16384; /* XXX */
159 1.1 dillo npe.p_fsize = 1024;
160 1.1 dillo npe.p_frag = 8;
161 1.1 dillo npe.p_cpg = 16;
162 1.1 dillo }
163 1.1 dillo else
164 1.1 dillo continue;
165 1.1 dillo
166 1.1 dillo temp = (uint64_t)part->pmDataCnt * (uint64_t)blksize;
167 1.1 dillo if (temp % label.d_secsize != 0) {
168 1.1 dillo warnx("partition size not multiple of sector size"
169 1.1 dillo ", skipping");
170 1.1 dillo continue;
171 1.1 dillo }
172 1.1 dillo npe.p_size = temp / label.d_secsize;
173 1.1 dillo temp = (uint64_t)(part->pmPyPartStart + part->pmLgDataStart)
174 1.1 dillo * (uint64_t)blksize;
175 1.1 dillo if (temp % label.d_secsize != 0) {
176 1.1 dillo warnx("partition offset not multiple of sector size"
177 1.1 dillo ", skipping");
178 1.1 dillo continue;
179 1.1 dillo }
180 1.1 dillo npe.p_offset = temp / label.d_secsize;
181 1.1 dillo
182 1.1 dillo /* find existing entry, or first free slot */
183 1.1 dillo unused = -1; /* flag as no free slot */
184 1.1 dillo if (verbose)
185 1.1 dillo printf(
186 1.1 dillo "Found %s partition; size %u (%u MB), offset %u\n",
187 1.1 dillo fstypenames[npe.p_fstype],
188 1.1 dillo npe.p_size, npe.p_size / 2048, npe.p_offset);
189 1.1 dillo for (j = 0; j < label.d_npartitions; j++) {
190 1.1 dillo struct partition *lpe;
191 1.1 dillo
192 1.1 dillo if (j == RAW_PART)
193 1.1 dillo continue;
194 1.1 dillo lpe = &label.d_partitions[j];
195 1.1 dillo if (lpe->p_size == npe.p_size &&
196 1.1 dillo lpe->p_offset == npe.p_offset
197 1.1 dillo #ifdef notyet
198 1.1 dillo && (lpe->p_fstype == npe.p_fstype ||
199 1.1 dillo lpe->p_fstype == FS_UNUSED) */
200 1.1 dillo #endif
201 1.1 dillo ) {
202 1.1 dillo if (verbose)
203 1.1 dillo printf(
204 1.1 dillo " skipping existing %s partition at slot %c.\n",
205 1.1 dillo fstypenames[lpe->p_fstype],
206 1.1 dillo j + 'a');
207 1.1 dillo unused = -2; /* flag as existing */
208 1.1 dillo break;
209 1.1 dillo }
210 1.1 dillo if (unused == -1 && lpe->p_size == 0 &&
211 1.1 dillo lpe->p_fstype == FS_UNUSED)
212 1.1 dillo unused = j;
213 1.1 dillo }
214 1.1 dillo if (unused == -2)
215 1.1 dillo continue; /* entry exists, skip... */
216 1.1 dillo if (unused == -1) {
217 1.1 dillo if (label.d_npartitions < MAXPARTITIONS) {
218 1.1 dillo unused = label.d_npartitions;
219 1.1 dillo label.d_npartitions++;
220 1.1 dillo } else {
221 1.1 dillo printf(
222 1.1 dillo " WARNING: no slots free for %s partition.\n",
223 1.1 dillo fstypenames[npe.p_fstype]);
224 1.1 dillo continue;
225 1.1 dillo }
226 1.1 dillo }
227 1.1 dillo
228 1.1 dillo if (verbose)
229 1.1 dillo printf(" adding %s partition to slot %c.\n",
230 1.1 dillo fstypenames[npe.p_fstype], unused + 'a');
231 1.1 dillo changed++;
232 1.1 dillo label.d_partitions[unused] = npe;
233 1.1 dillo }
234 1.1 dillo
235 1.1 dillo return (changed);
236 1.1 dillo }
237 1.1 dillo
238 1.1 dillo struct apple_drvr_map *
239 1.1 dillo convert_drvr_map(unsigned char *buf)
240 1.1 dillo {
241 1.1 dillo struct apple_drvr_map *drvr;
242 1.1 dillo int i;
243 1.1 dillo
244 1.1 dillo drvr = (struct apple_drvr_map *)buf;
245 1.1 dillo
246 1.1 dillo BE16TOH(drvr->sbSig);
247 1.1 dillo BE16TOH(drvr->sbBlockSize);
248 1.1 dillo BE32TOH(drvr->sbBlkCount);
249 1.1 dillo BE16TOH(drvr->sbDevType);
250 1.1 dillo BE16TOH(drvr->sbDevID);
251 1.1 dillo BE32TOH(drvr->sbData);
252 1.1 dillo BE16TOH(drvr->sbDrvrCount);
253 1.1 dillo for (i=0; i<APPLE_DRVR_MAP_MAX_DESCRIPTORS; i++) {
254 1.1 dillo BE32TOH(drvr->sb_dd[i].descBlock);
255 1.1 dillo BE16TOH(drvr->sb_dd[i].descSize);
256 1.1 dillo BE16TOH(drvr->sb_dd[i].descType);
257 1.1 dillo }
258 1.1 dillo
259 1.1 dillo return drvr;
260 1.1 dillo }
261 1.1 dillo
262 1.1 dillo struct apple_part_map_entry *
263 1.1 dillo convert_part_map_entry(unsigned char *buf)
264 1.1 dillo {
265 1.1 dillo struct apple_part_map_entry *part;
266 1.1 dillo
267 1.1 dillo part = (struct apple_part_map_entry *)buf;
268 1.1 dillo
269 1.1 dillo BE16TOH(part->pmSig);
270 1.1 dillo BE16TOH(part->pmSigPad);
271 1.1 dillo BE32TOH(part->pmMapBlkCnt);
272 1.1 dillo BE32TOH(part->pmPyPartStart);
273 1.1 dillo BE32TOH(part->pmPartBlkCnt);
274 1.1 dillo BE32TOH(part->pmLgDataStart);
275 1.1 dillo BE32TOH(part->pmDataCnt);
276 1.1 dillo BE32TOH(part->pmPartStatus);
277 1.1 dillo BE32TOH(part->pmLgBootStart);
278 1.1 dillo BE32TOH(part->pmBootSize);
279 1.1 dillo BE32TOH(part->pmBootLoad);
280 1.1 dillo BE32TOH(part->pmBootLoad2);
281 1.1 dillo BE32TOH(part->pmBootEntry);
282 1.1 dillo BE32TOH(part->pmBootEntry2);
283 1.1 dillo BE32TOH(part->pmBootCksum);
284 1.1 dillo
285 1.1 dillo return part;
286 1.1 dillo }
287 1.1 dillo
288 1.1 dillo void
289 1.1 dillo usage(void)
290 1.1 dillo {
291 1.1 dillo fprintf(stderr, "usage: %s [-fqrw] rawdisk\n",
292 1.1 dillo getprogname());
293 1.1 dillo exit(1);
294 1.1 dillo }
295 1.1 dillo
296 1.1 dillo
297 1.1 dillo int
298 1.1 dillo main(int argc, char **argv)
299 1.1 dillo {
300 1.1 dillo int sd, ch, changed;
301 1.1 dillo char name[MAXPATHLEN];
302 1.1 dillo int force; /* force label update */
303 1.1 dillo int raw; /* update on-disk label as well */
304 1.1 dillo int verbose; /* verbose output */
305 1.1 dillo int write_it; /* update in-core label if changed */
306 1.1 dillo
307 1.1 dillo force = 0;
308 1.1 dillo raw = 0;
309 1.1 dillo verbose = 1;
310 1.1 dillo write_it = 0;
311 1.1 dillo while ((ch = getopt(argc, argv, "fqrw")) != -1) {
312 1.1 dillo switch (ch) {
313 1.1 dillo case 'f':
314 1.1 dillo force = 1;
315 1.1 dillo break;
316 1.1 dillo case 'q':
317 1.1 dillo verbose = 0;
318 1.1 dillo break;
319 1.1 dillo case 'r':
320 1.1 dillo raw = 1;
321 1.1 dillo break;
322 1.1 dillo case 'w':
323 1.1 dillo write_it = 1;
324 1.1 dillo break;
325 1.1 dillo default:
326 1.1 dillo usage();
327 1.1 dillo }
328 1.1 dillo }
329 1.1 dillo argc -= optind;
330 1.1 dillo argv += optind;
331 1.1 dillo if (argc != 1)
332 1.1 dillo usage();
333 1.1 dillo
334 1.1 dillo if ((sd = opendisk(argv[0], write_it ? O_RDWR : O_RDONLY, name,
335 1.1 dillo (size_t)MAXPATHLEN, 1)) < 0) {
336 1.1 dillo perror(argv[0]);
337 1.1 dillo exit(1);
338 1.1 dillo }
339 1.1 dillo getlabel(sd);
340 1.1 dillo changed = getparts(sd, verbose);
341 1.1 dillo
342 1.1 dillo if (verbose) {
343 1.1 dillo putchar('\n');
344 1.1 dillo showpartitions(stdout, &label, 0);
345 1.1 dillo putchar('\n');
346 1.1 dillo }
347 1.1 dillo if (write_it) {
348 1.1 dillo if (! changed && ! force)
349 1.1 dillo printf("No change; not updating disk label.\n");
350 1.1 dillo else {
351 1.1 dillo if (verbose)
352 1.1 dillo printf("Updating in-core %sdisk label.\n",
353 1.1 dillo raw ? "and on-disk " : "");
354 1.1 dillo setlabel(sd, raw);
355 1.1 dillo }
356 1.1 dillo } else {
357 1.1 dillo printf("Not updating disk label.\n");
358 1.1 dillo }
359 1.1 dillo close(sd);
360 1.1 dillo return (0);
361 1.1 dillo }
362