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