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