1/* $NetBSD: apmlabel.c,v 1.1.1.1 2007/03/05 23:06:53 dillo 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.1.1.1 2007/03/05 23:06:53 dillo 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); 59static void getlabel(int); 60static void setlabel(int, int); 61static int getparts(int, int); 62static struct apple_drvr_map *convert_drvr_map(unsigned char *); 63static struct apple_part_map_entry *convert_part_map_entry(unsigned char *); 64 65static struct disklabel label; 66 67static void 68getlabel(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 83static void 84setlabel(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 100static int 101getparts(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 237static struct apple_drvr_map * 238convert_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 261static struct apple_part_map_entry * 262convert_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 287static void 288usage(void) 289{ 290 fprintf(stderr, "usage: %s [-fqrw] rawdisk\n", 291 getprogname()); 292 exit(1); 293} 294 295 296int 297main(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