1 /* $NetBSD: main.c,v 1.53 2019/08/03 04:21:37 isaki Exp $ */ 2 3 /* 4 * Copyright (c) 2006 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Julio M. Merino Vidal. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1987, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * This code is derived from software contributed to Berkeley by 37 * Symmetric Computer Systems. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 */ 63 64 #if HAVE_NBTOOL_CONFIG_H 65 #include "nbtool_config.h" 66 #endif 67 68 #include <sys/cdefs.h> 69 #ifndef lint 70 __COPYRIGHT("@(#) Copyright (c) 1987, 1993\ 71 The Regents of the University of California. All rights reserved."); 72 #endif /* not lint */ 73 74 #ifndef lint 75 #if 0 76 static char sccsid[] = "@(#)disklabel.c 8.4 (Berkeley) 5/4/95"; 77 /* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */ 78 #else 79 __RCSID("$NetBSD: main.c,v 1.53 2019/08/03 04:21:37 isaki Exp $"); 80 #endif 81 #endif /* not lint */ 82 83 #include <sys/param.h> 84 #include <sys/file.h> 85 #include <sys/stat.h> 86 #include <sys/wait.h> 87 #define DKTYPENAMES 88 #define FSTYPENAMES 89 90 #include <ctype.h> 91 #include <err.h> 92 #include <errno.h> 93 #include <signal.h> 94 #include <string.h> 95 #include <stdio.h> 96 #include <stdlib.h> 97 #include <limits.h> 98 #include <unistd.h> 99 100 #include <ufs/ufs/dinode.h> 101 #include <ufs/ffs/fs.h> 102 103 #if HAVE_NBTOOL_CONFIG_H 104 #include <nbinclude/sys/disklabel.h> 105 #include <nbinclude/sys/disklabel_acorn.h> 106 #include <nbinclude/sys/bootblock.h> 107 #include "../../include/disktab.h" 108 #else 109 #include <sys/ioctl.h> 110 #include <sys/disklabel.h> 111 #include <sys/disklabel_acorn.h> 112 #include <sys/bootblock.h> 113 #include <util.h> 114 #include <disktab.h> 115 #endif /* HAVE_NBTOOL_CONFIG_H */ 116 117 #include "pathnames.h" 118 #include "extern.h" 119 #include "dkcksum.h" 120 #include "bswap.h" 121 122 /* 123 * Disklabel: read and write disklabels. 124 * The label is usually placed on one of the first sectors of the disk. 125 * Many machines also place a bootstrap in the same area, 126 * in which case the label is embedded in the bootstrap. 127 * The bootstrap source must leave space at the proper offset 128 * for the label on such machines. 129 */ 130 131 #ifndef BBSIZE 132 #define BBSIZE 8192 /* size of boot area, with label */ 133 #endif 134 135 #define DISKMAGIC_REV bswap32(DISKMAGIC) 136 /* To delete a label, we just invert the magic numbers */ 137 #define DISKMAGIC_DELETED (~DISKMAGIC) 138 #define DISKMAGIC_DELETED_REV bswap32(~DISKMAGIC) 139 140 #define DEFEDITOR _PATH_VI 141 142 char specname[MAXPATHLEN]; 143 144 /* Some global data, all too hard to pass about */ 145 char bootarea[BBSIZE]; /* Buffer matching part of disk */ 146 int bootarea_len; /* Number of bytes we actually read */ 147 static struct disklabel lab; /* The label we have updated */ 148 149 static int Aflag; /* Action all labels */ 150 static int Fflag; /* Read/write from file */ 151 static int rflag; /* Read/write direct from disk */ 152 static int tflag; /* Format output as disktab */ 153 int Cflag; /* CHS format output */ 154 static int Dflag; /* Delete old labels (use with write) */ 155 static int Iflag; /* Read/write direct, but default if absent */ 156 static int lflag; /* List all known file system types and exit */ 157 static int verbose; 158 static int read_all; /* set if op = READ && Aflag */ 159 160 static int write_label(int); 161 static int readlabel_direct(int); 162 static void writelabel_direct(int); 163 static int update_label(int, u_int, u_int); 164 static struct disklabel *find_label(int, u_int); 165 #if !defined(NATIVELABEL_ONLY) 166 static void getmachineparams(const char *); 167 #endif 168 169 static void makedisktab(FILE *, struct disklabel *); 170 static void makelabel(const char *, const char *); 171 static void l_perror(const char *); 172 static void readlabel(int); 173 static int edit(int); 174 static int editit(const char *); 175 static char *skip(char *); 176 static char *word(char *); 177 static int getasciilabel(FILE *, struct disklabel *); 178 __dead static void usage(void); 179 static int qsort_strcmp(const void *, const void *); 180 static int getulong(const char *, char, char **, 181 unsigned long *, unsigned long); 182 #define GETNUM32(a, v) getulong(a, '\0', NULL, v, UINT32_MAX) 183 #define GETNUM16(a, v) getulong(a, '\0', NULL, v, UINT16_MAX) 184 #define GETNUM8(a, v) getulong(a, '\0', NULL, v, UINT8_MAX) 185 186 static int set_writable_fd = -1; 187 188 #if !defined(NATIVELABEL_ONLY) 189 static u_int labeloffset; 190 static u_int labelsector; 191 static int labelusesmbr; 192 u_int maxpartitions; 193 static int byteorder; 194 195 static int biendian_p; 196 #ifndef HAVE_NBTOOL_CONFIG_H 197 static int native_p = 1; 198 #endif 199 int bswap_p; 200 201 static const struct disklabel_params { 202 const char *machine; 203 u_char labelusesmbr : 1; 204 u_char labelsector : 7; 205 u_char maxpartitions; 206 u_char raw_part; 207 u_char oldmaxpartitions; 208 u_short labeloffset; 209 u_short byteorder; 210 } disklabel_params[] = { 211 { "mvme68k", 0, 0, 8, 2, 0, 0, BIG_ENDIAN }, /* m68k */ 212 { "next68k", 0, 0, 8, 2, 0, 0, BIG_ENDIAN }, /* m68k */ 213 214 { "algor", 0, 0, 8, 2, 0, 64, LITTLE_ENDIAN }, /* mips */ 215 { "alpha", 0, 0, 8, 2, 0, 64, LITTLE_ENDIAN }, /* alpha */ 216 { "luna68k", 0, 0, 8, 2, 0, 64, BIG_ENDIAN }, /* m68k */ 217 { "mac68k", 0, 0, 8, 2, 0, 64, BIG_ENDIAN }, /* m68k */ 218 { "news68k", 0, 0, 8, 2, 0, 64, BIG_ENDIAN }, /* m68k */ 219 { "newsmips", 0, 0, 8, 2, 0, 64, BIG_ENDIAN }, /* mips */ 220 { "pmax", 0, 0, 8, 2, 0, 64, LITTLE_ENDIAN }, /* mips */ 221 { "sun2", 0, 0, 8, 2, 0, 64, BIG_ENDIAN }, /* m68k */ 222 { "sun68k", 0, 0, 8, 2, 0, 64, BIG_ENDIAN }, /* m68010 */ 223 { "x68k", 0, 0, 8, 2, 0, 64, BIG_ENDIAN }, /* m68k */ 224 225 { "vax", 0, 0, 12, 2, 8, 64, LITTLE_ENDIAN }, /* vax */ 226 227 { "amiga", 0, 0, 16, 2, 0, 64, BIG_ENDIAN }, /* m68k */ 228 { "amigappc", 0, 0, 16, 2, 0, 64, BIG_ENDIAN }, /* powerpc */ 229 { "evbmips", 0, 0, 16, 2, 0, 64, 0 }, /* mips */ 230 { "evbppc", 0, 0, 16, 2, 0, 64, BIG_ENDIAN }, /* powerpc */ 231 232 { "sparc", 0, 0, 8, 2, 0, 128, BIG_ENDIAN }, /* sun */ 233 { "sparc64", 0, 0, 8, 2, 0, 128, BIG_ENDIAN }, /* sun */ 234 { "sun3", 0, 0, 8, 2, 0, 128, BIG_ENDIAN }, /* sun */ 235 236 { "atari", 0, 0, 16, 2, 0, 516, BIG_ENDIAN }, /* m68k */ 237 238 { "mipsco", 0, 1, 8, 2, 0, 0, BIG_ENDIAN }, /* mips */ 239 { "mvmeppc", 0, 1, 8, 3, 0, 0, BIG_ENDIAN }, /* powerpc */ 240 241 { "bebox", 0, 1, 8, 3, 0, 0, BIG_ENDIAN }, /* powerpc */ 242 243 { "emips", 0, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* mips */ 244 { "hppa", 0, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* hppa */ 245 { "ibmnws", 0, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* powerpc */ 246 { "ofppc", 0, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* powerpc */ 247 { "rs6000", 0, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* powerpc */ 248 { "sandpoint", 0, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* powerpc */ 249 { "sgimips", 0, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* mips */ 250 251 { "sbmips", 0, 1, 16, 3, 0, 0, 0 }, /* mips */ 252 253 { "cesfic", 0, 2, 8, 2, 0, 0, BIG_ENDIAN }, /* m68k */ 254 { "hp300", 0, 2, 8, 2, 0, 0, BIG_ENDIAN }, /* m68k */ 255 256 { "ews4800mips",0, 9, 16, 15, 0, 0, BIG_ENDIAN }, /* mips */ 257 258 { "macppc", 1, 0, 16, 2, 0, 64, BIG_ENDIAN }, /* powerpc */ 259 { "pmon", 1, 0, 16, 2, 0, 64, 0 }, /* evbmips */ 260 261 { "prep", 1, 1, 8, 2, 0, 0, BIG_ENDIAN }, /* powerpc */ 262 263 { "dreamcast", 1, 1, 16, 2, 0, 0, LITTLE_ENDIAN }, /* sh3 */ 264 { "evbcf", 1, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* coldfire */ 265 { "evbppc-mbr", 1, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* powerpc */ 266 { "evbsh3", 1, 1, 16, 2, 0, 0, 0 }, /* sh3 */ 267 { "hpcsh", 1, 1, 16, 2, 0, 0, LITTLE_ENDIAN }, /* sh3 */ 268 { "mmeye", 1, 1, 16, 2, 0, 0, 0 }, /* sh3 */ 269 { "or1k", 1, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* or1k */ 270 { "riscv", 1, 1, 16, 2, 0, 0, LITTLE_ENDIAN }, /* riscv */ 271 272 { "acorn32", 1, 1, 16, 2, 8, 0, LITTLE_ENDIAN }, /* arm */ 273 { "cats", 1, 1, 16, 2, 8, 0, LITTLE_ENDIAN }, /* arm */ 274 { "evbarm", 1, 1, 16, 2, 8, 0, 0 }, /* arm */ 275 { "iyonix", 1, 1, 16, 2, 8, 0, LITTLE_ENDIAN }, /* arm */ 276 { "netwinder", 1, 1, 16, 2, 8, 0, LITTLE_ENDIAN }, /* arm */ 277 { "shark", 1, 1, 16, 2, 8, 0, LITTLE_ENDIAN }, /* arm */ 278 279 { "amd64", 1, 1, 16, 3, 0, 0, LITTLE_ENDIAN }, /* x86 */ 280 { "arc", 1, 1, 16, 3, 0, 0, LITTLE_ENDIAN }, /* mips */ 281 { "cobalt", 1, 1, 16, 3, 0, 0, LITTLE_ENDIAN }, /* mips */ 282 { "landisk", 1, 1, 16, 3, 0, 0, LITTLE_ENDIAN }, /* sh3 */ 283 284 { "epoc32", 1, 1, 16, 3, 8, 0, LITTLE_ENDIAN }, /* arm */ 285 { "hpcarm", 1, 1, 16, 3, 8, 0, LITTLE_ENDIAN }, /* arm */ 286 { "hpcmips", 1, 1, 16, 3, 8, 0, LITTLE_ENDIAN }, /* mips */ 287 { "i386", 1, 1, 16, 3, 8, 0, LITTLE_ENDIAN }, /* x86 */ 288 { "ia64", 1, 1, 16, 3, 8, 0, LITTLE_ENDIAN }, /* x86 */ 289 { "zaurus", 1, 1, 16, 3, 8, 0, LITTLE_ENDIAN }, /* arm */ 290 291 { NULL, 0, 0, 0, 0, 0, 0, 0 }, /* must be last */ 292 }; 293 294 #ifndef HAVE_NBTOOL_CONFIG_H 295 static struct disklabel_params native_params; 296 #endif 297 298 static const struct arch_endian { 299 int byteorder; 300 const char *arch; 301 } arch_endians[] = { 302 { LITTLE_ENDIAN, "aarch64" }, 303 { LITTLE_ENDIAN, "alpha" }, 304 { LITTLE_ENDIAN, "arm" }, 305 { LITTLE_ENDIAN, "earm" }, 306 { LITTLE_ENDIAN, "earmhf" }, 307 { LITTLE_ENDIAN, "earmv4" }, 308 { LITTLE_ENDIAN, "earmv5" }, 309 { LITTLE_ENDIAN, "earmv6" }, 310 { LITTLE_ENDIAN, "earmv6hf" }, 311 { LITTLE_ENDIAN, "earmv7" }, 312 { LITTLE_ENDIAN, "earmv7hf" }, 313 { LITTLE_ENDIAN, "i386" }, 314 { LITTLE_ENDIAN, "ia64" }, 315 { LITTLE_ENDIAN, "mipsel" }, 316 { LITTLE_ENDIAN, "mips64el" }, 317 { LITTLE_ENDIAN, "riscv32" }, 318 { LITTLE_ENDIAN, "riscv64" }, 319 { LITTLE_ENDIAN, "sh3el" }, 320 { LITTLE_ENDIAN, "vax" }, 321 { LITTLE_ENDIAN, "x86_64" }, 322 323 { BIG_ENDIAN, "aarch64eb" }, 324 { BIG_ENDIAN, "armeb" }, 325 { BIG_ENDIAN, "coldfire" }, 326 { BIG_ENDIAN, "earmeb" }, 327 { BIG_ENDIAN, "earmhfeb" }, 328 { BIG_ENDIAN, "earmv4eb" }, 329 { BIG_ENDIAN, "earmv5eb" }, 330 { BIG_ENDIAN, "earmv6eb" }, 331 { BIG_ENDIAN, "earmv6hfeb" }, 332 { BIG_ENDIAN, "earmv7eb" }, 333 { BIG_ENDIAN, "earmv7hfeb" }, 334 { BIG_ENDIAN, "hppa" }, 335 { BIG_ENDIAN, "m68000" }, 336 { BIG_ENDIAN, "m68k" }, 337 { BIG_ENDIAN, "mipseb" }, 338 { BIG_ENDIAN, "mips64eb" }, 339 { BIG_ENDIAN, "or1k" }, 340 { BIG_ENDIAN, "powerpc" }, 341 { BIG_ENDIAN, "sh3eb" }, 342 { BIG_ENDIAN, "sparc" }, 343 { BIG_ENDIAN, "sparc64" }, 344 345 { 0, NULL }, 346 }; 347 348 /* Default location for label - only used if we don't find one to update */ 349 #define LABEL_OFFSET (dklabel_getlabelsector() * DEV_BSIZE + dklabel_getlabeloffset()) 350 #else 351 #define labeloffset LABELOFFSET 352 #define labelsector LABELSECTOR 353 #define labelusesmbr LABELUSESMBR 354 #define maxpartitions MAXPARTITIONS 355 #define LABEL_OFFSET LABELOFFSET 356 #endif /* !NATIVELABEL_ONLY */ 357 358 /* 359 * For portability it doesn't make sense to use any other value.... 360 * Except, maybe, the size of a physical sector. 361 * This value is used if we have to write a label to the start of an mbr ptn. 362 */ 363 #ifndef LABELOFFSET_MBR 364 #define LABELOFFSET_MBR 512 365 #endif 366 367 #if HAVE_NBTOOL_CONFIG_H 368 static int 369 opendisk(const char *path, int flags, char *buf, int buflen, int cooked) 370 { 371 int f; 372 f = open(path, flags, 0); 373 strlcpy(buf, path, buflen); 374 return f; 375 } 376 #endif /* HAVE_NBTOOL_CONFIG_H */ 377 378 #if !defined(NATIVELABEL_ONLY) 379 static void 380 setbyteorder(int new_byteorder) 381 { 382 static int set_p; 383 384 if ((!biendian_p || set_p) 385 && byteorder != 0 386 && byteorder != new_byteorder) { 387 warnx("changing %s byteorder to %s", 388 byteorder == LITTLE_ENDIAN ? "le" : "be", 389 new_byteorder == LITTLE_ENDIAN ? "le" : "be"); 390 } 391 byteorder = new_byteorder; 392 biendian_p = 0; 393 set_p = 1; 394 } 395 396 static void 397 getmachineparams(const char *mach) 398 { 399 const struct disklabel_params *dp = disklabel_params; 400 for (; dp->machine != NULL; dp++) { 401 if (!strcmp(mach, dp->machine)) { 402 labelusesmbr = dp->labelusesmbr; 403 labelsector = dp->labelsector; 404 labeloffset = dp->labeloffset; 405 maxpartitions = dp->maxpartitions; 406 biendian_p = (dp->byteorder == 0); 407 if (!biendian_p) 408 setbyteorder(dp->byteorder); 409 return; 410 } 411 } 412 errx(1, "%s: unknown machine type", mach); 413 } 414 415 static void 416 getarchbyteorder(const char *arch) 417 { 418 const struct arch_endian *p = arch_endians; 419 for (; p->arch != NULL; p++) { 420 if (!strcmp(arch, p->arch)) { 421 setbyteorder(p->byteorder); 422 return; 423 } 424 } 425 errx(1, "%s: unknown arch", arch); 426 } 427 428 static daddr_t 429 dklabel_getlabelsector(void) 430 { 431 unsigned long int nval; 432 char *end; 433 const char *val; 434 435 if ((val = getenv("DISKLABELSECTOR")) == NULL) 436 return labelsector; 437 if ((nval = strtoul(val, &end, 10)) == ULONG_MAX && errno == ERANGE) 438 err(EXIT_FAILURE, "DISKLABELSECTOR in environment"); 439 return nval; 440 } 441 442 static off_t 443 dklabel_getlabeloffset(void) 444 { 445 unsigned long int nval; 446 char *end; 447 const char *val; 448 449 if ((val = getenv("DISKLABELOFFSET")) == NULL) 450 return labeloffset; 451 if ((nval = strtoul(val, &end, 10)) == ULONG_MAX && errno == ERANGE) 452 err(EXIT_FAILURE, "DISKLABELOFFSET in environment"); 453 return nval; 454 } 455 #endif /* !NATIVELABEL_ONLY */ 456 457 static void 458 clear_writable(void) 459 { 460 static int zero = 0; 461 dk_ioctl(set_writable_fd, DIOCWLABEL, &zero); 462 } 463 464 int 465 main(int argc, char *argv[]) 466 { 467 FILE *t; 468 int ch, f, error; 469 char *dkname; 470 #if !defined(NATIVELABEL_ONLY) 471 char *cp; 472 #endif 473 struct stat sb; 474 int writable; 475 enum { 476 UNSPEC, EDIT, READ, RESTORE, SETWRITABLE, SETREADONLY, 477 WRITE, 478 #if !defined(NO_INTERACT) 479 INTERACT, 480 #endif 481 DELETE 482 } op = UNSPEC, old_op; 483 #if !defined(NATIVELABEL_ONLY) 484 unsigned long val; 485 #endif 486 487 #ifndef HAVE_NBTOOL_CONFIG_H 488 #if !defined(NATIVELABEL_ONLY) 489 labeloffset = native_params.labeloffset = getlabeloffset(); 490 labelsector = native_params.labelsector = getlabelsector(); 491 labelusesmbr = native_params.labelusesmbr = getlabelusesmbr(); 492 maxpartitions = native_params.maxpartitions = getmaxpartitions(); 493 byteorder = native_params.byteorder = BYTE_ORDER; 494 #endif 495 #endif 496 497 #if !defined(NATIVELABEL_ONLY) 498 if ((cp = getenv("MACHINE")) != NULL) { 499 getmachineparams(cp); 500 } 501 502 if ((cp = getenv("MACHINE_ARCH")) != NULL) { 503 getarchbyteorder(cp); 504 } 505 #endif 506 507 #if HAVE_NBTOOL_CONFIG_H 508 /* We must avoid doing any ioctl requests */ 509 Fflag = rflag = 1; 510 #endif 511 512 error = 0; 513 #if !defined(NATIVELABEL_ONLY) 514 while ((ch = getopt(argc, argv, "AB:CDFIL:M:NO:P:RWef:ilmnrtvw")) != -1) { 515 #else 516 while ((ch = getopt(argc, argv, "ACDFINRWef:ilrtvw")) != -1) { 517 #endif 518 old_op = op; 519 switch (ch) { 520 case 'A': /* Action all labels */ 521 Aflag = 1; 522 rflag = 1; 523 break; 524 case 'C': /* Display in CHS format */ 525 Cflag = 1; 526 break; 527 case 'D': /* Delete all existing labels */ 528 Dflag = 1; 529 rflag = 1; 530 break; 531 case 'F': /* Treat 'disk' as a regular file */ 532 Fflag = 1; 533 rflag = 1; /* Force direct access */ 534 break; 535 case 'I': /* Use default label if none found */ 536 Iflag = 1; 537 rflag = 1; /* Implies direct access */ 538 break; 539 case 'R': /* Restore label from text file */ 540 op = RESTORE; 541 break; 542 #if !defined(NATIVELABEL_ONLY) 543 case 'B': /* byteorder */ 544 if (!strcmp(optarg, "be")) { 545 setbyteorder(BIG_ENDIAN); 546 } else if (!strcmp(optarg, "le")) { 547 setbyteorder(LITTLE_ENDIAN); 548 } else { 549 errx(1, "%s: not be or le", optarg); 550 } 551 break; 552 case 'M': /* machine type */ 553 getmachineparams(optarg); 554 break; 555 #endif 556 case 'N': /* Disallow writes to label sector */ 557 op = SETREADONLY; 558 break; 559 #if !defined(NATIVELABEL_ONLY) 560 case 'L': /* Label sector */ 561 val = strtoul(optarg, NULL, 10); 562 if ((val == ULONG_MAX && errno == ERANGE) || val > UINT_MAX) 563 err(EXIT_FAILURE, "invalid label sector: %s", optarg); 564 labelsector = val; 565 break; 566 case 'O': /* Label offset */ 567 val = strtoul(optarg, NULL, 10); 568 if ((val == ULONG_MAX && errno == ERANGE) || val > UINT_MAX) 569 err(EXIT_FAILURE, "invalid label offset: %s", optarg); 570 labeloffset = val; 571 break; 572 case 'P': /* Max partitions */ 573 val = strtoul(optarg, NULL, 10); 574 if ((val == ULONG_MAX && errno == ERANGE) || val < 1 || val > UINT_MAX) 575 err(EXIT_FAILURE, "invalid max partitions: %s", optarg); 576 maxpartitions = val; 577 break; 578 #endif 579 case 'W': /* Allow writes to label sector */ 580 op = SETWRITABLE; 581 break; 582 case 'e': /* Edit label with $EDITOR */ 583 op = EDIT; 584 break; 585 case 'f': /* Name of disktab file */ 586 if (setdisktab(optarg) == -1) 587 usage(); 588 break; 589 #if !defined(NO_INTERACT) 590 case 'i': /* Edit using built-in editor */ 591 op = INTERACT; 592 break; 593 #endif /* !NO_INTERACT */ 594 case 'l': /* List all known file system types and exit */ 595 lflag = 1; 596 break; 597 #if !defined(NATIVELABEL_ONLY) 598 case 'm': /* Expect disk to have an MBR */ 599 labelusesmbr = 1; 600 break; 601 case 'n': /* Expect disk to not have an MBR */ 602 labelusesmbr = 0; 603 break; 604 #endif 605 case 'r': /* Read/write label directly from disk */ 606 rflag = 1; 607 break; 608 case 't': /* Format output as a disktab entry */ 609 tflag = 1; 610 break; 611 case 'v': /* verbose/diag output */ 612 verbose++; 613 break; 614 case 'w': /* Write label based on disktab entry */ 615 op = WRITE; 616 break; 617 case '?': 618 default: 619 usage(); 620 } 621 if (old_op != UNSPEC && old_op != op) 622 usage(); 623 } 624 625 if (maxpartitions > MAXPARTITIONS) { 626 errx(1, "too large maxpartitions > %u\n", MAXPARTITIONS); 627 } 628 629 #if !defined(NATIVELABEL_ONLY) 630 if (maxpartitions == 0) { 631 errx(1, "unknown label: use -M/-B and $MACHINE/$MACHINE_ARCH"); 632 } 633 if (byteorder != BIG_ENDIAN && byteorder != LITTLE_ENDIAN) { 634 errx(1, "unknown byteorder"); 635 } 636 bswap_p = (byteorder != BYTE_ORDER); 637 #ifdef DEBUG 638 printf("labelusesmbr=%d labelsector=%u labeloffset=%u maxpartitions=%u\n", 639 labelusesmbr, labelsector, labeloffset, maxpartitions); 640 printf("byteorder=%d bswap_p=%d\n", byteorder, bswap_p); 641 #endif 642 #ifndef HAVE_NBTOOL_CONFIG_H 643 /* 644 * If the disklabel has the same location as the native disklabel and 645 * fewer or equal paritions, we can use the native ioctls. Otherwise 646 * force file/raw access. 647 */ 648 native_p = native_params.labelusesmbr == labelusesmbr 649 && native_params.labelsector == labelsector 650 && native_params.labeloffset == labeloffset 651 && maxpartitions <= native_params.maxpartitions 652 && !bswap_p; 653 if (!native_p) 654 Fflag = rflag = 1; 655 #endif 656 #endif /* !NATIVELABEL_ONLY */ 657 658 argc -= optind; 659 argv += optind; 660 661 if (lflag) 662 exit(list_fs_types() ? EXIT_SUCCESS : EXIT_FAILURE); 663 664 if (op == UNSPEC) 665 op = Dflag ? DELETE : READ; 666 667 if (argc < 1) 668 usage(); 669 670 if (Iflag && op != EDIT 671 #if !defined(NO_INTERACT) 672 && op != INTERACT 673 #endif 674 ) 675 usage(); 676 677 dkname = argv[0]; 678 f = opendisk(dkname, op == READ ? O_RDONLY : O_RDWR, 679 specname, sizeof specname, 0); 680 if (f < 0) 681 err(4, "%s", specname); 682 683 if (!Fflag && fstat(f, &sb) == 0 && S_ISREG(sb.st_mode)) 684 Fflag = rflag = 1; 685 686 switch (op) { 687 688 case DELETE: /* Remove all existing labels */ 689 if (argc != 1) 690 usage(); 691 Dflag = 2; 692 writelabel_direct(f); 693 break; 694 695 case EDIT: 696 if (argc != 1) 697 usage(); 698 readlabel(f); 699 error = edit(f); 700 break; 701 702 #if !defined(NO_INTERACT) 703 case INTERACT: 704 if (argc != 1) 705 usage(); 706 readlabel(f); 707 /* 708 * XXX: Fill some default values so checklabel does not fail 709 */ 710 if (lab.d_bbsize == 0) 711 lab.d_bbsize = BBSIZE; 712 if (lab.d_sbsize == 0) 713 lab.d_sbsize = SBLOCKSIZE; 714 interact(&lab, f); 715 break; 716 #endif /* !NO_INTERACT */ 717 718 case READ: 719 if (argc != 1) 720 usage(); 721 read_all = Aflag; 722 readlabel(f); 723 if (read_all) 724 /* Label got printed in the bowels of readlabel */ 725 break; 726 if (tflag) 727 makedisktab(stdout, &lab); 728 else { 729 showinfo(stdout, &lab, specname); 730 showpartitions(stdout, &lab, Cflag); 731 } 732 error = checklabel(&lab); 733 if (error) 734 error += 100; 735 break; 736 737 case RESTORE: 738 if (argc != 2) 739 usage(); 740 if (!(t = fopen(argv[1], "r"))) 741 err(4, "%s", argv[1]); 742 if (getasciilabel(t, &lab)) 743 error = write_label(f); 744 else 745 error = 1; 746 break; 747 748 case SETREADONLY: 749 writable = 0; 750 goto do_diocwlabel; 751 case SETWRITABLE: 752 writable = 1; 753 do_diocwlabel: 754 if (argc != 1) 755 usage(); 756 if (dk_ioctl(f, DIOCWLABEL, &writable) < 0) 757 err(4, "ioctl DIOCWLABEL"); 758 break; 759 760 case WRITE: /* Create label from /etc/disktab entry & write */ 761 if (argc < 2 || argc > 3) 762 usage(); 763 makelabel(argv[1], argv[2]); 764 if (checklabel(&lab) == 0) 765 error = write_label(f); 766 else 767 error = 1; 768 break; 769 770 case UNSPEC: 771 usage(); 772 773 } 774 exit(error); 775 } 776 777 /* 778 * Construct a prototype disklabel from /etc/disktab. 779 */ 780 static void 781 makelabel(const char *type, const char *name) 782 { 783 struct disklabel *dp; 784 785 dp = getdiskbyname(type); 786 if (dp == NULL) 787 errx(1, "unknown disk type: %s", type); 788 lab = *dp; 789 790 /* d_packname is union d_boot[01], so zero */ 791 (void)memset(lab.d_packname, 0, sizeof(lab.d_packname)); 792 if (name) 793 (void)strncpy(lab.d_packname, name, sizeof(lab.d_packname)); 794 } 795 796 static int 797 write_label(int f) 798 { 799 int writable; 800 801 lab.d_magic = DISKMAGIC; 802 lab.d_magic2 = DISKMAGIC; 803 lab.d_checksum = 0; 804 lab.d_checksum = dkcksum(&lab); 805 806 if (rflag) { 807 /* Write the label directly to the disk */ 808 809 /* 810 * First set the kernel disk label, 811 * then write a label to the raw disk. 812 * If the SDINFO ioctl fails because it is unimplemented, 813 * keep going; otherwise, the kernel consistency checks 814 * may prevent us from changing the current (in-core) 815 * label. 816 */ 817 if (!Fflag && dk_ioctl(f, DIOCSDINFO, &lab) < 0 && 818 errno != ENODEV && errno != ENOTTY) { 819 l_perror("ioctl DIOCSDINFO"); 820 return (1); 821 } 822 /* 823 * write enable label sector before write (if necessary), 824 * disable after writing. 825 */ 826 writable = 1; 827 if (!Fflag) { 828 if (dk_ioctl(f, DIOCWLABEL, &writable) < 0) 829 perror("ioctl DIOCWLABEL"); 830 set_writable_fd = f; 831 atexit(clear_writable); 832 } 833 834 writelabel_direct(f); 835 836 /* 837 * Now issue a DIOCWDINFO. This will let the kernel convert the 838 * disklabel to some machdep format if needed. 839 */ 840 /* XXX: This is stupid! */ 841 if (!Fflag && dk_ioctl(f, DIOCWDINFO, &lab) < 0) { 842 l_perror("ioctl DIOCWDINFO"); 843 return (1); 844 } 845 } else { 846 /* Get the kernel to write the label */ 847 if (dk_ioctl(f, DIOCWDINFO, &lab) < 0) { 848 l_perror("ioctl DIOCWDINFO"); 849 return (1); 850 } 851 } 852 853 #ifdef VAX_ALTLABELS 854 if (lab.d_type == DKTYPE_SMD && lab.d_flags & D_BADSECT && 855 lab.d_secsize == 512) { 856 /* Write the label to the odd sectors of the last track! */ 857 daddr_t alt; 858 int i; 859 uint8_t sec0[512]; 860 861 if (pread(f, sec0, 512, 0) < 512) { 862 warn("read master label to write alternates"); 863 return 0; 864 } 865 866 alt = lab.d_ncylinders * lab.d_secpercyl - lab.d_nsectors; 867 for (i = 1; i < 11 && (uint32_t)i < lab.d_nsectors; i += 2) { 868 if (pwrite(f, sec0, 512, (off_t)(alt + i) * 512) < 512) 869 warn("alternate label %d write", i/2); 870 } 871 } 872 #endif /* VAX_ALTLABELS */ 873 874 return 0; 875 } 876 877 int 878 writelabel(int f, struct disklabel *lp) 879 { 880 if (lp != &lab) 881 lab = *lp; 882 return write_label(f); 883 } 884 885 static void 886 l_perror(const char *s) 887 { 888 889 switch (errno) { 890 891 case ESRCH: 892 warnx("%s: No disk label on disk;\n" 893 "use \"disklabel -I\" to install initial label", s); 894 break; 895 896 case EINVAL: 897 warnx("%s: Label magic number or checksum is wrong!\n" 898 "(disklabel or kernel is out of date?)", s); 899 break; 900 901 case EBUSY: 902 warnx("%s: Open partition would move or shrink", s); 903 break; 904 905 case EXDEV: 906 warnx("%s: Labeled partition or 'a' partition must start" 907 " at beginning of disk", s); 908 break; 909 910 default: 911 warn("%s", s); 912 break; 913 } 914 } 915 916 #ifdef NO_MBR_SUPPORT 917 #define process_mbr(f, action) 1 918 #else 919 /* 920 * Scan DOS/MBR partition table and extended partition list for NetBSD ptns. 921 */ 922 static int 923 process_mbr(int f, int (*action)(int, u_int)) 924 { 925 struct mbr_partition *dp; 926 struct mbr_sector mbr; 927 int rval = 1, res; 928 int part; 929 u_int ext_base, next_ext, this_ext, start; 930 931 ext_base = 0; 932 next_ext = 0; 933 for (;;) { 934 this_ext = next_ext; 935 next_ext = 0; 936 if (verbose > 1) 937 warnx("reading mbr sector %u", this_ext); 938 if (pread(f, &mbr, sizeof mbr, this_ext * (off_t)DEV_BSIZE) 939 != sizeof(mbr)) { 940 if (verbose) 941 warn("Can't read master boot record %u", 942 this_ext); 943 break; 944 } 945 946 /* Check if table is valid. */ 947 if (mbr.mbr_magic != htole16(MBR_MAGIC)) { 948 if (verbose) 949 warnx("Invalid signature in mbr record %u", 950 this_ext); 951 break; 952 } 953 954 dp = &mbr.mbr_parts[0]; 955 956 /* Find NetBSD partition(s). */ 957 for (part = 0; part < MBR_PART_COUNT; dp++, part++) { 958 start = le32toh(dp->mbrp_start); 959 switch (dp->mbrp_type) { 960 #ifdef COMPAT_386BSD_MBRPART 961 case MBR_PTYPE_386BSD: 962 if (ext_base != 0) 963 break; 964 /* FALLTHROUGH */ 965 #endif 966 case MBR_PTYPE_NETBSD: 967 res = action(f, this_ext + start); 968 if (res <= 0) 969 /* Found or failure */ 970 return res; 971 if (res > rval) 972 /* Keep largest value */ 973 rval = res; 974 break; 975 case MBR_PTYPE_EXT: 976 case MBR_PTYPE_EXT_LBA: 977 case MBR_PTYPE_EXT_LNX: 978 next_ext = start; 979 break; 980 default: 981 break; 982 } 983 } 984 if (next_ext == 0) 985 /* No more extended partitions */ 986 break; 987 next_ext += ext_base; 988 if (ext_base == 0) 989 ext_base = next_ext; 990 991 if (next_ext <= this_ext) { 992 if (verbose) 993 warnx("Invalid extended chain %x <= %x", 994 next_ext, this_ext); 995 break; 996 } 997 /* Maybe we should check against the disk size... */ 998 } 999 1000 return rval; 1001 } 1002 1003 static int 1004 readlabel_mbr(int f, u_int sector) 1005 { 1006 struct disklabel *disk_lp; 1007 1008 disk_lp = find_label(f, sector); 1009 if (disk_lp == NULL) 1010 return 1; 1011 targettohlabel(&lab, disk_lp); 1012 return 0; 1013 } 1014 1015 static int 1016 writelabel_mbr(int f, u_int sector) 1017 { 1018 return update_label(f, sector, labelusesmbr ? LABELOFFSET_MBR : ~0U) ? 2 : 0; 1019 } 1020 1021 #endif /* !NO_MBR_SUPPORT */ 1022 1023 #ifndef USE_ACORN 1024 #define get_filecore_partition(f) 0 1025 #else 1026 /* 1027 * static int filecore_checksum(u_char *bootblock) 1028 * 1029 * Calculates the filecore boot block checksum. This is used to validate 1030 * a filecore boot block on the disk. If a boot block is validated then 1031 * it is used to locate the partition table. If the boot block is not 1032 * validated, it is assumed that the whole disk is NetBSD. 1033 * 1034 * The basic algorithm is: 1035 * 1036 * for (each byte in block, excluding checksum) { 1037 * sum += byte; 1038 * if (sum > 255) 1039 * sum -= 255; 1040 * } 1041 * 1042 * That's equivalent to summing all of the bytes in the block 1043 * (excluding the checksum byte, of course), then calculating the 1044 * checksum as "cksum = sum - ((sum - 1) / 255) * 255)". That 1045 * expression may or may not yield a faster checksum function, 1046 * but it's easier to reason about. 1047 * 1048 * Note that if you have a block filled with bytes of a single 1049 * value "X" (regardless of that value!) and calculate the cksum 1050 * of the block (excluding the checksum byte), you will _always_ 1051 * end up with a checksum of X. (Do the math; that can be derived 1052 * from the checksum calculation function!) That means that 1053 * blocks which contain bytes which all have the same value will 1054 * always checksum properly. That's a _very_ unlikely occurence 1055 * (probably impossible, actually) for a valid filecore boot block, 1056 * so we treat such blocks as invalid. 1057 */ 1058 static int 1059 filecore_checksum(u_char *bootblock) 1060 { 1061 u_char byte0, accum_diff; 1062 u_int sum; 1063 int i; 1064 1065 sum = 0; 1066 accum_diff = 0; 1067 byte0 = bootblock[0]; 1068 1069 /* 1070 * Sum the contents of the block, keeping track of whether 1071 * or not all bytes are the same. If 'accum_diff' ends up 1072 * being zero, all of the bytes are, in fact, the same. 1073 */ 1074 for (i = 0; i < 511; ++i) { 1075 sum += bootblock[i]; 1076 accum_diff |= bootblock[i] ^ byte0; 1077 } 1078 1079 /* 1080 * Check to see if the checksum byte is the same as the 1081 * rest of the bytes, too. (Note that if all of the bytes 1082 * are the same except the checksum, a checksum compare 1083 * won't succeed, but that's not our problem.) 1084 */ 1085 accum_diff |= bootblock[i] ^ byte0; 1086 1087 /* All bytes in block are the same; call it invalid. */ 1088 if (accum_diff == 0) 1089 return (-1); 1090 1091 return (sum - ((sum - 1) / 255) * 255); 1092 } 1093 1094 /* 1095 * Check for the presence of a RiscOS filecore boot block 1096 * indicating an ADFS file system on the disc. 1097 * Return the offset to the NetBSD part of the disc if 1098 * this can be determined. 1099 * This routine will terminate disklabel if the disc 1100 * is found to be ADFS only. 1101 */ 1102 static u_int 1103 get_filecore_partition(int f) 1104 { 1105 struct filecore_bootblock *fcbb; 1106 static u_char bb[DEV_BSIZE]; 1107 u_int offset; 1108 struct riscix_partition_table *riscix_part; 1109 int loop; 1110 1111 if (pread(f, bb, sizeof(bb), (off_t)FILECORE_BOOT_SECTOR * DEV_BSIZE) != sizeof(bb)) 1112 err(4, "can't read filecore boot block"); 1113 fcbb = (struct filecore_bootblock *)bb; 1114 1115 /* Check if table is valid. */ 1116 if (filecore_checksum(bb) != fcbb->checksum) 1117 return (0); 1118 1119 /* 1120 * Check for NetBSD/arm32 (RiscBSD) partition marker. 1121 * If found the NetBSD disklabel location is easy. 1122 */ 1123 offset = (fcbb->partition_cyl_low + (fcbb->partition_cyl_high << 8)) 1124 * fcbb->heads * fcbb->secspertrack; 1125 1126 switch (fcbb->partition_type) { 1127 1128 case PARTITION_FORMAT_RISCBSD: 1129 return (offset); 1130 1131 case PARTITION_FORMAT_RISCIX: 1132 /* 1133 * Read the RISCiX partition table and search for the 1134 * first partition named "RiscBSD", "NetBSD", or "Empty:" 1135 * 1136 * XXX is use of 'Empty:' really desirable?! -- cgd 1137 */ 1138 1139 if (pread(f, bb, sizeof(bb), (off_t)offset * DEV_BSIZE) != sizeof(bb)) 1140 err(4, "can't read riscix partition table"); 1141 riscix_part = (struct riscix_partition_table *)bb; 1142 1143 for (loop = 0; loop < NRISCIX_PARTITIONS; ++loop) { 1144 if (strcmp((char *)riscix_part->partitions[loop].rp_name, 1145 "RiscBSD") == 0 || 1146 strcmp((char *)riscix_part->partitions[loop].rp_name, 1147 "NetBSD") == 0 || 1148 strcmp((char *)riscix_part->partitions[loop].rp_name, 1149 "Empty:") == 0) { 1150 return riscix_part->partitions[loop].rp_start; 1151 break; 1152 } 1153 } 1154 /* 1155 * Valid filecore boot block, RISCiX partition table 1156 * but no NetBSD partition. We should leave this 1157 * disc alone. 1158 */ 1159 errx(4, "cannot label: no NetBSD partition found" 1160 " in RISCiX partition table"); 1161 1162 default: 1163 /* 1164 * Valid filecore boot block and no non-ADFS partition. 1165 * This means that the whole disc is allocated for ADFS 1166 * so do not trash ! If the user really wants to put a 1167 * NetBSD disklabel on the disc then they should remove 1168 * the filecore boot block first with dd. 1169 */ 1170 errx(4, "cannot label: filecore-only disk" 1171 " (no non-ADFS partition)"); 1172 } 1173 return (0); 1174 } 1175 #endif /* USE_ACORN */ 1176 1177 /* 1178 * Fetch disklabel for disk to 'lab'. 1179 * Use ioctl to get label unless -r flag is given. 1180 */ 1181 static void 1182 readlabel(int f) 1183 { 1184 if (rflag) { 1185 /* Get label directly from disk */ 1186 if (readlabel_direct(f) == 0) 1187 return; 1188 /* 1189 * There was no label on the disk. Get the fictious one 1190 * as a basis for initialisation. 1191 */ 1192 if (!Fflag && Iflag && (dk_ioctl(f, DIOCGDINFO, &lab) == 0 || 1193 dk_ioctl(f, DIOCGDEFLABEL, &lab) == 0)) 1194 return; 1195 } else { 1196 /* Get label from kernel. */ 1197 if (dk_ioctl(f, DIOCGDINFO, &lab) < 0) 1198 err(4, "ioctl DIOCGDINFO"); 1199 return; 1200 } 1201 1202 if (read_all == 2) 1203 /* We actually found one, and printed it... */ 1204 exit(0); 1205 errx(1, "could not read existing label"); 1206 } 1207 1208 /* 1209 * Reading the label from the disk is largely a case of 'hunt the label'. 1210 * and since different architectures default to different places there 1211 * could even be more than one label that contradict each other! 1212 * For now we look in the expected place, then search through likely 1213 * other locations. 1214 */ 1215 static struct disklabel * 1216 find_label(int f, u_int sector) 1217 { 1218 struct disklabel *disk_lp, hlp, tlp; 1219 int i; 1220 off_t offset; 1221 const char *is_deleted; 1222 1223 bootarea_len = pread(f, bootarea, sizeof bootarea, 1224 sector * (off_t)DEV_BSIZE); 1225 if (bootarea_len <= 0) { 1226 if (verbose) 1227 warn("failed to read bootarea from sector %u", sector); 1228 return NULL; 1229 } 1230 1231 if (verbose > 2) 1232 warnx("read sector %u len %d looking for label", 1233 sector, bootarea_len); 1234 1235 /* Check expected offset first */ 1236 for (offset = LABEL_OFFSET, i = -4;; offset = i += 4) { 1237 is_deleted = ""; 1238 if (i == LABEL_OFFSET) 1239 continue; 1240 disk_lp = (void *)(bootarea + offset); 1241 memcpy(&tlp, disk_lp, sizeof(tlp)); 1242 if ((char *)(disk_lp + 1) > bootarea + bootarea_len) 1243 break; 1244 if (tlp.d_magic2 != tlp.d_magic) 1245 continue; 1246 if (read_all && (tlp.d_magic == DISKMAGIC_DELETED || 1247 tlp.d_magic == DISKMAGIC_DELETED_REV)) { 1248 tlp.d_magic ^= ~0u; 1249 tlp.d_magic2 ^= ~0u; 1250 is_deleted = "deleted "; 1251 } 1252 if (target32toh(tlp.d_magic) != DISKMAGIC) { 1253 /* XXX: Do something about byte-swapped labels ? */ 1254 if (target32toh(tlp.d_magic) == DISKMAGIC_REV && 1255 target32toh(tlp.d_magic2) == DISKMAGIC_REV) 1256 warnx("ignoring %sbyteswapped label" 1257 " at offset %jd from sector %u", 1258 is_deleted, (intmax_t)offset, sector); 1259 continue; 1260 } 1261 if (target16toh(tlp.d_npartitions) > maxpartitions || 1262 dkcksum_target(&tlp) != 0) { 1263 if (verbose > 0) 1264 warnx("corrupt label found at offset %jd in " 1265 "sector %u", (intmax_t)offset, sector); 1266 continue; 1267 } 1268 if (verbose > 1) 1269 warnx("%slabel found at offset %jd from sector %u", 1270 is_deleted, (intmax_t)offset, sector); 1271 if (!read_all) 1272 return disk_lp; 1273 1274 /* To print all the labels we have to do it here */ 1275 /* XXX: maybe we should compare them? */ 1276 targettohlabel(&hlp, &tlp); 1277 printf("# %ssector %u offset %jd bytes\n", 1278 is_deleted, sector, (intmax_t)offset); 1279 if (tflag) 1280 makedisktab(stdout, &hlp); 1281 else { 1282 showinfo(stdout, &hlp, specname); 1283 showpartitions(stdout, &hlp, Cflag); 1284 } 1285 checklabel(&hlp); 1286 htotargetlabel(&tlp, &hlp); 1287 memcpy(disk_lp, &tlp, sizeof(tlp)); 1288 /* Remember we've found a label */ 1289 read_all = 2; 1290 } 1291 return NULL; 1292 } 1293 1294 static void 1295 write_bootarea(int f, u_int sector) 1296 { 1297 int wlen; 1298 1299 if (bootarea_len <= 0) 1300 errx(1, "attempting to write after failed read"); 1301 1302 #ifdef ALPHA_BOOTBLOCK_CKSUM 1303 /* 1304 * The Alpha requires that the boot block be checksummed. 1305 * <sys/bootblock.h> provides a macro to do it. 1306 */ 1307 if (sector == 0) { 1308 struct alpha_boot_block *bb; 1309 1310 bb = (struct alpha_boot_block *)(void *)bootarea; 1311 bb->bb_cksum = 0; 1312 ALPHA_BOOT_BLOCK_CKSUM(bb, &bb->bb_cksum); 1313 } 1314 #endif /* ALPHA_BOOTBLOCK_CKSUM */ 1315 1316 wlen = pwrite(f, bootarea, bootarea_len, sector * (off_t)DEV_BSIZE); 1317 if (wlen == bootarea_len) 1318 return; 1319 if (wlen == -1) 1320 err(1, "disklabel write (sector %u) size %d failed", 1321 sector, bootarea_len); 1322 errx(1, "disklabel write (sector %u) size %d truncated to %d", 1323 sector, bootarea_len, wlen); 1324 } 1325 1326 static int 1327 update_label(int f, u_int label_sector, u_int label_offset) 1328 { 1329 struct disklabel *disk_lp; 1330 1331 disk_lp = find_label(f, label_sector); 1332 1333 if (disk_lp && Dflag) { 1334 /* Invalidate the existing label */ 1335 disk_lp->d_magic ^= ~0u; 1336 disk_lp->d_magic2 ^= ~0u; 1337 if (Dflag == 2) 1338 write_bootarea(f, label_sector); 1339 /* Force label to default location */ 1340 disk_lp = NULL; 1341 } 1342 1343 if (Dflag == 2) 1344 /* We are just deleting the label */ 1345 return 0; 1346 1347 if (disk_lp == NULL) { 1348 if (label_offset == ~0u) 1349 return 0; 1350 /* Nothing on the disk - we need to add it */ 1351 disk_lp = (void *)(bootarea + label_offset); 1352 if ((char *)(disk_lp + 1) > bootarea + bootarea_len) 1353 errx(1, "no space in bootarea (sector %u) " 1354 "to create label", label_sector); 1355 } 1356 1357 htotargetlabel(disk_lp, &lab); 1358 write_bootarea(f, label_sector); 1359 return 1; 1360 } 1361 1362 static void 1363 writelabel_direct(int f) 1364 { 1365 u_int label_sector; 1366 int written = 0; 1367 int rval; 1368 1369 label_sector = get_filecore_partition(f); 1370 if (label_sector != 0) 1371 /* The offset needs to be that from the acorn ports... */ 1372 written = update_label(f, label_sector, DEV_BSIZE); 1373 1374 rval = process_mbr(f, writelabel_mbr); 1375 1376 if (rval == 2 || written) 1377 /* Don't add a label to sector 0, but update one if there */ 1378 update_label(f, 0, ~0u); 1379 else 1380 update_label(f, 0, LABEL_OFFSET); 1381 } 1382 1383 static int 1384 readlabel_direct(int f) 1385 { 1386 struct disklabel *disk_lp; 1387 u_int filecore_partition_offset; 1388 1389 filecore_partition_offset = get_filecore_partition(f); 1390 if (filecore_partition_offset != 0) { 1391 disk_lp = find_label(f, filecore_partition_offset); 1392 if (disk_lp != NULL) { 1393 targettohlabel(&lab, disk_lp); 1394 return 0; 1395 } 1396 } 1397 1398 if (labelusesmbr && process_mbr(f, readlabel_mbr) == 0) 1399 return 0; 1400 1401 disk_lp = find_label(f, 0); 1402 if (disk_lp != NULL) { 1403 targettohlabel(&lab, disk_lp); 1404 return 0; 1405 } 1406 1407 if (!labelusesmbr && process_mbr(f, readlabel_mbr) == 0) 1408 return 0; 1409 1410 return 1; 1411 } 1412 1413 static void 1414 makedisktab(FILE *f, struct disklabel *lp) 1415 { 1416 int i; 1417 const char *did; 1418 struct partition *pp; 1419 1420 did = "\\\n\t:"; 1421 (void) fprintf(f, "%.*s|Automatically generated label:\\\n\t:dt=", 1422 (int) sizeof(lp->d_typename), lp->d_typename); 1423 if ((unsigned) lp->d_type < DKMAXTYPES) 1424 (void) fprintf(f, "%s:", dktypenames[lp->d_type]); 1425 else 1426 (void) fprintf(f, "unknown%" PRIu16 ":", lp->d_type); 1427 1428 (void) fprintf(f, "se#%" PRIu32 ":", lp->d_secsize); 1429 (void) fprintf(f, "ns#%" PRIu32 ":", lp->d_nsectors); 1430 (void) fprintf(f, "nt#%" PRIu32 ":", lp->d_ntracks); 1431 (void) fprintf(f, "sc#%" PRIu32 ":", lp->d_secpercyl); 1432 (void) fprintf(f, "nc#%" PRIu32 ":", lp->d_ncylinders); 1433 1434 if ((lp->d_secpercyl * lp->d_ncylinders) != lp->d_secperunit) { 1435 (void) fprintf(f, "%ssu#%" PRIu32 ":", did, lp->d_secperunit); 1436 did = ""; 1437 } 1438 if (lp->d_rpm != 3600) { 1439 (void) fprintf(f, "%srm#%" PRIu16 ":", did, lp->d_rpm); 1440 did = ""; 1441 } 1442 if (lp->d_interleave != 1) { 1443 (void) fprintf(f, "%sil#%" PRIu16 ":", did, lp->d_interleave); 1444 did = ""; 1445 } 1446 if (lp->d_trackskew != 0) { 1447 (void) fprintf(f, "%ssk#%" PRIu16 ":", did, lp->d_trackskew); 1448 did = ""; 1449 } 1450 if (lp->d_cylskew != 0) { 1451 (void) fprintf(f, "%scs#%" PRIu16 ":", did, lp->d_cylskew); 1452 did = ""; 1453 } 1454 if (lp->d_headswitch != 0) { 1455 (void) fprintf(f, "%shs#%" PRIu32 ":", did, lp->d_headswitch); 1456 did = ""; 1457 } 1458 if (lp->d_trkseek != 0) { 1459 (void) fprintf(f, "%sts#%" PRIu32 ":", did, lp->d_trkseek); 1460 did = ""; 1461 } 1462 #ifdef notyet 1463 (void) fprintf(f, "drivedata: "); 1464 for (i = NDDATA - 1; i >= 0; i--) 1465 if (lp->d_drivedata[i]) 1466 break; 1467 if (i < 0) 1468 i = 0; 1469 for (j = 0; j <= i; j++) 1470 (void) fprintf(f, "%" PRIu32 " ", lp->d_drivedata[j]); 1471 #endif /* notyet */ 1472 pp = lp->d_partitions; 1473 for (i = 0; i < lp->d_npartitions; i++, pp++) { 1474 if (pp->p_size) { 1475 char c = 'a' + i; 1476 (void) fprintf(f, "\\\n\t:"); 1477 (void) fprintf(f, "p%c#%" PRIu32 ":", c, pp->p_size); 1478 (void) fprintf(f, "o%c#%" PRIu32 ":", c, pp->p_offset); 1479 if (pp->p_fstype != FS_UNUSED) { 1480 if ((unsigned) pp->p_fstype < FSMAXTYPES) 1481 (void) fprintf(f, "t%c=%s:", c, 1482 fstypenames[pp->p_fstype]); 1483 else 1484 (void) fprintf(f, 1485 "t%c=unknown%" PRIu8 ":", 1486 c, pp->p_fstype); 1487 } 1488 switch (pp->p_fstype) { 1489 1490 case FS_UNUSED: 1491 break; 1492 1493 case FS_BSDFFS: 1494 case FS_BSDLFS: 1495 case FS_EX2FS: 1496 case FS_ADOS: 1497 case FS_APPLEUFS: 1498 (void) fprintf(f, "b%c#%" PRIu64 ":", c, 1499 (uint64_t)pp->p_fsize * pp->p_frag); 1500 (void) fprintf(f, "f%c#%" PRIu32 ":", c, 1501 pp->p_fsize); 1502 break; 1503 default: 1504 break; 1505 } 1506 } 1507 } 1508 (void) fprintf(f, "\n"); 1509 (void) fflush(f); 1510 } 1511 1512 static int 1513 edit(int f) 1514 { 1515 const char *tmpdir; 1516 char tmpfil[MAXPATHLEN]; 1517 int first, ch, fd; 1518 int get_ok; 1519 FILE *fp; 1520 1521 if ((tmpdir = getenv("TMPDIR")) == NULL) 1522 tmpdir = _PATH_TMP; 1523 (void)snprintf(tmpfil, sizeof(tmpfil), "%s/%s", tmpdir, TMPFILE); 1524 if ((fd = mkstemp(tmpfil)) == -1 || (fp = fdopen(fd, "w")) == NULL) { 1525 warn("%s", tmpfil); 1526 return (1); 1527 } 1528 (void)fchmod(fd, 0600); 1529 showinfo(fp, &lab, specname); 1530 showpartitions(fp, &lab, Cflag); 1531 (void) fclose(fp); 1532 for (;;) { 1533 if (!editit(tmpfil)) 1534 break; 1535 fp = fopen(tmpfil, "r"); 1536 if (fp == NULL) { 1537 warn("%s", tmpfil); 1538 break; 1539 } 1540 (void) memset(&lab, 0, sizeof(lab)); 1541 get_ok = getasciilabel(fp, &lab); 1542 fclose(fp); 1543 if (get_ok && write_label(f) == 0) { 1544 (void) unlink(tmpfil); 1545 return (0); 1546 } 1547 (void) printf("re-edit the label? [y]: "); 1548 (void) fflush(stdout); 1549 first = ch = getchar(); 1550 while (ch != '\n' && ch != EOF) 1551 ch = getchar(); 1552 if (first == 'n' || first == 'N') 1553 break; 1554 } 1555 (void)unlink(tmpfil); 1556 return (1); 1557 } 1558 1559 static int 1560 editit(const char *tmpfil) 1561 { 1562 int pid, xpid; 1563 int status; 1564 sigset_t nsigset, osigset; 1565 1566 sigemptyset(&nsigset); 1567 sigaddset(&nsigset, SIGINT); 1568 sigaddset(&nsigset, SIGQUIT); 1569 sigaddset(&nsigset, SIGHUP); 1570 sigprocmask(SIG_BLOCK, &nsigset, &osigset); 1571 while ((pid = fork()) < 0) { 1572 if (errno != EAGAIN) { 1573 sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); 1574 warn("fork"); 1575 return (0); 1576 } 1577 sleep(1); 1578 } 1579 if (pid == 0) { 1580 const char *ed; 1581 char *buf; 1582 int retval; 1583 1584 sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); 1585 setgid(getgid()); 1586 setuid(getuid()); 1587 if ((ed = getenv("EDITOR")) == (char *)0) 1588 ed = DEFEDITOR; 1589 /* 1590 * Jump through a few extra hoops in case someone's editor 1591 * is "editor arg1 arg2". 1592 */ 1593 asprintf(&buf, "%s %s", ed, tmpfil); 1594 if (!buf) 1595 err(1, "malloc"); 1596 retval = execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", buf, NULL); 1597 if (retval == -1) 1598 perror(ed); 1599 exit(retval); 1600 } 1601 while ((xpid = wait(&status)) >= 0) 1602 if (xpid == pid) 1603 break; 1604 sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); 1605 return (!status); 1606 } 1607 1608 static char * 1609 skip(char *cp) 1610 { 1611 1612 cp += strspn(cp, " \t"); 1613 if (*cp == '\0') 1614 return (NULL); 1615 return (cp); 1616 } 1617 1618 static char * 1619 word(char *cp) 1620 { 1621 1622 if (cp == NULL || *cp == '\0') 1623 return (NULL); 1624 1625 cp += strcspn(cp, " \t"); 1626 if (*cp == '\0') 1627 return (NULL); 1628 *cp++ = '\0'; 1629 cp += strspn(cp, " \t"); 1630 if (*cp == '\0') 1631 return (NULL); 1632 return (cp); 1633 } 1634 1635 #define _CHECKLINE \ 1636 if (tp == NULL || *tp == '\0') { \ 1637 warnx("line %d: too few fields", lineno); \ 1638 errors++; \ 1639 break; \ 1640 } 1641 1642 #define __CHECKLINE \ 1643 if (*tp == NULL || **tp == '\0') { \ 1644 warnx("line %d: too few fields", lineno); \ 1645 *tp = _error_; \ 1646 return 0; \ 1647 } 1648 1649 static char _error_[] = ""; 1650 #define NXTNUM(n) if ((n = nxtnum(&tp, lineno),0) + tp != _error_) \ 1651 ; else goto error 1652 #define NXTXNUM(n) if ((n = nxtxnum(&tp, lp, lineno),0) + tp != _error_) \ 1653 ; else goto error 1654 1655 static unsigned long 1656 nxtnum(char **tp, int lineno) 1657 { 1658 char *cp; 1659 unsigned long v; 1660 1661 __CHECKLINE 1662 if (getulong(*tp, '\0', &cp, &v, UINT32_MAX) != 0) { 1663 warnx("line %d: syntax error", lineno); 1664 *tp = _error_; 1665 return 0; 1666 } 1667 *tp = cp; 1668 return v; 1669 } 1670 1671 static unsigned long 1672 nxtxnum(char **tp, struct disklabel *lp, int lineno) 1673 { 1674 char *cp, *ncp; 1675 unsigned long n, v; 1676 1677 __CHECKLINE 1678 cp = *tp; 1679 if (getulong(cp, '/', &ncp, &n, UINT32_MAX) != 0) 1680 goto bad; 1681 1682 if (*ncp == '/') { 1683 n *= lp->d_secpercyl; 1684 cp = ncp + 1; 1685 if (getulong(cp, '/', &ncp, &v, UINT32_MAX) != 0) 1686 goto bad; 1687 n += v * lp->d_nsectors; 1688 cp = ncp + 1; 1689 if (getulong(cp, '\0', &ncp, &v, UINT32_MAX) != 0) 1690 goto bad; 1691 n += v; 1692 } 1693 *tp = ncp; 1694 return n; 1695 bad: 1696 warnx("line %d: invalid format", lineno); 1697 *tp = _error_; 1698 return 0; 1699 } 1700 1701 /* 1702 * Read an ascii label in from fd f, 1703 * in the same format as that put out by showinfo() and showpartitions(), 1704 * and fill in lp. 1705 */ 1706 static int 1707 getasciilabel(FILE *f, struct disklabel *lp) 1708 { 1709 const char *const *cpp, *s; 1710 struct partition *pp; 1711 char *cp, *tp, line[BUFSIZ], tbuf[15]; 1712 int lineno, errors; 1713 unsigned long v; 1714 unsigned int part; 1715 1716 lineno = 0; 1717 errors = 0; 1718 lp->d_bbsize = BBSIZE; /* XXX */ 1719 lp->d_sbsize = SBLOCKSIZE; /* XXX */ 1720 while (fgets(line, sizeof(line) - 1, f)) { 1721 lineno++; 1722 if ((cp = strpbrk(line, "#\r\n")) != NULL) 1723 *cp = '\0'; 1724 cp = skip(line); 1725 if (cp == NULL) /* blank line or comment line */ 1726 continue; 1727 tp = strchr(cp, ':'); /* everything has a colon in it */ 1728 if (tp == NULL) { 1729 warnx("line %d: syntax error", lineno); 1730 errors++; 1731 continue; 1732 } 1733 *tp++ = '\0', tp = skip(tp); 1734 if (!strcmp(cp, "type")) { 1735 if (tp == NULL) { 1736 strlcpy(tbuf, "unknown", sizeof(tbuf)); 1737 tp = tbuf; 1738 } 1739 cpp = dktypenames; 1740 for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) 1741 if ((s = *cpp) && !strcasecmp(s, tp)) { 1742 lp->d_type = cpp - dktypenames; 1743 goto next; 1744 } 1745 if (GETNUM16(tp, &v) != 0) { 1746 warnx("line %d: syntax error", lineno); 1747 errors++; 1748 continue; 1749 } 1750 if (v >= DKMAXTYPES) 1751 warnx("line %d: warning, unknown disk type: %s", 1752 lineno, tp); 1753 lp->d_type = v; 1754 continue; 1755 } 1756 if (!strcmp(cp, "flags")) { 1757 for (v = 0; (cp = tp) && *cp != '\0';) { 1758 tp = word(cp); 1759 if (!strcasecmp(cp, "removable")) 1760 v |= D_REMOVABLE; 1761 else if (!strcasecmp(cp, "ecc")) 1762 v |= D_ECC; 1763 else if (!strcasecmp(cp, "badsect")) 1764 v |= D_BADSECT; 1765 else { 1766 warnx("line %d: bad flag: %s", 1767 lineno, cp); 1768 errors++; 1769 } 1770 } 1771 lp->d_flags = v; 1772 continue; 1773 } 1774 if (!strcmp(cp, "drivedata")) { 1775 int i; 1776 1777 for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) { 1778 if (GETNUM32(cp, &v) != 0) { 1779 warnx("line %d: bad drive data", 1780 lineno); 1781 errors++; 1782 } else 1783 lp->d_drivedata[i] = v; 1784 i++; 1785 tp = word(cp); 1786 } 1787 continue; 1788 } 1789 if (sscanf(cp, "%lu partitions", &v) == 1) { 1790 if (v == 0 || v > maxpartitions) { 1791 warnx("line %d: bad # of partitions", lineno); 1792 lp->d_npartitions = maxpartitions; 1793 errors++; 1794 } else 1795 lp->d_npartitions = v; 1796 continue; 1797 } 1798 if (tp == NULL) { 1799 tbuf[0] = '\0'; 1800 tp = tbuf; 1801 } 1802 if (!strcmp(cp, "disk")) { 1803 strncpy(lp->d_typename, tp, sizeof(lp->d_typename)); 1804 continue; 1805 } 1806 if (!strcmp(cp, "label")) { 1807 strncpy(lp->d_packname, tp, sizeof(lp->d_packname)); 1808 continue; 1809 } 1810 if (!strcmp(cp, "bytes/sector")) { 1811 if (GETNUM32(tp, &v) != 0 || v <= 0 || (v % 512) != 0) { 1812 warnx("line %d: bad %s: %s", lineno, cp, tp); 1813 errors++; 1814 } else 1815 lp->d_secsize = v; 1816 continue; 1817 } 1818 if (!strcmp(cp, "sectors/track")) { 1819 if (GETNUM32(tp, &v) != 0) { 1820 warnx("line %d: bad %s: %s", lineno, cp, tp); 1821 errors++; 1822 } else 1823 lp->d_nsectors = v; 1824 continue; 1825 } 1826 if (!strcmp(cp, "sectors/cylinder")) { 1827 if (GETNUM32(tp, &v) != 0) { 1828 warnx("line %d: bad %s: %s", lineno, cp, tp); 1829 errors++; 1830 } else 1831 lp->d_secpercyl = v; 1832 continue; 1833 } 1834 if (!strcmp(cp, "tracks/cylinder")) { 1835 if (GETNUM32(tp, &v) != 0) { 1836 warnx("line %d: bad %s: %s", lineno, cp, tp); 1837 errors++; 1838 } else 1839 lp->d_ntracks = v; 1840 continue; 1841 } 1842 if (!strcmp(cp, "cylinders")) { 1843 if (GETNUM32(tp, &v) != 0) { 1844 warnx("line %d: bad %s: %s", lineno, cp, tp); 1845 errors++; 1846 } else 1847 lp->d_ncylinders = v; 1848 continue; 1849 } 1850 if (!strcmp(cp, "total sectors") || 1851 !strcmp(cp, "sectors/unit")) { 1852 if (GETNUM32(tp, &v) != 0) { 1853 warnx("line %d: bad %s: %s", lineno, cp, tp); 1854 errors++; 1855 } else 1856 lp->d_secperunit = v; 1857 continue; 1858 } 1859 if (!strcmp(cp, "rpm")) { 1860 if (GETNUM16(tp, &v) != 0) { 1861 warnx("line %d: bad %s: %s", lineno, cp, tp); 1862 errors++; 1863 } else 1864 lp->d_rpm = v; 1865 continue; 1866 } 1867 if (!strcmp(cp, "interleave")) { 1868 if (GETNUM16(tp, &v) != 0) { 1869 warnx("line %d: bad %s: %s", lineno, cp, tp); 1870 errors++; 1871 } else 1872 lp->d_interleave = v; 1873 continue; 1874 } 1875 if (!strcmp(cp, "trackskew")) { 1876 if (GETNUM16(tp, &v) != 0) { 1877 warnx("line %d: bad %s: %s", lineno, cp, tp); 1878 errors++; 1879 } else 1880 lp->d_trackskew = v; 1881 continue; 1882 } 1883 if (!strcmp(cp, "cylinderskew")) { 1884 if (GETNUM16(tp, &v) != 0) { 1885 warnx("line %d: bad %s: %s", lineno, cp, tp); 1886 errors++; 1887 } else 1888 lp->d_cylskew = v; 1889 continue; 1890 } 1891 if (!strcmp(cp, "headswitch")) { 1892 if (GETNUM32(tp, &v) != 0) { 1893 warnx("line %d: bad %s: %s", lineno, cp, tp); 1894 errors++; 1895 } else 1896 lp->d_headswitch = v; 1897 continue; 1898 } 1899 if (!strcmp(cp, "track-to-track seek")) { 1900 if (GETNUM32(tp, &v) != 0) { 1901 warnx("line %d: bad %s: %s", lineno, cp, tp); 1902 errors++; 1903 } else 1904 lp->d_trkseek = v; 1905 continue; 1906 } 1907 if ('a' > *cp || *cp > 'z' || cp[1] != '\0') { 1908 warnx("line %d: unknown field: %s", lineno, cp); 1909 errors++; 1910 continue; 1911 } 1912 1913 /* We have a partition entry */ 1914 part = *cp - 'a'; 1915 1916 if (part >= maxpartitions) { 1917 warnx("line %d: bad partition name: %s", lineno, cp); 1918 errors++; 1919 continue; 1920 } 1921 if (part >= __arraycount(lp->d_partitions)) { 1922 warnx("line %d: partition id %s, >= %zu", lineno, 1923 cp, __arraycount(lp->d_partitions)); 1924 errors++; 1925 continue; 1926 } 1927 pp = &lp->d_partitions[part]; 1928 1929 NXTXNUM(pp->p_size); 1930 NXTXNUM(pp->p_offset); 1931 /* can't use word() here because of blanks in fstypenames[] */ 1932 tp += strspn(tp, " \t"); 1933 _CHECKLINE 1934 cp = tp; 1935 cpp = fstypenames; 1936 for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) { 1937 s = *cpp; 1938 if (s == NULL || 1939 (cp[strlen(s)] != ' ' && 1940 cp[strlen(s)] != '\t' && 1941 cp[strlen(s)] != '\0')) 1942 continue; 1943 if (!memcmp(s, cp, strlen(s))) { 1944 pp->p_fstype = cpp - fstypenames; 1945 tp += strlen(s); 1946 if (*tp == '\0') 1947 tp = NULL; 1948 else { 1949 tp += strspn(tp, " \t"); 1950 if (*tp == '\0') 1951 tp = NULL; 1952 } 1953 goto gottype; 1954 } 1955 } 1956 tp = word(cp); 1957 if (isdigit(*cp & 0xff)) { 1958 if (GETNUM8(cp, &v) != 0) { 1959 warnx("line %d: syntax error", lineno); 1960 errors++; 1961 } 1962 } else 1963 v = FSMAXTYPES; 1964 if ((unsigned)v >= FSMAXTYPES) { 1965 warnx("line %d: warning, unknown file system type: %s", 1966 lineno, cp); 1967 warnx("tip: use -l to see all valid file system " 1968 "types"); 1969 v = FS_UNUSED; 1970 } 1971 pp->p_fstype = v; 1972 gottype: 1973 switch (pp->p_fstype) { 1974 1975 case FS_UNUSED: /* XXX */ 1976 NXTNUM(pp->p_fsize); 1977 if (pp->p_fsize == 0) 1978 break; 1979 NXTNUM(v); 1980 pp->p_frag = v / pp->p_fsize; 1981 break; 1982 1983 case FS_BSDFFS: 1984 case FS_ADOS: 1985 case FS_APPLEUFS: 1986 NXTNUM(pp->p_fsize); 1987 if (pp->p_fsize == 0) 1988 break; 1989 NXTNUM(v); 1990 pp->p_frag = v / pp->p_fsize; 1991 NXTNUM(pp->p_cpg); 1992 break; 1993 case FS_BSDLFS: 1994 NXTNUM(pp->p_fsize); 1995 if (pp->p_fsize == 0) 1996 break; 1997 NXTNUM(v); 1998 pp->p_frag = v / pp->p_fsize; 1999 NXTNUM(pp->p_sgs); 2000 break; 2001 case FS_EX2FS: 2002 NXTNUM(pp->p_fsize); 2003 if (pp->p_fsize == 0) 2004 break; 2005 NXTNUM(v); 2006 pp->p_frag = v / pp->p_fsize; 2007 break; 2008 case FS_ISO9660: 2009 NXTNUM(pp->p_cdsession); 2010 break; 2011 default: 2012 break; 2013 } 2014 continue; 2015 error: 2016 errors++; 2017 next: 2018 ; 2019 } 2020 errors += checklabel(lp); 2021 return (errors == 0); 2022 } 2023 2024 /* 2025 * Check disklabel for errors and fill in 2026 * derived fields according to supplied values. 2027 */ 2028 int 2029 checklabel(struct disklabel *lp) 2030 { 2031 struct partition *pp, *qp; 2032 int i, j, errors; 2033 char part; 2034 2035 errors = 0; 2036 if (lp->d_secsize == 0) { 2037 warnx("sector size %" PRIu32, lp->d_secsize); 2038 return (1); 2039 } 2040 if (lp->d_nsectors == 0) { 2041 warnx("sectors/track %" PRIu32, lp->d_nsectors); 2042 return (1); 2043 } 2044 if (lp->d_ntracks == 0) { 2045 warnx("tracks/cylinder %" PRIu32, lp->d_ntracks); 2046 return (1); 2047 } 2048 if (lp->d_ncylinders == 0) { 2049 warnx("cylinders/unit %" PRIu32, lp->d_ncylinders); 2050 errors++; 2051 } 2052 if (lp->d_rpm == 0) 2053 warnx("warning, revolutions/minute %" PRIu16, lp->d_rpm); 2054 if (lp->d_secpercyl == 0) 2055 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 2056 if (lp->d_secperunit == 0) 2057 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 2058 if (lp->d_bbsize == 0) { 2059 warnx("boot block size %" PRIu32, lp->d_bbsize); 2060 errors++; 2061 } else if (lp->d_bbsize % lp->d_secsize) 2062 warnx("warning, boot block size %% sector-size != 0"); 2063 if (lp->d_sbsize == 0) { 2064 warnx("super block size %" PRIu32, lp->d_sbsize); 2065 errors++; 2066 } else if (lp->d_sbsize % lp->d_secsize) 2067 warnx("warning, super block size %% sector-size != 0"); 2068 if (lp->d_npartitions > maxpartitions) 2069 warnx("warning, number of partitions (%" PRIu16 ") > " 2070 "MAXPARTITIONS (%d)", 2071 lp->d_npartitions, maxpartitions); 2072 else 2073 for (i = maxpartitions - 1; i >= lp->d_npartitions; i--) { 2074 part = 'a' + i; 2075 pp = &lp->d_partitions[i]; 2076 if (pp->p_size || pp->p_offset) { 2077 warnx("warning, partition %c increased " 2078 "number of partitions from %" PRIu16 2079 " to %d", 2080 part, lp->d_npartitions, i + 1); 2081 lp->d_npartitions = i + 1; 2082 break; 2083 } 2084 } 2085 for (i = 0; i < lp->d_npartitions; i++) { 2086 part = 'a' + i; 2087 pp = &lp->d_partitions[i]; 2088 if (pp->p_size == 0 && pp->p_offset != 0) 2089 warnx("warning, partition %c: size 0, but " 2090 "offset %" PRIu32, 2091 part, pp->p_offset); 2092 #ifdef STRICT_CYLINDER_ALIGNMENT 2093 if (pp->p_offset % lp->d_secpercyl) { 2094 warnx("warning, partition %c:" 2095 " not starting on cylinder boundary", 2096 part); 2097 errors++; 2098 } 2099 #endif /* STRICT_CYLINDER_ALIGNMENT */ 2100 if (pp->p_offset > lp->d_secperunit) { 2101 warnx("partition %c: offset past end of unit", part); 2102 errors++; 2103 } 2104 if (pp->p_offset + pp->p_size > lp->d_secperunit) { 2105 warnx("partition %c: partition extends" 2106 " past end of unit", 2107 part); 2108 errors++; 2109 } 2110 if (pp->p_fstype != FS_UNUSED) 2111 for (j = i + 1; j < lp->d_npartitions; j++) { 2112 qp = &lp->d_partitions[j]; 2113 if (qp->p_fstype == FS_UNUSED) 2114 continue; 2115 if (pp->p_offset < qp->p_offset + qp->p_size && 2116 qp->p_offset < pp->p_offset + pp->p_size) 2117 warnx("partitions %c and %c overlap", 2118 part, 'a' + j); 2119 } 2120 } 2121 return (errors); 2122 } 2123 2124 static void 2125 usage(void) 2126 { 2127 static const struct { 2128 const char *name; 2129 const char *expn; 2130 } usages[] = { 2131 { "[-ABCFMrtv] disk", "(to read label)" }, 2132 { "-w [-BDFMrv] [-f disktab] disk disktype [packid]", "(to write label)" }, 2133 { "-e [-BCDFMIrv] disk", "(to edit label)" }, 2134 #if !defined(NO_INTERACT) 2135 { "-i [-BDFMIrv] disk", "(to create a label interactively)" }, 2136 #endif 2137 { "-D [-v] disk", "(to delete existing label(s))" }, 2138 { "-R [-BDFMrv] disk protofile", "(to restore label)" }, 2139 { "[-NW] disk", "(to write disable/enable label)" }, 2140 { "-l", "(to show all known file system types)" }, 2141 { NULL, NULL } 2142 }; 2143 int i; 2144 const char *pn = getprogname(); 2145 const char *t = "usage:"; 2146 2147 for (i = 0; usages[i].name != NULL; i++) { 2148 (void)fprintf(stderr, "%s %s %s\n\t%s\n", 2149 t, pn, usages[i].name, usages[i].expn); 2150 t = "or"; 2151 } 2152 exit(1); 2153 } 2154 2155 static int 2156 getulong(const char *str, char sep, char **epp, unsigned long *ul, 2157 unsigned long max) 2158 { 2159 char *ep; 2160 2161 if (epp == NULL) 2162 epp = &ep; 2163 2164 *ul = strtoul(str, epp, 10); 2165 2166 if ((*ul == ULONG_MAX && errno == ERANGE) || *ul > max) 2167 return ERANGE; 2168 2169 if (*str == '\0' || (**epp != '\0' && **epp != sep && 2170 !isspace((unsigned char)**epp))) 2171 return EFTYPE; 2172 2173 return 0; 2174 } 2175 2176 /* 2177 * This is a wrapper over the standard strcmp function to be used with 2178 * qsort on an array of pointers to strings. 2179 */ 2180 static int 2181 qsort_strcmp(const void *v1, const void *v2) 2182 { 2183 const char *const *sp1 = (const char *const *)v1; 2184 const char *const *sp2 = (const char *const *)v2; 2185 2186 return strcmp(*sp1, *sp2); 2187 } 2188 2189 /* 2190 * Prints all know file system types for a partition. 2191 * Returns 1 on success, 0 on failure. 2192 */ 2193 int 2194 list_fs_types(void) 2195 { 2196 int ret; 2197 size_t nelems; 2198 2199 nelems = 0; 2200 { 2201 const char *const *namep; 2202 2203 namep = fstypenames; 2204 while (*namep++ != NULL) 2205 nelems++; 2206 } 2207 2208 ret = 1; 2209 if (nelems > 0) { 2210 const char **list; 2211 size_t i; 2212 2213 list = (const char **)malloc(sizeof(char *) * nelems); 2214 if (list == NULL) { 2215 warnx("sorry, could not allocate memory for list"); 2216 ret = 0; 2217 } else { 2218 for (i = 0; i < nelems; i++) 2219 list[i] = fstypenames[i]; 2220 2221 qsort(list, nelems, sizeof(char *), qsort_strcmp); 2222 2223 for (i = 0; i < nelems; i++) 2224 (void)printf("%s\n", list[i]); 2225 2226 free(list); 2227 } 2228 } 2229 2230 return ret; 2231 } 2232 2233 #ifndef HAVE_NBTOOL_CONFIG_H 2234 int 2235 dk_ioctl(int f, u_long cmd, void *arg) 2236 { 2237 #if !defined(NATIVELABEL_ONLY) 2238 if (!native_p) { 2239 errno = ENOTTY; 2240 return -1; 2241 } 2242 #endif 2243 return ioctl(f, cmd, arg); 2244 } 2245 #endif 2246