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