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