1*10dfba40Stsutsui /* $NetBSD: main.c,v 1.59 2025/01/19 04:37:15 tsutsui Exp $ */ 291af0d68Sjmmv 391af0d68Sjmmv /* 491af0d68Sjmmv * Copyright (c) 2006 The NetBSD Foundation, Inc. 591af0d68Sjmmv * All rights reserved. 691af0d68Sjmmv * 791af0d68Sjmmv * This code is derived from software contributed to The NetBSD Foundation 891af0d68Sjmmv * by Julio M. Merino Vidal. 991af0d68Sjmmv * 1091af0d68Sjmmv * Redistribution and use in source and binary forms, with or without 1191af0d68Sjmmv * modification, are permitted provided that the following conditions 1291af0d68Sjmmv * are met: 1391af0d68Sjmmv * 1. Redistributions of source code must retain the above copyright 1491af0d68Sjmmv * notice, this list of conditions and the following disclaimer. 1591af0d68Sjmmv * 2. Redistributions in binary form must reproduce the above copyright 1691af0d68Sjmmv * notice, this list of conditions and the following disclaimer in the 1791af0d68Sjmmv * documentation and/or other materials provided with the distribution. 1891af0d68Sjmmv * 1991af0d68Sjmmv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2091af0d68Sjmmv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2191af0d68Sjmmv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2291af0d68Sjmmv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2391af0d68Sjmmv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2491af0d68Sjmmv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2591af0d68Sjmmv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2691af0d68Sjmmv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2791af0d68Sjmmv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2891af0d68Sjmmv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2991af0d68Sjmmv * POSSIBILITY OF SUCH DAMAGE. 3091af0d68Sjmmv */ 311726c417Sdyoung 321726c417Sdyoung /* 331726c417Sdyoung * Copyright (c) 1987, 1993 341726c417Sdyoung * The Regents of the University of California. All rights reserved. 351726c417Sdyoung * 361726c417Sdyoung * This code is derived from software contributed to Berkeley by 371726c417Sdyoung * Symmetric Computer Systems. 381726c417Sdyoung * 391726c417Sdyoung * Redistribution and use in source and binary forms, with or without 401726c417Sdyoung * modification, are permitted provided that the following conditions 411726c417Sdyoung * are met: 421726c417Sdyoung * 1. Redistributions of source code must retain the above copyright 431726c417Sdyoung * notice, this list of conditions and the following disclaimer. 441726c417Sdyoung * 2. Redistributions in binary form must reproduce the above copyright 451726c417Sdyoung * notice, this list of conditions and the following disclaimer in the 461726c417Sdyoung * documentation and/or other materials provided with the distribution. 471726c417Sdyoung * 3. Neither the name of the University nor the names of its contributors 481726c417Sdyoung * may be used to endorse or promote products derived from this software 491726c417Sdyoung * without specific prior written permission. 501726c417Sdyoung * 511726c417Sdyoung * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 521726c417Sdyoung * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 531726c417Sdyoung * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 541726c417Sdyoung * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 551726c417Sdyoung * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 561726c417Sdyoung * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 571726c417Sdyoung * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 581726c417Sdyoung * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 591726c417Sdyoung * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 601726c417Sdyoung * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 611726c417Sdyoung * SUCH DAMAGE. 621726c417Sdyoung */ 631726c417Sdyoung 641726c417Sdyoung #if HAVE_NBTOOL_CONFIG_H 651726c417Sdyoung #include "nbtool_config.h" 661726c417Sdyoung #endif 671726c417Sdyoung 681726c417Sdyoung #include <sys/cdefs.h> 691726c417Sdyoung #ifndef lint 706543a91fSlukem __COPYRIGHT("@(#) Copyright (c) 1987, 1993\ 716543a91fSlukem The Regents of the University of California. All rights reserved."); 721726c417Sdyoung #endif /* not lint */ 731726c417Sdyoung 741726c417Sdyoung #ifndef lint 751726c417Sdyoung #if 0 761726c417Sdyoung static char sccsid[] = "@(#)disklabel.c 8.4 (Berkeley) 5/4/95"; 771726c417Sdyoung /* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */ 781726c417Sdyoung #else 79*10dfba40Stsutsui __RCSID("$NetBSD: main.c,v 1.59 2025/01/19 04:37:15 tsutsui Exp $"); 801726c417Sdyoung #endif 811726c417Sdyoung #endif /* not lint */ 821726c417Sdyoung 831726c417Sdyoung #include <sys/param.h> 841726c417Sdyoung #include <sys/file.h> 851726c417Sdyoung #include <sys/stat.h> 861726c417Sdyoung #include <sys/wait.h> 871726c417Sdyoung #define DKTYPENAMES 881726c417Sdyoung #define FSTYPENAMES 891726c417Sdyoung 901726c417Sdyoung #include <ctype.h> 911726c417Sdyoung #include <err.h> 921726c417Sdyoung #include <errno.h> 931726c417Sdyoung #include <signal.h> 941726c417Sdyoung #include <string.h> 951726c417Sdyoung #include <stdio.h> 961726c417Sdyoung #include <stdlib.h> 976f3106ebSdyoung #include <limits.h> 981726c417Sdyoung #include <unistd.h> 991726c417Sdyoung 1001726c417Sdyoung #include <ufs/ufs/dinode.h> 1011726c417Sdyoung #include <ufs/ffs/fs.h> 1021726c417Sdyoung 1031726c417Sdyoung #if HAVE_NBTOOL_CONFIG_H 1041726c417Sdyoung #include <nbinclude/sys/disklabel.h> 10565151c95Sdsl #include <nbinclude/sys/disklabel_acorn.h> 1061726c417Sdyoung #include <nbinclude/sys/bootblock.h> 1071726c417Sdyoung #include "../../include/disktab.h" 1081726c417Sdyoung #else 1091726c417Sdyoung #include <sys/ioctl.h> 1101726c417Sdyoung #include <sys/disklabel.h> 11165151c95Sdsl #include <sys/disklabel_acorn.h> 1121726c417Sdyoung #include <sys/bootblock.h> 1131726c417Sdyoung #include <util.h> 1141726c417Sdyoung #include <disktab.h> 1151726c417Sdyoung #endif /* HAVE_NBTOOL_CONFIG_H */ 1161726c417Sdyoung 1171726c417Sdyoung #include "pathnames.h" 1181726c417Sdyoung #include "extern.h" 1191726c417Sdyoung #include "dkcksum.h" 120d3724ba4Stsutsui #include "bswap.h" 1211726c417Sdyoung 1221726c417Sdyoung /* 1231726c417Sdyoung * Disklabel: read and write disklabels. 1241726c417Sdyoung * The label is usually placed on one of the first sectors of the disk. 1251726c417Sdyoung * Many machines also place a bootstrap in the same area, 1261726c417Sdyoung * in which case the label is embedded in the bootstrap. 1271726c417Sdyoung * The bootstrap source must leave space at the proper offset 1281726c417Sdyoung * for the label on such machines. 1291726c417Sdyoung */ 1301726c417Sdyoung 1311726c417Sdyoung #ifndef BBSIZE 1321726c417Sdyoung #define BBSIZE 8192 /* size of boot area, with label */ 1331726c417Sdyoung #endif 1341726c417Sdyoung 13565151c95Sdsl #define DISKMAGIC_REV bswap32(DISKMAGIC) 13665151c95Sdsl /* To delete a label, we just invert the magic numbers */ 13765151c95Sdsl #define DISKMAGIC_DELETED (~DISKMAGIC) 13865151c95Sdsl #define DISKMAGIC_DELETED_REV bswap32(~DISKMAGIC) 13965151c95Sdsl 1401726c417Sdyoung #define DEFEDITOR _PATH_VI 1411726c417Sdyoung 14265151c95Sdsl char specname[MAXPATHLEN]; 1431726c417Sdyoung 14465151c95Sdsl /* Some global data, all too hard to pass about */ 145628f1591Sdrochner char bootarea[BBSIZE]; /* Buffer matching part of disk */ 14665151c95Sdsl int bootarea_len; /* Number of bytes we actually read */ 14765151c95Sdsl static struct disklabel lab; /* The label we have updated */ 1481726c417Sdyoung 14965151c95Sdsl static int Aflag; /* Action all labels */ 15065151c95Sdsl static int Fflag; /* Read/write from file */ 15165151c95Sdsl static int rflag; /* Read/write direct from disk */ 15265151c95Sdsl static int tflag; /* Format output as disktab */ 15365151c95Sdsl int Cflag; /* CHS format output */ 15465151c95Sdsl static int Dflag; /* Delete old labels (use with write) */ 15565151c95Sdsl static int Iflag; /* Read/write direct, but default if absent */ 15691af0d68Sjmmv static int lflag; /* List all known file system types and exit */ 15765151c95Sdsl static int verbose; 15865151c95Sdsl static int read_all; /* set if op = READ && Aflag */ 1591726c417Sdyoung 16065151c95Sdsl static int write_label(int); 16165151c95Sdsl static int readlabel_direct(int); 16265151c95Sdsl static void writelabel_direct(int); 16365151c95Sdsl static int update_label(int, u_int, u_int); 16465151c95Sdsl static struct disklabel *find_label(int, u_int); 1650636a2feSchristos #if !defined(NATIVELABEL_ONLY) 166af8f0546Smatt static void getmachineparams(const char *); 1670636a2feSchristos #endif 1681726c417Sdyoung 1691726c417Sdyoung static void makedisktab(FILE *, struct disklabel *); 17065151c95Sdsl static void makelabel(const char *, const char *); 1711726c417Sdyoung static void l_perror(const char *); 17265151c95Sdsl static void readlabel(int); 17365151c95Sdsl static int edit(int); 17465151c95Sdsl static int editit(const char *); 1751726c417Sdyoung static char *skip(char *); 1761726c417Sdyoung static char *word(char *); 1771726c417Sdyoung static int getasciilabel(FILE *, struct disklabel *); 178baa8e84bSjoerg __dead static void usage(void); 17991af0d68Sjmmv static int qsort_strcmp(const void *, const void *); 1801726c417Sdyoung static int getulong(const char *, char, char **, 1811726c417Sdyoung unsigned long *, unsigned long); 1821726c417Sdyoung #define GETNUM32(a, v) getulong(a, '\0', NULL, v, UINT32_MAX) 1831726c417Sdyoung #define GETNUM16(a, v) getulong(a, '\0', NULL, v, UINT16_MAX) 1841726c417Sdyoung #define GETNUM8(a, v) getulong(a, '\0', NULL, v, UINT8_MAX) 1851726c417Sdyoung 18665151c95Sdsl static int set_writable_fd = -1; 18765151c95Sdsl 1880636a2feSchristos #if !defined(NATIVELABEL_ONLY) 189af8f0546Smatt static u_int labeloffset; 190af8f0546Smatt static u_int labelsector; 191af8f0546Smatt static int labelusesmbr; 192af8f0546Smatt u_int maxpartitions; 193af8f0546Smatt static int byteorder; 194af8f0546Smatt 195af8f0546Smatt static int biendian_p; 196af8f0546Smatt #ifndef HAVE_NBTOOL_CONFIG_H 197af8f0546Smatt static int native_p = 1; 1981726c417Sdyoung #endif 199af8f0546Smatt int bswap_p; 200af8f0546Smatt 201af8f0546Smatt static const struct disklabel_params { 202af8f0546Smatt const char *machine; 203c902c296Schristos u_char labelusesmbr : 1; 204c902c296Schristos u_char labelsector : 7; 20574c7e628Schristos u_char maxpartitions; 20674c7e628Schristos u_char raw_part; 20774c7e628Schristos u_char oldmaxpartitions; 20874c7e628Schristos u_short labeloffset; 20974c7e628Schristos u_short byteorder; 210af8f0546Smatt } disklabel_params[] = { 21174c7e628Schristos { "mvme68k", 0, 0, 8, 2, 0, 0, BIG_ENDIAN }, /* m68k */ 21274c7e628Schristos { "next68k", 0, 0, 8, 2, 0, 0, BIG_ENDIAN }, /* m68k */ 213af8f0546Smatt 21474c7e628Schristos { "algor", 0, 0, 8, 2, 0, 64, LITTLE_ENDIAN }, /* mips */ 21574c7e628Schristos { "alpha", 0, 0, 8, 2, 0, 64, LITTLE_ENDIAN }, /* alpha */ 21674c7e628Schristos { "luna68k", 0, 0, 8, 2, 0, 64, BIG_ENDIAN }, /* m68k */ 21774c7e628Schristos { "mac68k", 0, 0, 8, 2, 0, 64, BIG_ENDIAN }, /* m68k */ 21874c7e628Schristos { "news68k", 0, 0, 8, 2, 0, 64, BIG_ENDIAN }, /* m68k */ 21974c7e628Schristos { "newsmips", 0, 0, 8, 2, 0, 64, BIG_ENDIAN }, /* mips */ 22074c7e628Schristos { "pmax", 0, 0, 8, 2, 0, 64, LITTLE_ENDIAN }, /* mips */ 22174c7e628Schristos { "sun2", 0, 0, 8, 2, 0, 64, BIG_ENDIAN }, /* m68k */ 22274c7e628Schristos { "sun68k", 0, 0, 8, 2, 0, 64, BIG_ENDIAN }, /* m68010 */ 223*10dfba40Stsutsui { "virt68k", 0, 0, 8, 2, 0, 64, BIG_ENDIAN }, /* m68k */ 224002042ffSisaki { "x68k", 0, 0, 8, 2, 0, 64, BIG_ENDIAN }, /* m68k */ 225af8f0546Smatt 22674c7e628Schristos { "vax", 0, 0, 12, 2, 8, 64, LITTLE_ENDIAN }, /* vax */ 227af8f0546Smatt 22874c7e628Schristos { "amiga", 0, 0, 16, 2, 0, 64, BIG_ENDIAN }, /* m68k */ 22974c7e628Schristos { "amigappc", 0, 0, 16, 2, 0, 64, BIG_ENDIAN }, /* powerpc */ 23074c7e628Schristos { "evbmips", 0, 0, 16, 2, 0, 64, 0 }, /* mips */ 23174c7e628Schristos { "evbppc", 0, 0, 16, 2, 0, 64, BIG_ENDIAN }, /* powerpc */ 232af8f0546Smatt 23374c7e628Schristos { "sparc", 0, 0, 8, 2, 0, 128, BIG_ENDIAN }, /* sun */ 23474c7e628Schristos { "sparc64", 0, 0, 8, 2, 0, 128, BIG_ENDIAN }, /* sun */ 23574c7e628Schristos { "sun3", 0, 0, 8, 2, 0, 128, BIG_ENDIAN }, /* sun */ 236af8f0546Smatt 23774c7e628Schristos { "atari", 0, 0, 16, 2, 0, 516, BIG_ENDIAN }, /* m68k */ 238af8f0546Smatt 23974c7e628Schristos { "mipsco", 0, 1, 8, 2, 0, 0, BIG_ENDIAN }, /* mips */ 24074c7e628Schristos { "mvmeppc", 0, 1, 8, 3, 0, 0, BIG_ENDIAN }, /* powerpc */ 241af8f0546Smatt 24274c7e628Schristos { "bebox", 0, 1, 8, 3, 0, 0, BIG_ENDIAN }, /* powerpc */ 243af8f0546Smatt 24474c7e628Schristos { "emips", 0, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* mips */ 24574c7e628Schristos { "hppa", 0, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* hppa */ 24674c7e628Schristos { "ibmnws", 0, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* powerpc */ 24774c7e628Schristos { "ofppc", 0, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* powerpc */ 24874c7e628Schristos { "rs6000", 0, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* powerpc */ 24974c7e628Schristos { "sandpoint", 0, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* powerpc */ 25074c7e628Schristos { "sgimips", 0, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* mips */ 251af8f0546Smatt 25274c7e628Schristos { "sbmips", 0, 1, 16, 3, 0, 0, 0 }, /* mips */ 253af8f0546Smatt 25474c7e628Schristos { "cesfic", 0, 2, 8, 2, 0, 0, BIG_ENDIAN }, /* m68k */ 25574c7e628Schristos { "hp300", 0, 2, 8, 2, 0, 0, BIG_ENDIAN }, /* m68k */ 256af8f0546Smatt 25774c7e628Schristos { "ews4800mips",0, 9, 16, 15, 0, 0, BIG_ENDIAN }, /* mips */ 258af8f0546Smatt 25974c7e628Schristos { "macppc", 1, 0, 16, 2, 0, 64, BIG_ENDIAN }, /* powerpc */ 26074c7e628Schristos { "pmon", 1, 0, 16, 2, 0, 64, 0 }, /* evbmips */ 261af8f0546Smatt 262c902c296Schristos { "prep", 1, 1, 8, 2, 0, 0, BIG_ENDIAN }, /* powerpc */ 263af8f0546Smatt 264c902c296Schristos { "dreamcast", 1, 1, 16, 2, 0, 0, LITTLE_ENDIAN }, /* sh3 */ 265c902c296Schristos { "evbcf", 1, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* coldfire */ 266c902c296Schristos { "evbppc-mbr", 1, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* powerpc */ 267c902c296Schristos { "evbsh3", 1, 1, 16, 2, 0, 0, 0 }, /* sh3 */ 268c902c296Schristos { "hpcsh", 1, 1, 16, 2, 0, 0, LITTLE_ENDIAN }, /* sh3 */ 269c902c296Schristos { "mmeye", 1, 1, 16, 2, 0, 0, 0 }, /* sh3 */ 270c902c296Schristos { "or1k", 1, 1, 16, 2, 0, 0, BIG_ENDIAN }, /* or1k */ 271c902c296Schristos { "riscv", 1, 1, 16, 2, 0, 0, LITTLE_ENDIAN }, /* riscv */ 272af8f0546Smatt 273c902c296Schristos { "acorn32", 1, 1, 16, 2, 8, 0, LITTLE_ENDIAN }, /* arm */ 274c902c296Schristos { "cats", 1, 1, 16, 2, 8, 0, LITTLE_ENDIAN }, /* arm */ 275c902c296Schristos { "evbarm", 1, 1, 16, 2, 8, 0, 0 }, /* arm */ 276c902c296Schristos { "iyonix", 1, 1, 16, 2, 8, 0, LITTLE_ENDIAN }, /* arm */ 277c902c296Schristos { "netwinder", 1, 1, 16, 2, 8, 0, LITTLE_ENDIAN }, /* arm */ 278c902c296Schristos { "shark", 1, 1, 16, 2, 8, 0, LITTLE_ENDIAN }, /* arm */ 279af8f0546Smatt 280c902c296Schristos { "amd64", 1, 1, 16, 3, 0, 0, LITTLE_ENDIAN }, /* x86 */ 281c902c296Schristos { "arc", 1, 1, 16, 3, 0, 0, LITTLE_ENDIAN }, /* mips */ 282c902c296Schristos { "cobalt", 1, 1, 16, 3, 0, 0, LITTLE_ENDIAN }, /* mips */ 283c902c296Schristos { "landisk", 1, 1, 16, 3, 0, 0, LITTLE_ENDIAN }, /* sh3 */ 284af8f0546Smatt 285c902c296Schristos { "epoc32", 1, 1, 16, 3, 8, 0, LITTLE_ENDIAN }, /* arm */ 286c902c296Schristos { "hpcarm", 1, 1, 16, 3, 8, 0, LITTLE_ENDIAN }, /* arm */ 287c902c296Schristos { "hpcmips", 1, 1, 16, 3, 8, 0, LITTLE_ENDIAN }, /* mips */ 288c902c296Schristos { "i386", 1, 1, 16, 3, 8, 0, LITTLE_ENDIAN }, /* x86 */ 289c902c296Schristos { "ia64", 1, 1, 16, 3, 8, 0, LITTLE_ENDIAN }, /* x86 */ 290c902c296Schristos { "zaurus", 1, 1, 16, 3, 8, 0, LITTLE_ENDIAN }, /* arm */ 291af8f0546Smatt 292af8f0546Smatt { NULL, 0, 0, 0, 0, 0, 0, 0 }, /* must be last */ 293af8f0546Smatt }; 294af8f0546Smatt 295af8f0546Smatt #ifndef HAVE_NBTOOL_CONFIG_H 296af8f0546Smatt static struct disklabel_params native_params; 297af8f0546Smatt #endif 298af8f0546Smatt 299af8f0546Smatt static const struct arch_endian { 300af8f0546Smatt int byteorder; 301af8f0546Smatt const char *arch; 302af8f0546Smatt } arch_endians[] = { 303547b3a3bSmatt { LITTLE_ENDIAN, "aarch64" }, 304af8f0546Smatt { LITTLE_ENDIAN, "alpha" }, 305af8f0546Smatt { LITTLE_ENDIAN, "arm" }, 306af8f0546Smatt { LITTLE_ENDIAN, "earm" }, 307af8f0546Smatt { LITTLE_ENDIAN, "earmhf" }, 308eab05440Sriz { LITTLE_ENDIAN, "earmv4" }, 309eab05440Sriz { LITTLE_ENDIAN, "earmv5" }, 310eab05440Sriz { LITTLE_ENDIAN, "earmv6" }, 311eab05440Sriz { LITTLE_ENDIAN, "earmv6hf" }, 312eab05440Sriz { LITTLE_ENDIAN, "earmv7" }, 313eab05440Sriz { LITTLE_ENDIAN, "earmv7hf" }, 314af8f0546Smatt { LITTLE_ENDIAN, "i386" }, 315af8f0546Smatt { LITTLE_ENDIAN, "ia64" }, 316af8f0546Smatt { LITTLE_ENDIAN, "mipsel" }, 317af8f0546Smatt { LITTLE_ENDIAN, "mips64el" }, 3183bbdf28dSmatt { LITTLE_ENDIAN, "riscv32" }, 3193bbdf28dSmatt { LITTLE_ENDIAN, "riscv64" }, 320af8f0546Smatt { LITTLE_ENDIAN, "sh3el" }, 321af8f0546Smatt { LITTLE_ENDIAN, "vax" }, 3224cc906c4Sskrll { LITTLE_ENDIAN, "x86_64" }, 323af8f0546Smatt 324547b3a3bSmatt { BIG_ENDIAN, "aarch64eb" }, 325af8f0546Smatt { BIG_ENDIAN, "armeb" }, 3268176d969Smatt { BIG_ENDIAN, "coldfire" }, 327af8f0546Smatt { BIG_ENDIAN, "earmeb" }, 328af8f0546Smatt { BIG_ENDIAN, "earmhfeb" }, 329eab05440Sriz { BIG_ENDIAN, "earmv4eb" }, 330eab05440Sriz { BIG_ENDIAN, "earmv5eb" }, 331eab05440Sriz { BIG_ENDIAN, "earmv6eb" }, 332eab05440Sriz { BIG_ENDIAN, "earmv6hfeb" }, 333eab05440Sriz { BIG_ENDIAN, "earmv7eb" }, 334eab05440Sriz { BIG_ENDIAN, "earmv7hfeb" }, 335af8f0546Smatt { BIG_ENDIAN, "hppa" }, 3368176d969Smatt { BIG_ENDIAN, "m68000" }, 337af8f0546Smatt { BIG_ENDIAN, "m68k" }, 338af8f0546Smatt { BIG_ENDIAN, "mipseb" }, 339af8f0546Smatt { BIG_ENDIAN, "mips64eb" }, 3403bbdf28dSmatt { BIG_ENDIAN, "or1k" }, 341af8f0546Smatt { BIG_ENDIAN, "powerpc" }, 342af8f0546Smatt { BIG_ENDIAN, "sh3eb" }, 343af8f0546Smatt { BIG_ENDIAN, "sparc" }, 344af8f0546Smatt { BIG_ENDIAN, "sparc64" }, 345af8f0546Smatt 346af8f0546Smatt { 0, NULL }, 347af8f0546Smatt }; 3481726c417Sdyoung 34965151c95Sdsl /* Default location for label - only used if we don't find one to update */ 3506f3106ebSdyoung #define LABEL_OFFSET (dklabel_getlabelsector() * DEV_BSIZE + dklabel_getlabeloffset()) 3510636a2feSchristos #else 3520636a2feSchristos #define labeloffset LABELOFFSET 3530636a2feSchristos #define labelsector LABELSECTOR 3540636a2feSchristos #define labelusesmbr LABELUSESMBR 3550636a2feSchristos #define maxpartitions MAXPARTITIONS 356edc3e298Stsutsui #define LABEL_OFFSET (LABELSECTOR * DEV_BSIZE + LABELOFFSET) 3570636a2feSchristos #endif /* !NATIVELABEL_ONLY */ 35865151c95Sdsl 35965151c95Sdsl /* 36065151c95Sdsl * For portability it doesn't make sense to use any other value.... 36165151c95Sdsl * Except, maybe, the size of a physical sector. 36265151c95Sdsl * This value is used if we have to write a label to the start of an mbr ptn. 36365151c95Sdsl */ 36465151c95Sdsl #ifndef LABELOFFSET_MBR 36565151c95Sdsl #define LABELOFFSET_MBR 512 36665151c95Sdsl #endif 36765151c95Sdsl 36865151c95Sdsl #if HAVE_NBTOOL_CONFIG_H 36965151c95Sdsl static int 37065151c95Sdsl opendisk(const char *path, int flags, char *buf, int buflen, int cooked) 37165151c95Sdsl { 37265151c95Sdsl int f; 37365151c95Sdsl f = open(path, flags, 0); 37465151c95Sdsl strlcpy(buf, path, buflen); 37565151c95Sdsl return f; 37665151c95Sdsl } 37765151c95Sdsl #endif /* HAVE_NBTOOL_CONFIG_H */ 37865151c95Sdsl 3790636a2feSchristos #if !defined(NATIVELABEL_ONLY) 380af8f0546Smatt static void 381af8f0546Smatt setbyteorder(int new_byteorder) 382af8f0546Smatt { 383af8f0546Smatt static int set_p; 384af8f0546Smatt 385af8f0546Smatt if ((!biendian_p || set_p) 386af8f0546Smatt && byteorder != 0 387af8f0546Smatt && byteorder != new_byteorder) { 388037063a2Schs warnx("changing %s byteorder to %s", 389af8f0546Smatt byteorder == LITTLE_ENDIAN ? "le" : "be", 390af8f0546Smatt new_byteorder == LITTLE_ENDIAN ? "le" : "be"); 391af8f0546Smatt } 392af8f0546Smatt byteorder = new_byteorder; 393af8f0546Smatt biendian_p = 0; 394af8f0546Smatt set_p = 1; 395af8f0546Smatt } 396af8f0546Smatt 397af8f0546Smatt static void 398af8f0546Smatt getmachineparams(const char *mach) 399af8f0546Smatt { 400af8f0546Smatt const struct disklabel_params *dp = disklabel_params; 401af8f0546Smatt for (; dp->machine != NULL; dp++) { 402af8f0546Smatt if (!strcmp(mach, dp->machine)) { 403af8f0546Smatt labelusesmbr = dp->labelusesmbr; 404af8f0546Smatt labelsector = dp->labelsector; 405af8f0546Smatt labeloffset = dp->labeloffset; 406af8f0546Smatt maxpartitions = dp->maxpartitions; 407af8f0546Smatt biendian_p = (dp->byteorder == 0); 408af8f0546Smatt if (!biendian_p) 409af8f0546Smatt setbyteorder(dp->byteorder); 410af8f0546Smatt return; 411af8f0546Smatt } 412af8f0546Smatt } 413af8f0546Smatt errx(1, "%s: unknown machine type", mach); 414af8f0546Smatt } 415af8f0546Smatt 416af8f0546Smatt static void 417af8f0546Smatt getarchbyteorder(const char *arch) 418af8f0546Smatt { 419af8f0546Smatt const struct arch_endian *p = arch_endians; 420af8f0546Smatt for (; p->arch != NULL; p++) { 421af8f0546Smatt if (!strcmp(arch, p->arch)) { 422af8f0546Smatt setbyteorder(p->byteorder); 423af8f0546Smatt return; 424af8f0546Smatt } 425af8f0546Smatt } 426af8f0546Smatt errx(1, "%s: unknown arch", arch); 427af8f0546Smatt } 428af8f0546Smatt 4296f3106ebSdyoung static daddr_t 4306f3106ebSdyoung dklabel_getlabelsector(void) 4316f3106ebSdyoung { 4326f3106ebSdyoung unsigned long int nval; 4336f3106ebSdyoung char *end; 4346f3106ebSdyoung const char *val; 4356f3106ebSdyoung 4366f3106ebSdyoung if ((val = getenv("DISKLABELSECTOR")) == NULL) 437af8f0546Smatt return labelsector; 4386f3106ebSdyoung if ((nval = strtoul(val, &end, 10)) == ULONG_MAX && errno == ERANGE) 4396f3106ebSdyoung err(EXIT_FAILURE, "DISKLABELSECTOR in environment"); 4406f3106ebSdyoung return nval; 4416f3106ebSdyoung } 4426f3106ebSdyoung 4436f3106ebSdyoung static off_t 4446f3106ebSdyoung dklabel_getlabeloffset(void) 4456f3106ebSdyoung { 4466f3106ebSdyoung unsigned long int nval; 4476f3106ebSdyoung char *end; 4486f3106ebSdyoung const char *val; 4496f3106ebSdyoung 4506f3106ebSdyoung if ((val = getenv("DISKLABELOFFSET")) == NULL) 451af8f0546Smatt return labeloffset; 4526f3106ebSdyoung if ((nval = strtoul(val, &end, 10)) == ULONG_MAX && errno == ERANGE) 4536f3106ebSdyoung err(EXIT_FAILURE, "DISKLABELOFFSET in environment"); 4546f3106ebSdyoung return nval; 4556f3106ebSdyoung } 4560636a2feSchristos #endif /* !NATIVELABEL_ONLY */ 4576f3106ebSdyoung 45865151c95Sdsl static void 45965151c95Sdsl clear_writable(void) 46065151c95Sdsl { 46165151c95Sdsl static int zero = 0; 46265151c95Sdsl dk_ioctl(set_writable_fd, DIOCWLABEL, &zero); 46365151c95Sdsl } 46465151c95Sdsl 4651726c417Sdyoung int 4661726c417Sdyoung main(int argc, char *argv[]) 4671726c417Sdyoung { 4681726c417Sdyoung FILE *t; 46965151c95Sdsl int ch, f, error; 47065151c95Sdsl char *dkname; 4710636a2feSchristos #if !defined(NATIVELABEL_ONLY) 472af8f0546Smatt char *cp; 4730636a2feSchristos #endif 47465151c95Sdsl struct stat sb; 47565151c95Sdsl int writable; 47665151c95Sdsl enum { 47765151c95Sdsl UNSPEC, EDIT, READ, RESTORE, SETWRITABLE, SETREADONLY, 4780636a2feSchristos WRITE, 4790636a2feSchristos #if !defined(NO_INTERACT) 4800636a2feSchristos INTERACT, 4810636a2feSchristos #endif 4820636a2feSchristos DELETE 48365151c95Sdsl } op = UNSPEC, old_op; 48445a6f3d5Smlelstv #if !defined(NATIVELABEL_ONLY) 4851b979fccSmlelstv unsigned long val; 48645a6f3d5Smlelstv #endif 48765151c95Sdsl 488af8f0546Smatt #ifndef HAVE_NBTOOL_CONFIG_H 4890636a2feSchristos #if !defined(NATIVELABEL_ONLY) 490af8f0546Smatt labeloffset = native_params.labeloffset = getlabeloffset(); 491af8f0546Smatt labelsector = native_params.labelsector = getlabelsector(); 492af8f0546Smatt labelusesmbr = native_params.labelusesmbr = getlabelusesmbr(); 493af8f0546Smatt maxpartitions = native_params.maxpartitions = getmaxpartitions(); 4944fdf02c1Smatt byteorder = native_params.byteorder = BYTE_ORDER; 495af8f0546Smatt #endif 4960636a2feSchristos #endif 497af8f0546Smatt 4980636a2feSchristos #if !defined(NATIVELABEL_ONLY) 499af8f0546Smatt if ((cp = getenv("MACHINE")) != NULL) { 500af8f0546Smatt getmachineparams(cp); 501af8f0546Smatt } 502af8f0546Smatt 503af8f0546Smatt if ((cp = getenv("MACHINE_ARCH")) != NULL) { 504af8f0546Smatt getarchbyteorder(cp); 505af8f0546Smatt } 5060636a2feSchristos #endif 507af8f0546Smatt 50865151c95Sdsl #if HAVE_NBTOOL_CONFIG_H 50965151c95Sdsl /* We must avoid doing any ioctl requests */ 51065151c95Sdsl Fflag = rflag = 1; 51165151c95Sdsl #endif 5121726c417Sdyoung 5131726c417Sdyoung error = 0; 51445a6f3d5Smlelstv #if !defined(NATIVELABEL_ONLY) 5151b979fccSmlelstv while ((ch = getopt(argc, argv, "AB:CDFIL:M:NO:P:RWef:ilmnrtvw")) != -1) { 51645a6f3d5Smlelstv #else 51745a6f3d5Smlelstv while ((ch = getopt(argc, argv, "ACDFINRWef:ilrtvw")) != -1) { 51845a6f3d5Smlelstv #endif 51965151c95Sdsl old_op = op; 5201726c417Sdyoung switch (ch) { 52165151c95Sdsl case 'A': /* Action all labels */ 52265151c95Sdsl Aflag = 1; 52365151c95Sdsl rflag = 1; 5241726c417Sdyoung break; 52565151c95Sdsl case 'C': /* Display in CHS format */ 52665151c95Sdsl Cflag = 1; 5271726c417Sdyoung break; 52865151c95Sdsl case 'D': /* Delete all existing labels */ 52965151c95Sdsl Dflag = 1; 53065151c95Sdsl rflag = 1; 5311726c417Sdyoung break; 53265151c95Sdsl case 'F': /* Treat 'disk' as a regular file */ 53365151c95Sdsl Fflag = 1; 53465151c95Sdsl rflag = 1; /* Force direct access */ 53565151c95Sdsl break; 53665151c95Sdsl case 'I': /* Use default label if none found */ 53765151c95Sdsl Iflag = 1; 53865151c95Sdsl rflag = 1; /* Implies direct access */ 53965151c95Sdsl break; 54065151c95Sdsl case 'R': /* Restore label from text file */ 5411726c417Sdyoung op = RESTORE; 5421726c417Sdyoung break; 5430636a2feSchristos #if !defined(NATIVELABEL_ONLY) 544af8f0546Smatt case 'B': /* byteorder */ 545af8f0546Smatt if (!strcmp(optarg, "be")) { 546af8f0546Smatt setbyteorder(BIG_ENDIAN); 547af8f0546Smatt } else if (!strcmp(optarg, "le")) { 548af8f0546Smatt setbyteorder(LITTLE_ENDIAN); 549af8f0546Smatt } else { 550af8f0546Smatt errx(1, "%s: not be or le", optarg); 551af8f0546Smatt } 552af8f0546Smatt break; 553af8f0546Smatt case 'M': /* machine type */ 554af8f0546Smatt getmachineparams(optarg); 555af8f0546Smatt break; 5560636a2feSchristos #endif 55765151c95Sdsl case 'N': /* Disallow writes to label sector */ 55865151c95Sdsl op = SETREADONLY; 55965151c95Sdsl break; 56045a6f3d5Smlelstv #if !defined(NATIVELABEL_ONLY) 5611b979fccSmlelstv case 'L': /* Label sector */ 5621b979fccSmlelstv val = strtoul(optarg, NULL, 10); 5631b979fccSmlelstv if ((val == ULONG_MAX && errno == ERANGE) || val > UINT_MAX) 5641b979fccSmlelstv err(EXIT_FAILURE, "invalid label sector: %s", optarg); 5651b979fccSmlelstv labelsector = val; 5661b979fccSmlelstv break; 5671b979fccSmlelstv case 'O': /* Label offset */ 5681b979fccSmlelstv val = strtoul(optarg, NULL, 10); 5691b979fccSmlelstv if ((val == ULONG_MAX && errno == ERANGE) || val > UINT_MAX) 5701b979fccSmlelstv err(EXIT_FAILURE, "invalid label offset: %s", optarg); 5711b979fccSmlelstv labeloffset = val; 5721b979fccSmlelstv break; 5731b979fccSmlelstv case 'P': /* Max partitions */ 5741b979fccSmlelstv val = strtoul(optarg, NULL, 10); 5751b979fccSmlelstv if ((val == ULONG_MAX && errno == ERANGE) || val < 1 || val > UINT_MAX) 5761b979fccSmlelstv err(EXIT_FAILURE, "invalid max partitions: %s", optarg); 5771b979fccSmlelstv maxpartitions = val; 5781b979fccSmlelstv break; 57945a6f3d5Smlelstv #endif 58065151c95Sdsl case 'W': /* Allow writes to label sector */ 5811726c417Sdyoung op = SETWRITABLE; 5821726c417Sdyoung break; 58365151c95Sdsl case 'e': /* Edit label with $EDITOR */ 5841726c417Sdyoung op = EDIT; 5851726c417Sdyoung break; 58665151c95Sdsl case 'f': /* Name of disktab file */ 5871726c417Sdyoung if (setdisktab(optarg) == -1) 5881726c417Sdyoung usage(); 5891726c417Sdyoung break; 5900636a2feSchristos #if !defined(NO_INTERACT) 59165151c95Sdsl case 'i': /* Edit using built-in editor */ 5921726c417Sdyoung op = INTERACT; 5931726c417Sdyoung break; 5940636a2feSchristos #endif /* !NO_INTERACT */ 59591af0d68Sjmmv case 'l': /* List all known file system types and exit */ 59691af0d68Sjmmv lflag = 1; 59791af0d68Sjmmv break; 59845a6f3d5Smlelstv #if !defined(NATIVELABEL_ONLY) 59965151c95Sdsl case 'm': /* Expect disk to have an MBR */ 6001b979fccSmlelstv labelusesmbr = 1; 6011b979fccSmlelstv break; 6021b979fccSmlelstv case 'n': /* Expect disk to not have an MBR */ 6031b979fccSmlelstv labelusesmbr = 0; 6041726c417Sdyoung break; 60545a6f3d5Smlelstv #endif 60665151c95Sdsl case 'r': /* Read/write label directly from disk */ 60765151c95Sdsl rflag = 1; 6081726c417Sdyoung break; 60965151c95Sdsl case 't': /* Format output as a disktab entry */ 61065151c95Sdsl tflag = 1; 61165151c95Sdsl break; 61265151c95Sdsl case 'v': /* verbose/diag output */ 61365151c95Sdsl verbose++; 61465151c95Sdsl break; 61565151c95Sdsl case 'w': /* Write label based on disktab entry */ 6161726c417Sdyoung op = WRITE; 6171726c417Sdyoung break; 6181726c417Sdyoung case '?': 6191726c417Sdyoung default: 6201726c417Sdyoung usage(); 6211726c417Sdyoung } 62265151c95Sdsl if (old_op != UNSPEC && old_op != op) 62365151c95Sdsl usage(); 62465151c95Sdsl } 625af8f0546Smatt 6261b979fccSmlelstv if (maxpartitions > MAXPARTITIONS) { 6271b979fccSmlelstv errx(1, "too large maxpartitions > %u\n", MAXPARTITIONS); 6281b979fccSmlelstv } 6291b979fccSmlelstv 6300636a2feSchristos #if !defined(NATIVELABEL_ONLY) 631af8f0546Smatt if (maxpartitions == 0) { 632af8f0546Smatt errx(1, "unknown label: use -M/-B and $MACHINE/$MACHINE_ARCH"); 633af8f0546Smatt } 634af8f0546Smatt if (byteorder != BIG_ENDIAN && byteorder != LITTLE_ENDIAN) { 635af8f0546Smatt errx(1, "unknown byteorder"); 636af8f0546Smatt } 637af8f0546Smatt bswap_p = (byteorder != BYTE_ORDER); 638af8f0546Smatt #ifdef DEBUG 639b1e3ebd4Smatt printf("labelusesmbr=%d labelsector=%u labeloffset=%u maxpartitions=%u\n", 640af8f0546Smatt labelusesmbr, labelsector, labeloffset, maxpartitions); 641af8f0546Smatt printf("byteorder=%d bswap_p=%d\n", byteorder, bswap_p); 642af8f0546Smatt #endif 643af8f0546Smatt #ifndef HAVE_NBTOOL_CONFIG_H 644af8f0546Smatt /* 645af8f0546Smatt * If the disklabel has the same location as the native disklabel and 646811d5a8bSmsaitoh * fewer or equal partitions, we can use the native ioctls. Otherwise 647af8f0546Smatt * force file/raw access. 648af8f0546Smatt */ 649af8f0546Smatt native_p = native_params.labelusesmbr == labelusesmbr 650af8f0546Smatt && native_params.labelsector == labelsector 651af8f0546Smatt && native_params.labeloffset == labeloffset 652b1e3ebd4Smatt && maxpartitions <= native_params.maxpartitions 653af8f0546Smatt && !bswap_p; 654af8f0546Smatt if (!native_p) 655af8f0546Smatt Fflag = rflag = 1; 656af8f0546Smatt #endif 6570636a2feSchristos #endif /* !NATIVELABEL_ONLY */ 658af8f0546Smatt 6591726c417Sdyoung argc -= optind; 6601726c417Sdyoung argv += optind; 6611726c417Sdyoung 66291af0d68Sjmmv if (lflag) 66391af0d68Sjmmv exit(list_fs_types() ? EXIT_SUCCESS : EXIT_FAILURE); 66491af0d68Sjmmv 6651726c417Sdyoung if (op == UNSPEC) 66665151c95Sdsl op = Dflag ? DELETE : READ; 6671726c417Sdyoung 6681726c417Sdyoung if (argc < 1) 6691726c417Sdyoung usage(); 6701726c417Sdyoung 6710636a2feSchristos if (Iflag && op != EDIT 6720636a2feSchristos #if !defined(NO_INTERACT) 6730636a2feSchristos && op != INTERACT 6740636a2feSchristos #endif 6750636a2feSchristos ) 6761726c417Sdyoung usage(); 6771726c417Sdyoung 6781726c417Sdyoung dkname = argv[0]; 67965151c95Sdsl f = opendisk(dkname, op == READ ? O_RDONLY : O_RDWR, 68065151c95Sdsl specname, sizeof specname, 0); 6811726c417Sdyoung if (f < 0) 6821726c417Sdyoung err(4, "%s", specname); 6831726c417Sdyoung 68465151c95Sdsl if (!Fflag && fstat(f, &sb) == 0 && S_ISREG(sb.st_mode)) 68565151c95Sdsl Fflag = rflag = 1; 6861726c417Sdyoung 6871726c417Sdyoung switch (op) { 6881726c417Sdyoung 68965151c95Sdsl case DELETE: /* Remove all existing labels */ 69065151c95Sdsl if (argc != 1) 69165151c95Sdsl usage(); 69265151c95Sdsl Dflag = 2; 69365151c95Sdsl writelabel_direct(f); 69465151c95Sdsl break; 69565151c95Sdsl 6961726c417Sdyoung case EDIT: 6971726c417Sdyoung if (argc != 1) 6981726c417Sdyoung usage(); 69965151c95Sdsl readlabel(f); 70065151c95Sdsl error = edit(f); 7011726c417Sdyoung break; 7021726c417Sdyoung 7030636a2feSchristos #if !defined(NO_INTERACT) 7041726c417Sdyoung case INTERACT: 7051726c417Sdyoung if (argc != 1) 7061726c417Sdyoung usage(); 70765151c95Sdsl readlabel(f); 7081726c417Sdyoung /* 7091726c417Sdyoung * XXX: Fill some default values so checklabel does not fail 7101726c417Sdyoung */ 71165151c95Sdsl if (lab.d_bbsize == 0) 71265151c95Sdsl lab.d_bbsize = BBSIZE; 71365151c95Sdsl if (lab.d_sbsize == 0) 71465151c95Sdsl lab.d_sbsize = SBLOCKSIZE; 71565151c95Sdsl interact(&lab, f); 7161726c417Sdyoung break; 7170636a2feSchristos #endif /* !NO_INTERACT */ 7181726c417Sdyoung 7191726c417Sdyoung case READ: 7201726c417Sdyoung if (argc != 1) 7211726c417Sdyoung usage(); 72265151c95Sdsl read_all = Aflag; 72365151c95Sdsl readlabel(f); 72465151c95Sdsl if (read_all) 72565151c95Sdsl /* Label got printed in the bowels of readlabel */ 72665151c95Sdsl break; 7271726c417Sdyoung if (tflag) 72865151c95Sdsl makedisktab(stdout, &lab); 7291726c417Sdyoung else { 73065151c95Sdsl showinfo(stdout, &lab, specname); 73165151c95Sdsl showpartitions(stdout, &lab, Cflag); 7321726c417Sdyoung } 73365151c95Sdsl error = checklabel(&lab); 7341726c417Sdyoung if (error) 7351726c417Sdyoung error += 100; 7361726c417Sdyoung break; 7371726c417Sdyoung 7381726c417Sdyoung case RESTORE: 73965151c95Sdsl if (argc != 2) 7401726c417Sdyoung usage(); 7411726c417Sdyoung if (!(t = fopen(argv[1], "r"))) 7421726c417Sdyoung err(4, "%s", argv[1]); 74365151c95Sdsl if (getasciilabel(t, &lab)) 74465151c95Sdsl error = write_label(f); 7451726c417Sdyoung else 7461726c417Sdyoung error = 1; 7471726c417Sdyoung break; 7481726c417Sdyoung 74965151c95Sdsl case SETREADONLY: 75065151c95Sdsl writable = 0; 75165151c95Sdsl goto do_diocwlabel; 7521726c417Sdyoung case SETWRITABLE: 75365151c95Sdsl writable = 1; 75465151c95Sdsl do_diocwlabel: 75565151c95Sdsl if (argc != 1) 75665151c95Sdsl usage(); 75765151c95Sdsl if (dk_ioctl(f, DIOCWLABEL, &writable) < 0) 7581726c417Sdyoung err(4, "ioctl DIOCWLABEL"); 7591726c417Sdyoung break; 7601726c417Sdyoung 76165151c95Sdsl case WRITE: /* Create label from /etc/disktab entry & write */ 7621726c417Sdyoung if (argc < 2 || argc > 3) 7631726c417Sdyoung usage(); 76465151c95Sdsl makelabel(argv[1], argv[2]); 76565151c95Sdsl if (checklabel(&lab) == 0) 76665151c95Sdsl error = write_label(f); 7671726c417Sdyoung else 7681726c417Sdyoung error = 1; 7691726c417Sdyoung break; 7701726c417Sdyoung 7711726c417Sdyoung case UNSPEC: 7721726c417Sdyoung usage(); 7731726c417Sdyoung 7741726c417Sdyoung } 7751726c417Sdyoung exit(error); 7761726c417Sdyoung } 7771726c417Sdyoung 7781726c417Sdyoung /* 77965151c95Sdsl * Construct a prototype disklabel from /etc/disktab. 7801726c417Sdyoung */ 7811726c417Sdyoung static void 78265151c95Sdsl makelabel(const char *type, const char *name) 7831726c417Sdyoung { 7841726c417Sdyoung struct disklabel *dp; 7851726c417Sdyoung 7861726c417Sdyoung dp = getdiskbyname(type); 7871726c417Sdyoung if (dp == NULL) 7881726c417Sdyoung errx(1, "unknown disk type: %s", type); 78965151c95Sdsl lab = *dp; 7901726c417Sdyoung 7911726c417Sdyoung /* d_packname is union d_boot[01], so zero */ 79265151c95Sdsl (void)memset(lab.d_packname, 0, sizeof(lab.d_packname)); 7931726c417Sdyoung if (name) 79465151c95Sdsl (void)strncpy(lab.d_packname, name, sizeof(lab.d_packname)); 7951726c417Sdyoung } 7961726c417Sdyoung 79765151c95Sdsl static int 79865151c95Sdsl write_label(int f) 7991726c417Sdyoung { 8001726c417Sdyoung int writable; 8011726c417Sdyoung 80265151c95Sdsl lab.d_magic = DISKMAGIC; 80365151c95Sdsl lab.d_magic2 = DISKMAGIC; 80465151c95Sdsl lab.d_checksum = 0; 80565151c95Sdsl lab.d_checksum = dkcksum(&lab); 8061726c417Sdyoung 80765151c95Sdsl if (rflag) { 80865151c95Sdsl /* Write the label directly to the disk */ 8091726c417Sdyoung 8101726c417Sdyoung /* 8111726c417Sdyoung * First set the kernel disk label, 8121726c417Sdyoung * then write a label to the raw disk. 8131726c417Sdyoung * If the SDINFO ioctl fails because it is unimplemented, 8141726c417Sdyoung * keep going; otherwise, the kernel consistency checks 8151726c417Sdyoung * may prevent us from changing the current (in-core) 8161726c417Sdyoung * label. 8171726c417Sdyoung */ 81865151c95Sdsl if (!Fflag && dk_ioctl(f, DIOCSDINFO, &lab) < 0 && 8191726c417Sdyoung errno != ENODEV && errno != ENOTTY) { 8201726c417Sdyoung l_perror("ioctl DIOCSDINFO"); 8211726c417Sdyoung return (1); 8221726c417Sdyoung } 8231726c417Sdyoung /* 8241726c417Sdyoung * write enable label sector before write (if necessary), 8251726c417Sdyoung * disable after writing. 8261726c417Sdyoung */ 8271726c417Sdyoung writable = 1; 82865151c95Sdsl if (!Fflag) { 82965151c95Sdsl if (dk_ioctl(f, DIOCWLABEL, &writable) < 0) 8301726c417Sdyoung perror("ioctl DIOCWLABEL"); 83165151c95Sdsl set_writable_fd = f; 83265151c95Sdsl atexit(clear_writable); 8331726c417Sdyoung } 8341726c417Sdyoung 83565151c95Sdsl writelabel_direct(f); 83665151c95Sdsl 8371726c417Sdyoung /* 8381726c417Sdyoung * Now issue a DIOCWDINFO. This will let the kernel convert the 8391726c417Sdyoung * disklabel to some machdep format if needed. 8401726c417Sdyoung */ 84165151c95Sdsl /* XXX: This is stupid! */ 84265151c95Sdsl if (!Fflag && dk_ioctl(f, DIOCWDINFO, &lab) < 0) { 8431726c417Sdyoung l_perror("ioctl DIOCWDINFO"); 8441726c417Sdyoung return (1); 8451726c417Sdyoung } 8461726c417Sdyoung } else { 84765151c95Sdsl /* Get the kernel to write the label */ 84865151c95Sdsl if (dk_ioctl(f, DIOCWDINFO, &lab) < 0) { 8491726c417Sdyoung l_perror("ioctl DIOCWDINFO"); 8501726c417Sdyoung return (1); 8511726c417Sdyoung } 8521726c417Sdyoung } 8531726c417Sdyoung 854e7730664Stsutsui #ifdef VAX_ALTLABELS 85552e8eb13Schristos if (lab.d_type == DKTYPE_SMD && lab.d_flags & D_BADSECT && 85665151c95Sdsl lab.d_secsize == 512) { 85765151c95Sdsl /* Write the label to the odd sectors of the last track! */ 8581726c417Sdyoung daddr_t alt; 8591726c417Sdyoung int i; 86065151c95Sdsl uint8_t sec0[512]; 8611726c417Sdyoung 86265151c95Sdsl if (pread(f, sec0, 512, 0) < 512) { 86365151c95Sdsl warn("read master label to write alternates"); 86465151c95Sdsl return 0; 86565151c95Sdsl } 86665151c95Sdsl 86765151c95Sdsl alt = lab.d_ncylinders * lab.d_secpercyl - lab.d_nsectors; 8680428b65eSmhitch for (i = 1; i < 11 && (uint32_t)i < lab.d_nsectors; i += 2) { 86965151c95Sdsl if (pwrite(f, sec0, 512, (off_t)(alt + i) * 512) < 512) 8701726c417Sdyoung warn("alternate label %d write", i/2); 8711726c417Sdyoung } 8721726c417Sdyoung } 873e7730664Stsutsui #endif /* VAX_ALTLABELS */ 8741726c417Sdyoung 87565151c95Sdsl return 0; 87665151c95Sdsl } 87765151c95Sdsl 87865151c95Sdsl int 87965151c95Sdsl writelabel(int f, struct disklabel *lp) 88065151c95Sdsl { 88165151c95Sdsl if (lp != &lab) 88265151c95Sdsl lab = *lp; 88365151c95Sdsl return write_label(f); 8841726c417Sdyoung } 8851726c417Sdyoung 8861726c417Sdyoung static void 8871726c417Sdyoung l_perror(const char *s) 8881726c417Sdyoung { 8891726c417Sdyoung 8901726c417Sdyoung switch (errno) { 8911726c417Sdyoung 8921726c417Sdyoung case ESRCH: 8931726c417Sdyoung warnx("%s: No disk label on disk;\n" 8941726c417Sdyoung "use \"disklabel -I\" to install initial label", s); 8951726c417Sdyoung break; 8961726c417Sdyoung 8971726c417Sdyoung case EINVAL: 8981726c417Sdyoung warnx("%s: Label magic number or checksum is wrong!\n" 8991726c417Sdyoung "(disklabel or kernel is out of date?)", s); 9001726c417Sdyoung break; 9011726c417Sdyoung 9021726c417Sdyoung case EBUSY: 9031726c417Sdyoung warnx("%s: Open partition would move or shrink", s); 9041726c417Sdyoung break; 9051726c417Sdyoung 9061726c417Sdyoung case EXDEV: 9071726c417Sdyoung warnx("%s: Labeled partition or 'a' partition must start" 9081726c417Sdyoung " at beginning of disk", s); 9091726c417Sdyoung break; 9101726c417Sdyoung 9111726c417Sdyoung default: 9121726c417Sdyoung warn("%s", s); 9131726c417Sdyoung break; 9141726c417Sdyoung } 9151726c417Sdyoung } 9161726c417Sdyoung 91765151c95Sdsl #ifdef NO_MBR_SUPPORT 91865151c95Sdsl #define process_mbr(f, action) 1 91965151c95Sdsl #else 9201726c417Sdyoung /* 92165151c95Sdsl * Scan DOS/MBR partition table and extended partition list for NetBSD ptns. 9221726c417Sdyoung */ 92365151c95Sdsl static int 92465151c95Sdsl process_mbr(int f, int (*action)(int, u_int)) 9251726c417Sdyoung { 9261726c417Sdyoung struct mbr_partition *dp; 9271726c417Sdyoung struct mbr_sector mbr; 92865151c95Sdsl int rval = 1, res; 9291726c417Sdyoung int part; 93065151c95Sdsl u_int ext_base, next_ext, this_ext, start; 9311726c417Sdyoung 9321726c417Sdyoung ext_base = 0; 9331726c417Sdyoung next_ext = 0; 9341726c417Sdyoung for (;;) { 9351726c417Sdyoung this_ext = next_ext; 9361726c417Sdyoung next_ext = 0; 93765151c95Sdsl if (verbose > 1) 93865151c95Sdsl warnx("reading mbr sector %u", this_ext); 9391726c417Sdyoung if (pread(f, &mbr, sizeof mbr, this_ext * (off_t)DEV_BSIZE) 9401726c417Sdyoung != sizeof(mbr)) { 94165151c95Sdsl if (verbose) 94263df928bSapb warn("Can't read master boot record %u", 94365151c95Sdsl this_ext); 94465151c95Sdsl break; 9451726c417Sdyoung } 9461726c417Sdyoung 9471726c417Sdyoung /* Check if table is valid. */ 9481726c417Sdyoung if (mbr.mbr_magic != htole16(MBR_MAGIC)) { 94965151c95Sdsl if (verbose) 95063df928bSapb warnx("Invalid signature in mbr record %u", 95165151c95Sdsl this_ext); 95265151c95Sdsl break; 9531726c417Sdyoung } 9541726c417Sdyoung 9551726c417Sdyoung dp = &mbr.mbr_parts[0]; 9561726c417Sdyoung 95765151c95Sdsl /* Find NetBSD partition(s). */ 9581726c417Sdyoung for (part = 0; part < MBR_PART_COUNT; dp++, part++) { 95965151c95Sdsl start = le32toh(dp->mbrp_start); 9601726c417Sdyoung switch (dp->mbrp_type) { 96165151c95Sdsl #ifdef COMPAT_386BSD_MBRPART 96265151c95Sdsl case MBR_PTYPE_386BSD: 96365151c95Sdsl if (ext_base != 0) 96465151c95Sdsl break; 96565151c95Sdsl /* FALLTHROUGH */ 96665151c95Sdsl #endif 9671726c417Sdyoung case MBR_PTYPE_NETBSD: 96865151c95Sdsl res = action(f, this_ext + start); 96965151c95Sdsl if (res <= 0) 97065151c95Sdsl /* Found or failure */ 97165151c95Sdsl return res; 97265151c95Sdsl if (res > rval) 97365151c95Sdsl /* Keep largest value */ 97465151c95Sdsl rval = res; 9751726c417Sdyoung break; 9761726c417Sdyoung case MBR_PTYPE_EXT: 9771726c417Sdyoung case MBR_PTYPE_EXT_LBA: 9781726c417Sdyoung case MBR_PTYPE_EXT_LNX: 97965151c95Sdsl next_ext = start; 98065151c95Sdsl break; 9811726c417Sdyoung default: 9821726c417Sdyoung break; 9831726c417Sdyoung } 98465151c95Sdsl } 9851726c417Sdyoung if (next_ext == 0) 9861726c417Sdyoung /* No more extended partitions */ 9871726c417Sdyoung break; 9881726c417Sdyoung next_ext += ext_base; 9891726c417Sdyoung if (ext_base == 0) 9901726c417Sdyoung ext_base = next_ext; 9911726c417Sdyoung 9921726c417Sdyoung if (next_ext <= this_ext) { 99365151c95Sdsl if (verbose) 9941726c417Sdyoung warnx("Invalid extended chain %x <= %x", 9951726c417Sdyoung next_ext, this_ext); 9961726c417Sdyoung break; 9971726c417Sdyoung } 99865151c95Sdsl /* Maybe we should check against the disk size... */ 9991726c417Sdyoung } 10001726c417Sdyoung 100165151c95Sdsl return rval; 100265151c95Sdsl } 100365151c95Sdsl 100465151c95Sdsl static int 100565151c95Sdsl readlabel_mbr(int f, u_int sector) 100665151c95Sdsl { 1007d3724ba4Stsutsui struct disklabel *disk_lp; 100865151c95Sdsl 1009d3724ba4Stsutsui disk_lp = find_label(f, sector); 1010d3724ba4Stsutsui if (disk_lp == NULL) 101165151c95Sdsl return 1; 1012d3724ba4Stsutsui targettohlabel(&lab, disk_lp); 10131726c417Sdyoung return 0; 10141726c417Sdyoung } 10151726c417Sdyoung 101665151c95Sdsl static int 101765151c95Sdsl writelabel_mbr(int f, u_int sector) 101865151c95Sdsl { 10191b979fccSmlelstv return update_label(f, sector, labelusesmbr ? LABELOFFSET_MBR : ~0U) ? 2 : 0; 102065151c95Sdsl } 102165151c95Sdsl 102265151c95Sdsl #endif /* !NO_MBR_SUPPORT */ 102365151c95Sdsl 102465151c95Sdsl #ifndef USE_ACORN 102565151c95Sdsl #define get_filecore_partition(f) 0 102665151c95Sdsl #else 10271726c417Sdyoung /* 10281726c417Sdyoung * static int filecore_checksum(u_char *bootblock) 10291726c417Sdyoung * 10301726c417Sdyoung * Calculates the filecore boot block checksum. This is used to validate 10311726c417Sdyoung * a filecore boot block on the disk. If a boot block is validated then 10321726c417Sdyoung * it is used to locate the partition table. If the boot block is not 10331726c417Sdyoung * validated, it is assumed that the whole disk is NetBSD. 10341726c417Sdyoung * 10351726c417Sdyoung * The basic algorithm is: 10361726c417Sdyoung * 10371726c417Sdyoung * for (each byte in block, excluding checksum) { 10381726c417Sdyoung * sum += byte; 10391726c417Sdyoung * if (sum > 255) 10401726c417Sdyoung * sum -= 255; 10411726c417Sdyoung * } 10421726c417Sdyoung * 10431726c417Sdyoung * That's equivalent to summing all of the bytes in the block 10441726c417Sdyoung * (excluding the checksum byte, of course), then calculating the 10451726c417Sdyoung * checksum as "cksum = sum - ((sum - 1) / 255) * 255)". That 10461726c417Sdyoung * expression may or may not yield a faster checksum function, 10471726c417Sdyoung * but it's easier to reason about. 10481726c417Sdyoung * 10491726c417Sdyoung * Note that if you have a block filled with bytes of a single 10501726c417Sdyoung * value "X" (regardless of that value!) and calculate the cksum 10511726c417Sdyoung * of the block (excluding the checksum byte), you will _always_ 10521726c417Sdyoung * end up with a checksum of X. (Do the math; that can be derived 10531726c417Sdyoung * from the checksum calculation function!) That means that 10541726c417Sdyoung * blocks which contain bytes which all have the same value will 105557920690Smsaitoh * always checksum properly. That's a _very_ unlikely occurrence 10561726c417Sdyoung * (probably impossible, actually) for a valid filecore boot block, 10571726c417Sdyoung * so we treat such blocks as invalid. 10581726c417Sdyoung */ 10591726c417Sdyoung static int 10601726c417Sdyoung filecore_checksum(u_char *bootblock) 10611726c417Sdyoung { 10621726c417Sdyoung u_char byte0, accum_diff; 10631726c417Sdyoung u_int sum; 10641726c417Sdyoung int i; 10651726c417Sdyoung 10661726c417Sdyoung sum = 0; 10671726c417Sdyoung accum_diff = 0; 10681726c417Sdyoung byte0 = bootblock[0]; 10691726c417Sdyoung 10701726c417Sdyoung /* 10711726c417Sdyoung * Sum the contents of the block, keeping track of whether 10721726c417Sdyoung * or not all bytes are the same. If 'accum_diff' ends up 10731726c417Sdyoung * being zero, all of the bytes are, in fact, the same. 10741726c417Sdyoung */ 10751726c417Sdyoung for (i = 0; i < 511; ++i) { 10761726c417Sdyoung sum += bootblock[i]; 10771726c417Sdyoung accum_diff |= bootblock[i] ^ byte0; 10781726c417Sdyoung } 10791726c417Sdyoung 10801726c417Sdyoung /* 10811726c417Sdyoung * Check to see if the checksum byte is the same as the 10821726c417Sdyoung * rest of the bytes, too. (Note that if all of the bytes 10831726c417Sdyoung * are the same except the checksum, a checksum compare 10841726c417Sdyoung * won't succeed, but that's not our problem.) 10851726c417Sdyoung */ 10861726c417Sdyoung accum_diff |= bootblock[i] ^ byte0; 10871726c417Sdyoung 10881726c417Sdyoung /* All bytes in block are the same; call it invalid. */ 10891726c417Sdyoung if (accum_diff == 0) 10901726c417Sdyoung return (-1); 10911726c417Sdyoung 10921726c417Sdyoung return (sum - ((sum - 1) / 255) * 255); 10931726c417Sdyoung } 10941726c417Sdyoung 10951726c417Sdyoung /* 109665151c95Sdsl * Check for the presence of a RiscOS filecore boot block 109765151c95Sdsl * indicating an ADFS file system on the disc. 109865151c95Sdsl * Return the offset to the NetBSD part of the disc if 109965151c95Sdsl * this can be determined. 110065151c95Sdsl * This routine will terminate disklabel if the disc 110165151c95Sdsl * is found to be ADFS only. 11021726c417Sdyoung */ 11031726c417Sdyoung static u_int 11041726c417Sdyoung get_filecore_partition(int f) 11051726c417Sdyoung { 11061726c417Sdyoung struct filecore_bootblock *fcbb; 110729c1a4c2Schristos static u_char bb[DEV_BSIZE]; 11081726c417Sdyoung u_int offset; 110965151c95Sdsl struct riscix_partition_table *riscix_part; 111065151c95Sdsl int loop; 11111726c417Sdyoung 111265151c95Sdsl if (pread(f, bb, sizeof(bb), (off_t)FILECORE_BOOT_SECTOR * DEV_BSIZE) != sizeof(bb)) 11131726c417Sdyoung err(4, "can't read filecore boot block"); 11141726c417Sdyoung fcbb = (struct filecore_bootblock *)bb; 11151726c417Sdyoung 11161726c417Sdyoung /* Check if table is valid. */ 11171726c417Sdyoung if (filecore_checksum(bb) != fcbb->checksum) 11181726c417Sdyoung return (0); 11191726c417Sdyoung 11201726c417Sdyoung /* 11211726c417Sdyoung * Check for NetBSD/arm32 (RiscBSD) partition marker. 11221726c417Sdyoung * If found the NetBSD disklabel location is easy. 11231726c417Sdyoung */ 11241726c417Sdyoung offset = (fcbb->partition_cyl_low + (fcbb->partition_cyl_high << 8)) 11251726c417Sdyoung * fcbb->heads * fcbb->secspertrack; 11261726c417Sdyoung 112765151c95Sdsl switch (fcbb->partition_type) { 112865151c95Sdsl 112965151c95Sdsl case PARTITION_FORMAT_RISCBSD: 113065151c95Sdsl return (offset); 113165151c95Sdsl 113265151c95Sdsl case PARTITION_FORMAT_RISCIX: 11331726c417Sdyoung /* 11341726c417Sdyoung * Read the RISCiX partition table and search for the 11351726c417Sdyoung * first partition named "RiscBSD", "NetBSD", or "Empty:" 11361726c417Sdyoung * 11371726c417Sdyoung * XXX is use of 'Empty:' really desirable?! -- cgd 11381726c417Sdyoung */ 11391726c417Sdyoung 114065151c95Sdsl if (pread(f, bb, sizeof(bb), (off_t)offset * DEV_BSIZE) != sizeof(bb)) 11411726c417Sdyoung err(4, "can't read riscix partition table"); 11421726c417Sdyoung riscix_part = (struct riscix_partition_table *)bb; 11431726c417Sdyoung 11441726c417Sdyoung for (loop = 0; loop < NRISCIX_PARTITIONS; ++loop) { 114529c1a4c2Schristos if (strcmp((char *)riscix_part->partitions[loop].rp_name, 11461726c417Sdyoung "RiscBSD") == 0 || 114729c1a4c2Schristos strcmp((char *)riscix_part->partitions[loop].rp_name, 11481726c417Sdyoung "NetBSD") == 0 || 114929c1a4c2Schristos strcmp((char *)riscix_part->partitions[loop].rp_name, 11501726c417Sdyoung "Empty:") == 0) { 115165151c95Sdsl return riscix_part->partitions[loop].rp_start; 11521726c417Sdyoung break; 11531726c417Sdyoung } 11541726c417Sdyoung } 11551726c417Sdyoung /* 11561726c417Sdyoung * Valid filecore boot block, RISCiX partition table 11571726c417Sdyoung * but no NetBSD partition. We should leave this 11581726c417Sdyoung * disc alone. 11591726c417Sdyoung */ 11601726c417Sdyoung errx(4, "cannot label: no NetBSD partition found" 11611726c417Sdyoung " in RISCiX partition table"); 116265151c95Sdsl 116365151c95Sdsl default: 11641726c417Sdyoung /* 11651726c417Sdyoung * Valid filecore boot block and no non-ADFS partition. 11661726c417Sdyoung * This means that the whole disc is allocated for ADFS 11671726c417Sdyoung * so do not trash ! If the user really wants to put a 11681726c417Sdyoung * NetBSD disklabel on the disc then they should remove 11691726c417Sdyoung * the filecore boot block first with dd. 11701726c417Sdyoung */ 11711726c417Sdyoung errx(4, "cannot label: filecore-only disk" 11721726c417Sdyoung " (no non-ADFS partition)"); 11731726c417Sdyoung } 11741726c417Sdyoung return (0); 11751726c417Sdyoung } 11761726c417Sdyoung #endif /* USE_ACORN */ 11771726c417Sdyoung 11781726c417Sdyoung /* 117965151c95Sdsl * Fetch disklabel for disk to 'lab'. 11801726c417Sdyoung * Use ioctl to get label unless -r flag is given. 11811726c417Sdyoung */ 118265151c95Sdsl static void 11831726c417Sdyoung readlabel(int f) 11841726c417Sdyoung { 118565151c95Sdsl if (rflag) { 118665151c95Sdsl /* Get label directly from disk */ 118765151c95Sdsl if (readlabel_direct(f) == 0) 118865151c95Sdsl return; 11891726c417Sdyoung /* 11901726c417Sdyoung * There was no label on the disk. Get the fictious one 11911726c417Sdyoung * as a basis for initialisation. 11921726c417Sdyoung */ 119365151c95Sdsl if (!Fflag && Iflag && (dk_ioctl(f, DIOCGDINFO, &lab) == 0 || 119465151c95Sdsl dk_ioctl(f, DIOCGDEFLABEL, &lab) == 0)) 119565151c95Sdsl return; 11961726c417Sdyoung } else { 119765151c95Sdsl /* Get label from kernel. */ 119865151c95Sdsl if (dk_ioctl(f, DIOCGDINFO, &lab) < 0) 11991726c417Sdyoung err(4, "ioctl DIOCGDINFO"); 120065151c95Sdsl return; 12011726c417Sdyoung } 120265151c95Sdsl 120365151c95Sdsl if (read_all == 2) 120465151c95Sdsl /* We actually found one, and printed it... */ 120565151c95Sdsl exit(0); 120665151c95Sdsl errx(1, "could not read existing label"); 12071726c417Sdyoung } 12081726c417Sdyoung 12091726c417Sdyoung /* 121065151c95Sdsl * Reading the label from the disk is largely a case of 'hunt the label'. 121165151c95Sdsl * and since different architectures default to different places there 121265151c95Sdsl * could even be more than one label that contradict each other! 121365151c95Sdsl * For now we look in the expected place, then search through likely 121465151c95Sdsl * other locations. 12151726c417Sdyoung */ 12161726c417Sdyoung static struct disklabel * 121765151c95Sdsl find_label(int f, u_int sector) 12181726c417Sdyoung { 1219bd8efe16Skamil struct disklabel *disk_lp, hlp, tlp; 122063df928bSapb int i; 12211e2e5a91Schristos off_t offset; 122265151c95Sdsl const char *is_deleted; 12231726c417Sdyoung 122465151c95Sdsl bootarea_len = pread(f, bootarea, sizeof bootarea, 122565151c95Sdsl sector * (off_t)DEV_BSIZE); 122665151c95Sdsl if (bootarea_len <= 0) { 122765151c95Sdsl if (verbose) 122865151c95Sdsl warn("failed to read bootarea from sector %u", sector); 122965151c95Sdsl return NULL; 12301726c417Sdyoung } 12311726c417Sdyoung 123265151c95Sdsl if (verbose > 2) 123363df928bSapb warnx("read sector %u len %d looking for label", 123465151c95Sdsl sector, bootarea_len); 12351726c417Sdyoung 123665151c95Sdsl /* Check expected offset first */ 123765151c95Sdsl for (offset = LABEL_OFFSET, i = -4;; offset = i += 4) { 123865151c95Sdsl is_deleted = ""; 123965151c95Sdsl if (i == LABEL_OFFSET) 124065151c95Sdsl continue; 1241bd8efe16Skamil disk_lp = (void *)(bootarea + offset); 1242d3724ba4Stsutsui if ((char *)(disk_lp + 1) > bootarea + bootarea_len) 124365151c95Sdsl break; 1244141e8cbcSchristos memcpy(&tlp, disk_lp, sizeof(tlp)); 1245bd8efe16Skamil if (tlp.d_magic2 != tlp.d_magic) 124665151c95Sdsl continue; 1247bd8efe16Skamil if (read_all && (tlp.d_magic == DISKMAGIC_DELETED || 1248bd8efe16Skamil tlp.d_magic == DISKMAGIC_DELETED_REV)) { 1249bd8efe16Skamil tlp.d_magic ^= ~0u; 1250bd8efe16Skamil tlp.d_magic2 ^= ~0u; 125165151c95Sdsl is_deleted = "deleted "; 12521726c417Sdyoung } 1253bd8efe16Skamil if (target32toh(tlp.d_magic) != DISKMAGIC) { 125465151c95Sdsl /* XXX: Do something about byte-swapped labels ? */ 1255bd8efe16Skamil if (target32toh(tlp.d_magic) == DISKMAGIC_REV && 1256bd8efe16Skamil target32toh(tlp.d_magic2) == DISKMAGIC_REV) 125765151c95Sdsl warnx("ignoring %sbyteswapped label" 1258cb39557cSchristos " at offset %jd from sector %u", 1259cb39557cSchristos is_deleted, (intmax_t)offset, sector); 126065151c95Sdsl continue; 126165151c95Sdsl } 1262bd8efe16Skamil if (target16toh(tlp.d_npartitions) > maxpartitions || 1263bd8efe16Skamil dkcksum_target(&tlp) != 0) { 126465151c95Sdsl if (verbose > 0) 1265cb39557cSchristos warnx("corrupt label found at offset %jd in " 1266cb39557cSchristos "sector %u", (intmax_t)offset, sector); 126765151c95Sdsl continue; 126865151c95Sdsl } 126965151c95Sdsl if (verbose > 1) 1270cb39557cSchristos warnx("%slabel found at offset %jd from sector %u", 1271cb39557cSchristos is_deleted, (intmax_t)offset, sector); 127265151c95Sdsl if (!read_all) 1273d3724ba4Stsutsui return disk_lp; 12741726c417Sdyoung 127565151c95Sdsl /* To print all the labels we have to do it here */ 127665151c95Sdsl /* XXX: maybe we should compare them? */ 1277bd8efe16Skamil targettohlabel(&hlp, &tlp); 1278cb39557cSchristos printf("# %ssector %u offset %jd bytes\n", 1279cb39557cSchristos is_deleted, sector, (intmax_t)offset); 128065151c95Sdsl if (tflag) 1281d3724ba4Stsutsui makedisktab(stdout, &hlp); 128265151c95Sdsl else { 1283d3724ba4Stsutsui showinfo(stdout, &hlp, specname); 1284d3724ba4Stsutsui showpartitions(stdout, &hlp, Cflag); 128565151c95Sdsl } 1286d3724ba4Stsutsui checklabel(&hlp); 1287bd8efe16Skamil htotargetlabel(&tlp, &hlp); 1288bd8efe16Skamil memcpy(disk_lp, &tlp, sizeof(tlp)); 128965151c95Sdsl /* Remember we've found a label */ 129065151c95Sdsl read_all = 2; 129165151c95Sdsl } 129265151c95Sdsl return NULL; 129365151c95Sdsl } 129465151c95Sdsl 129565151c95Sdsl static void 129665151c95Sdsl write_bootarea(int f, u_int sector) 129765151c95Sdsl { 129865151c95Sdsl int wlen; 129965151c95Sdsl 130065151c95Sdsl if (bootarea_len <= 0) 130165151c95Sdsl errx(1, "attempting to write after failed read"); 130265151c95Sdsl 1303e7730664Stsutsui #ifdef ALPHA_BOOTBLOCK_CKSUM 13041726c417Sdyoung /* 130565151c95Sdsl * The Alpha requires that the boot block be checksummed. 1306e7730664Stsutsui * <sys/bootblock.h> provides a macro to do it. 13071726c417Sdyoung */ 130865151c95Sdsl if (sector == 0) { 130965151c95Sdsl struct alpha_boot_block *bb; 131065151c95Sdsl 13110bf2e000Schristos bb = (struct alpha_boot_block *)(void *)bootarea; 131265151c95Sdsl bb->bb_cksum = 0; 131365151c95Sdsl ALPHA_BOOT_BLOCK_CKSUM(bb, &bb->bb_cksum); 131465151c95Sdsl } 1315e7730664Stsutsui #endif /* ALPHA_BOOTBLOCK_CKSUM */ 131665151c95Sdsl 131765151c95Sdsl wlen = pwrite(f, bootarea, bootarea_len, sector * (off_t)DEV_BSIZE); 131865151c95Sdsl if (wlen == bootarea_len) 131965151c95Sdsl return; 132065151c95Sdsl if (wlen == -1) 132163df928bSapb err(1, "disklabel write (sector %u) size %d failed", 132265151c95Sdsl sector, bootarea_len); 132363df928bSapb errx(1, "disklabel write (sector %u) size %d truncated to %d", 132465151c95Sdsl sector, bootarea_len, wlen); 132565151c95Sdsl } 132665151c95Sdsl 132765151c95Sdsl static int 132865151c95Sdsl update_label(int f, u_int label_sector, u_int label_offset) 132965151c95Sdsl { 133065151c95Sdsl struct disklabel *disk_lp; 133165151c95Sdsl 133265151c95Sdsl disk_lp = find_label(f, label_sector); 133365151c95Sdsl 133465151c95Sdsl if (disk_lp && Dflag) { 133565151c95Sdsl /* Invalidate the existing label */ 133665151c95Sdsl disk_lp->d_magic ^= ~0u; 133765151c95Sdsl disk_lp->d_magic2 ^= ~0u; 133865151c95Sdsl if (Dflag == 2) 133965151c95Sdsl write_bootarea(f, label_sector); 134065151c95Sdsl /* Force label to default location */ 134165151c95Sdsl disk_lp = NULL; 134265151c95Sdsl } 134365151c95Sdsl 134465151c95Sdsl if (Dflag == 2) 134565151c95Sdsl /* We are just deleting the label */ 134665151c95Sdsl return 0; 134765151c95Sdsl 134865151c95Sdsl if (disk_lp == NULL) { 134965151c95Sdsl if (label_offset == ~0u) 135065151c95Sdsl return 0; 135165151c95Sdsl /* Nothing on the disk - we need to add it */ 1352628f1591Sdrochner disk_lp = (void *)(bootarea + label_offset); 1353628f1591Sdrochner if ((char *)(disk_lp + 1) > bootarea + bootarea_len) 135465151c95Sdsl errx(1, "no space in bootarea (sector %u) " 135565151c95Sdsl "to create label", label_sector); 135665151c95Sdsl } 135765151c95Sdsl 1358d3724ba4Stsutsui htotargetlabel(disk_lp, &lab); 135965151c95Sdsl write_bootarea(f, label_sector); 136065151c95Sdsl return 1; 136165151c95Sdsl } 136265151c95Sdsl 136365151c95Sdsl static void 136465151c95Sdsl writelabel_direct(int f) 136565151c95Sdsl { 136665151c95Sdsl u_int label_sector; 136765151c95Sdsl int written = 0; 136865151c95Sdsl int rval; 136965151c95Sdsl 137065151c95Sdsl label_sector = get_filecore_partition(f); 137165151c95Sdsl if (label_sector != 0) 137265151c95Sdsl /* The offset needs to be that from the acorn ports... */ 137365151c95Sdsl written = update_label(f, label_sector, DEV_BSIZE); 137465151c95Sdsl 137565151c95Sdsl rval = process_mbr(f, writelabel_mbr); 137665151c95Sdsl 137765151c95Sdsl if (rval == 2 || written) 137865151c95Sdsl /* Don't add a label to sector 0, but update one if there */ 137965151c95Sdsl update_label(f, 0, ~0u); 138065151c95Sdsl else 138165151c95Sdsl update_label(f, 0, LABEL_OFFSET); 138265151c95Sdsl } 138365151c95Sdsl 138465151c95Sdsl static int 138565151c95Sdsl readlabel_direct(int f) 138665151c95Sdsl { 138765151c95Sdsl struct disklabel *disk_lp; 138865151c95Sdsl u_int filecore_partition_offset; 138965151c95Sdsl 139065151c95Sdsl filecore_partition_offset = get_filecore_partition(f); 139165151c95Sdsl if (filecore_partition_offset != 0) { 139265151c95Sdsl disk_lp = find_label(f, filecore_partition_offset); 139365151c95Sdsl if (disk_lp != NULL) { 1394d3724ba4Stsutsui targettohlabel(&lab, disk_lp); 139565151c95Sdsl return 0; 139665151c95Sdsl } 139765151c95Sdsl } 139865151c95Sdsl 13991b979fccSmlelstv if (labelusesmbr && process_mbr(f, readlabel_mbr) == 0) 140065151c95Sdsl return 0; 140165151c95Sdsl 140265151c95Sdsl disk_lp = find_label(f, 0); 140365151c95Sdsl if (disk_lp != NULL) { 1404d3724ba4Stsutsui targettohlabel(&lab, disk_lp); 140565151c95Sdsl return 0; 140665151c95Sdsl } 140765151c95Sdsl 14081b979fccSmlelstv if (!labelusesmbr && process_mbr(f, readlabel_mbr) == 0) 140965151c95Sdsl return 0; 141065151c95Sdsl 141165151c95Sdsl return 1; 14121726c417Sdyoung } 14131726c417Sdyoung 14141726c417Sdyoung static void 14151726c417Sdyoung makedisktab(FILE *f, struct disklabel *lp) 14161726c417Sdyoung { 14171726c417Sdyoung int i; 14181726c417Sdyoung const char *did; 14191726c417Sdyoung struct partition *pp; 14201726c417Sdyoung 14211726c417Sdyoung did = "\\\n\t:"; 14221726c417Sdyoung (void) fprintf(f, "%.*s|Automatically generated label:\\\n\t:dt=", 14231726c417Sdyoung (int) sizeof(lp->d_typename), lp->d_typename); 14241726c417Sdyoung if ((unsigned) lp->d_type < DKMAXTYPES) 14251726c417Sdyoung (void) fprintf(f, "%s:", dktypenames[lp->d_type]); 14261726c417Sdyoung else 1427621e83eaSchristos (void) fprintf(f, "unknown%" PRIu16 ":", lp->d_type); 14281726c417Sdyoung 1429621e83eaSchristos (void) fprintf(f, "se#%" PRIu32 ":", lp->d_secsize); 1430621e83eaSchristos (void) fprintf(f, "ns#%" PRIu32 ":", lp->d_nsectors); 1431621e83eaSchristos (void) fprintf(f, "nt#%" PRIu32 ":", lp->d_ntracks); 1432621e83eaSchristos (void) fprintf(f, "sc#%" PRIu32 ":", lp->d_secpercyl); 1433621e83eaSchristos (void) fprintf(f, "nc#%" PRIu32 ":", lp->d_ncylinders); 14341726c417Sdyoung 14351726c417Sdyoung if ((lp->d_secpercyl * lp->d_ncylinders) != lp->d_secperunit) { 1436621e83eaSchristos (void) fprintf(f, "%ssu#%" PRIu32 ":", did, lp->d_secperunit); 14371726c417Sdyoung did = ""; 14381726c417Sdyoung } 14391726c417Sdyoung if (lp->d_rpm != 3600) { 1440621e83eaSchristos (void) fprintf(f, "%srm#%" PRIu16 ":", did, lp->d_rpm); 14411726c417Sdyoung did = ""; 14421726c417Sdyoung } 14431726c417Sdyoung if (lp->d_interleave != 1) { 1444621e83eaSchristos (void) fprintf(f, "%sil#%" PRIu16 ":", did, lp->d_interleave); 14451726c417Sdyoung did = ""; 14461726c417Sdyoung } 14471726c417Sdyoung if (lp->d_trackskew != 0) { 1448621e83eaSchristos (void) fprintf(f, "%ssk#%" PRIu16 ":", did, lp->d_trackskew); 14491726c417Sdyoung did = ""; 14501726c417Sdyoung } 14511726c417Sdyoung if (lp->d_cylskew != 0) { 1452621e83eaSchristos (void) fprintf(f, "%scs#%" PRIu16 ":", did, lp->d_cylskew); 14531726c417Sdyoung did = ""; 14541726c417Sdyoung } 14551726c417Sdyoung if (lp->d_headswitch != 0) { 145663b30d82Sjoerg (void) fprintf(f, "%shs#%" PRIu32 ":", did, lp->d_headswitch); 14571726c417Sdyoung did = ""; 14581726c417Sdyoung } 14591726c417Sdyoung if (lp->d_trkseek != 0) { 1460621e83eaSchristos (void) fprintf(f, "%sts#%" PRIu32 ":", did, lp->d_trkseek); 14611726c417Sdyoung did = ""; 14621726c417Sdyoung } 14631726c417Sdyoung #ifdef notyet 14641726c417Sdyoung (void) fprintf(f, "drivedata: "); 14651726c417Sdyoung for (i = NDDATA - 1; i >= 0; i--) 14661726c417Sdyoung if (lp->d_drivedata[i]) 14671726c417Sdyoung break; 14681726c417Sdyoung if (i < 0) 14691726c417Sdyoung i = 0; 14701726c417Sdyoung for (j = 0; j <= i; j++) 1471621e83eaSchristos (void) fprintf(f, "%" PRIu32 " ", lp->d_drivedata[j]); 14721726c417Sdyoung #endif /* notyet */ 14731726c417Sdyoung pp = lp->d_partitions; 14741726c417Sdyoung for (i = 0; i < lp->d_npartitions; i++, pp++) { 14751726c417Sdyoung if (pp->p_size) { 14761726c417Sdyoung char c = 'a' + i; 14771726c417Sdyoung (void) fprintf(f, "\\\n\t:"); 1478621e83eaSchristos (void) fprintf(f, "p%c#%" PRIu32 ":", c, pp->p_size); 1479621e83eaSchristos (void) fprintf(f, "o%c#%" PRIu32 ":", c, pp->p_offset); 14801726c417Sdyoung if (pp->p_fstype != FS_UNUSED) { 14811726c417Sdyoung if ((unsigned) pp->p_fstype < FSMAXTYPES) 14821726c417Sdyoung (void) fprintf(f, "t%c=%s:", c, 14831726c417Sdyoung fstypenames[pp->p_fstype]); 14841726c417Sdyoung else 148563df928bSapb (void) fprintf(f, 148663df928bSapb "t%c=unknown%" PRIu8 ":", 148763df928bSapb c, pp->p_fstype); 14881726c417Sdyoung } 14891726c417Sdyoung switch (pp->p_fstype) { 14901726c417Sdyoung 14911726c417Sdyoung case FS_UNUSED: 14921726c417Sdyoung break; 14931726c417Sdyoung 14941726c417Sdyoung case FS_BSDFFS: 14951726c417Sdyoung case FS_BSDLFS: 14961726c417Sdyoung case FS_EX2FS: 14971726c417Sdyoung case FS_ADOS: 14981726c417Sdyoung case FS_APPLEUFS: 1499621e83eaSchristos (void) fprintf(f, "b%c#%" PRIu64 ":", c, 1500621e83eaSchristos (uint64_t)pp->p_fsize * pp->p_frag); 1501621e83eaSchristos (void) fprintf(f, "f%c#%" PRIu32 ":", c, 1502621e83eaSchristos pp->p_fsize); 15031726c417Sdyoung break; 15041726c417Sdyoung default: 15051726c417Sdyoung break; 15061726c417Sdyoung } 15071726c417Sdyoung } 15081726c417Sdyoung } 15091726c417Sdyoung (void) fprintf(f, "\n"); 15101726c417Sdyoung (void) fflush(f); 15111726c417Sdyoung } 15121726c417Sdyoung 15131726c417Sdyoung static int 151465151c95Sdsl edit(int f) 15151726c417Sdyoung { 15161726c417Sdyoung const char *tmpdir; 151765151c95Sdsl char tmpfil[MAXPATHLEN]; 15181726c417Sdyoung int first, ch, fd; 151946b640e7Sdsl int get_ok; 15201726c417Sdyoung FILE *fp; 15211726c417Sdyoung 15221726c417Sdyoung if ((tmpdir = getenv("TMPDIR")) == NULL) 15231726c417Sdyoung tmpdir = _PATH_TMP; 15241726c417Sdyoung (void)snprintf(tmpfil, sizeof(tmpfil), "%s/%s", tmpdir, TMPFILE); 15251726c417Sdyoung if ((fd = mkstemp(tmpfil)) == -1 || (fp = fdopen(fd, "w")) == NULL) { 15261726c417Sdyoung warn("%s", tmpfil); 15271726c417Sdyoung return (1); 15281726c417Sdyoung } 15291726c417Sdyoung (void)fchmod(fd, 0600); 153065151c95Sdsl showinfo(fp, &lab, specname); 153165151c95Sdsl showpartitions(fp, &lab, Cflag); 15321726c417Sdyoung (void) fclose(fp); 15331726c417Sdyoung for (;;) { 153465151c95Sdsl if (!editit(tmpfil)) 15351726c417Sdyoung break; 15361726c417Sdyoung fp = fopen(tmpfil, "r"); 15371726c417Sdyoung if (fp == NULL) { 15381726c417Sdyoung warn("%s", tmpfil); 15391726c417Sdyoung break; 15401726c417Sdyoung } 154165151c95Sdsl (void) memset(&lab, 0, sizeof(lab)); 154246b640e7Sdsl get_ok = getasciilabel(fp, &lab); 154346b640e7Sdsl fclose(fp); 154446b640e7Sdsl if (get_ok && write_label(f) == 0) { 15451726c417Sdyoung (void) unlink(tmpfil); 15461726c417Sdyoung return (0); 15471726c417Sdyoung } 15481726c417Sdyoung (void) printf("re-edit the label? [y]: "); 15491726c417Sdyoung (void) fflush(stdout); 15501726c417Sdyoung first = ch = getchar(); 15511726c417Sdyoung while (ch != '\n' && ch != EOF) 15521726c417Sdyoung ch = getchar(); 15531726c417Sdyoung if (first == 'n' || first == 'N') 15541726c417Sdyoung break; 15551726c417Sdyoung } 15561726c417Sdyoung (void)unlink(tmpfil); 15571726c417Sdyoung return (1); 15581726c417Sdyoung } 15591726c417Sdyoung 15601726c417Sdyoung static int 156165151c95Sdsl editit(const char *tmpfil) 15621726c417Sdyoung { 15631726c417Sdyoung int pid, xpid; 15641726c417Sdyoung int status; 15651726c417Sdyoung sigset_t nsigset, osigset; 15661726c417Sdyoung 15671726c417Sdyoung sigemptyset(&nsigset); 15681726c417Sdyoung sigaddset(&nsigset, SIGINT); 15691726c417Sdyoung sigaddset(&nsigset, SIGQUIT); 15701726c417Sdyoung sigaddset(&nsigset, SIGHUP); 15711726c417Sdyoung sigprocmask(SIG_BLOCK, &nsigset, &osigset); 15721726c417Sdyoung while ((pid = fork()) < 0) { 15731726c417Sdyoung if (errno != EAGAIN) { 15741726c417Sdyoung sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); 15751726c417Sdyoung warn("fork"); 15761726c417Sdyoung return (0); 15771726c417Sdyoung } 15781726c417Sdyoung sleep(1); 15791726c417Sdyoung } 15801726c417Sdyoung if (pid == 0) { 15811726c417Sdyoung const char *ed; 15821726c417Sdyoung char *buf; 15831726c417Sdyoung int retval; 15841726c417Sdyoung 15851726c417Sdyoung sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); 15861726c417Sdyoung setgid(getgid()); 15871726c417Sdyoung setuid(getuid()); 15881726c417Sdyoung if ((ed = getenv("EDITOR")) == (char *)0) 15891726c417Sdyoung ed = DEFEDITOR; 15901726c417Sdyoung /* 15911726c417Sdyoung * Jump through a few extra hoops in case someone's editor 15921726c417Sdyoung * is "editor arg1 arg2". 15931726c417Sdyoung */ 15941726c417Sdyoung asprintf(&buf, "%s %s", ed, tmpfil); 15951726c417Sdyoung if (!buf) 15961726c417Sdyoung err(1, "malloc"); 15971726c417Sdyoung retval = execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", buf, NULL); 15981726c417Sdyoung if (retval == -1) 15991726c417Sdyoung perror(ed); 16001726c417Sdyoung exit(retval); 16011726c417Sdyoung } 16021726c417Sdyoung while ((xpid = wait(&status)) >= 0) 16031726c417Sdyoung if (xpid == pid) 16041726c417Sdyoung break; 16051726c417Sdyoung sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); 16061726c417Sdyoung return (!status); 16071726c417Sdyoung } 16081726c417Sdyoung 16091726c417Sdyoung static char * 16101726c417Sdyoung skip(char *cp) 16111726c417Sdyoung { 16121726c417Sdyoung 16131726c417Sdyoung cp += strspn(cp, " \t"); 16141726c417Sdyoung if (*cp == '\0') 16151726c417Sdyoung return (NULL); 16161726c417Sdyoung return (cp); 16171726c417Sdyoung } 16181726c417Sdyoung 16191726c417Sdyoung static char * 16201726c417Sdyoung word(char *cp) 16211726c417Sdyoung { 16221726c417Sdyoung 16231726c417Sdyoung if (cp == NULL || *cp == '\0') 16241726c417Sdyoung return (NULL); 16251726c417Sdyoung 16261726c417Sdyoung cp += strcspn(cp, " \t"); 16271726c417Sdyoung if (*cp == '\0') 16281726c417Sdyoung return (NULL); 16291726c417Sdyoung *cp++ = '\0'; 16301726c417Sdyoung cp += strspn(cp, " \t"); 16311726c417Sdyoung if (*cp == '\0') 16321726c417Sdyoung return (NULL); 16331726c417Sdyoung return (cp); 16341726c417Sdyoung } 16351726c417Sdyoung 16361726c417Sdyoung #define _CHECKLINE \ 16371726c417Sdyoung if (tp == NULL || *tp == '\0') { \ 16381726c417Sdyoung warnx("line %d: too few fields", lineno); \ 16391726c417Sdyoung errors++; \ 16401726c417Sdyoung break; \ 16411726c417Sdyoung } 16421726c417Sdyoung 16431726c417Sdyoung #define __CHECKLINE \ 16441726c417Sdyoung if (*tp == NULL || **tp == '\0') { \ 16451726c417Sdyoung warnx("line %d: too few fields", lineno); \ 16461726c417Sdyoung *tp = _error_; \ 16471726c417Sdyoung return 0; \ 16481726c417Sdyoung } 16491726c417Sdyoung 16501726c417Sdyoung static char _error_[] = ""; 16511726c417Sdyoung #define NXTNUM(n) if ((n = nxtnum(&tp, lineno),0) + tp != _error_) \ 16521726c417Sdyoung ; else goto error 16531726c417Sdyoung #define NXTXNUM(n) if ((n = nxtxnum(&tp, lp, lineno),0) + tp != _error_) \ 16541726c417Sdyoung ; else goto error 16551726c417Sdyoung 16561726c417Sdyoung static unsigned long 16571726c417Sdyoung nxtnum(char **tp, int lineno) 16581726c417Sdyoung { 16591726c417Sdyoung char *cp; 16601726c417Sdyoung unsigned long v; 16611726c417Sdyoung 16621726c417Sdyoung __CHECKLINE 16631726c417Sdyoung if (getulong(*tp, '\0', &cp, &v, UINT32_MAX) != 0) { 16641726c417Sdyoung warnx("line %d: syntax error", lineno); 16651726c417Sdyoung *tp = _error_; 16661726c417Sdyoung return 0; 16671726c417Sdyoung } 16681726c417Sdyoung *tp = cp; 16691726c417Sdyoung return v; 16701726c417Sdyoung } 16711726c417Sdyoung 16721726c417Sdyoung static unsigned long 16731726c417Sdyoung nxtxnum(char **tp, struct disklabel *lp, int lineno) 16741726c417Sdyoung { 16751726c417Sdyoung char *cp, *ncp; 16761726c417Sdyoung unsigned long n, v; 16771726c417Sdyoung 16781726c417Sdyoung __CHECKLINE 16791726c417Sdyoung cp = *tp; 16801726c417Sdyoung if (getulong(cp, '/', &ncp, &n, UINT32_MAX) != 0) 16811726c417Sdyoung goto bad; 16821726c417Sdyoung 16831726c417Sdyoung if (*ncp == '/') { 16841726c417Sdyoung n *= lp->d_secpercyl; 16851726c417Sdyoung cp = ncp + 1; 16861726c417Sdyoung if (getulong(cp, '/', &ncp, &v, UINT32_MAX) != 0) 16871726c417Sdyoung goto bad; 16881726c417Sdyoung n += v * lp->d_nsectors; 16891726c417Sdyoung cp = ncp + 1; 16901726c417Sdyoung if (getulong(cp, '\0', &ncp, &v, UINT32_MAX) != 0) 16911726c417Sdyoung goto bad; 16921726c417Sdyoung n += v; 16931726c417Sdyoung } 16941726c417Sdyoung *tp = ncp; 16951726c417Sdyoung return n; 16961726c417Sdyoung bad: 16971726c417Sdyoung warnx("line %d: invalid format", lineno); 16981726c417Sdyoung *tp = _error_; 16991726c417Sdyoung return 0; 17001726c417Sdyoung } 17011726c417Sdyoung 17021726c417Sdyoung /* 17031726c417Sdyoung * Read an ascii label in from fd f, 17041726c417Sdyoung * in the same format as that put out by showinfo() and showpartitions(), 17051726c417Sdyoung * and fill in lp. 17061726c417Sdyoung */ 17071726c417Sdyoung static int 17081726c417Sdyoung getasciilabel(FILE *f, struct disklabel *lp) 17091726c417Sdyoung { 17101726c417Sdyoung const char *const *cpp, *s; 17111726c417Sdyoung struct partition *pp; 17121726c417Sdyoung char *cp, *tp, line[BUFSIZ], tbuf[15]; 17131726c417Sdyoung int lineno, errors; 17141726c417Sdyoung unsigned long v; 17151726c417Sdyoung unsigned int part; 17161726c417Sdyoung 17171726c417Sdyoung lineno = 0; 17181726c417Sdyoung errors = 0; 17191726c417Sdyoung lp->d_bbsize = BBSIZE; /* XXX */ 17201726c417Sdyoung lp->d_sbsize = SBLOCKSIZE; /* XXX */ 17211726c417Sdyoung while (fgets(line, sizeof(line) - 1, f)) { 17221726c417Sdyoung lineno++; 17231726c417Sdyoung if ((cp = strpbrk(line, "#\r\n")) != NULL) 17241726c417Sdyoung *cp = '\0'; 17251726c417Sdyoung cp = skip(line); 17261726c417Sdyoung if (cp == NULL) /* blank line or comment line */ 17271726c417Sdyoung continue; 17281726c417Sdyoung tp = strchr(cp, ':'); /* everything has a colon in it */ 17291726c417Sdyoung if (tp == NULL) { 17301726c417Sdyoung warnx("line %d: syntax error", lineno); 17311726c417Sdyoung errors++; 17321726c417Sdyoung continue; 17331726c417Sdyoung } 17341726c417Sdyoung *tp++ = '\0', tp = skip(tp); 17351726c417Sdyoung if (!strcmp(cp, "type")) { 17361726c417Sdyoung if (tp == NULL) { 17371726c417Sdyoung strlcpy(tbuf, "unknown", sizeof(tbuf)); 17381726c417Sdyoung tp = tbuf; 17391726c417Sdyoung } 17401726c417Sdyoung cpp = dktypenames; 17411726c417Sdyoung for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) 17421726c417Sdyoung if ((s = *cpp) && !strcasecmp(s, tp)) { 17431726c417Sdyoung lp->d_type = cpp - dktypenames; 17441726c417Sdyoung goto next; 17451726c417Sdyoung } 17461726c417Sdyoung if (GETNUM16(tp, &v) != 0) { 17471726c417Sdyoung warnx("line %d: syntax error", lineno); 17481726c417Sdyoung errors++; 17491726c417Sdyoung continue; 17501726c417Sdyoung } 17511726c417Sdyoung if (v >= DKMAXTYPES) 17521726c417Sdyoung warnx("line %d: warning, unknown disk type: %s", 17531726c417Sdyoung lineno, tp); 17541726c417Sdyoung lp->d_type = v; 17551726c417Sdyoung continue; 17561726c417Sdyoung } 17571726c417Sdyoung if (!strcmp(cp, "flags")) { 17581726c417Sdyoung for (v = 0; (cp = tp) && *cp != '\0';) { 17591726c417Sdyoung tp = word(cp); 17601726c417Sdyoung if (!strcasecmp(cp, "removable")) 17611726c417Sdyoung v |= D_REMOVABLE; 17621726c417Sdyoung else if (!strcasecmp(cp, "ecc")) 17631726c417Sdyoung v |= D_ECC; 17641726c417Sdyoung else if (!strcasecmp(cp, "badsect")) 17651726c417Sdyoung v |= D_BADSECT; 17661726c417Sdyoung else { 17671726c417Sdyoung warnx("line %d: bad flag: %s", 17681726c417Sdyoung lineno, cp); 17691726c417Sdyoung errors++; 17701726c417Sdyoung } 17711726c417Sdyoung } 17721726c417Sdyoung lp->d_flags = v; 17731726c417Sdyoung continue; 17741726c417Sdyoung } 17751726c417Sdyoung if (!strcmp(cp, "drivedata")) { 17761726c417Sdyoung int i; 17771726c417Sdyoung 17781726c417Sdyoung for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) { 17791726c417Sdyoung if (GETNUM32(cp, &v) != 0) { 17801726c417Sdyoung warnx("line %d: bad drive data", 17811726c417Sdyoung lineno); 17821726c417Sdyoung errors++; 17831726c417Sdyoung } else 17841726c417Sdyoung lp->d_drivedata[i] = v; 17851726c417Sdyoung i++; 17861726c417Sdyoung tp = word(cp); 17871726c417Sdyoung } 17881726c417Sdyoung continue; 17891726c417Sdyoung } 17901726c417Sdyoung if (sscanf(cp, "%lu partitions", &v) == 1) { 1791af8f0546Smatt if (v == 0 || v > maxpartitions) { 17921726c417Sdyoung warnx("line %d: bad # of partitions", lineno); 1793af8f0546Smatt lp->d_npartitions = maxpartitions; 17941726c417Sdyoung errors++; 17951726c417Sdyoung } else 17961726c417Sdyoung lp->d_npartitions = v; 17971726c417Sdyoung continue; 17981726c417Sdyoung } 17991726c417Sdyoung if (tp == NULL) { 18001726c417Sdyoung tbuf[0] = '\0'; 18011726c417Sdyoung tp = tbuf; 18021726c417Sdyoung } 18031726c417Sdyoung if (!strcmp(cp, "disk")) { 18041726c417Sdyoung strncpy(lp->d_typename, tp, sizeof(lp->d_typename)); 18051726c417Sdyoung continue; 18061726c417Sdyoung } 18071726c417Sdyoung if (!strcmp(cp, "label")) { 18081726c417Sdyoung strncpy(lp->d_packname, tp, sizeof(lp->d_packname)); 18091726c417Sdyoung continue; 18101726c417Sdyoung } 18111726c417Sdyoung if (!strcmp(cp, "bytes/sector")) { 18121726c417Sdyoung if (GETNUM32(tp, &v) != 0 || v <= 0 || (v % 512) != 0) { 18131726c417Sdyoung warnx("line %d: bad %s: %s", lineno, cp, tp); 18141726c417Sdyoung errors++; 18151726c417Sdyoung } else 18161726c417Sdyoung lp->d_secsize = v; 18171726c417Sdyoung continue; 18181726c417Sdyoung } 18191726c417Sdyoung if (!strcmp(cp, "sectors/track")) { 18201726c417Sdyoung if (GETNUM32(tp, &v) != 0) { 18211726c417Sdyoung warnx("line %d: bad %s: %s", lineno, cp, tp); 18221726c417Sdyoung errors++; 18231726c417Sdyoung } else 18241726c417Sdyoung lp->d_nsectors = v; 18251726c417Sdyoung continue; 18261726c417Sdyoung } 18271726c417Sdyoung if (!strcmp(cp, "sectors/cylinder")) { 18281726c417Sdyoung if (GETNUM32(tp, &v) != 0) { 18291726c417Sdyoung warnx("line %d: bad %s: %s", lineno, cp, tp); 18301726c417Sdyoung errors++; 18311726c417Sdyoung } else 18321726c417Sdyoung lp->d_secpercyl = v; 18331726c417Sdyoung continue; 18341726c417Sdyoung } 18351726c417Sdyoung if (!strcmp(cp, "tracks/cylinder")) { 18361726c417Sdyoung if (GETNUM32(tp, &v) != 0) { 18371726c417Sdyoung warnx("line %d: bad %s: %s", lineno, cp, tp); 18381726c417Sdyoung errors++; 18391726c417Sdyoung } else 18401726c417Sdyoung lp->d_ntracks = v; 18411726c417Sdyoung continue; 18421726c417Sdyoung } 18431726c417Sdyoung if (!strcmp(cp, "cylinders")) { 18441726c417Sdyoung if (GETNUM32(tp, &v) != 0) { 18451726c417Sdyoung warnx("line %d: bad %s: %s", lineno, cp, tp); 18461726c417Sdyoung errors++; 18471726c417Sdyoung } else 18481726c417Sdyoung lp->d_ncylinders = v; 18491726c417Sdyoung continue; 18501726c417Sdyoung } 185165c3a166Schristos if (!strcmp(cp, "total sectors") || 185265c3a166Schristos !strcmp(cp, "sectors/unit")) { 18531726c417Sdyoung if (GETNUM32(tp, &v) != 0) { 18541726c417Sdyoung warnx("line %d: bad %s: %s", lineno, cp, tp); 18551726c417Sdyoung errors++; 18561726c417Sdyoung } else 18571726c417Sdyoung lp->d_secperunit = v; 18581726c417Sdyoung continue; 18591726c417Sdyoung } 18601726c417Sdyoung if (!strcmp(cp, "rpm")) { 18611726c417Sdyoung if (GETNUM16(tp, &v) != 0) { 18621726c417Sdyoung warnx("line %d: bad %s: %s", lineno, cp, tp); 18631726c417Sdyoung errors++; 18641726c417Sdyoung } else 18651726c417Sdyoung lp->d_rpm = v; 18661726c417Sdyoung continue; 18671726c417Sdyoung } 18681726c417Sdyoung if (!strcmp(cp, "interleave")) { 18691726c417Sdyoung if (GETNUM16(tp, &v) != 0) { 18701726c417Sdyoung warnx("line %d: bad %s: %s", lineno, cp, tp); 18711726c417Sdyoung errors++; 18721726c417Sdyoung } else 18731726c417Sdyoung lp->d_interleave = v; 18741726c417Sdyoung continue; 18751726c417Sdyoung } 18761726c417Sdyoung if (!strcmp(cp, "trackskew")) { 18771726c417Sdyoung if (GETNUM16(tp, &v) != 0) { 18781726c417Sdyoung warnx("line %d: bad %s: %s", lineno, cp, tp); 18791726c417Sdyoung errors++; 18801726c417Sdyoung } else 18811726c417Sdyoung lp->d_trackskew = v; 18821726c417Sdyoung continue; 18831726c417Sdyoung } 18841726c417Sdyoung if (!strcmp(cp, "cylinderskew")) { 18851726c417Sdyoung if (GETNUM16(tp, &v) != 0) { 18861726c417Sdyoung warnx("line %d: bad %s: %s", lineno, cp, tp); 18871726c417Sdyoung errors++; 18881726c417Sdyoung } else 18891726c417Sdyoung lp->d_cylskew = v; 18901726c417Sdyoung continue; 18911726c417Sdyoung } 18921726c417Sdyoung if (!strcmp(cp, "headswitch")) { 18931726c417Sdyoung if (GETNUM32(tp, &v) != 0) { 18941726c417Sdyoung warnx("line %d: bad %s: %s", lineno, cp, tp); 18951726c417Sdyoung errors++; 18961726c417Sdyoung } else 18971726c417Sdyoung lp->d_headswitch = v; 18981726c417Sdyoung continue; 18991726c417Sdyoung } 19001726c417Sdyoung if (!strcmp(cp, "track-to-track seek")) { 19011726c417Sdyoung if (GETNUM32(tp, &v) != 0) { 19021726c417Sdyoung warnx("line %d: bad %s: %s", lineno, cp, tp); 19031726c417Sdyoung errors++; 19041726c417Sdyoung } else 19051726c417Sdyoung lp->d_trkseek = v; 19061726c417Sdyoung continue; 19071726c417Sdyoung } 19081726c417Sdyoung if ('a' > *cp || *cp > 'z' || cp[1] != '\0') { 19091726c417Sdyoung warnx("line %d: unknown field: %s", lineno, cp); 19101726c417Sdyoung errors++; 19111726c417Sdyoung continue; 19121726c417Sdyoung } 19131726c417Sdyoung 19141726c417Sdyoung /* We have a partition entry */ 19151726c417Sdyoung part = *cp - 'a'; 19161726c417Sdyoung 1917af8f0546Smatt if (part >= maxpartitions) { 19181726c417Sdyoung warnx("line %d: bad partition name: %s", lineno, cp); 19191726c417Sdyoung errors++; 19201726c417Sdyoung continue; 19211726c417Sdyoung } 19227d501621Schristos if (part >= __arraycount(lp->d_partitions)) { 19237d501621Schristos warnx("line %d: partition id %s, >= %zu", lineno, 19247d501621Schristos cp, __arraycount(lp->d_partitions)); 19257d501621Schristos errors++; 19267d501621Schristos continue; 19277d501621Schristos } 19281726c417Sdyoung pp = &lp->d_partitions[part]; 19291726c417Sdyoung 19301726c417Sdyoung NXTXNUM(pp->p_size); 19311726c417Sdyoung NXTXNUM(pp->p_offset); 19321726c417Sdyoung /* can't use word() here because of blanks in fstypenames[] */ 19331726c417Sdyoung tp += strspn(tp, " \t"); 19341726c417Sdyoung _CHECKLINE 19351726c417Sdyoung cp = tp; 19361726c417Sdyoung cpp = fstypenames; 19371726c417Sdyoung for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) { 19381726c417Sdyoung s = *cpp; 19391726c417Sdyoung if (s == NULL || 19401726c417Sdyoung (cp[strlen(s)] != ' ' && 19411726c417Sdyoung cp[strlen(s)] != '\t' && 19421726c417Sdyoung cp[strlen(s)] != '\0')) 19431726c417Sdyoung continue; 19441726c417Sdyoung if (!memcmp(s, cp, strlen(s))) { 19451726c417Sdyoung pp->p_fstype = cpp - fstypenames; 19461726c417Sdyoung tp += strlen(s); 19471726c417Sdyoung if (*tp == '\0') 19481726c417Sdyoung tp = NULL; 19491726c417Sdyoung else { 19501726c417Sdyoung tp += strspn(tp, " \t"); 19511726c417Sdyoung if (*tp == '\0') 19521726c417Sdyoung tp = NULL; 19531726c417Sdyoung } 19541726c417Sdyoung goto gottype; 19551726c417Sdyoung } 19561726c417Sdyoung } 19571726c417Sdyoung tp = word(cp); 19581726c417Sdyoung if (isdigit(*cp & 0xff)) { 19591726c417Sdyoung if (GETNUM8(cp, &v) != 0) { 19601726c417Sdyoung warnx("line %d: syntax error", lineno); 19611726c417Sdyoung errors++; 19621726c417Sdyoung } 19631726c417Sdyoung } else 19641726c417Sdyoung v = FSMAXTYPES; 19651726c417Sdyoung if ((unsigned)v >= FSMAXTYPES) { 19661726c417Sdyoung warnx("line %d: warning, unknown file system type: %s", 19671726c417Sdyoung lineno, cp); 196891af0d68Sjmmv warnx("tip: use -l to see all valid file system " 196991af0d68Sjmmv "types"); 19701726c417Sdyoung v = FS_UNUSED; 19711726c417Sdyoung } 19721726c417Sdyoung pp->p_fstype = v; 19731726c417Sdyoung gottype: 19741726c417Sdyoung switch (pp->p_fstype) { 19751726c417Sdyoung 19761726c417Sdyoung case FS_UNUSED: /* XXX */ 19771726c417Sdyoung NXTNUM(pp->p_fsize); 19781726c417Sdyoung if (pp->p_fsize == 0) 19791726c417Sdyoung break; 19801726c417Sdyoung NXTNUM(v); 19811726c417Sdyoung pp->p_frag = v / pp->p_fsize; 19821726c417Sdyoung break; 19831726c417Sdyoung 19841726c417Sdyoung case FS_BSDFFS: 19851726c417Sdyoung case FS_ADOS: 19861726c417Sdyoung case FS_APPLEUFS: 19871726c417Sdyoung NXTNUM(pp->p_fsize); 19881726c417Sdyoung if (pp->p_fsize == 0) 19891726c417Sdyoung break; 19901726c417Sdyoung NXTNUM(v); 19911726c417Sdyoung pp->p_frag = v / pp->p_fsize; 19921726c417Sdyoung NXTNUM(pp->p_cpg); 19931726c417Sdyoung break; 19941726c417Sdyoung case FS_BSDLFS: 19951726c417Sdyoung NXTNUM(pp->p_fsize); 19961726c417Sdyoung if (pp->p_fsize == 0) 19971726c417Sdyoung break; 19981726c417Sdyoung NXTNUM(v); 19991726c417Sdyoung pp->p_frag = v / pp->p_fsize; 20001726c417Sdyoung NXTNUM(pp->p_sgs); 20011726c417Sdyoung break; 20021726c417Sdyoung case FS_EX2FS: 20031726c417Sdyoung NXTNUM(pp->p_fsize); 20041726c417Sdyoung if (pp->p_fsize == 0) 20051726c417Sdyoung break; 20061726c417Sdyoung NXTNUM(v); 20071726c417Sdyoung pp->p_frag = v / pp->p_fsize; 20081726c417Sdyoung break; 20091726c417Sdyoung case FS_ISO9660: 20101726c417Sdyoung NXTNUM(pp->p_cdsession); 20111726c417Sdyoung break; 20121726c417Sdyoung default: 20131726c417Sdyoung break; 20141726c417Sdyoung } 20151726c417Sdyoung continue; 20161726c417Sdyoung error: 20171726c417Sdyoung errors++; 20181726c417Sdyoung next: 20191726c417Sdyoung ; 20201726c417Sdyoung } 20211726c417Sdyoung errors += checklabel(lp); 20221726c417Sdyoung return (errors == 0); 20231726c417Sdyoung } 20241726c417Sdyoung 20251726c417Sdyoung /* 20261726c417Sdyoung * Check disklabel for errors and fill in 20271726c417Sdyoung * derived fields according to supplied values. 20281726c417Sdyoung */ 20291726c417Sdyoung int 20301726c417Sdyoung checklabel(struct disklabel *lp) 20311726c417Sdyoung { 20321726c417Sdyoung struct partition *pp, *qp; 20331726c417Sdyoung int i, j, errors; 20341726c417Sdyoung char part; 20351726c417Sdyoung 20361726c417Sdyoung errors = 0; 20371726c417Sdyoung if (lp->d_secsize == 0) { 2038621e83eaSchristos warnx("sector size %" PRIu32, lp->d_secsize); 20391726c417Sdyoung return (1); 20401726c417Sdyoung } 20411726c417Sdyoung if (lp->d_nsectors == 0) { 2042621e83eaSchristos warnx("sectors/track %" PRIu32, lp->d_nsectors); 20431726c417Sdyoung return (1); 20441726c417Sdyoung } 20451726c417Sdyoung if (lp->d_ntracks == 0) { 2046621e83eaSchristos warnx("tracks/cylinder %" PRIu32, lp->d_ntracks); 20471726c417Sdyoung return (1); 20481726c417Sdyoung } 20491726c417Sdyoung if (lp->d_ncylinders == 0) { 2050621e83eaSchristos warnx("cylinders/unit %" PRIu32, lp->d_ncylinders); 20511726c417Sdyoung errors++; 20521726c417Sdyoung } 20531726c417Sdyoung if (lp->d_rpm == 0) 2054621e83eaSchristos warnx("warning, revolutions/minute %" PRIu16, lp->d_rpm); 20551726c417Sdyoung if (lp->d_secpercyl == 0) 20561726c417Sdyoung lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 20571726c417Sdyoung if (lp->d_secperunit == 0) 20581726c417Sdyoung lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 20591726c417Sdyoung if (lp->d_bbsize == 0) { 2060621e83eaSchristos warnx("boot block size %" PRIu32, lp->d_bbsize); 20611726c417Sdyoung errors++; 20621726c417Sdyoung } else if (lp->d_bbsize % lp->d_secsize) 20631726c417Sdyoung warnx("warning, boot block size %% sector-size != 0"); 20641726c417Sdyoung if (lp->d_sbsize == 0) { 2065621e83eaSchristos warnx("super block size %" PRIu32, lp->d_sbsize); 20661726c417Sdyoung errors++; 20671726c417Sdyoung } else if (lp->d_sbsize % lp->d_secsize) 20681726c417Sdyoung warnx("warning, super block size %% sector-size != 0"); 2069af8f0546Smatt if (lp->d_npartitions > maxpartitions) 207063df928bSapb warnx("warning, number of partitions (%" PRIu16 ") > " 207163df928bSapb "MAXPARTITIONS (%d)", 2072af8f0546Smatt lp->d_npartitions, maxpartitions); 20731726c417Sdyoung else 2074af8f0546Smatt for (i = maxpartitions - 1; i >= lp->d_npartitions; i--) { 20751726c417Sdyoung part = 'a' + i; 20761726c417Sdyoung pp = &lp->d_partitions[i]; 20771726c417Sdyoung if (pp->p_size || pp->p_offset) { 20781726c417Sdyoung warnx("warning, partition %c increased " 207963df928bSapb "number of partitions from %" PRIu16 208063df928bSapb " to %d", 20811726c417Sdyoung part, lp->d_npartitions, i + 1); 20821726c417Sdyoung lp->d_npartitions = i + 1; 20831726c417Sdyoung break; 20841726c417Sdyoung } 20851726c417Sdyoung } 20861726c417Sdyoung for (i = 0; i < lp->d_npartitions; i++) { 20871726c417Sdyoung part = 'a' + i; 20881726c417Sdyoung pp = &lp->d_partitions[i]; 20891726c417Sdyoung if (pp->p_size == 0 && pp->p_offset != 0) 209063df928bSapb warnx("warning, partition %c: size 0, but " 209163df928bSapb "offset %" PRIu32, 20921726c417Sdyoung part, pp->p_offset); 20931726c417Sdyoung #ifdef STRICT_CYLINDER_ALIGNMENT 20941726c417Sdyoung if (pp->p_offset % lp->d_secpercyl) { 20951726c417Sdyoung warnx("warning, partition %c:" 20961726c417Sdyoung " not starting on cylinder boundary", 20971726c417Sdyoung part); 20981726c417Sdyoung errors++; 20991726c417Sdyoung } 21001726c417Sdyoung #endif /* STRICT_CYLINDER_ALIGNMENT */ 21011726c417Sdyoung if (pp->p_offset > lp->d_secperunit) { 21021726c417Sdyoung warnx("partition %c: offset past end of unit", part); 21031726c417Sdyoung errors++; 21041726c417Sdyoung } 21051726c417Sdyoung if (pp->p_offset + pp->p_size > lp->d_secperunit) { 21061726c417Sdyoung warnx("partition %c: partition extends" 21071726c417Sdyoung " past end of unit", 21081726c417Sdyoung part); 21091726c417Sdyoung errors++; 21101726c417Sdyoung } 21111726c417Sdyoung if (pp->p_fstype != FS_UNUSED) 21121726c417Sdyoung for (j = i + 1; j < lp->d_npartitions; j++) { 21131726c417Sdyoung qp = &lp->d_partitions[j]; 21141726c417Sdyoung if (qp->p_fstype == FS_UNUSED) 21151726c417Sdyoung continue; 21161726c417Sdyoung if (pp->p_offset < qp->p_offset + qp->p_size && 21171726c417Sdyoung qp->p_offset < pp->p_offset + pp->p_size) 21181726c417Sdyoung warnx("partitions %c and %c overlap", 21191726c417Sdyoung part, 'a' + j); 21201726c417Sdyoung } 21211726c417Sdyoung } 21221726c417Sdyoung return (errors); 21231726c417Sdyoung } 21241726c417Sdyoung 21251726c417Sdyoung static void 21261726c417Sdyoung usage(void) 21271726c417Sdyoung { 21281726c417Sdyoung static const struct { 21291726c417Sdyoung const char *name; 21301726c417Sdyoung const char *expn; 21311726c417Sdyoung } usages[] = { 2132af8f0546Smatt { "[-ABCFMrtv] disk", "(to read label)" }, 2133af8f0546Smatt { "-w [-BDFMrv] [-f disktab] disk disktype [packid]", "(to write label)" }, 2134af8f0546Smatt { "-e [-BCDFMIrv] disk", "(to edit label)" }, 21350636a2feSchristos #if !defined(NO_INTERACT) 2136af8f0546Smatt { "-i [-BDFMIrv] disk", "(to create a label interactively)" }, 21370636a2feSchristos #endif 213865151c95Sdsl { "-D [-v] disk", "(to delete existing label(s))" }, 2139af8f0546Smatt { "-R [-BDFMrv] disk protofile", "(to restore label)" }, 2140506fe182Sdsl { "[-NW] disk", "(to write disable/enable label)" }, 214191af0d68Sjmmv { "-l", "(to show all known file system types)" }, 2142506fe182Sdsl { NULL, NULL } 21431726c417Sdyoung }; 21441726c417Sdyoung int i; 2145506fe182Sdsl const char *pn = getprogname(); 2146506fe182Sdsl const char *t = "usage:"; 21471726c417Sdyoung 2148506fe182Sdsl for (i = 0; usages[i].name != NULL; i++) { 2149506fe182Sdsl (void)fprintf(stderr, "%s %s %s\n\t%s\n", 2150506fe182Sdsl t, pn, usages[i].name, usages[i].expn); 2151506fe182Sdsl t = "or"; 21521726c417Sdyoung } 21531726c417Sdyoung exit(1); 21541726c417Sdyoung } 21551726c417Sdyoung 21561726c417Sdyoung static int 21571726c417Sdyoung getulong(const char *str, char sep, char **epp, unsigned long *ul, 21581726c417Sdyoung unsigned long max) 21591726c417Sdyoung { 21601726c417Sdyoung char *ep; 21611726c417Sdyoung 21621726c417Sdyoung if (epp == NULL) 21631726c417Sdyoung epp = &ep; 21641726c417Sdyoung 21651726c417Sdyoung *ul = strtoul(str, epp, 10); 21661726c417Sdyoung 21671726c417Sdyoung if ((*ul == ULONG_MAX && errno == ERANGE) || *ul > max) 21681726c417Sdyoung return ERANGE; 21691726c417Sdyoung 21701726c417Sdyoung if (*str == '\0' || (**epp != '\0' && **epp != sep && 21711726c417Sdyoung !isspace((unsigned char)**epp))) 21721726c417Sdyoung return EFTYPE; 21731726c417Sdyoung 21741726c417Sdyoung return 0; 21751726c417Sdyoung } 217691af0d68Sjmmv 217791af0d68Sjmmv /* 217891af0d68Sjmmv * This is a wrapper over the standard strcmp function to be used with 217991af0d68Sjmmv * qsort on an array of pointers to strings. 218091af0d68Sjmmv */ 218191af0d68Sjmmv static int 218291af0d68Sjmmv qsort_strcmp(const void *v1, const void *v2) 218391af0d68Sjmmv { 218491af0d68Sjmmv const char *const *sp1 = (const char *const *)v1; 218591af0d68Sjmmv const char *const *sp2 = (const char *const *)v2; 218691af0d68Sjmmv 218791af0d68Sjmmv return strcmp(*sp1, *sp2); 218891af0d68Sjmmv } 218991af0d68Sjmmv 219091af0d68Sjmmv /* 219191af0d68Sjmmv * Prints all know file system types for a partition. 219291af0d68Sjmmv * Returns 1 on success, 0 on failure. 219391af0d68Sjmmv */ 219491af0d68Sjmmv int 219591af0d68Sjmmv list_fs_types(void) 219691af0d68Sjmmv { 219791af0d68Sjmmv int ret; 219891af0d68Sjmmv size_t nelems; 219991af0d68Sjmmv 220091af0d68Sjmmv nelems = 0; 220191af0d68Sjmmv { 220291af0d68Sjmmv const char *const *namep; 220391af0d68Sjmmv 220491af0d68Sjmmv namep = fstypenames; 220591af0d68Sjmmv while (*namep++ != NULL) 220691af0d68Sjmmv nelems++; 220791af0d68Sjmmv } 220891af0d68Sjmmv 220991af0d68Sjmmv ret = 1; 221091af0d68Sjmmv if (nelems > 0) { 2211ccf8c4a2Snia const char **list = NULL; 221291af0d68Sjmmv size_t i; 221391af0d68Sjmmv 2214ccf8c4a2Snia if (reallocarr(&list, nelems, sizeof(char *)) != 0) { 221591af0d68Sjmmv warnx("sorry, could not allocate memory for list"); 221691af0d68Sjmmv ret = 0; 221791af0d68Sjmmv } else { 221891af0d68Sjmmv for (i = 0; i < nelems; i++) 221991af0d68Sjmmv list[i] = fstypenames[i]; 222091af0d68Sjmmv 222191af0d68Sjmmv qsort(list, nelems, sizeof(char *), qsort_strcmp); 222291af0d68Sjmmv 222391af0d68Sjmmv for (i = 0; i < nelems; i++) 222491af0d68Sjmmv (void)printf("%s\n", list[i]); 222591af0d68Sjmmv 222691af0d68Sjmmv free(list); 222791af0d68Sjmmv } 222891af0d68Sjmmv } 222991af0d68Sjmmv 223091af0d68Sjmmv return ret; 223191af0d68Sjmmv } 2232af8f0546Smatt 2233af8f0546Smatt #ifndef HAVE_NBTOOL_CONFIG_H 2234af8f0546Smatt int 2235af8f0546Smatt dk_ioctl(int f, u_long cmd, void *arg) 2236af8f0546Smatt { 22370636a2feSchristos #if !defined(NATIVELABEL_ONLY) 2238af8f0546Smatt if (!native_p) { 2239af8f0546Smatt errno = ENOTTY; 2240af8f0546Smatt return -1; 2241af8f0546Smatt } 22420636a2feSchristos #endif 2243af8f0546Smatt return ioctl(f, cmd, arg); 2244af8f0546Smatt } 2245af8f0546Smatt #endif 2246