bsdlabel.c revision 111286
11558Srgrimes/* 292058Sobrien * Copyright (c) 1994, 1995 Gordon W. Ross 392058Sobrien * Copyright (c) 1994 Theo de Raadt 492058Sobrien * All rights reserved. 51558Srgrimes * Copyright (c) 1987, 1993 61558Srgrimes * The Regents of the University of California. All rights reserved. 71558Srgrimes * 81558Srgrimes * This code is derived from software contributed to Berkeley by 91558Srgrimes * Symmetric Computer Systems. 101558Srgrimes * 111558Srgrimes * Redistribution and use in source and binary forms, with or without 121558Srgrimes * modification, are permitted provided that the following conditions 131558Srgrimes * are met: 141558Srgrimes * 1. Redistributions of source code must retain the above copyright 151558Srgrimes * notice, this list of conditions and the following disclaimer. 161558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171558Srgrimes * notice, this list of conditions and the following disclaimer in the 181558Srgrimes * documentation and/or other materials provided with the distribution. 191558Srgrimes * 3. All advertising materials mentioning features or use of this software 201558Srgrimes * must display the following acknowledgement: 211558Srgrimes * This product includes software developed by the University of 221558Srgrimes * California, Berkeley and its contributors. 2392058Sobrien * This product includes software developed by Theo de Raadt. 241558Srgrimes * 4. Neither the name of the University nor the names of its contributors 251558Srgrimes * may be used to endorse or promote products derived from this software 261558Srgrimes * without specific prior written permission. 271558Srgrimes * 281558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 291558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 301558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 311558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 321558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 331558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 341558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 351558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 361558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 371558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 381558Srgrimes * SUCH DAMAGE. 3992058Sobrien * 4092058Sobrien * from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $ 411558Srgrimes */ 421558Srgrimes 431558Srgrimes#ifndef lint 4436632Scharnierstatic const char copyright[] = 451558Srgrimes"@(#) Copyright (c) 1987, 1993\n\ 461558Srgrimes The Regents of the University of California. All rights reserved.\n"; 471558Srgrimes#endif /* not lint */ 481558Srgrimes 491558Srgrimes#ifndef lint 5036632Scharnier#if 0 511558Srgrimesstatic char sccsid[] = "@(#)disklabel.c 8.2 (Berkeley) 1/7/94"; 521558Srgrimes/* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */ 5336632Scharnier#endif 541558Srgrimes#endif /* not lint */ 551558Srgrimes 5699365Smarkm#include <sys/cdefs.h> 5799365Smarkm__FBSDID("$FreeBSD: head/sbin/bsdlabel/bsdlabel.c 111286 2003-02-23 01:48:42Z ru $"); 5899365Smarkm 591558Srgrimes#include <sys/param.h> 601558Srgrimes#include <sys/file.h> 611558Srgrimes#include <sys/stat.h> 6213544Sjoerg#include <sys/wait.h> 63103669Sphk#include <sys/disk.h> 641558Srgrimes#define DKTYPENAMES 65101994Sbmilekic#define FSTYPENAMES 661558Srgrimes#include <sys/disklabel.h> 67104674Snyan#ifdef PC98 68104674Snyan#include <sys/diskpc98.h> 69104674Snyan#else 70104272Sphk#include <sys/diskmbr.h> 71104674Snyan#endif 7299365Smarkm 731558Srgrimes#include <unistd.h> 741558Srgrimes#include <string.h> 751558Srgrimes#include <stdio.h> 7613544Sjoerg#include <stdlib.h> 7713544Sjoerg#include <signal.h> 7813544Sjoerg#include <stdarg.h> 791558Srgrimes#include <ctype.h> 8026542Scharnier#include <err.h> 8159216Simp#include <errno.h> 8299365Smarkm 831558Srgrimes#include "pathnames.h" 841558Srgrimes 851558Srgrimes/* 861558Srgrimes * Disklabel: read and write disklabels. 871558Srgrimes * The label is usually placed on one of the first sectors of the disk. 881558Srgrimes * Many machines also place a bootstrap in the same area, 891558Srgrimes * in which case the label is embedded in the bootstrap. 901558Srgrimes * The bootstrap source must leave space at the proper offset 911558Srgrimes * for the label on such machines. 921558Srgrimes */ 931558Srgrimes 941558Srgrimes#ifndef BBSIZE 951558Srgrimes#define BBSIZE 8192 /* size of boot area, with label */ 961558Srgrimes#endif 971558Srgrimes 9873034Sjwd/* FIX! These are too low, but are traditional */ 9973034Sjwd#define DEFAULT_NEWFS_BLOCK 8192U 10073034Sjwd#define DEFAULT_NEWFS_FRAG 1024U 10173034Sjwd#define DEFAULT_NEWFS_CPG 16U 10273034Sjwd 10373034Sjwd#define BIG_NEWFS_BLOCK 16384U 10497535Siedowse#define BIG_NEWFS_FRAG 2048U 10573034Sjwd#define BIG_NEWFS_CPG 64U 10673034Sjwd 107109882Sphk#if defined(__i386__) 108109882Sphk#elif defined(__alpha__) 109109891Sphk#elif defined(__ia64__) 1101558Srgrimes#else 111109884Sphk#error I do not know about this architecture, and shall probably not be compiled for it. 1121558Srgrimes#endif 1131558Srgrimes 11492541Simpvoid makelabel(const char *, const char *, struct disklabel *); 11592541Simpint writelabel(int, const char *, struct disklabel *); 11692541Simpvoid l_perror(const char *); 11792541Simpstruct disklabel *readlabel(int); 11892541Simpstruct disklabel *makebootarea(char *, struct disklabel *, int); 11992541Simpvoid display(FILE *, const struct disklabel *); 12092541Simpint edit(struct disklabel *, int); 12192541Simpint editit(void); 12292541Simpchar *skip(char *); 12392541Simpchar *word(char *); 12492541Simpint getasciilabel(FILE *, struct disklabel *); 12597534Siedowseint getasciipartspec(char *, struct disklabel *, int, int); 12692541Simpint checklabel(struct disklabel *); 12792541Simpvoid Warning(const char *, ...) __printflike(1, 2); 12892541Simpvoid usage(void); 12992541Simpstruct disklabel *getvirginlabel(void); 13013544Sjoerg 1311558Srgrimes#define DEFEDITOR _PATH_VI 1321558Srgrimes#define streq(a,b) (strcmp(a,b) == 0) 1331558Srgrimes 1341558Srgrimeschar *dkname; 1351558Srgrimeschar *specname; 13655742Skrischar tmpfil[] = PATH_TMPFILE; 1371558Srgrimes 1381558Srgrimeschar namebuf[BBSIZE], *np = namebuf; 1391558Srgrimesstruct disklabel lab; 1401558Srgrimeschar bootarea[BBSIZE]; 14199365Smarkmchar blank[] = ""; 14299365Smarkmchar unknown[] = "unknown"; 1431558Srgrimes 14473034Sjwd#define MAX_PART ('z') 14573034Sjwd#define MAX_NUM_PARTS (1 + MAX_PART - 'a') 14673034Sjwdchar part_size_type[MAX_NUM_PARTS]; 14773034Sjwdchar part_offset_type[MAX_NUM_PARTS]; 14873034Sjwdint part_set[MAX_NUM_PARTS]; 14973034Sjwd 1501558Srgrimesint installboot; /* non-zero if we should install a boot program */ 1511558Srgrimeschar *xxboot; /* primary boot */ 1521558Srgrimeschar boot0[MAXPATHLEN]; 1531558Srgrimes 1541558Srgrimesenum { 155109872Sphk UNSPEC, EDIT, READ, RESTORE, WRITE, WRITEBOOT 1561558Srgrimes} op = UNSPEC; 1571558Srgrimes 1581558Srgrimesint rflag; 15973034Sjwdint disable_write; /* set to disable writing to disk label */ 1601558Srgrimes 161109872Sphk#define OPTIONS "BRb:enrs:w" 1621558Srgrimes 16313544Sjoergint 16492541Simpmain(int argc, char *argv[]) 1651558Srgrimes{ 16692715Simp struct disklabel *lp; 1671558Srgrimes FILE *t; 168109872Sphk int ch, f = 0, error = 0; 1691558Srgrimes char *name = 0; 1701558Srgrimes 17124359Simp while ((ch = getopt(argc, argv, OPTIONS)) != -1) 1721558Srgrimes switch (ch) { 1731558Srgrimes case 'B': 1741558Srgrimes ++installboot; 1751558Srgrimes break; 1761558Srgrimes case 'b': 1771558Srgrimes xxboot = optarg; 1781558Srgrimes break; 17973034Sjwd case 'n': 18073034Sjwd disable_write = 1; 18173034Sjwd break; 1821558Srgrimes case 'R': 1831558Srgrimes if (op != UNSPEC) 1841558Srgrimes usage(); 1851558Srgrimes op = RESTORE; 1861558Srgrimes break; 1871558Srgrimes case 'e': 1881558Srgrimes if (op != UNSPEC) 1891558Srgrimes usage(); 1901558Srgrimes op = EDIT; 1911558Srgrimes break; 1921558Srgrimes case 'r': 1931558Srgrimes ++rflag; 1941558Srgrimes break; 1951558Srgrimes case 'w': 1961558Srgrimes if (op != UNSPEC) 1971558Srgrimes usage(); 1981558Srgrimes op = WRITE; 1991558Srgrimes break; 2001558Srgrimes case '?': 2011558Srgrimes default: 2021558Srgrimes usage(); 2031558Srgrimes } 2041558Srgrimes argc -= optind; 2051558Srgrimes argv += optind; 2061558Srgrimes if (installboot) { 2071558Srgrimes rflag++; 2081558Srgrimes if (op == UNSPEC) 2091558Srgrimes op = WRITEBOOT; 2101558Srgrimes } else { 2111558Srgrimes if (op == UNSPEC) 2121558Srgrimes op = READ; 213109889Sphk xxboot = 0; 2141558Srgrimes } 2151558Srgrimes if (argc < 1) 2161558Srgrimes usage(); 2171558Srgrimes 2181558Srgrimes dkname = argv[0]; 2191558Srgrimes if (dkname[0] != '/') { 22059114Sobrien (void)sprintf(np, "%s%s%c", _PATH_DEV, dkname, 'a' + RAW_PART); 2211558Srgrimes specname = np; 2221558Srgrimes np += strlen(specname) + 1; 2231558Srgrimes } else 2241558Srgrimes specname = dkname; 2251558Srgrimes f = open(specname, op == READ ? O_RDONLY : O_RDWR); 2261558Srgrimes if (f < 0 && errno == ENOENT && dkname[0] != '/') { 22759429Sobrien (void)sprintf(specname, "%s%s", _PATH_DEV, dkname); 2281558Srgrimes np = namebuf + strlen(specname) + 1; 2291558Srgrimes f = open(specname, op == READ ? O_RDONLY : O_RDWR); 2301558Srgrimes } 231109901Sphk if (f < 0 && errno == EBUSY) { 232109901Sphk /* lets try to get by with ioctls */ 233109901Sphk f = open(specname, O_RDONLY); 234109901Sphk } 2351558Srgrimes if (f < 0) 23626542Scharnier err(4, "%s", specname); 2371558Srgrimes 2381558Srgrimes switch(op) { 2391558Srgrimes 24048957Sbillf case UNSPEC: 24148957Sbillf break; 24248957Sbillf 2431558Srgrimes case EDIT: 2441558Srgrimes if (argc != 1) 2451558Srgrimes usage(); 2461558Srgrimes lp = readlabel(f); 2471558Srgrimes error = edit(lp, f); 2481558Srgrimes break; 2491558Srgrimes 2501558Srgrimes case READ: 2511558Srgrimes if (argc != 1) 2521558Srgrimes usage(); 2531558Srgrimes lp = readlabel(f); 2541558Srgrimes display(stdout, lp); 2551558Srgrimes error = checklabel(lp); 2561558Srgrimes break; 2571558Srgrimes 2581558Srgrimes case RESTORE: 2591558Srgrimes if (argc != 2) 2601558Srgrimes usage(); 2611558Srgrimes if (!(t = fopen(argv[1], "r"))) 26226542Scharnier err(4, "%s", argv[1]); 26337865Sbde if (!getasciilabel(t, &lab)) 26437865Sbde exit(1); 26537865Sbde lp = makebootarea(bootarea, &lab, f); 26637865Sbde *lp = lab; 26737865Sbde error = writelabel(f, bootarea, lp); 2681558Srgrimes break; 2691558Srgrimes 2701558Srgrimes case WRITE: 2711558Srgrimes if (argc == 3) { 2721558Srgrimes name = argv[2]; 2731558Srgrimes argc--; 2741558Srgrimes } 2751558Srgrimes if (argc != 2) 2761558Srgrimes usage(); 2771558Srgrimes makelabel(argv[1], name, &lab); 2781558Srgrimes lp = makebootarea(bootarea, &lab, f); 2791558Srgrimes *lp = lab; 2801558Srgrimes if (checklabel(lp) == 0) 2811558Srgrimes error = writelabel(f, bootarea, lp); 2821558Srgrimes break; 2831558Srgrimes 2841558Srgrimes case WRITEBOOT: 2851558Srgrimes { 2861558Srgrimes struct disklabel tlab; 2871558Srgrimes 2881558Srgrimes lp = readlabel(f); 2891558Srgrimes tlab = *lp; 2901558Srgrimes if (argc == 2) 2911558Srgrimes makelabel(argv[1], 0, &lab); 2921558Srgrimes lp = makebootarea(bootarea, &lab, f); 2931558Srgrimes *lp = tlab; 2941558Srgrimes if (checklabel(lp) == 0) 2951558Srgrimes error = writelabel(f, bootarea, lp); 2961558Srgrimes break; 2971558Srgrimes } 2981558Srgrimes } 2991558Srgrimes exit(error); 3001558Srgrimes} 3011558Srgrimes 3021558Srgrimes/* 303111286Sru * Construct a prototype disklabel from /etc/disktab. 3041558Srgrimes */ 30513544Sjoergvoid 30692541Simpmakelabel(const char *type, const char *name, struct disklabel *lp) 3071558Srgrimes{ 30892541Simp struct disklabel *dp; 30913550Sjoerg 31013550Sjoerg if (strcmp(type, "auto") == 0) 31113550Sjoerg dp = getvirginlabel(); 31213550Sjoerg else 31313544Sjoerg dp = getdiskbyname(type); 31436632Scharnier if (dp == NULL) 31536632Scharnier errx(1, "%s: unknown disk type", type); 3161558Srgrimes *lp = *dp; 3171558Srgrimes bzero(lp->d_packname, sizeof(lp->d_packname)); 3181558Srgrimes if (name) 3191558Srgrimes (void)strncpy(lp->d_packname, name, sizeof(lp->d_packname)); 3201558Srgrimes} 3211558Srgrimes 32213544Sjoergint 32392541Simpwritelabel(int f, const char *boot, struct disklabel *lp) 3241558Srgrimes{ 32538384Sdfr#ifdef __alpha__ 32638384Sdfr u_long *p, sum; 32738384Sdfr int i; 32838384Sdfr#endif 32938384Sdfr 33073034Sjwd if (disable_write) { 33173034Sjwd Warning("write to disk label supressed - label was as follows:"); 33273034Sjwd display(stdout, lp); 33373034Sjwd return (0); 334109878Sphk } 335109878Sphk 336109878Sphk lp->d_magic = DISKMAGIC; 337109878Sphk lp->d_magic2 = DISKMAGIC; 338109878Sphk lp->d_checksum = 0; 339109878Sphk lp->d_checksum = dkcksum(lp); 340109878Sphk if (!rflag) { 341109878Sphk if (ioctl(f, DIOCWDINFO, lp) < 0) { 342109878Sphk l_perror("ioctl DIOCWDINFO"); 343109878Sphk return (1); 344109878Sphk } 345109878Sphk return (0); 346109878Sphk } 347109878Sphk 348109878Sphk /* 349109878Sphk * First set the kernel disk label, 350109878Sphk * then write a label to the raw disk. 351109878Sphk * If the SDINFO ioctl fails because it is unimplemented, 352109878Sphk * keep going; otherwise, the kernel consistency checks 353109878Sphk * may prevent us from changing the current (in-core) 354109878Sphk * label. 355109878Sphk */ 356109878Sphk if (ioctl(f, DIOCSDINFO, lp) < 0 && 357109878Sphk errno != ENODEV && errno != ENOTTY) { 358109878Sphk l_perror("ioctl DIOCSDINFO"); 359109878Sphk return (1); 360109878Sphk } 361109878Sphk (void)lseek(f, (off_t)0, SEEK_SET); 362109878Sphk 36338411Sbde#ifdef __alpha__ 364109878Sphk /* 365109878Sphk * Generate the bootblock checksum for the SRM console. 366109878Sphk */ 367109878Sphk for (p = (u_long *)boot, i = 0, sum = 0; i < 63; i++) 368109878Sphk sum += p[i]; 369109878Sphk p[63] = sum; 37038384Sdfr#endif 371109901Sphk if (ioctl(f, DIOCBSDBB, &boot) == 0) 372109901Sphk return (0); 373109878Sphk if (write(f, boot, lp->d_bbsize) != (int)lp->d_bbsize) { 374109878Sphk warn("write"); 375109878Sphk return (1); 376109878Sphk } 3771558Srgrimes return (0); 3781558Srgrimes} 3791558Srgrimes 38013544Sjoergvoid 38192541Simpl_perror(const char *s) 3821558Srgrimes{ 38336632Scharnier switch (errno) { 3841558Srgrimes 3851558Srgrimes case ESRCH: 38636756Scharnier warnx("%s: no disk label on disk;", s); 38775915Simp fprintf(stderr, "add \"-r\" to install initial label\n"); 3881558Srgrimes break; 3891558Srgrimes 3901558Srgrimes case EINVAL: 39136756Scharnier warnx("%s: label magic number or checksum is wrong!", s); 39236756Scharnier fprintf(stderr, "(disklabel or kernel is out of date?)\n"); 3931558Srgrimes break; 3941558Srgrimes 3951558Srgrimes case EBUSY: 39636632Scharnier warnx("%s: open partition would move or shrink", s); 3971558Srgrimes break; 3981558Srgrimes 3991558Srgrimes case EXDEV: 40040475Sbde warnx("%s: '%c' partition must start at beginning of disk", 40140475Sbde s, 'a' + RAW_PART); 4021558Srgrimes break; 4031558Srgrimes 4041558Srgrimes default: 40536632Scharnier warn((char *)NULL); 4061558Srgrimes break; 4071558Srgrimes } 4081558Srgrimes} 4091558Srgrimes 4101558Srgrimes/* 4111558Srgrimes * Fetch disklabel for disk. 4121558Srgrimes * Use ioctl to get label unless -r flag is given. 4131558Srgrimes */ 4141558Srgrimesstruct disklabel * 41592541Simpreadlabel(int f) 4161558Srgrimes{ 41792541Simp struct disklabel *lp; 4181558Srgrimes 4191558Srgrimes if (rflag) { 4201558Srgrimes if (read(f, bootarea, BBSIZE) < BBSIZE) 42126542Scharnier err(4, "%s", specname); 4221558Srgrimes for (lp = (struct disklabel *)bootarea; 4231558Srgrimes lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp)); 4241558Srgrimes lp = (struct disklabel *)((char *)lp + 16)) 4251558Srgrimes if (lp->d_magic == DISKMAGIC && 4261558Srgrimes lp->d_magic2 == DISKMAGIC) 4271558Srgrimes break; 4281558Srgrimes if (lp > (struct disklabel *)(bootarea+BBSIZE-sizeof(*lp)) || 4291558Srgrimes lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC || 43036756Scharnier dkcksum(lp) != 0) 43136756Scharnier errx(1, 43236756Scharnier "bad pack magic number (label is damaged, or pack is unlabeled)"); 4331558Srgrimes } else { 4341558Srgrimes lp = &lab; 4351558Srgrimes if (ioctl(f, DIOCGDINFO, lp) < 0) 43626542Scharnier err(4, "ioctl DIOCGDINFO"); 4371558Srgrimes } 4381558Srgrimes return (lp); 4391558Srgrimes} 4401558Srgrimes 4411558Srgrimes/* 4421558Srgrimes * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot'' 4431558Srgrimes * Returns a pointer to the disklabel portion of the bootarea. 4441558Srgrimes */ 4451558Srgrimesstruct disklabel * 44692541Simpmakebootarea(char *boot, struct disklabel *dp, int f) 4471558Srgrimes{ 44838483Sbde struct disklabel *lp; 44992541Simp char *p; 4501558Srgrimes int b; 4511558Srgrimes char *dkbasename; 4521558Srgrimes struct stat sb; 45338411Sbde#ifdef __alpha__ 45438483Sbde u_long *bootinfo; 45538411Sbde int n; 45638411Sbde#endif 45713892Sjoerg#ifdef __i386__ 45813892Sjoerg char *tmpbuf; 459109889Sphk int i, found, dps; 46013544Sjoerg#endif 4611558Srgrimes 4621558Srgrimes /* XXX */ 4631558Srgrimes if (dp->d_secsize == 0) { 4641558Srgrimes dp->d_secsize = DEV_BSIZE; 4651558Srgrimes dp->d_bbsize = BBSIZE; 4661558Srgrimes } 4671558Srgrimes lp = (struct disklabel *) 4681558Srgrimes (boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET); 4691558Srgrimes bzero((char *)lp, sizeof *lp); 4701558Srgrimes /* 4711558Srgrimes * If we are not installing a boot program but we are installing a 4721558Srgrimes * label on disk then we must read the current bootarea so we don't 4731558Srgrimes * clobber the existing boot. 4741558Srgrimes */ 4751558Srgrimes if (!installboot) { 4761558Srgrimes if (rflag) { 4771558Srgrimes if (read(f, boot, BBSIZE) < BBSIZE) 47826542Scharnier err(4, "%s", specname); 4791558Srgrimes bzero((char *)lp, sizeof *lp); 4801558Srgrimes } 4811558Srgrimes return (lp); 4821558Srgrimes } 4831558Srgrimes /* 4841558Srgrimes * We are installing a boot program. Determine the name(s) and 4851558Srgrimes * read them into the appropriate places in the boot area. 4861558Srgrimes */ 487109889Sphk if (!xxboot) { 4881558Srgrimes dkbasename = np; 4891558Srgrimes if ((p = rindex(dkname, '/')) == NULL) 4901558Srgrimes p = dkname; 4911558Srgrimes else 4921558Srgrimes p++; 4931558Srgrimes while (*p && !isdigit(*p)) 4941558Srgrimes *np++ = *p++; 4951558Srgrimes *np++ = '\0'; 4961558Srgrimes 4971558Srgrimes if (!xxboot) { 498109889Sphk (void)sprintf(boot0, "%s/boot", _PATH_BOOTDIR); 49941901Sjkh xxboot = boot0; 5001558Srgrimes } 5011558Srgrimes } 5021558Srgrimes 5031558Srgrimes b = open(xxboot, O_RDONLY); 5041558Srgrimes if (b < 0) 50526542Scharnier err(4, "%s", xxboot); 506109889Sphk if (fstat(b, &sb) != 0) 507109889Sphk err(4, "%s", xxboot); 50813892Sjoerg#ifdef __i386__ 509109889Sphk if (sb.st_size > BBSIZE) 510109889Sphk errx(4, "%s too large", xxboot); 51113892Sjoerg /* 51213892Sjoerg * XXX Botch alert. 513109889Sphk * The i386/PC98 has the so-called fdisk table embedded into the 51413892Sjoerg * primary bootstrap. We take care to not clobber it, but 51513892Sjoerg * only if it does already contain some data. (Otherwise, 51613892Sjoerg * the xxboot provides a template.) 51713892Sjoerg */ 51813892Sjoerg if ((tmpbuf = (char *)malloc((int)dp->d_secsize)) == 0) 51926542Scharnier err(4, "%s", xxboot); 52013892Sjoerg memcpy((void *)tmpbuf, (void *)boot, (int)dp->d_secsize); 521109889Sphk 522109889Sphk if (read(b, boot, BBSIZE) < 0) 52326542Scharnier err(4, "%s", xxboot); 524109889Sphk 525109889Sphk /* XXX: rely on some very precise overlaps in definitions */ 526108650Snyan#ifdef PC98 527109889Sphk dps = sizeof(struct pc98_partition); 528109889Sphk#else 529109889Sphk dps = sizeof(struct dos_partition); 530109889Sphk#endif 53113892Sjoerg for (i = DOSPARTOFF, found = 0; 532109889Sphk !found && i < (int)(DOSPARTOFF + NDOSPART * dps); 533108650Snyan i++) 534108650Snyan found = tmpbuf[i] != 0; 535108650Snyan if (found) 536108650Snyan memcpy((void *)&boot[DOSPARTOFF], 537108650Snyan (void *)&tmpbuf[DOSPARTOFF], 538109889Sphk NDOSPART * dps); 539108650Snyan free(tmpbuf); 54097553Salfred#endif /* __i386__ */ 541109889Sphk 54238384Sdfr#ifdef __alpha__ 543109889Sphk if (sb.st_size > BBSIZE - dp->d_secsize) 544109889Sphk errx(4, "%s too large", xxboot); 54538411Sbde /* 54638411Sbde * On the alpha, the primary bootstrap starts at the 54738411Sbde * second sector of the boot area. The first sector 54838411Sbde * contains the label and must be edited to contain the 54938411Sbde * size and location of the primary bootstrap. 55038411Sbde */ 551109889Sphk n = read(b, boot + dp->d_secsize, BBSIZE - dp->d_secsize); 55238411Sbde if (n < 0) 55338384Sdfr err(4, "%s", xxboot); 55438483Sbde bootinfo = (u_long *)(boot + 480); 55538483Sbde bootinfo[0] = (n + dp->d_secsize - 1) / dp->d_secsize; 55638483Sbde bootinfo[1] = 1; /* start at sector 1 */ 55738483Sbde bootinfo[2] = 0; /* flags (must be zero) */ 55838411Sbde#endif /* __alpha__ */ 559109889Sphk 5601558Srgrimes (void)close(b); 5611558Srgrimes /* 5621558Srgrimes * Make sure no part of the bootstrap is written in the area 5631558Srgrimes * reserved for the label. 5641558Srgrimes */ 5651558Srgrimes for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++) 56636632Scharnier if (*p) 56736632Scharnier errx(2, "bootstrap doesn't leave room for disk label"); 5681558Srgrimes return (lp); 5691558Srgrimes} 5701558Srgrimes 57113544Sjoergvoid 57292541Simpdisplay(FILE *f, const struct disklabel *lp) 5731558Srgrimes{ 57492541Simp int i, j; 57592541Simp const struct partition *pp; 5761558Srgrimes 5771558Srgrimes fprintf(f, "# %s:\n", specname); 578107041Sjulian if (lp->d_type < DKMAXTYPES) 5791558Srgrimes fprintf(f, "type: %s\n", dktypenames[lp->d_type]); 5801558Srgrimes else 58137234Sbde fprintf(f, "type: %u\n", lp->d_type); 58213544Sjoerg fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename), 58313544Sjoerg lp->d_typename); 58413544Sjoerg fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname), 58513544Sjoerg lp->d_packname); 5861558Srgrimes fprintf(f, "flags:"); 5871558Srgrimes if (lp->d_flags & D_REMOVABLE) 5881558Srgrimes fprintf(f, " removeable"); 5891558Srgrimes if (lp->d_flags & D_ECC) 5901558Srgrimes fprintf(f, " ecc"); 5911558Srgrimes if (lp->d_flags & D_BADSECT) 5921558Srgrimes fprintf(f, " badsect"); 5931558Srgrimes fprintf(f, "\n"); 59437234Sbde fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize); 59537234Sbde fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors); 59637234Sbde fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks); 59737234Sbde fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl); 59837234Sbde fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders); 59937234Sbde fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit); 60037234Sbde fprintf(f, "rpm: %u\n", lp->d_rpm); 60137234Sbde fprintf(f, "interleave: %u\n", lp->d_interleave); 60237234Sbde fprintf(f, "trackskew: %u\n", lp->d_trackskew); 60337234Sbde fprintf(f, "cylinderskew: %u\n", lp->d_cylskew); 60437234Sbde fprintf(f, "headswitch: %lu\t\t# milliseconds\n", 60537234Sbde (u_long)lp->d_headswitch); 60613544Sjoerg fprintf(f, "track-to-track seek: %ld\t# milliseconds\n", 60737234Sbde (u_long)lp->d_trkseek); 6081558Srgrimes fprintf(f, "drivedata: "); 6091558Srgrimes for (i = NDDATA - 1; i >= 0; i--) 6101558Srgrimes if (lp->d_drivedata[i]) 6111558Srgrimes break; 6121558Srgrimes if (i < 0) 6131558Srgrimes i = 0; 6141558Srgrimes for (j = 0; j <= i; j++) 61537234Sbde fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]); 61637234Sbde fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions); 6171558Srgrimes fprintf(f, 6185393Sgibbs "# size offset fstype [fsize bsize bps/cpg]\n"); 6191558Srgrimes pp = lp->d_partitions; 6201558Srgrimes for (i = 0; i < lp->d_npartitions; i++, pp++) { 6211558Srgrimes if (pp->p_size) { 62237234Sbde fprintf(f, " %c: %8lu %8lu ", 'a' + i, 62337234Sbde (u_long)pp->p_size, (u_long)pp->p_offset); 624107041Sjulian if (pp->p_fstype < FSMAXTYPES) 6251558Srgrimes fprintf(f, "%8.8s", fstypenames[pp->p_fstype]); 6261558Srgrimes else 6271558Srgrimes fprintf(f, "%8d", pp->p_fstype); 6281558Srgrimes switch (pp->p_fstype) { 6291558Srgrimes 6301558Srgrimes case FS_UNUSED: /* XXX */ 63137234Sbde fprintf(f, " %5lu %5lu %5.5s ", 63237234Sbde (u_long)pp->p_fsize, 63337234Sbde (u_long)(pp->p_fsize * pp->p_frag), ""); 6341558Srgrimes break; 6351558Srgrimes 6361558Srgrimes case FS_BSDFFS: 63737234Sbde fprintf(f, " %5lu %5lu %5u ", 63837234Sbde (u_long)pp->p_fsize, 63937234Sbde (u_long)(pp->p_fsize * pp->p_frag), 6401558Srgrimes pp->p_cpg); 6411558Srgrimes break; 6421558Srgrimes 6435393Sgibbs case FS_BSDLFS: 64437234Sbde fprintf(f, " %5lu %5lu %5d", 64537234Sbde (u_long)pp->p_fsize, 64637234Sbde (u_long)(pp->p_fsize * pp->p_frag), 6475393Sgibbs pp->p_cpg); 6485393Sgibbs break; 6495393Sgibbs 6501558Srgrimes default: 6511558Srgrimes fprintf(f, "%20.20s", ""); 6521558Srgrimes break; 6531558Srgrimes } 65437234Sbde fprintf(f, "\t# (Cyl. %4lu", 65537234Sbde (u_long)(pp->p_offset / lp->d_secpercyl)); 6561558Srgrimes if (pp->p_offset % lp->d_secpercyl) 6571558Srgrimes putc('*', f); 6581558Srgrimes else 6591558Srgrimes putc(' ', f); 66037234Sbde fprintf(f, "- %lu", 66137234Sbde (u_long)((pp->p_offset + pp->p_size + 66237234Sbde lp->d_secpercyl - 1) / 66337234Sbde lp->d_secpercyl - 1)); 6641558Srgrimes if (pp->p_size % lp->d_secpercyl) 6651558Srgrimes putc('*', f); 6661558Srgrimes fprintf(f, ")\n"); 6671558Srgrimes } 6681558Srgrimes } 6691558Srgrimes fflush(f); 6701558Srgrimes} 6711558Srgrimes 67213544Sjoergint 67392541Simpedit(struct disklabel *lp, int f) 6741558Srgrimes{ 67592541Simp int c, fd; 6761558Srgrimes struct disklabel label; 67724180Simp FILE *fp; 6781558Srgrimes 67924180Simp if ((fd = mkstemp(tmpfil)) == -1 || 68024180Simp (fp = fdopen(fd, "w")) == NULL) { 68136632Scharnier warnx("can't create %s", tmpfil); 6821558Srgrimes return (1); 6831558Srgrimes } 68424180Simp display(fp, lp); 68524180Simp fclose(fp); 6861558Srgrimes for (;;) { 6871558Srgrimes if (!editit()) 6881558Srgrimes break; 68924180Simp fp = fopen(tmpfil, "r"); 69024180Simp if (fp == NULL) { 69136632Scharnier warnx("can't reopen %s for reading", tmpfil); 6921558Srgrimes break; 6931558Srgrimes } 6941558Srgrimes bzero((char *)&label, sizeof(label)); 69524180Simp if (getasciilabel(fp, &label)) { 6961558Srgrimes *lp = label; 6971558Srgrimes if (writelabel(f, bootarea, lp) == 0) { 69824180Simp fclose(fp); 6991558Srgrimes (void) unlink(tmpfil); 7001558Srgrimes return (0); 7011558Srgrimes } 7021558Srgrimes } 70324180Simp fclose(fp); 7041558Srgrimes printf("re-edit the label? [y]: "); fflush(stdout); 7051558Srgrimes c = getchar(); 7061558Srgrimes if (c != EOF && c != (int)'\n') 7071558Srgrimes while (getchar() != (int)'\n') 7081558Srgrimes ; 7091558Srgrimes if (c == (int)'n') 7101558Srgrimes break; 7111558Srgrimes } 7121558Srgrimes (void) unlink(tmpfil); 7131558Srgrimes return (1); 7141558Srgrimes} 7151558Srgrimes 71613544Sjoergint 71792541Simpeditit(void) 7181558Srgrimes{ 71992541Simp int pid, xpid; 72099365Smarkm int locstat, omask; 72199365Smarkm const char *ed; 7221558Srgrimes 7231558Srgrimes omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 7241558Srgrimes while ((pid = fork()) < 0) { 7251558Srgrimes if (errno == EPROCLIM) { 72636632Scharnier warnx("you have too many processes"); 7271558Srgrimes return(0); 7281558Srgrimes } 7291558Srgrimes if (errno != EAGAIN) { 73036632Scharnier warn("fork"); 7311558Srgrimes return(0); 7321558Srgrimes } 7331558Srgrimes sleep(1); 7341558Srgrimes } 7351558Srgrimes if (pid == 0) { 7361558Srgrimes sigsetmask(omask); 7371558Srgrimes setgid(getgid()); 7381558Srgrimes setuid(getuid()); 7391558Srgrimes if ((ed = getenv("EDITOR")) == (char *)0) 7401558Srgrimes ed = DEFEDITOR; 74179452Sbrian execlp(ed, ed, tmpfil, (char *)0); 74236632Scharnier err(1, "%s", ed); 7431558Srgrimes } 74499365Smarkm while ((xpid = wait(&locstat)) >= 0) 7451558Srgrimes if (xpid == pid) 7461558Srgrimes break; 7471558Srgrimes sigsetmask(omask); 74899365Smarkm return(!locstat); 7491558Srgrimes} 7501558Srgrimes 7511558Srgrimeschar * 75292541Simpskip(char *cp) 7531558Srgrimes{ 7541558Srgrimes 7551558Srgrimes while (*cp != '\0' && isspace(*cp)) 7561558Srgrimes cp++; 7571558Srgrimes if (*cp == '\0' || *cp == '#') 75892541Simp return (NULL); 7591558Srgrimes return (cp); 7601558Srgrimes} 7611558Srgrimes 7621558Srgrimeschar * 76392541Simpword(char *cp) 7641558Srgrimes{ 76592541Simp char c; 7661558Srgrimes 7671558Srgrimes while (*cp != '\0' && !isspace(*cp) && *cp != '#') 7681558Srgrimes cp++; 7691558Srgrimes if ((c = *cp) != '\0') { 7701558Srgrimes *cp++ = '\0'; 7711558Srgrimes if (c != '#') 7721558Srgrimes return (skip(cp)); 7731558Srgrimes } 77492541Simp return (NULL); 7751558Srgrimes} 7761558Srgrimes 7771558Srgrimes/* 7781558Srgrimes * Read an ascii label in from fd f, 7791558Srgrimes * in the same format as that put out by display(), 7801558Srgrimes * and fill in lp. 7811558Srgrimes */ 78213544Sjoergint 78392541Simpgetasciilabel(FILE *f, struct disklabel *lp) 7841558Srgrimes{ 78594065Sphk char *cp; 78694065Sphk const char **cpp; 787107041Sjulian u_int part; 78894065Sphk char *tp, line[BUFSIZ]; 789107041Sjulian u_long v; 790107041Sjulian int lineno = 0, errors = 0; 79192541Simp int i; 7921558Srgrimes 793109378Sdes bzero(&part_set, sizeof(part_set)); 794109378Sdes bzero(&part_size_type, sizeof(part_size_type)); 795109378Sdes bzero(&part_offset_type, sizeof(part_offset_type)); 7961558Srgrimes lp->d_bbsize = BBSIZE; /* XXX */ 79796475Sphk lp->d_sbsize = 0; /* XXX */ 7981558Srgrimes while (fgets(line, sizeof(line) - 1, f)) { 7991558Srgrimes lineno++; 80013544Sjoerg if ((cp = index(line,'\n')) != 0) 8011558Srgrimes *cp = '\0'; 8021558Srgrimes cp = skip(line); 8031558Srgrimes if (cp == NULL) 8041558Srgrimes continue; 8051558Srgrimes tp = index(cp, ':'); 8061558Srgrimes if (tp == NULL) { 8071558Srgrimes fprintf(stderr, "line %d: syntax error\n", lineno); 8081558Srgrimes errors++; 8091558Srgrimes continue; 8101558Srgrimes } 8111558Srgrimes *tp++ = '\0', tp = skip(tp); 8121558Srgrimes if (streq(cp, "type")) { 8131558Srgrimes if (tp == NULL) 81499365Smarkm tp = unknown; 8151558Srgrimes cpp = dktypenames; 8161558Srgrimes for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) 81794065Sphk if (*cpp && streq(*cpp, tp)) { 8181558Srgrimes lp->d_type = cpp - dktypenames; 81997855Siedowse break; 8201558Srgrimes } 82197855Siedowse if (cpp < &dktypenames[DKMAXTYPES]) 82297855Siedowse continue; 823107041Sjulian v = strtoul(tp, NULL, 10); 824107041Sjulian if (v >= DKMAXTYPES) 825107041Sjulian fprintf(stderr, "line %d:%s %lu\n", lineno, 8261558Srgrimes "Warning, unknown disk type", v); 8271558Srgrimes lp->d_type = v; 8281558Srgrimes continue; 8291558Srgrimes } 8301558Srgrimes if (streq(cp, "flags")) { 8311558Srgrimes for (v = 0; (cp = tp) && *cp != '\0';) { 8321558Srgrimes tp = word(cp); 8331558Srgrimes if (streq(cp, "removeable")) 8341558Srgrimes v |= D_REMOVABLE; 8351558Srgrimes else if (streq(cp, "ecc")) 8361558Srgrimes v |= D_ECC; 8371558Srgrimes else if (streq(cp, "badsect")) 8381558Srgrimes v |= D_BADSECT; 8391558Srgrimes else { 8401558Srgrimes fprintf(stderr, 8411558Srgrimes "line %d: %s: bad flag\n", 8421558Srgrimes lineno, cp); 8431558Srgrimes errors++; 8441558Srgrimes } 8451558Srgrimes } 8461558Srgrimes lp->d_flags = v; 8471558Srgrimes continue; 8481558Srgrimes } 8491558Srgrimes if (streq(cp, "drivedata")) { 8501558Srgrimes for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) { 851107041Sjulian lp->d_drivedata[i++] = strtoul(cp, NULL, 10); 8521558Srgrimes tp = word(cp); 8531558Srgrimes } 8541558Srgrimes continue; 8551558Srgrimes } 856107041Sjulian if (sscanf(cp, "%lu partitions", &v) == 1) { 857107041Sjulian if (v == 0 || v > MAXPARTITIONS) { 8581558Srgrimes fprintf(stderr, 8591558Srgrimes "line %d: bad # of partitions\n", lineno); 8601558Srgrimes lp->d_npartitions = MAXPARTITIONS; 8611558Srgrimes errors++; 8621558Srgrimes } else 8631558Srgrimes lp->d_npartitions = v; 8641558Srgrimes continue; 8651558Srgrimes } 8661558Srgrimes if (tp == NULL) 86799365Smarkm tp = blank; 8681558Srgrimes if (streq(cp, "disk")) { 8691558Srgrimes strncpy(lp->d_typename, tp, sizeof (lp->d_typename)); 8701558Srgrimes continue; 8711558Srgrimes } 8721558Srgrimes if (streq(cp, "label")) { 8731558Srgrimes strncpy(lp->d_packname, tp, sizeof (lp->d_packname)); 8741558Srgrimes continue; 8751558Srgrimes } 8761558Srgrimes if (streq(cp, "bytes/sector")) { 877107041Sjulian v = strtoul(tp, NULL, 10); 878107041Sjulian if (v == 0 || (v % DEV_BSIZE) != 0) { 8791558Srgrimes fprintf(stderr, 8801558Srgrimes "line %d: %s: bad sector size\n", 8811558Srgrimes lineno, tp); 8821558Srgrimes errors++; 8831558Srgrimes } else 8841558Srgrimes lp->d_secsize = v; 8851558Srgrimes continue; 8861558Srgrimes } 8871558Srgrimes if (streq(cp, "sectors/track")) { 888107041Sjulian v = strtoul(tp, NULL, 10); 889107041Sjulian#if (ULONG_MAX != 0xffffffffUL) 890107041Sjulian if (v == 0 || v > 0xffffffff) { 891107041Sjulian#else 892107041Sjulian if (v == 0) { 893107041Sjulian#endif 8941558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 8951558Srgrimes lineno, tp, cp); 8961558Srgrimes errors++; 8971558Srgrimes } else 8981558Srgrimes lp->d_nsectors = v; 8991558Srgrimes continue; 9001558Srgrimes } 9011558Srgrimes if (streq(cp, "sectors/cylinder")) { 902107041Sjulian v = strtoul(tp, NULL, 10); 903107041Sjulian if (v == 0) { 9041558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 9051558Srgrimes lineno, tp, cp); 9061558Srgrimes errors++; 9071558Srgrimes } else 9081558Srgrimes lp->d_secpercyl = v; 9091558Srgrimes continue; 9101558Srgrimes } 9111558Srgrimes if (streq(cp, "tracks/cylinder")) { 912107041Sjulian v = strtoul(tp, NULL, 10); 913107041Sjulian if (v == 0) { 9141558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 9151558Srgrimes lineno, tp, cp); 9161558Srgrimes errors++; 9171558Srgrimes } else 9181558Srgrimes lp->d_ntracks = v; 9191558Srgrimes continue; 9201558Srgrimes } 9211558Srgrimes if (streq(cp, "cylinders")) { 922107041Sjulian v = strtoul(tp, NULL, 10); 923107041Sjulian if (v == 0) { 9241558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 9251558Srgrimes lineno, tp, cp); 9261558Srgrimes errors++; 9271558Srgrimes } else 9281558Srgrimes lp->d_ncylinders = v; 9291558Srgrimes continue; 9301558Srgrimes } 9316643Sbde if (streq(cp, "sectors/unit")) { 932107041Sjulian v = strtoul(tp, NULL, 10); 933107041Sjulian if (v == 0) { 9346643Sbde fprintf(stderr, "line %d: %s: bad %s\n", 9356643Sbde lineno, tp, cp); 9366643Sbde errors++; 9376643Sbde } else 9386643Sbde lp->d_secperunit = v; 9396643Sbde continue; 9406643Sbde } 9411558Srgrimes if (streq(cp, "rpm")) { 942107041Sjulian v = strtoul(tp, NULL, 10); 943107041Sjulian if (v == 0 || v > USHRT_MAX) { 9441558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 9451558Srgrimes lineno, tp, cp); 9461558Srgrimes errors++; 9471558Srgrimes } else 9481558Srgrimes lp->d_rpm = v; 9491558Srgrimes continue; 9501558Srgrimes } 9511558Srgrimes if (streq(cp, "interleave")) { 952107041Sjulian v = strtoul(tp, NULL, 10); 953107041Sjulian if (v == 0 || v > USHRT_MAX) { 9541558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 9551558Srgrimes lineno, tp, cp); 9561558Srgrimes errors++; 9571558Srgrimes } else 9581558Srgrimes lp->d_interleave = v; 9591558Srgrimes continue; 9601558Srgrimes } 9611558Srgrimes if (streq(cp, "trackskew")) { 962107041Sjulian v = strtoul(tp, NULL, 10); 963107041Sjulian if (v > USHRT_MAX) { 9641558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 9651558Srgrimes lineno, tp, cp); 9661558Srgrimes errors++; 9671558Srgrimes } else 9681558Srgrimes lp->d_trackskew = v; 9691558Srgrimes continue; 9701558Srgrimes } 9711558Srgrimes if (streq(cp, "cylinderskew")) { 972107041Sjulian v = strtoul(tp, NULL, 10); 973107041Sjulian if (v > USHRT_MAX) { 9741558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 9751558Srgrimes lineno, tp, cp); 9761558Srgrimes errors++; 9771558Srgrimes } else 9781558Srgrimes lp->d_cylskew = v; 9791558Srgrimes continue; 9801558Srgrimes } 9811558Srgrimes if (streq(cp, "headswitch")) { 982107041Sjulian v = strtoul(tp, NULL, 10); 983107041Sjulian lp->d_headswitch = v; 9841558Srgrimes continue; 9851558Srgrimes } 9861558Srgrimes if (streq(cp, "track-to-track seek")) { 987107041Sjulian v = strtoul(tp, NULL, 10); 988107041Sjulian lp->d_trkseek = v; 9891558Srgrimes continue; 9901558Srgrimes } 99173034Sjwd /* the ':' was removed above */ 99297534Siedowse if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') { 99397534Siedowse fprintf(stderr, 99497534Siedowse "line %d: %s: Unknown disklabel field\n", lineno, 99597534Siedowse cp); 99697534Siedowse errors++; 99797534Siedowse continue; 99897534Siedowse } 99997534Siedowse 100097534Siedowse /* Process a partition specification line. */ 100197534Siedowse part = *cp - 'a'; 100297534Siedowse if (part >= lp->d_npartitions) { 100397534Siedowse fprintf(stderr, 100497534Siedowse "line %d: partition name out of range a-%c: %s\n", 100597534Siedowse lineno, 'a' + lp->d_npartitions - 1, cp); 100697534Siedowse errors++; 100797534Siedowse continue; 100897534Siedowse } 100997534Siedowse part_set[part] = 1; 101097534Siedowse 101197534Siedowse if (getasciipartspec(tp, lp, part, lineno) != 0) { 101297534Siedowse errors++; 101397534Siedowse break; 101497534Siedowse } 101597534Siedowse } 101697534Siedowse errors += checklabel(lp); 101797534Siedowse return (errors == 0); 101897534Siedowse} 101997534Siedowse 102097534Siedowse#define NXTNUM(n) do { \ 10213111Spst if (tp == NULL) { \ 10223111Spst fprintf(stderr, "line %d: too few numeric fields\n", lineno); \ 102397534Siedowse return (1); \ 10243111Spst } else { \ 10253111Spst cp = tp, tp = word(cp); \ 1026107041Sjulian (n) = strtoul(cp, NULL, 10); \ 10273111Spst } \ 102897534Siedowse} while (0) 102997534Siedowse 103073034Sjwd/* retain 1 character following number */ 103197534Siedowse#define NXTWORD(w,n) do { \ 103273034Sjwd if (tp == NULL) { \ 103373034Sjwd fprintf(stderr, "line %d: too few numeric fields\n", lineno); \ 103497534Siedowse return (1); \ 103573034Sjwd } else { \ 103673034Sjwd char *tmp; \ 103773034Sjwd cp = tp, tp = word(cp); \ 1038107041Sjulian (n) = strtoul(cp, &tmp, 10); \ 103973034Sjwd if (tmp) (w) = *tmp; \ 104073034Sjwd } \ 104197534Siedowse} while (0) 10421558Srgrimes 104397534Siedowse/* 104497534Siedowse * Read a partition line into partition `part' in the specified disklabel. 104597534Siedowse * Return 0 on success, 1 on failure. 104697534Siedowse */ 104797534Siedowseint 104897534Siedowsegetasciipartspec(char *tp, struct disklabel *lp, int part, int lineno) 104997534Siedowse{ 105097534Siedowse struct partition *pp; 105197534Siedowse char *cp; 105297534Siedowse const char **cpp; 1053107041Sjulian u_long v; 10541558Srgrimes 105597534Siedowse pp = &lp->d_partitions[part]; 105697534Siedowse cp = NULL; 10571558Srgrimes 105897534Siedowse v = 0; 105997534Siedowse NXTWORD(part_size_type[part],v); 1060107041Sjulian if (v == 0 && part_size_type[part] != '*') { 1061107041Sjulian fprintf(stderr, 1062107041Sjulian "line %d: %s: bad partition size\n", lineno, cp); 106397534Siedowse return (1); 106497534Siedowse } 106597534Siedowse pp->p_size = v; 106697534Siedowse 106797534Siedowse v = 0; 106897534Siedowse NXTWORD(part_offset_type[part],v); 1069107041Sjulian if (v == 0 && part_offset_type[part] != '*' && 1070107041Sjulian part_offset_type[part] != '\0') { 1071107041Sjulian fprintf(stderr, 1072107041Sjulian "line %d: %s: bad partition offset\n", lineno, cp); 107397534Siedowse return (1); 107497534Siedowse } 107597534Siedowse pp->p_offset = v; 107697534Siedowse cp = tp, tp = word(cp); 107797534Siedowse for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++) 107897534Siedowse if (*cpp && streq(*cpp, cp)) 107997534Siedowse break; 108097534Siedowse if (*cpp != NULL) { 108197534Siedowse pp->p_fstype = cpp - fstypenames; 108297534Siedowse } else { 108397534Siedowse if (isdigit(*cp)) 1084107041Sjulian v = strtoul(cp, NULL, 10); 108597534Siedowse else 108697534Siedowse v = FSMAXTYPES; 1087107041Sjulian if (v >= FSMAXTYPES) { 108897534Siedowse fprintf(stderr, 1089102231Strhodes "line %d: Warning, unknown file system type %s\n", 109097534Siedowse lineno, cp); 109197534Siedowse v = FS_UNUSED; 109297534Siedowse } 109397534Siedowse pp->p_fstype = v; 109497534Siedowse } 109597534Siedowse 109697534Siedowse switch (pp->p_fstype) { 109797534Siedowse case FS_UNUSED: 109897534Siedowse /* 109997534Siedowse * allow us to accept defaults for 110097534Siedowse * fsize/frag/cpg 110197534Siedowse */ 110297534Siedowse if (tp) { 110397534Siedowse NXTNUM(pp->p_fsize); 110497534Siedowse if (pp->p_fsize == 0) 110597534Siedowse break; 110697534Siedowse NXTNUM(v); 110797534Siedowse pp->p_frag = v / pp->p_fsize; 110897534Siedowse } 110997534Siedowse /* else default to 0's */ 111097534Siedowse break; 111197534Siedowse 111297534Siedowse /* These happen to be the same */ 111397534Siedowse case FS_BSDFFS: 111497534Siedowse case FS_BSDLFS: 111597534Siedowse if (tp) { 111697534Siedowse NXTNUM(pp->p_fsize); 111797534Siedowse if (pp->p_fsize == 0) 111897534Siedowse break; 111997534Siedowse NXTNUM(v); 112097534Siedowse pp->p_frag = v / pp->p_fsize; 112197534Siedowse NXTNUM(pp->p_cpg); 112297534Siedowse } else { 112397534Siedowse /* 112497534Siedowse * FIX! poor attempt at adaptive 112597534Siedowse */ 112697534Siedowse /* 1 GB */ 112797534Siedowse if (pp->p_size < 1024*1024*1024 / lp->d_secsize) { 112897534Siedowse /* 112997534Siedowse * FIX! These are too low, but are traditional 113097534Siedowse */ 113197535Siedowse pp->p_fsize = DEFAULT_NEWFS_FRAG; 113297535Siedowse pp->p_frag = DEFAULT_NEWFS_BLOCK / 113397535Siedowse DEFAULT_NEWFS_FRAG; 113497534Siedowse pp->p_cpg = DEFAULT_NEWFS_CPG; 113597534Siedowse } else { 113697535Siedowse pp->p_fsize = BIG_NEWFS_FRAG; 113797535Siedowse pp->p_frag = BIG_NEWFS_BLOCK / 113897535Siedowse BIG_NEWFS_FRAG; 113997534Siedowse pp->p_cpg = BIG_NEWFS_CPG; 11401558Srgrimes } 11411558Srgrimes } 114297534Siedowse default: 114397534Siedowse break; 11441558Srgrimes } 114597534Siedowse return (0); 11461558Srgrimes} 11471558Srgrimes 11481558Srgrimes/* 11491558Srgrimes * Check disklabel for errors and fill in 11501558Srgrimes * derived fields according to supplied values. 11511558Srgrimes */ 115213544Sjoergint 115392541Simpchecklabel(struct disklabel *lp) 11541558Srgrimes{ 115592541Simp struct partition *pp; 11561558Srgrimes int i, errors = 0; 11571558Srgrimes char part; 1158107041Sjulian u_long total_size, total_percent, current_offset; 115973034Sjwd int seen_default_offset; 116073034Sjwd int hog_part; 116173034Sjwd int j; 116273034Sjwd struct partition *pp2; 11631558Srgrimes 11641558Srgrimes if (lp->d_secsize == 0) { 116537234Sbde fprintf(stderr, "sector size 0\n"); 11661558Srgrimes return (1); 11671558Srgrimes } 11681558Srgrimes if (lp->d_nsectors == 0) { 116937234Sbde fprintf(stderr, "sectors/track 0\n"); 11701558Srgrimes return (1); 11711558Srgrimes } 11721558Srgrimes if (lp->d_ntracks == 0) { 117337234Sbde fprintf(stderr, "tracks/cylinder 0\n"); 11741558Srgrimes return (1); 11751558Srgrimes } 11761558Srgrimes if (lp->d_ncylinders == 0) { 117737234Sbde fprintf(stderr, "cylinders/unit 0\n"); 11781558Srgrimes errors++; 11791558Srgrimes } 11801558Srgrimes if (lp->d_rpm == 0) 118137234Sbde Warning("revolutions/minute 0"); 11821558Srgrimes if (lp->d_secpercyl == 0) 11831558Srgrimes lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 11841558Srgrimes if (lp->d_secperunit == 0) 11851558Srgrimes lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 11861558Srgrimes if (lp->d_bbsize == 0) { 118737234Sbde fprintf(stderr, "boot block size 0\n"); 11881558Srgrimes errors++; 11891558Srgrimes } else if (lp->d_bbsize % lp->d_secsize) 11901558Srgrimes Warning("boot block size %% sector-size != 0"); 11911558Srgrimes if (lp->d_npartitions > MAXPARTITIONS) 119237234Sbde Warning("number of partitions (%lu) > MAXPARTITIONS (%d)", 119337234Sbde (u_long)lp->d_npartitions, MAXPARTITIONS); 119473034Sjwd 119573034Sjwd /* first allocate space to the partitions, then offsets */ 119673034Sjwd total_size = 0; /* in sectors */ 119773034Sjwd total_percent = 0; /* in percent */ 119873034Sjwd hog_part = -1; 119973034Sjwd /* find all fixed partitions */ 12001558Srgrimes for (i = 0; i < lp->d_npartitions; i++) { 120173034Sjwd pp = &lp->d_partitions[i]; 120273034Sjwd if (part_set[i]) { 120373034Sjwd if (part_size_type[i] == '*') { 120494065Sphk if (i == RAW_PART) { 120573034Sjwd pp->p_size = lp->d_secperunit; 120673034Sjwd } else { 120773034Sjwd if (hog_part != -1) 120873034Sjwd Warning("Too many '*' partitions (%c and %c)", 120973034Sjwd hog_part + 'a',i + 'a'); 121073034Sjwd else 121173034Sjwd hog_part = i; 121273034Sjwd } 121373034Sjwd } else { 121473573Simp off_t size; 121573034Sjwd 121673034Sjwd size = pp->p_size; 121773034Sjwd switch (part_size_type[i]) { 121873034Sjwd case '%': 121973034Sjwd total_percent += size; 122073034Sjwd break; 122173034Sjwd case 'k': 122273034Sjwd case 'K': 122373573Simp size *= 1024ULL; 122473034Sjwd break; 122573034Sjwd case 'm': 122673034Sjwd case 'M': 122773573Simp size *= 1024ULL * 1024ULL; 122873034Sjwd break; 122973034Sjwd case 'g': 123073034Sjwd case 'G': 123173573Simp size *= 1024ULL * 1024ULL * 1024ULL; 123273034Sjwd break; 123373034Sjwd case '\0': 123473034Sjwd break; 123573034Sjwd default: 123673034Sjwd Warning("unknown size specifier '%c' (K/M/G are valid)",part_size_type[i]); 123773034Sjwd break; 123873034Sjwd } 123973034Sjwd /* don't count %'s yet */ 124073034Sjwd if (part_size_type[i] != '%') { 124173034Sjwd /* 124273034Sjwd * for all not in sectors, convert to 124373034Sjwd * sectors 124473034Sjwd */ 124573034Sjwd if (part_size_type[i] != '\0') { 124673034Sjwd if (size % lp->d_secsize != 0) 124773034Sjwd Warning("partition %c not an integer number of sectors", 124873034Sjwd i + 'a'); 124973034Sjwd size /= lp->d_secsize; 125073034Sjwd pp->p_size = size; 125173034Sjwd } 125273034Sjwd /* else already in sectors */ 125394065Sphk if (i != RAW_PART) 125473034Sjwd total_size += size; 125573034Sjwd } 125673034Sjwd } 125773034Sjwd } 125873034Sjwd } 125973034Sjwd /* handle % partitions - note %'s don't need to add up to 100! */ 126073034Sjwd if (total_percent != 0) { 126173034Sjwd long free_space = lp->d_secperunit - total_size; 126273034Sjwd if (total_percent > 100) { 126394065Sphk fprintf(stderr,"total percentage %lu is greater than 100\n", 126473034Sjwd total_percent); 126573034Sjwd errors++; 126673034Sjwd } 126773034Sjwd 126873034Sjwd if (free_space > 0) { 126973034Sjwd for (i = 0; i < lp->d_npartitions; i++) { 127073034Sjwd pp = &lp->d_partitions[i]; 127173034Sjwd if (part_set[i] && part_size_type[i] == '%') { 127273034Sjwd /* careful of overflows! and integer roundoff */ 127373034Sjwd pp->p_size = ((double)pp->p_size/100) * free_space; 127473034Sjwd total_size += pp->p_size; 127573034Sjwd 127673034Sjwd /* FIX we can lose a sector or so due to roundoff per 127773034Sjwd partition. A more complex algorithm could avoid that */ 127873034Sjwd } 127973034Sjwd } 128073034Sjwd } else { 128173034Sjwd fprintf(stderr, 128294065Sphk "%ld sectors available to give to '*' and '%%' partitions\n", 128373034Sjwd free_space); 128473034Sjwd errors++; 128573034Sjwd /* fix? set all % partitions to size 0? */ 128673034Sjwd } 128773034Sjwd } 128873034Sjwd /* give anything remaining to the hog partition */ 128973034Sjwd if (hog_part != -1) { 129073034Sjwd lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size; 129173034Sjwd total_size = lp->d_secperunit; 129273034Sjwd } 129373034Sjwd 129473034Sjwd /* Now set the offsets for each partition */ 129573034Sjwd current_offset = 0; /* in sectors */ 129673034Sjwd seen_default_offset = 0; 129773034Sjwd for (i = 0; i < lp->d_npartitions; i++) { 12981558Srgrimes part = 'a' + i; 12991558Srgrimes pp = &lp->d_partitions[i]; 130073034Sjwd if (part_set[i]) { 130173034Sjwd if (part_offset_type[i] == '*') { 130294065Sphk if (i == RAW_PART) { 130373034Sjwd pp->p_offset = 0; 130473034Sjwd } else { 130573034Sjwd pp->p_offset = current_offset; 130673034Sjwd seen_default_offset = 1; 130773034Sjwd } 130873034Sjwd } else { 130973034Sjwd /* allow them to be out of order for old-style tables */ 131073034Sjwd if (pp->p_offset < current_offset && 1311107534Sgrog seen_default_offset && i != RAW_PART && 1312107534Sgrog pp->p_fstype != FS_VINUM) { 131373034Sjwd fprintf(stderr, 131494065Sphk"Offset %ld for partition %c overlaps previous partition which ends at %lu\n", 131594065Sphk (long)pp->p_offset,i+'a',current_offset); 131673034Sjwd fprintf(stderr, 131773034Sjwd"Labels with any *'s for offset must be in ascending order by sector\n"); 131873034Sjwd errors++; 131973034Sjwd } else if (pp->p_offset != current_offset && 132094065Sphk i != RAW_PART && seen_default_offset) { 132173034Sjwd /* 132273034Sjwd * this may give unneeded warnings if 132373034Sjwd * partitions are out-of-order 132473034Sjwd */ 132573034Sjwd Warning( 132673034Sjwd"Offset %ld for partition %c doesn't match expected value %ld", 132794065Sphk (long)pp->p_offset, i + 'a', current_offset); 132873034Sjwd } 132973034Sjwd } 133094065Sphk if (i != RAW_PART) 133173034Sjwd current_offset = pp->p_offset + pp->p_size; 133273034Sjwd } 133373034Sjwd } 133473034Sjwd 133573034Sjwd for (i = 0; i < lp->d_npartitions; i++) { 133673034Sjwd part = 'a' + i; 133773034Sjwd pp = &lp->d_partitions[i]; 13381558Srgrimes if (pp->p_size == 0 && pp->p_offset != 0) 133937234Sbde Warning("partition %c: size 0, but offset %lu", 134037234Sbde part, (u_long)pp->p_offset); 13411558Srgrimes#ifdef notdef 13421558Srgrimes if (pp->p_size % lp->d_secpercyl) 13431558Srgrimes Warning("partition %c: size %% cylinder-size != 0", 13441558Srgrimes part); 13451558Srgrimes if (pp->p_offset % lp->d_secpercyl) 13461558Srgrimes Warning("partition %c: offset %% cylinder-size != 0", 13471558Srgrimes part); 13481558Srgrimes#endif 13491558Srgrimes if (pp->p_offset > lp->d_secperunit) { 13501558Srgrimes fprintf(stderr, 13511558Srgrimes "partition %c: offset past end of unit\n", part); 13521558Srgrimes errors++; 13531558Srgrimes } 13541558Srgrimes if (pp->p_offset + pp->p_size > lp->d_secperunit) { 13551558Srgrimes fprintf(stderr, 135613544Sjoerg "partition %c: partition extends past end of unit\n", 13571558Srgrimes part); 13581558Srgrimes errors++; 13591558Srgrimes } 136094065Sphk if (i == RAW_PART) 136173034Sjwd { 136273034Sjwd if (pp->p_fstype != FS_UNUSED) 136373034Sjwd Warning("partition %c is not marked as unused!",part); 136473034Sjwd if (pp->p_offset != 0) 136573034Sjwd Warning("partition %c doesn't start at 0!",part); 136673034Sjwd if (pp->p_size != lp->d_secperunit) 136773034Sjwd Warning("partition %c doesn't cover the whole unit!",part); 136873034Sjwd 136973034Sjwd if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) || 137073034Sjwd (pp->p_size != lp->d_secperunit)) { 137173034Sjwd Warning("An incorrect partition %c may cause problems for " 137273034Sjwd "standard system utilities",part); 137373034Sjwd } 137473034Sjwd } 137573034Sjwd 137673034Sjwd /* check for overlaps */ 137773034Sjwd /* this will check for all possible overlaps once and only once */ 137873034Sjwd for (j = 0; j < i; j++) { 1379107534Sgrog pp2 = &lp->d_partitions[j]; 1380107534Sgrog if (j != RAW_PART && i != RAW_PART && 1381107534Sgrog pp->p_fstype != FS_VINUM && 1382107534Sgrog pp2->p_fstype != FS_VINUM && 138373034Sjwd part_set[i] && part_set[j]) { 138473034Sjwd if (pp2->p_offset < pp->p_offset + pp->p_size && 138573034Sjwd (pp2->p_offset + pp2->p_size > pp->p_offset || 138673034Sjwd pp2->p_offset >= pp->p_offset)) { 138773034Sjwd fprintf(stderr,"partitions %c and %c overlap!\n", 138873034Sjwd j + 'a', i + 'a'); 138973034Sjwd errors++; 139073034Sjwd } 139173034Sjwd } 139273034Sjwd } 13931558Srgrimes } 13941558Srgrimes for (; i < MAXPARTITIONS; i++) { 13951558Srgrimes part = 'a' + i; 13961558Srgrimes pp = &lp->d_partitions[i]; 13971558Srgrimes if (pp->p_size || pp->p_offset) 139837234Sbde Warning("unused partition %c: size %d offset %lu", 139937234Sbde 'a' + i, pp->p_size, (u_long)pp->p_offset); 14001558Srgrimes } 14011558Srgrimes return (errors); 14021558Srgrimes} 14031558Srgrimes 14041558Srgrimes/* 140513550Sjoerg * When operating on a "virgin" disk, try getting an initial label 140613550Sjoerg * from the associated device driver. This might work for all device 140713550Sjoerg * drivers that are able to fetch some initial device parameters 140813550Sjoerg * without even having access to a (BSD) disklabel, like SCSI disks, 140913550Sjoerg * most IDE drives, or vn devices. 141013550Sjoerg * 141113550Sjoerg * The device name must be given in its "canonical" form. 141213550Sjoerg */ 141313550Sjoergstruct disklabel * 141413550Sjoerggetvirginlabel(void) 141513550Sjoerg{ 141699365Smarkm static struct disklabel loclab; 1417103669Sphk struct partition *dp; 141899365Smarkm char lnamebuf[BBSIZE]; 141913550Sjoerg int f; 1420103669Sphk u_int secsize, u; 1421103669Sphk off_t mediasize; 142213550Sjoerg 142313550Sjoerg if (dkname[0] == '/') { 142437773Sbde warnx("\"auto\" requires the usage of a canonical disk name"); 142516431Sbde return (NULL); 142613550Sjoerg } 142799365Smarkm (void)snprintf(lnamebuf, BBSIZE, "%s%s", _PATH_DEV, dkname); 142899365Smarkm if ((f = open(lnamebuf, O_RDONLY)) == -1) { 142999365Smarkm warn("cannot open %s", lnamebuf); 143016431Sbde return (NULL); 143113550Sjoerg } 143268044Sjkh 1433103669Sphk /* New world order */ 1434103669Sphk if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0) || 1435103669Sphk (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) { 1436103669Sphk close (f); 1437103669Sphk return (NULL); 1438103669Sphk } 1439103669Sphk memset(&loclab, 0, sizeof loclab); 1440103669Sphk loclab.d_magic = DISKMAGIC; 1441103669Sphk loclab.d_magic2 = DISKMAGIC; 1442103669Sphk loclab.d_secsize = secsize; 1443103669Sphk loclab.d_secperunit = mediasize / secsize; 1444103669Sphk 144568044Sjkh /* 1446103669Sphk * Nobody in these enligthened days uses the CHS geometry for 1447103669Sphk * anything, but nontheless try to get it right. If we fail 1448103669Sphk * to get any good ideas from the device, construct something 1449103669Sphk * which is IBM-PC friendly. 145068044Sjkh */ 1451103669Sphk if (ioctl(f, DIOCGFWSECTORS, &u) == 0) 1452103669Sphk loclab.d_nsectors = u; 1453103669Sphk else 1454103669Sphk loclab.d_nsectors = 63; 1455103669Sphk if (ioctl(f, DIOCGFWHEADS, &u) == 0) 1456103669Sphk loclab.d_ntracks = u; 1457103669Sphk else if (loclab.d_secperunit <= 63*1*1024) 1458103669Sphk loclab.d_ntracks = 1; 1459103669Sphk else if (loclab.d_secperunit <= 63*16*1024) 1460103669Sphk loclab.d_ntracks = 16; 1461103669Sphk else 1462103669Sphk loclab.d_ntracks = 255; 1463103669Sphk loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors; 1464103669Sphk loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl; 1465103669Sphk loclab.d_npartitions = MAXPARTITIONS; 1466103669Sphk 1467103669Sphk /* Various (unneeded) compat stuff */ 1468103669Sphk loclab.d_rpm = 3600; 1469103669Sphk loclab.d_bbsize = BBSIZE; 1470103669Sphk loclab.d_interleave = 1;; 1471103669Sphk strncpy(loclab.d_typename, "amnesiac", 1472103669Sphk sizeof(loclab.d_typename)); 1473103669Sphk 1474103669Sphk dp = &loclab.d_partitions[RAW_PART]; 1475103669Sphk dp->p_size = loclab.d_secperunit; 1476103669Sphk loclab.d_checksum = dkcksum(&loclab); 1477103669Sphk close (f); 147899365Smarkm return (&loclab); 147913550Sjoerg} 148013550Sjoerg 14811558Srgrimes 14821558Srgrimes/*VARARGS1*/ 148313544Sjoergvoid 148492541SimpWarning(const char *fmt, ...) 14851558Srgrimes{ 148613544Sjoerg va_list ap; 14871558Srgrimes 14881558Srgrimes fprintf(stderr, "Warning, "); 148913544Sjoerg va_start(ap, fmt); 149013544Sjoerg vfprintf(stderr, fmt, ap); 14911558Srgrimes fprintf(stderr, "\n"); 149213544Sjoerg va_end(ap); 14931558Srgrimes} 14941558Srgrimes 149513544Sjoergvoid 149692541Simpusage(void) 14971558Srgrimes{ 1498109878Sphk fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 149926542Scharnier "usage: disklabel [-r] disk", 150026542Scharnier "\t\t(to read label)", 150173034Sjwd " disklabel -w [-r] [-n] disk type [ packid ]", 150226542Scharnier "\t\t(to write label with existing boot program)", 150373034Sjwd " disklabel -e [-r] [-n] disk", 150426542Scharnier "\t\t(to edit label)", 150573034Sjwd " disklabel -R [-r] [-n] disk protofile", 150626542Scharnier "\t\t(to restore label with existing boot program)", 150773034Sjwd " disklabel -B [-n] [ -b bootprog ] disk [ type ]", 150826542Scharnier "\t\t(to install boot program with existing on-disk label)", 150973034Sjwd " disklabel -w -B [-n] [ -b bootprog ] disk type [ packid ]", 151026542Scharnier "\t\t(to write label and install boot program)", 1511111286Sru " disklabel -R -B [-n] [ -b bootprog ] disk protofile", 1512109878Sphk "\t\t(to restore label and install boot program)" 1513109878Sphk ); 15141558Srgrimes exit(1); 15151558Srgrimes} 1516