bsdlabel.c revision 59216
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1987, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * This code is derived from software contributed to Berkeley by 61558Srgrimes * Symmetric Computer Systems. 71558Srgrimes * 81558Srgrimes * Redistribution and use in source and binary forms, with or without 91558Srgrimes * modification, are permitted provided that the following conditions 101558Srgrimes * are met: 111558Srgrimes * 1. Redistributions of source code must retain the above copyright 121558Srgrimes * notice, this list of conditions and the following disclaimer. 131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141558Srgrimes * notice, this list of conditions and the following disclaimer in the 151558Srgrimes * documentation and/or other materials provided with the distribution. 161558Srgrimes * 3. All advertising materials mentioning features or use of this software 171558Srgrimes * must display the following acknowledgement: 181558Srgrimes * This product includes software developed by the University of 191558Srgrimes * California, Berkeley and its contributors. 201558Srgrimes * 4. Neither the name of the University nor the names of its contributors 211558Srgrimes * may be used to endorse or promote products derived from this software 221558Srgrimes * without specific prior written permission. 231558Srgrimes * 241558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341558Srgrimes * SUCH DAMAGE. 351558Srgrimes */ 361558Srgrimes 371558Srgrimes#ifndef lint 3836632Scharnierstatic const char copyright[] = 391558Srgrimes"@(#) Copyright (c) 1987, 1993\n\ 401558Srgrimes The Regents of the University of California. All rights reserved.\n"; 411558Srgrimes#endif /* not lint */ 421558Srgrimes 431558Srgrimes#ifndef lint 4436632Scharnier#if 0 451558Srgrimesstatic char sccsid[] = "@(#)disklabel.c 8.2 (Berkeley) 1/7/94"; 461558Srgrimes/* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */ 4736632Scharnier#endif 4836632Scharnierstatic const char rcsid[] = 4950476Speter "$FreeBSD: head/sbin/bsdlabel/bsdlabel.c 59216 2000-04-14 06:15:01Z imp $"; 501558Srgrimes#endif /* not lint */ 511558Srgrimes 521558Srgrimes#include <sys/param.h> 531558Srgrimes#include <sys/file.h> 541558Srgrimes#include <sys/stat.h> 5513544Sjoerg#include <sys/wait.h> 561558Srgrimes#define DKTYPENAMES 571558Srgrimes#include <sys/disklabel.h> 581558Srgrimes#include <ufs/ffs/fs.h> 591558Srgrimes#include <unistd.h> 601558Srgrimes#include <string.h> 611558Srgrimes#include <stdio.h> 6213544Sjoerg#include <stdlib.h> 6313544Sjoerg#include <signal.h> 6413544Sjoerg#include <stdarg.h> 651558Srgrimes#include <ctype.h> 6626542Scharnier#include <err.h> 6759216Simp#include <errno.h> 681558Srgrimes#include "pathnames.h" 691558Srgrimes 701558Srgrimes/* 711558Srgrimes * Disklabel: read and write disklabels. 721558Srgrimes * The label is usually placed on one of the first sectors of the disk. 731558Srgrimes * Many machines also place a bootstrap in the same area, 741558Srgrimes * in which case the label is embedded in the bootstrap. 751558Srgrimes * The bootstrap source must leave space at the proper offset 761558Srgrimes * for the label on such machines. 771558Srgrimes */ 781558Srgrimes 791558Srgrimes#ifndef BBSIZE 801558Srgrimes#define BBSIZE 8192 /* size of boot area, with label */ 811558Srgrimes#endif 821558Srgrimes 831558Srgrimes#ifdef tahoe 841558Srgrimes#define NUMBOOT 0 851558Srgrimes#else 8638411Sbde#if defined(__alpha__) || defined(hp300) || defined(hp800) 871558Srgrimes#define NUMBOOT 1 881558Srgrimes#else 891558Srgrimes#define NUMBOOT 2 901558Srgrimes#endif 911558Srgrimes#endif 921558Srgrimes 9313544Sjoergvoid makelabel __P((char *, char *, struct disklabel *)); 9413544Sjoergint writelabel __P((int, char *, struct disklabel *)); 9513544Sjoergvoid l_perror __P((char *)); 9613544Sjoergstruct disklabel * readlabel __P((int)); 9713544Sjoergstruct disklabel * makebootarea __P((char *, struct disklabel *, int)); 9813544Sjoergvoid display __P((FILE *, struct disklabel *)); 9913544Sjoergint edit __P((struct disklabel *, int)); 10013544Sjoergint editit __P((void)); 10113544Sjoergchar * skip __P((char *)); 10213544Sjoergchar * word __P((char *)); 10313544Sjoergint getasciilabel __P((FILE *, struct disklabel *)); 10413544Sjoergint checklabel __P((struct disklabel *)); 10513544Sjoergvoid setbootflag __P((struct disklabel *)); 10613544Sjoergvoid Warning (char *, ...); 10713544Sjoergvoid usage __P((void)); 10813544Sjoergextern u_short dkcksum __P((struct disklabel *)); 10913550Sjoergstruct disklabel * getvirginlabel __P((void)); 11013544Sjoerg 1111558Srgrimes#define DEFEDITOR _PATH_VI 1121558Srgrimes#define streq(a,b) (strcmp(a,b) == 0) 1131558Srgrimes 1141558Srgrimeschar *dkname; 1151558Srgrimeschar *specname; 11655742Skrischar tmpfil[] = PATH_TMPFILE; 1171558Srgrimes 1181558Srgrimeschar namebuf[BBSIZE], *np = namebuf; 1191558Srgrimesstruct disklabel lab; 1201558Srgrimeschar bootarea[BBSIZE]; 1211558Srgrimes 1221558Srgrimes#if NUMBOOT > 0 1231558Srgrimesint installboot; /* non-zero if we should install a boot program */ 1241558Srgrimeschar *bootbuf; /* pointer to buffer with remainder of boot prog */ 1251558Srgrimesint bootsize; /* size of remaining boot program */ 1261558Srgrimeschar *xxboot; /* primary boot */ 1271558Srgrimeschar *bootxx; /* secondary boot */ 1281558Srgrimeschar boot0[MAXPATHLEN]; 1291558Srgrimeschar boot1[MAXPATHLEN]; 1301558Srgrimes#endif 1311558Srgrimes 1321558Srgrimesenum { 1331558Srgrimes UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT 1341558Srgrimes} op = UNSPEC; 1351558Srgrimes 1361558Srgrimesint rflag; 1371558Srgrimes 1381558Srgrimes#ifdef DEBUG 1391558Srgrimesint debug; 1401558Srgrimes#define OPTIONS "BNRWb:ders:w" 1411558Srgrimes#else 1421558Srgrimes#define OPTIONS "BNRWb:ers:w" 1431558Srgrimes#endif 1441558Srgrimes 14513544Sjoergint 1461558Srgrimesmain(argc, argv) 1471558Srgrimes int argc; 1481558Srgrimes char *argv[]; 1491558Srgrimes{ 1501558Srgrimes register struct disklabel *lp; 1511558Srgrimes FILE *t; 15248957Sbillf int ch, f = 0, flag, error = 0; 1531558Srgrimes char *name = 0; 1541558Srgrimes 15524359Simp while ((ch = getopt(argc, argv, OPTIONS)) != -1) 1561558Srgrimes switch (ch) { 1571558Srgrimes#if NUMBOOT > 0 1581558Srgrimes case 'B': 1591558Srgrimes ++installboot; 1601558Srgrimes break; 1611558Srgrimes case 'b': 1621558Srgrimes xxboot = optarg; 1631558Srgrimes break; 1641558Srgrimes#if NUMBOOT > 1 1651558Srgrimes case 's': 1661558Srgrimes bootxx = optarg; 1671558Srgrimes break; 1681558Srgrimes#endif 1691558Srgrimes#endif 1701558Srgrimes case 'N': 1711558Srgrimes if (op != UNSPEC) 1721558Srgrimes usage(); 1731558Srgrimes op = NOWRITE; 1741558Srgrimes break; 1751558Srgrimes case 'R': 1761558Srgrimes if (op != UNSPEC) 1771558Srgrimes usage(); 1781558Srgrimes op = RESTORE; 1791558Srgrimes break; 1801558Srgrimes case 'W': 1811558Srgrimes if (op != UNSPEC) 1821558Srgrimes usage(); 1831558Srgrimes op = WRITEABLE; 1841558Srgrimes break; 1851558Srgrimes case 'e': 1861558Srgrimes if (op != UNSPEC) 1871558Srgrimes usage(); 1881558Srgrimes op = EDIT; 1891558Srgrimes break; 1901558Srgrimes case 'r': 1911558Srgrimes ++rflag; 1921558Srgrimes break; 1931558Srgrimes case 'w': 1941558Srgrimes if (op != UNSPEC) 1951558Srgrimes usage(); 1961558Srgrimes op = WRITE; 1971558Srgrimes break; 1981558Srgrimes#ifdef DEBUG 1991558Srgrimes case 'd': 2001558Srgrimes debug++; 2011558Srgrimes break; 2021558Srgrimes#endif 2031558Srgrimes case '?': 2041558Srgrimes default: 2051558Srgrimes usage(); 2061558Srgrimes } 2071558Srgrimes argc -= optind; 2081558Srgrimes argv += optind; 2091558Srgrimes#if NUMBOOT > 0 2101558Srgrimes if (installboot) { 2111558Srgrimes rflag++; 2121558Srgrimes if (op == UNSPEC) 2131558Srgrimes op = WRITEBOOT; 2141558Srgrimes } else { 2151558Srgrimes if (op == UNSPEC) 2161558Srgrimes op = READ; 2171558Srgrimes xxboot = bootxx = 0; 2181558Srgrimes } 2191558Srgrimes#else 2201558Srgrimes if (op == UNSPEC) 2211558Srgrimes op = READ; 2221558Srgrimes#endif 2231558Srgrimes if (argc < 1) 2241558Srgrimes usage(); 2251558Srgrimes 2261558Srgrimes dkname = argv[0]; 2271558Srgrimes if (dkname[0] != '/') { 22859114Sobrien (void)sprintf(np, "%s%s%c", _PATH_DEV, dkname, 'a' + RAW_PART); 2291558Srgrimes specname = np; 2301558Srgrimes np += strlen(specname) + 1; 2311558Srgrimes } else 2321558Srgrimes specname = dkname; 2331558Srgrimes f = open(specname, op == READ ? O_RDONLY : O_RDWR); 2341558Srgrimes if (f < 0 && errno == ENOENT && dkname[0] != '/') { 2351558Srgrimes (void)sprintf(specname, "%sr%s", _PATH_DEV, dkname); 2361558Srgrimes np = namebuf + strlen(specname) + 1; 2371558Srgrimes f = open(specname, op == READ ? O_RDONLY : O_RDWR); 2381558Srgrimes } 2391558Srgrimes if (f < 0) 24026542Scharnier err(4, "%s", specname); 2411558Srgrimes 2421558Srgrimes switch(op) { 2431558Srgrimes 24448957Sbillf case UNSPEC: 24548957Sbillf break; 24648957Sbillf 2471558Srgrimes case EDIT: 2481558Srgrimes if (argc != 1) 2491558Srgrimes usage(); 2501558Srgrimes lp = readlabel(f); 2511558Srgrimes error = edit(lp, f); 2521558Srgrimes break; 2531558Srgrimes 2541558Srgrimes case NOWRITE: 2551558Srgrimes flag = 0; 2561558Srgrimes if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) 25726542Scharnier err(4, "ioctl DIOCWLABEL"); 2581558Srgrimes break; 2591558Srgrimes 2601558Srgrimes case READ: 2611558Srgrimes if (argc != 1) 2621558Srgrimes usage(); 2631558Srgrimes lp = readlabel(f); 2641558Srgrimes display(stdout, lp); 2651558Srgrimes error = checklabel(lp); 2661558Srgrimes break; 2671558Srgrimes 2681558Srgrimes case RESTORE: 2691558Srgrimes#if NUMBOOT > 0 2701558Srgrimes if (installboot && argc == 3) { 2711558Srgrimes makelabel(argv[2], 0, &lab); 2721558Srgrimes argc--; 27337865Sbde 27437865Sbde /* 27537865Sbde * We only called makelabel() for its side effect 27637865Sbde * of setting the bootstrap file names. Discard 27737865Sbde * all changes to `lab' so that all values in the 27837865Sbde * final label come from the ASCII label. 27937865Sbde */ 28037865Sbde bzero((char *)&lab, sizeof(lab)); 2811558Srgrimes } 2821558Srgrimes#endif 2831558Srgrimes if (argc != 2) 2841558Srgrimes usage(); 2851558Srgrimes if (!(t = fopen(argv[1], "r"))) 28626542Scharnier err(4, "%s", argv[1]); 28737865Sbde if (!getasciilabel(t, &lab)) 28837865Sbde exit(1); 28937865Sbde lp = makebootarea(bootarea, &lab, f); 29037865Sbde *lp = lab; 29137865Sbde error = writelabel(f, bootarea, lp); 2921558Srgrimes break; 2931558Srgrimes 2941558Srgrimes case WRITE: 2951558Srgrimes if (argc == 3) { 2961558Srgrimes name = argv[2]; 2971558Srgrimes argc--; 2981558Srgrimes } 2991558Srgrimes if (argc != 2) 3001558Srgrimes usage(); 3011558Srgrimes makelabel(argv[1], name, &lab); 3021558Srgrimes lp = makebootarea(bootarea, &lab, f); 3031558Srgrimes *lp = lab; 3041558Srgrimes if (checklabel(lp) == 0) 3051558Srgrimes error = writelabel(f, bootarea, lp); 3061558Srgrimes break; 3071558Srgrimes 3081558Srgrimes case WRITEABLE: 3091558Srgrimes flag = 1; 3101558Srgrimes if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) 31126542Scharnier err(4, "ioctl DIOCWLABEL"); 3121558Srgrimes break; 3131558Srgrimes 3141558Srgrimes#if NUMBOOT > 0 3151558Srgrimes case WRITEBOOT: 3161558Srgrimes { 3171558Srgrimes struct disklabel tlab; 3181558Srgrimes 3191558Srgrimes lp = readlabel(f); 3201558Srgrimes tlab = *lp; 3211558Srgrimes if (argc == 2) 3221558Srgrimes makelabel(argv[1], 0, &lab); 3231558Srgrimes lp = makebootarea(bootarea, &lab, f); 3241558Srgrimes *lp = tlab; 3251558Srgrimes if (checklabel(lp) == 0) 3261558Srgrimes error = writelabel(f, bootarea, lp); 3271558Srgrimes break; 3281558Srgrimes } 3291558Srgrimes#endif 3301558Srgrimes } 3311558Srgrimes exit(error); 3321558Srgrimes} 3331558Srgrimes 3341558Srgrimes/* 3351558Srgrimes * Construct a prototype disklabel from /etc/disktab. As a side 3361558Srgrimes * effect, set the names of the primary and secondary boot files 3371558Srgrimes * if specified. 3381558Srgrimes */ 33913544Sjoergvoid 3401558Srgrimesmakelabel(type, name, lp) 3411558Srgrimes char *type, *name; 3421558Srgrimes register struct disklabel *lp; 3431558Srgrimes{ 3441558Srgrimes register struct disklabel *dp; 34513550Sjoerg 34613550Sjoerg if (strcmp(type, "auto") == 0) 34713550Sjoerg dp = getvirginlabel(); 34813550Sjoerg else 34913544Sjoerg dp = getdiskbyname(type); 35036632Scharnier if (dp == NULL) 35136632Scharnier errx(1, "%s: unknown disk type", type); 3521558Srgrimes *lp = *dp; 3531558Srgrimes#if NUMBOOT > 0 3541558Srgrimes /* 3551558Srgrimes * Set bootstrap name(s). 3561558Srgrimes * 1. If set from command line, use those, 3571558Srgrimes * 2. otherwise, check if disktab specifies them (b0 or b1), 3581558Srgrimes * 3. otherwise, makebootarea() will choose ones based on the name 3591558Srgrimes * of the disk special file. E.g. /dev/ra0 -> raboot, bootra 3601558Srgrimes */ 3611558Srgrimes if (!xxboot && lp->d_boot0) { 3621558Srgrimes if (*lp->d_boot0 != '/') 3631558Srgrimes (void)sprintf(boot0, "%s/%s", 3641558Srgrimes _PATH_BOOTDIR, lp->d_boot0); 3651558Srgrimes else 3661558Srgrimes (void)strcpy(boot0, lp->d_boot0); 3671558Srgrimes xxboot = boot0; 3681558Srgrimes } 3691558Srgrimes#if NUMBOOT > 1 3701558Srgrimes if (!bootxx && lp->d_boot1) { 3711558Srgrimes if (*lp->d_boot1 != '/') 3721558Srgrimes (void)sprintf(boot1, "%s/%s", 3731558Srgrimes _PATH_BOOTDIR, lp->d_boot1); 3741558Srgrimes else 3751558Srgrimes (void)strcpy(boot1, lp->d_boot1); 3761558Srgrimes bootxx = boot1; 3771558Srgrimes } 3781558Srgrimes#endif 3791558Srgrimes#endif 3801558Srgrimes /* d_packname is union d_boot[01], so zero */ 3811558Srgrimes bzero(lp->d_packname, sizeof(lp->d_packname)); 3821558Srgrimes if (name) 3831558Srgrimes (void)strncpy(lp->d_packname, name, sizeof(lp->d_packname)); 3841558Srgrimes} 3851558Srgrimes 38613544Sjoergint 3871558Srgrimeswritelabel(f, boot, lp) 3881558Srgrimes int f; 3891558Srgrimes char *boot; 3901558Srgrimes register struct disklabel *lp; 3911558Srgrimes{ 3921558Srgrimes int flag; 39338384Sdfr#ifdef __alpha__ 39438384Sdfr u_long *p, sum; 39538384Sdfr int i; 39638384Sdfr#endif 39738411Sbde#ifdef vax 39838411Sbde register int i; 39938411Sbde#endif 40038384Sdfr 4011558Srgrimes setbootflag(lp); 4021558Srgrimes lp->d_magic = DISKMAGIC; 4031558Srgrimes lp->d_magic2 = DISKMAGIC; 4041558Srgrimes lp->d_checksum = 0; 4051558Srgrimes lp->d_checksum = dkcksum(lp); 4061558Srgrimes if (rflag) { 4071558Srgrimes /* 4081558Srgrimes * First set the kernel disk label, 4091558Srgrimes * then write a label to the raw disk. 4101558Srgrimes * If the SDINFO ioctl fails because it is unimplemented, 4111558Srgrimes * keep going; otherwise, the kernel consistency checks 4121558Srgrimes * may prevent us from changing the current (in-core) 4131558Srgrimes * label. 4141558Srgrimes */ 4151558Srgrimes if (ioctl(f, DIOCSDINFO, lp) < 0 && 4161558Srgrimes errno != ENODEV && errno != ENOTTY) { 4171558Srgrimes l_perror("ioctl DIOCSDINFO"); 4181558Srgrimes return (1); 4191558Srgrimes } 4201558Srgrimes (void)lseek(f, (off_t)0, SEEK_SET); 42138411Sbde 42238411Sbde#ifdef __alpha__ 4231558Srgrimes /* 42438411Sbde * Generate the bootblock checksum for the SRM console. 4251558Srgrimes */ 42638384Sdfr for (p = (u_long *)boot, i = 0, sum = 0; i < 63; i++) 42738411Sbde sum += p[i]; 42838384Sdfr p[63] = sum; 42938384Sdfr#endif 43038384Sdfr 43138411Sbde /* 43238411Sbde * write enable label sector before write (if necessary), 43338411Sbde * disable after writing. 43438411Sbde */ 43538411Sbde flag = 1; 4361558Srgrimes if (ioctl(f, DIOCWLABEL, &flag) < 0) 43736632Scharnier warn("ioctl DIOCWLABEL"); 4381558Srgrimes if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) { 43936632Scharnier warn("write"); 4401558Srgrimes return (1); 4411558Srgrimes } 4421558Srgrimes#if NUMBOOT > 0 4431558Srgrimes /* 4441558Srgrimes * Output the remainder of the disklabel 4451558Srgrimes */ 4461558Srgrimes if (bootbuf && write(f, bootbuf, bootsize) != bootsize) { 44736632Scharnier warn("write"); 4481558Srgrimes return(1); 4491558Srgrimes } 4501558Srgrimes#endif 4511558Srgrimes flag = 0; 4521558Srgrimes (void) ioctl(f, DIOCWLABEL, &flag); 4531558Srgrimes } else if (ioctl(f, DIOCWDINFO, lp) < 0) { 4541558Srgrimes l_perror("ioctl DIOCWDINFO"); 4551558Srgrimes return (1); 4561558Srgrimes } 4571558Srgrimes#ifdef vax 4581558Srgrimes if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { 4591558Srgrimes daddr_t alt; 4601558Srgrimes 4611558Srgrimes alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; 4621558Srgrimes for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { 4631558Srgrimes (void)lseek(f, (off_t)((alt + i) * lp->d_secsize), 4641558Srgrimes SEEK_SET); 46536632Scharnier if (write(f, boot, lp->d_secsize) < lp->d_secsize) 46636632Scharnier warn("alternate label %d write", i/2); 4671558Srgrimes } 4681558Srgrimes } 4691558Srgrimes#endif 4701558Srgrimes return (0); 4711558Srgrimes} 4721558Srgrimes 47313544Sjoergvoid 4741558Srgrimesl_perror(s) 4751558Srgrimes char *s; 4761558Srgrimes{ 47736632Scharnier switch (errno) { 4781558Srgrimes 4791558Srgrimes case ESRCH: 48036756Scharnier warnx("%s: no disk label on disk;", s); 48136756Scharnier fprintf(stderr, 48240475Sbde "use \"disklabel -r\" to install initial label\n"); 4831558Srgrimes break; 4841558Srgrimes 4851558Srgrimes case EINVAL: 48636756Scharnier warnx("%s: label magic number or checksum is wrong!", s); 48736756Scharnier fprintf(stderr, "(disklabel or kernel is out of date?)\n"); 4881558Srgrimes break; 4891558Srgrimes 4901558Srgrimes case EBUSY: 49136632Scharnier warnx("%s: open partition would move or shrink", s); 4921558Srgrimes break; 4931558Srgrimes 4941558Srgrimes case EXDEV: 49540475Sbde warnx("%s: '%c' partition must start at beginning of disk", 49640475Sbde s, 'a' + RAW_PART); 4971558Srgrimes break; 4981558Srgrimes 4991558Srgrimes default: 50036632Scharnier warn((char *)NULL); 5011558Srgrimes break; 5021558Srgrimes } 5031558Srgrimes} 5041558Srgrimes 5051558Srgrimes/* 5061558Srgrimes * Fetch disklabel for disk. 5071558Srgrimes * Use ioctl to get label unless -r flag is given. 5081558Srgrimes */ 5091558Srgrimesstruct disklabel * 5101558Srgrimesreadlabel(f) 5111558Srgrimes int f; 5121558Srgrimes{ 5131558Srgrimes register struct disklabel *lp; 5141558Srgrimes 5151558Srgrimes if (rflag) { 5161558Srgrimes if (read(f, bootarea, BBSIZE) < BBSIZE) 51726542Scharnier err(4, "%s", specname); 5181558Srgrimes for (lp = (struct disklabel *)bootarea; 5191558Srgrimes lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp)); 5201558Srgrimes lp = (struct disklabel *)((char *)lp + 16)) 5211558Srgrimes if (lp->d_magic == DISKMAGIC && 5221558Srgrimes lp->d_magic2 == DISKMAGIC) 5231558Srgrimes break; 5241558Srgrimes if (lp > (struct disklabel *)(bootarea+BBSIZE-sizeof(*lp)) || 5251558Srgrimes lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC || 52636756Scharnier dkcksum(lp) != 0) 52736756Scharnier errx(1, 52836756Scharnier "bad pack magic number (label is damaged, or pack is unlabeled)"); 5291558Srgrimes } else { 5301558Srgrimes lp = &lab; 5311558Srgrimes if (ioctl(f, DIOCGDINFO, lp) < 0) 53226542Scharnier err(4, "ioctl DIOCGDINFO"); 5331558Srgrimes } 5341558Srgrimes return (lp); 5351558Srgrimes} 5361558Srgrimes 5371558Srgrimes/* 5381558Srgrimes * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot'' 5391558Srgrimes * Returns a pointer to the disklabel portion of the bootarea. 5401558Srgrimes */ 5411558Srgrimesstruct disklabel * 5421558Srgrimesmakebootarea(boot, dp, f) 5431558Srgrimes char *boot; 5441558Srgrimes register struct disklabel *dp; 5451558Srgrimes int f; 5461558Srgrimes{ 54738483Sbde struct disklabel *lp; 5481558Srgrimes register char *p; 5491558Srgrimes int b; 5501558Srgrimes#if NUMBOOT > 0 5511558Srgrimes char *dkbasename; 5521558Srgrimes struct stat sb; 55338411Sbde#endif 55438411Sbde#ifdef __alpha__ 55538483Sbde u_long *bootinfo; 55638411Sbde int n; 55738411Sbde#endif 55813892Sjoerg#ifdef __i386__ 55913892Sjoerg char *tmpbuf; 56013892Sjoerg int i, found; 56113544Sjoerg#endif 5621558Srgrimes 5631558Srgrimes /* XXX */ 5641558Srgrimes if (dp->d_secsize == 0) { 5651558Srgrimes dp->d_secsize = DEV_BSIZE; 5661558Srgrimes dp->d_bbsize = BBSIZE; 5671558Srgrimes } 5681558Srgrimes lp = (struct disklabel *) 5691558Srgrimes (boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET); 5701558Srgrimes bzero((char *)lp, sizeof *lp); 5711558Srgrimes#if NUMBOOT > 0 5721558Srgrimes /* 5731558Srgrimes * If we are not installing a boot program but we are installing a 5741558Srgrimes * label on disk then we must read the current bootarea so we don't 5751558Srgrimes * clobber the existing boot. 5761558Srgrimes */ 5771558Srgrimes if (!installboot) { 5781558Srgrimes if (rflag) { 5791558Srgrimes if (read(f, boot, BBSIZE) < BBSIZE) 58026542Scharnier err(4, "%s", specname); 5811558Srgrimes bzero((char *)lp, sizeof *lp); 5821558Srgrimes } 5831558Srgrimes return (lp); 5841558Srgrimes } 5851558Srgrimes /* 5861558Srgrimes * We are installing a boot program. Determine the name(s) and 5871558Srgrimes * read them into the appropriate places in the boot area. 5881558Srgrimes */ 5891558Srgrimes if (!xxboot || !bootxx) { 5901558Srgrimes dkbasename = np; 5911558Srgrimes if ((p = rindex(dkname, '/')) == NULL) 5921558Srgrimes p = dkname; 5931558Srgrimes else 5941558Srgrimes p++; 5951558Srgrimes while (*p && !isdigit(*p)) 5961558Srgrimes *np++ = *p++; 5971558Srgrimes *np++ = '\0'; 5981558Srgrimes 5991558Srgrimes if (!xxboot) { 60041901Sjkh (void)sprintf(boot0, "%s/boot1", _PATH_BOOTDIR); 60141901Sjkh xxboot = boot0; 6021558Srgrimes } 6031558Srgrimes#if NUMBOOT > 1 6041558Srgrimes if (!bootxx) { 60541901Sjkh (void)sprintf(boot1, "%s/boot2", _PATH_BOOTDIR); 60641901Sjkh bootxx = boot1; 6071558Srgrimes } 6081558Srgrimes#endif 6091558Srgrimes } 6101558Srgrimes#ifdef DEBUG 6111558Srgrimes if (debug) 6121558Srgrimes fprintf(stderr, "bootstraps: xxboot = %s, bootxx = %s\n", 6131558Srgrimes xxboot, bootxx ? bootxx : "NONE"); 6141558Srgrimes#endif 6151558Srgrimes 6161558Srgrimes /* 6171558Srgrimes * Strange rules: 6181558Srgrimes * 1. One-piece bootstrap (hp300/hp800) 6191558Srgrimes * up to d_bbsize bytes of ``xxboot'' go in bootarea, the rest 6201558Srgrimes * is remembered and written later following the bootarea. 6211558Srgrimes * 2. Two-piece bootstraps (vax/i386?/mips?) 6221558Srgrimes * up to d_secsize bytes of ``xxboot'' go in first d_secsize 6231558Srgrimes * bytes of bootarea, remaining d_bbsize-d_secsize filled 6241558Srgrimes * from ``bootxx''. 6251558Srgrimes */ 6261558Srgrimes b = open(xxboot, O_RDONLY); 6271558Srgrimes if (b < 0) 62826542Scharnier err(4, "%s", xxboot); 6291558Srgrimes#if NUMBOOT > 1 63013892Sjoerg#ifdef __i386__ 63113892Sjoerg /* 63213892Sjoerg * XXX Botch alert. 63313892Sjoerg * The i386 has the so-called fdisk table embedded into the 63413892Sjoerg * primary bootstrap. We take care to not clobber it, but 63513892Sjoerg * only if it does already contain some data. (Otherwise, 63613892Sjoerg * the xxboot provides a template.) 63713892Sjoerg */ 63813892Sjoerg if ((tmpbuf = (char *)malloc((int)dp->d_secsize)) == 0) 63926542Scharnier err(4, "%s", xxboot); 64013892Sjoerg memcpy((void *)tmpbuf, (void *)boot, (int)dp->d_secsize); 64113892Sjoerg#endif /* i386 */ 6421558Srgrimes if (read(b, boot, (int)dp->d_secsize) < 0) 64326542Scharnier err(4, "%s", xxboot); 6441558Srgrimes (void)close(b); 64513892Sjoerg#ifdef __i386__ 64613892Sjoerg for (i = DOSPARTOFF, found = 0; 64713892Sjoerg !found && i < DOSPARTOFF + NDOSPART*sizeof(struct dos_partition); 64813892Sjoerg i++) 64913892Sjoerg found = tmpbuf[i] != 0; 65013892Sjoerg if (found) 65113892Sjoerg memcpy((void *)&boot[DOSPARTOFF], 65213892Sjoerg (void *)&tmpbuf[DOSPARTOFF], 65313892Sjoerg NDOSPART * sizeof(struct dos_partition)); 65413892Sjoerg free(tmpbuf); 65513892Sjoerg#endif /* i386 */ 6561558Srgrimes b = open(bootxx, O_RDONLY); 6571558Srgrimes if (b < 0) 65826542Scharnier err(4, "%s", bootxx); 65937865Sbde if (fstat(b, &sb) != 0) 66037865Sbde err(4, "%s", bootxx); 66137865Sbde if (dp->d_secsize + sb.st_size > dp->d_bbsize) 66237865Sbde errx(4, "%s too large", bootxx); 66313544Sjoerg if (read(b, &boot[dp->d_secsize], 66413544Sjoerg (int)(dp->d_bbsize-dp->d_secsize)) < 0) 66526542Scharnier err(4, "%s", bootxx); 66638411Sbde#else /* !(NUMBOOT > 1) */ 66738384Sdfr#ifdef __alpha__ 66838411Sbde /* 66938411Sbde * On the alpha, the primary bootstrap starts at the 67038411Sbde * second sector of the boot area. The first sector 67138411Sbde * contains the label and must be edited to contain the 67238411Sbde * size and location of the primary bootstrap. 67338411Sbde */ 67438411Sbde n = read(b, boot + dp->d_secsize, (int)dp->d_bbsize); 67538411Sbde if (n < 0) 67638384Sdfr err(4, "%s", xxboot); 67738483Sbde bootinfo = (u_long *)(boot + 480); 67838483Sbde bootinfo[0] = (n + dp->d_secsize - 1) / dp->d_secsize; 67938483Sbde bootinfo[1] = 1; /* start at sector 1 */ 68038483Sbde bootinfo[2] = 0; /* flags (must be zero) */ 68138411Sbde#else /* !__alpha__ */ 6821558Srgrimes if (read(b, boot, (int)dp->d_bbsize) < 0) 68326542Scharnier err(4, "%s", xxboot); 68438411Sbde#endif /* __alpha__ */ 68537865Sbde if (fstat(b, &sb) != 0) 68637865Sbde err(4, "%s", xxboot); 6871558Srgrimes bootsize = (int)sb.st_size - dp->d_bbsize; 6881558Srgrimes if (bootsize > 0) { 6891558Srgrimes /* XXX assume d_secsize is a power of two */ 6901558Srgrimes bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1); 6911558Srgrimes bootbuf = (char *)malloc((size_t)bootsize); 6921558Srgrimes if (bootbuf == 0) 69326542Scharnier err(4, "%s", xxboot); 6941558Srgrimes if (read(b, bootbuf, bootsize) < 0) { 6951558Srgrimes free(bootbuf); 69626542Scharnier err(4, "%s", xxboot); 6971558Srgrimes } 6981558Srgrimes } 69938411Sbde#endif /* NUMBOOT > 1 */ 7001558Srgrimes (void)close(b); 70138411Sbde#endif /* NUMBOOT > 0 */ 7021558Srgrimes /* 7031558Srgrimes * Make sure no part of the bootstrap is written in the area 7041558Srgrimes * reserved for the label. 7051558Srgrimes */ 7061558Srgrimes for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++) 70736632Scharnier if (*p) 70836632Scharnier errx(2, "bootstrap doesn't leave room for disk label"); 7091558Srgrimes return (lp); 7101558Srgrimes} 7111558Srgrimes 71213544Sjoergvoid 7131558Srgrimesdisplay(f, lp) 7141558Srgrimes FILE *f; 7151558Srgrimes register struct disklabel *lp; 7161558Srgrimes{ 7171558Srgrimes register int i, j; 7181558Srgrimes register struct partition *pp; 7191558Srgrimes 7201558Srgrimes fprintf(f, "# %s:\n", specname); 7211558Srgrimes if ((unsigned) lp->d_type < DKMAXTYPES) 7221558Srgrimes fprintf(f, "type: %s\n", dktypenames[lp->d_type]); 7231558Srgrimes else 72437234Sbde fprintf(f, "type: %u\n", lp->d_type); 72513544Sjoerg fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename), 72613544Sjoerg lp->d_typename); 72713544Sjoerg fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname), 72813544Sjoerg lp->d_packname); 7291558Srgrimes fprintf(f, "flags:"); 7301558Srgrimes if (lp->d_flags & D_REMOVABLE) 7311558Srgrimes fprintf(f, " removeable"); 7321558Srgrimes if (lp->d_flags & D_ECC) 7331558Srgrimes fprintf(f, " ecc"); 7341558Srgrimes if (lp->d_flags & D_BADSECT) 7351558Srgrimes fprintf(f, " badsect"); 7361558Srgrimes fprintf(f, "\n"); 73737234Sbde fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize); 73837234Sbde fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors); 73937234Sbde fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks); 74037234Sbde fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl); 74137234Sbde fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders); 74237234Sbde fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit); 74337234Sbde fprintf(f, "rpm: %u\n", lp->d_rpm); 74437234Sbde fprintf(f, "interleave: %u\n", lp->d_interleave); 74537234Sbde fprintf(f, "trackskew: %u\n", lp->d_trackskew); 74637234Sbde fprintf(f, "cylinderskew: %u\n", lp->d_cylskew); 74737234Sbde fprintf(f, "headswitch: %lu\t\t# milliseconds\n", 74837234Sbde (u_long)lp->d_headswitch); 74913544Sjoerg fprintf(f, "track-to-track seek: %ld\t# milliseconds\n", 75037234Sbde (u_long)lp->d_trkseek); 7511558Srgrimes fprintf(f, "drivedata: "); 7521558Srgrimes for (i = NDDATA - 1; i >= 0; i--) 7531558Srgrimes if (lp->d_drivedata[i]) 7541558Srgrimes break; 7551558Srgrimes if (i < 0) 7561558Srgrimes i = 0; 7571558Srgrimes for (j = 0; j <= i; j++) 75837234Sbde fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]); 75937234Sbde fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions); 7601558Srgrimes fprintf(f, 7615393Sgibbs "# size offset fstype [fsize bsize bps/cpg]\n"); 7621558Srgrimes pp = lp->d_partitions; 7631558Srgrimes for (i = 0; i < lp->d_npartitions; i++, pp++) { 7641558Srgrimes if (pp->p_size) { 76537234Sbde fprintf(f, " %c: %8lu %8lu ", 'a' + i, 76637234Sbde (u_long)pp->p_size, (u_long)pp->p_offset); 7671558Srgrimes if ((unsigned) pp->p_fstype < FSMAXTYPES) 7681558Srgrimes fprintf(f, "%8.8s", fstypenames[pp->p_fstype]); 7691558Srgrimes else 7701558Srgrimes fprintf(f, "%8d", pp->p_fstype); 7711558Srgrimes switch (pp->p_fstype) { 7721558Srgrimes 7731558Srgrimes case FS_UNUSED: /* XXX */ 77437234Sbde fprintf(f, " %5lu %5lu %5.5s ", 77537234Sbde (u_long)pp->p_fsize, 77637234Sbde (u_long)(pp->p_fsize * pp->p_frag), ""); 7771558Srgrimes break; 7781558Srgrimes 7791558Srgrimes case FS_BSDFFS: 78037234Sbde fprintf(f, " %5lu %5lu %5u ", 78137234Sbde (u_long)pp->p_fsize, 78237234Sbde (u_long)(pp->p_fsize * pp->p_frag), 7831558Srgrimes pp->p_cpg); 7841558Srgrimes break; 7851558Srgrimes 7865393Sgibbs case FS_BSDLFS: 78737234Sbde fprintf(f, " %5lu %5lu %5d", 78837234Sbde (u_long)pp->p_fsize, 78937234Sbde (u_long)(pp->p_fsize * pp->p_frag), 7905393Sgibbs pp->p_cpg); 7915393Sgibbs break; 7925393Sgibbs 7931558Srgrimes default: 7941558Srgrimes fprintf(f, "%20.20s", ""); 7951558Srgrimes break; 7961558Srgrimes } 79737234Sbde fprintf(f, "\t# (Cyl. %4lu", 79837234Sbde (u_long)(pp->p_offset / lp->d_secpercyl)); 7991558Srgrimes if (pp->p_offset % lp->d_secpercyl) 8001558Srgrimes putc('*', f); 8011558Srgrimes else 8021558Srgrimes putc(' ', f); 80337234Sbde fprintf(f, "- %lu", 80437234Sbde (u_long)((pp->p_offset + pp->p_size + 80537234Sbde lp->d_secpercyl - 1) / 80637234Sbde lp->d_secpercyl - 1)); 8071558Srgrimes if (pp->p_size % lp->d_secpercyl) 8081558Srgrimes putc('*', f); 8091558Srgrimes fprintf(f, ")\n"); 8101558Srgrimes } 8111558Srgrimes } 8121558Srgrimes fflush(f); 8131558Srgrimes} 8141558Srgrimes 81513544Sjoergint 8161558Srgrimesedit(lp, f) 8171558Srgrimes struct disklabel *lp; 8181558Srgrimes int f; 8191558Srgrimes{ 82024180Simp register int c, fd; 8211558Srgrimes struct disklabel label; 82224180Simp FILE *fp; 8231558Srgrimes 82424180Simp if ((fd = mkstemp(tmpfil)) == -1 || 82524180Simp (fp = fdopen(fd, "w")) == NULL) { 82636632Scharnier warnx("can't create %s", tmpfil); 8271558Srgrimes return (1); 8281558Srgrimes } 82924180Simp display(fp, lp); 83024180Simp fclose(fp); 8311558Srgrimes for (;;) { 8321558Srgrimes if (!editit()) 8331558Srgrimes break; 83424180Simp fp = fopen(tmpfil, "r"); 83524180Simp if (fp == NULL) { 83636632Scharnier warnx("can't reopen %s for reading", tmpfil); 8371558Srgrimes break; 8381558Srgrimes } 8391558Srgrimes bzero((char *)&label, sizeof(label)); 84024180Simp if (getasciilabel(fp, &label)) { 8411558Srgrimes *lp = label; 8421558Srgrimes if (writelabel(f, bootarea, lp) == 0) { 84324180Simp fclose(fp); 8441558Srgrimes (void) unlink(tmpfil); 8451558Srgrimes return (0); 8461558Srgrimes } 8471558Srgrimes } 84824180Simp fclose(fp); 8491558Srgrimes printf("re-edit the label? [y]: "); fflush(stdout); 8501558Srgrimes c = getchar(); 8511558Srgrimes if (c != EOF && c != (int)'\n') 8521558Srgrimes while (getchar() != (int)'\n') 8531558Srgrimes ; 8541558Srgrimes if (c == (int)'n') 8551558Srgrimes break; 8561558Srgrimes } 8571558Srgrimes (void) unlink(tmpfil); 8581558Srgrimes return (1); 8591558Srgrimes} 8601558Srgrimes 86113544Sjoergint 8621558Srgrimeseditit() 8631558Srgrimes{ 8641558Srgrimes register int pid, xpid; 8651558Srgrimes int stat, omask; 8661558Srgrimes 8671558Srgrimes omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 8681558Srgrimes while ((pid = fork()) < 0) { 8691558Srgrimes if (errno == EPROCLIM) { 87036632Scharnier warnx("you have too many processes"); 8711558Srgrimes return(0); 8721558Srgrimes } 8731558Srgrimes if (errno != EAGAIN) { 87436632Scharnier warn("fork"); 8751558Srgrimes return(0); 8761558Srgrimes } 8771558Srgrimes sleep(1); 8781558Srgrimes } 8791558Srgrimes if (pid == 0) { 8801558Srgrimes register char *ed; 8811558Srgrimes 8821558Srgrimes sigsetmask(omask); 8831558Srgrimes setgid(getgid()); 8841558Srgrimes setuid(getuid()); 8851558Srgrimes if ((ed = getenv("EDITOR")) == (char *)0) 8861558Srgrimes ed = DEFEDITOR; 8871558Srgrimes execlp(ed, ed, tmpfil, 0); 88836632Scharnier err(1, "%s", ed); 8891558Srgrimes } 8901558Srgrimes while ((xpid = wait(&stat)) >= 0) 8911558Srgrimes if (xpid == pid) 8921558Srgrimes break; 8931558Srgrimes sigsetmask(omask); 8941558Srgrimes return(!stat); 8951558Srgrimes} 8961558Srgrimes 8971558Srgrimeschar * 8981558Srgrimesskip(cp) 8991558Srgrimes register char *cp; 9001558Srgrimes{ 9011558Srgrimes 9021558Srgrimes while (*cp != '\0' && isspace(*cp)) 9031558Srgrimes cp++; 9041558Srgrimes if (*cp == '\0' || *cp == '#') 9051558Srgrimes return ((char *)NULL); 9061558Srgrimes return (cp); 9071558Srgrimes} 9081558Srgrimes 9091558Srgrimeschar * 9101558Srgrimesword(cp) 9111558Srgrimes register char *cp; 9121558Srgrimes{ 9131558Srgrimes register char c; 9141558Srgrimes 9151558Srgrimes while (*cp != '\0' && !isspace(*cp) && *cp != '#') 9161558Srgrimes cp++; 9171558Srgrimes if ((c = *cp) != '\0') { 9181558Srgrimes *cp++ = '\0'; 9191558Srgrimes if (c != '#') 9201558Srgrimes return (skip(cp)); 9211558Srgrimes } 9221558Srgrimes return ((char *)NULL); 9231558Srgrimes} 9241558Srgrimes 9251558Srgrimes/* 9261558Srgrimes * Read an ascii label in from fd f, 9271558Srgrimes * in the same format as that put out by display(), 9281558Srgrimes * and fill in lp. 9291558Srgrimes */ 93013544Sjoergint 9311558Srgrimesgetasciilabel(f, lp) 9321558Srgrimes FILE *f; 9331558Srgrimes register struct disklabel *lp; 9341558Srgrimes{ 9351558Srgrimes register char **cpp, *cp; 9361558Srgrimes register struct partition *pp; 9371558Srgrimes char *tp, *s, line[BUFSIZ]; 9381558Srgrimes int v, lineno = 0, errors = 0; 9391558Srgrimes 9401558Srgrimes lp->d_bbsize = BBSIZE; /* XXX */ 9411558Srgrimes lp->d_sbsize = SBSIZE; /* XXX */ 9421558Srgrimes while (fgets(line, sizeof(line) - 1, f)) { 9431558Srgrimes lineno++; 94413544Sjoerg if ((cp = index(line,'\n')) != 0) 9451558Srgrimes *cp = '\0'; 9461558Srgrimes cp = skip(line); 9471558Srgrimes if (cp == NULL) 9481558Srgrimes continue; 9491558Srgrimes tp = index(cp, ':'); 9501558Srgrimes if (tp == NULL) { 9511558Srgrimes fprintf(stderr, "line %d: syntax error\n", lineno); 9521558Srgrimes errors++; 9531558Srgrimes continue; 9541558Srgrimes } 9551558Srgrimes *tp++ = '\0', tp = skip(tp); 9561558Srgrimes if (streq(cp, "type")) { 9571558Srgrimes if (tp == NULL) 9581558Srgrimes tp = "unknown"; 9591558Srgrimes cpp = dktypenames; 9601558Srgrimes for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) 9611558Srgrimes if ((s = *cpp) && streq(s, tp)) { 9621558Srgrimes lp->d_type = cpp - dktypenames; 9631558Srgrimes goto next; 9641558Srgrimes } 9651558Srgrimes v = atoi(tp); 9661558Srgrimes if ((unsigned)v >= DKMAXTYPES) 9671558Srgrimes fprintf(stderr, "line %d:%s %d\n", lineno, 9681558Srgrimes "Warning, unknown disk type", v); 9691558Srgrimes lp->d_type = v; 9701558Srgrimes continue; 9711558Srgrimes } 9721558Srgrimes if (streq(cp, "flags")) { 9731558Srgrimes for (v = 0; (cp = tp) && *cp != '\0';) { 9741558Srgrimes tp = word(cp); 9751558Srgrimes if (streq(cp, "removeable")) 9761558Srgrimes v |= D_REMOVABLE; 9771558Srgrimes else if (streq(cp, "ecc")) 9781558Srgrimes v |= D_ECC; 9791558Srgrimes else if (streq(cp, "badsect")) 9801558Srgrimes v |= D_BADSECT; 9811558Srgrimes else { 9821558Srgrimes fprintf(stderr, 9831558Srgrimes "line %d: %s: bad flag\n", 9841558Srgrimes lineno, cp); 9851558Srgrimes errors++; 9861558Srgrimes } 9871558Srgrimes } 9881558Srgrimes lp->d_flags = v; 9891558Srgrimes continue; 9901558Srgrimes } 9911558Srgrimes if (streq(cp, "drivedata")) { 9921558Srgrimes register int i; 9931558Srgrimes 9941558Srgrimes for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) { 9951558Srgrimes lp->d_drivedata[i++] = atoi(cp); 9961558Srgrimes tp = word(cp); 9971558Srgrimes } 9981558Srgrimes continue; 9991558Srgrimes } 10001558Srgrimes if (sscanf(cp, "%d partitions", &v) == 1) { 10011558Srgrimes if (v == 0 || (unsigned)v > MAXPARTITIONS) { 10021558Srgrimes fprintf(stderr, 10031558Srgrimes "line %d: bad # of partitions\n", lineno); 10041558Srgrimes lp->d_npartitions = MAXPARTITIONS; 10051558Srgrimes errors++; 10061558Srgrimes } else 10071558Srgrimes lp->d_npartitions = v; 10081558Srgrimes continue; 10091558Srgrimes } 10101558Srgrimes if (tp == NULL) 10111558Srgrimes tp = ""; 10121558Srgrimes if (streq(cp, "disk")) { 10131558Srgrimes strncpy(lp->d_typename, tp, sizeof (lp->d_typename)); 10141558Srgrimes continue; 10151558Srgrimes } 10161558Srgrimes if (streq(cp, "label")) { 10171558Srgrimes strncpy(lp->d_packname, tp, sizeof (lp->d_packname)); 10181558Srgrimes continue; 10191558Srgrimes } 10201558Srgrimes if (streq(cp, "bytes/sector")) { 10211558Srgrimes v = atoi(tp); 102237865Sbde if (v <= 0 || (v % DEV_BSIZE) != 0) { 10231558Srgrimes fprintf(stderr, 10241558Srgrimes "line %d: %s: bad sector size\n", 10251558Srgrimes lineno, tp); 10261558Srgrimes errors++; 10271558Srgrimes } else 10281558Srgrimes lp->d_secsize = v; 10291558Srgrimes continue; 10301558Srgrimes } 10311558Srgrimes if (streq(cp, "sectors/track")) { 10321558Srgrimes v = atoi(tp); 10331558Srgrimes if (v <= 0) { 10341558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 10351558Srgrimes lineno, tp, cp); 10361558Srgrimes errors++; 10371558Srgrimes } else 10381558Srgrimes lp->d_nsectors = v; 10391558Srgrimes continue; 10401558Srgrimes } 10411558Srgrimes if (streq(cp, "sectors/cylinder")) { 10421558Srgrimes v = atoi(tp); 10431558Srgrimes if (v <= 0) { 10441558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 10451558Srgrimes lineno, tp, cp); 10461558Srgrimes errors++; 10471558Srgrimes } else 10481558Srgrimes lp->d_secpercyl = v; 10491558Srgrimes continue; 10501558Srgrimes } 10511558Srgrimes if (streq(cp, "tracks/cylinder")) { 10521558Srgrimes v = atoi(tp); 10531558Srgrimes if (v <= 0) { 10541558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 10551558Srgrimes lineno, tp, cp); 10561558Srgrimes errors++; 10571558Srgrimes } else 10581558Srgrimes lp->d_ntracks = v; 10591558Srgrimes continue; 10601558Srgrimes } 10611558Srgrimes if (streq(cp, "cylinders")) { 10621558Srgrimes v = atoi(tp); 10631558Srgrimes if (v <= 0) { 10641558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 10651558Srgrimes lineno, tp, cp); 10661558Srgrimes errors++; 10671558Srgrimes } else 10681558Srgrimes lp->d_ncylinders = v; 10691558Srgrimes continue; 10701558Srgrimes } 10716643Sbde if (streq(cp, "sectors/unit")) { 10726643Sbde v = atoi(tp); 10736643Sbde if (v <= 0) { 10746643Sbde fprintf(stderr, "line %d: %s: bad %s\n", 10756643Sbde lineno, tp, cp); 10766643Sbde errors++; 10776643Sbde } else 10786643Sbde lp->d_secperunit = v; 10796643Sbde continue; 10806643Sbde } 10811558Srgrimes if (streq(cp, "rpm")) { 10821558Srgrimes v = atoi(tp); 10831558Srgrimes if (v <= 0) { 10841558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 10851558Srgrimes lineno, tp, cp); 10861558Srgrimes errors++; 10871558Srgrimes } else 10881558Srgrimes lp->d_rpm = v; 10891558Srgrimes continue; 10901558Srgrimes } 10911558Srgrimes if (streq(cp, "interleave")) { 10921558Srgrimes v = atoi(tp); 10931558Srgrimes if (v <= 0) { 10941558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 10951558Srgrimes lineno, tp, cp); 10961558Srgrimes errors++; 10971558Srgrimes } else 10981558Srgrimes lp->d_interleave = v; 10991558Srgrimes continue; 11001558Srgrimes } 11011558Srgrimes if (streq(cp, "trackskew")) { 11021558Srgrimes v = atoi(tp); 11031558Srgrimes if (v < 0) { 11041558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 11051558Srgrimes lineno, tp, cp); 11061558Srgrimes errors++; 11071558Srgrimes } else 11081558Srgrimes lp->d_trackskew = v; 11091558Srgrimes continue; 11101558Srgrimes } 11111558Srgrimes if (streq(cp, "cylinderskew")) { 11121558Srgrimes v = atoi(tp); 11131558Srgrimes if (v < 0) { 11141558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 11151558Srgrimes lineno, tp, cp); 11161558Srgrimes errors++; 11171558Srgrimes } else 11181558Srgrimes lp->d_cylskew = v; 11191558Srgrimes continue; 11201558Srgrimes } 11211558Srgrimes if (streq(cp, "headswitch")) { 11221558Srgrimes v = atoi(tp); 11231558Srgrimes if (v < 0) { 11241558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 11251558Srgrimes lineno, tp, cp); 11261558Srgrimes errors++; 11271558Srgrimes } else 11281558Srgrimes lp->d_headswitch = v; 11291558Srgrimes continue; 11301558Srgrimes } 11311558Srgrimes if (streq(cp, "track-to-track seek")) { 11321558Srgrimes v = atoi(tp); 11331558Srgrimes if (v < 0) { 11341558Srgrimes fprintf(stderr, "line %d: %s: bad %s\n", 11351558Srgrimes lineno, tp, cp); 11361558Srgrimes errors++; 11371558Srgrimes } else 11381558Srgrimes lp->d_trkseek = v; 11391558Srgrimes continue; 11401558Srgrimes } 11411558Srgrimes if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') { 11421558Srgrimes unsigned part = *cp - 'a'; 11431558Srgrimes 11441558Srgrimes if (part > lp->d_npartitions) { 11451558Srgrimes fprintf(stderr, 11461558Srgrimes "line %d: bad partition name\n", lineno); 11471558Srgrimes errors++; 11481558Srgrimes continue; 11491558Srgrimes } 11501558Srgrimes pp = &lp->d_partitions[part]; 11511558Srgrimes#define NXTNUM(n) { \ 11523111Spst if (tp == NULL) { \ 11533111Spst fprintf(stderr, "line %d: too few numeric fields\n", lineno); \ 11543111Spst errors++; \ 11553111Spst break; \ 11563111Spst } else { \ 11573111Spst cp = tp, tp = word(cp); \ 11583111Spst if (tp == NULL) \ 11593111Spst tp = cp; \ 11603111Spst (n) = atoi(cp); \ 11613111Spst } \ 11621558Srgrimes } 11631558Srgrimes 11641558Srgrimes NXTNUM(v); 11651558Srgrimes if (v < 0) { 11661558Srgrimes fprintf(stderr, 11671558Srgrimes "line %d: %s: bad partition size\n", 11681558Srgrimes lineno, cp); 11691558Srgrimes errors++; 11701558Srgrimes } else 11711558Srgrimes pp->p_size = v; 11721558Srgrimes NXTNUM(v); 11731558Srgrimes if (v < 0) { 11741558Srgrimes fprintf(stderr, 11751558Srgrimes "line %d: %s: bad partition offset\n", 11761558Srgrimes lineno, cp); 11771558Srgrimes errors++; 11781558Srgrimes } else 11791558Srgrimes pp->p_offset = v; 11801558Srgrimes cp = tp, tp = word(cp); 11811558Srgrimes cpp = fstypenames; 11821558Srgrimes for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) 11831558Srgrimes if ((s = *cpp) && streq(s, cp)) { 11841558Srgrimes pp->p_fstype = cpp - fstypenames; 11851558Srgrimes goto gottype; 11861558Srgrimes } 11871558Srgrimes if (isdigit(*cp)) 11881558Srgrimes v = atoi(cp); 11891558Srgrimes else 11901558Srgrimes v = FSMAXTYPES; 11911558Srgrimes if ((unsigned)v >= FSMAXTYPES) { 11921558Srgrimes fprintf(stderr, "line %d: %s %s\n", lineno, 11931558Srgrimes "Warning, unknown filesystem type", cp); 11941558Srgrimes v = FS_UNUSED; 11951558Srgrimes } 11961558Srgrimes pp->p_fstype = v; 11971558Srgrimes gottype: 11981558Srgrimes 11991558Srgrimes switch (pp->p_fstype) { 12001558Srgrimes 12011558Srgrimes case FS_UNUSED: /* XXX */ 12021558Srgrimes NXTNUM(pp->p_fsize); 12031558Srgrimes if (pp->p_fsize == 0) 12041558Srgrimes break; 12051558Srgrimes NXTNUM(v); 12061558Srgrimes pp->p_frag = v / pp->p_fsize; 12071558Srgrimes break; 12081558Srgrimes 12091558Srgrimes case FS_BSDFFS: 12101558Srgrimes NXTNUM(pp->p_fsize); 12111558Srgrimes if (pp->p_fsize == 0) 12121558Srgrimes break; 12131558Srgrimes NXTNUM(v); 12141558Srgrimes pp->p_frag = v / pp->p_fsize; 12151558Srgrimes NXTNUM(pp->p_cpg); 12161558Srgrimes break; 12171558Srgrimes 12185393Sgibbs case FS_BSDLFS: 12195393Sgibbs NXTNUM(pp->p_fsize); 12205393Sgibbs if (pp->p_fsize == 0) 12215393Sgibbs break; 12225393Sgibbs NXTNUM(v); 12235393Sgibbs pp->p_frag = v / pp->p_fsize; 12245393Sgibbs NXTNUM(pp->p_cpg); 12255393Sgibbs break; 12265393Sgibbs 12271558Srgrimes default: 12281558Srgrimes break; 12291558Srgrimes } 12301558Srgrimes continue; 12311558Srgrimes } 12321558Srgrimes fprintf(stderr, "line %d: %s: Unknown disklabel field\n", 12331558Srgrimes lineno, cp); 12341558Srgrimes errors++; 12351558Srgrimes next: 12361558Srgrimes ; 12371558Srgrimes } 12381558Srgrimes errors += checklabel(lp); 12391558Srgrimes return (errors == 0); 12401558Srgrimes} 12411558Srgrimes 12421558Srgrimes/* 12431558Srgrimes * Check disklabel for errors and fill in 12441558Srgrimes * derived fields according to supplied values. 12451558Srgrimes */ 124613544Sjoergint 12471558Srgrimeschecklabel(lp) 12481558Srgrimes register struct disklabel *lp; 12491558Srgrimes{ 12501558Srgrimes register struct partition *pp; 12511558Srgrimes int i, errors = 0; 12521558Srgrimes char part; 12531558Srgrimes 12541558Srgrimes if (lp->d_secsize == 0) { 125537234Sbde fprintf(stderr, "sector size 0\n"); 12561558Srgrimes return (1); 12571558Srgrimes } 12581558Srgrimes if (lp->d_nsectors == 0) { 125937234Sbde fprintf(stderr, "sectors/track 0\n"); 12601558Srgrimes return (1); 12611558Srgrimes } 12621558Srgrimes if (lp->d_ntracks == 0) { 126337234Sbde fprintf(stderr, "tracks/cylinder 0\n"); 12641558Srgrimes return (1); 12651558Srgrimes } 12661558Srgrimes if (lp->d_ncylinders == 0) { 126737234Sbde fprintf(stderr, "cylinders/unit 0\n"); 12681558Srgrimes errors++; 12691558Srgrimes } 12701558Srgrimes if (lp->d_rpm == 0) 127137234Sbde Warning("revolutions/minute 0"); 12721558Srgrimes if (lp->d_secpercyl == 0) 12731558Srgrimes lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 12741558Srgrimes if (lp->d_secperunit == 0) 12751558Srgrimes lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 12761558Srgrimes if (lp->d_bbsize == 0) { 127737234Sbde fprintf(stderr, "boot block size 0\n"); 12781558Srgrimes errors++; 12791558Srgrimes } else if (lp->d_bbsize % lp->d_secsize) 12801558Srgrimes Warning("boot block size %% sector-size != 0"); 12811558Srgrimes if (lp->d_sbsize == 0) { 128237234Sbde fprintf(stderr, "super block size 0\n"); 12831558Srgrimes errors++; 12841558Srgrimes } else if (lp->d_sbsize % lp->d_secsize) 12851558Srgrimes Warning("super block size %% sector-size != 0"); 12861558Srgrimes if (lp->d_npartitions > MAXPARTITIONS) 128737234Sbde Warning("number of partitions (%lu) > MAXPARTITIONS (%d)", 128837234Sbde (u_long)lp->d_npartitions, MAXPARTITIONS); 12891558Srgrimes for (i = 0; i < lp->d_npartitions; i++) { 12901558Srgrimes part = 'a' + i; 12911558Srgrimes pp = &lp->d_partitions[i]; 12921558Srgrimes if (pp->p_size == 0 && pp->p_offset != 0) 129337234Sbde Warning("partition %c: size 0, but offset %lu", 129437234Sbde part, (u_long)pp->p_offset); 12951558Srgrimes#ifdef notdef 12961558Srgrimes if (pp->p_size % lp->d_secpercyl) 12971558Srgrimes Warning("partition %c: size %% cylinder-size != 0", 12981558Srgrimes part); 12991558Srgrimes if (pp->p_offset % lp->d_secpercyl) 13001558Srgrimes Warning("partition %c: offset %% cylinder-size != 0", 13011558Srgrimes part); 13021558Srgrimes#endif 13031558Srgrimes if (pp->p_offset > lp->d_secperunit) { 13041558Srgrimes fprintf(stderr, 13051558Srgrimes "partition %c: offset past end of unit\n", part); 13061558Srgrimes errors++; 13071558Srgrimes } 13081558Srgrimes if (pp->p_offset + pp->p_size > lp->d_secperunit) { 13091558Srgrimes fprintf(stderr, 131013544Sjoerg "partition %c: partition extends past end of unit\n", 13111558Srgrimes part); 13121558Srgrimes errors++; 13131558Srgrimes } 13141558Srgrimes } 13151558Srgrimes for (; i < MAXPARTITIONS; i++) { 13161558Srgrimes part = 'a' + i; 13171558Srgrimes pp = &lp->d_partitions[i]; 13181558Srgrimes if (pp->p_size || pp->p_offset) 131937234Sbde Warning("unused partition %c: size %d offset %lu", 132037234Sbde 'a' + i, pp->p_size, (u_long)pp->p_offset); 13211558Srgrimes } 13221558Srgrimes return (errors); 13231558Srgrimes} 13241558Srgrimes 13251558Srgrimes/* 132613550Sjoerg * When operating on a "virgin" disk, try getting an initial label 132713550Sjoerg * from the associated device driver. This might work for all device 132813550Sjoerg * drivers that are able to fetch some initial device parameters 132913550Sjoerg * without even having access to a (BSD) disklabel, like SCSI disks, 133013550Sjoerg * most IDE drives, or vn devices. 133113550Sjoerg * 133213550Sjoerg * The device name must be given in its "canonical" form. 133313550Sjoerg */ 133413550Sjoergstruct disklabel * 133513550Sjoerggetvirginlabel(void) 133613550Sjoerg{ 133713550Sjoerg static struct disklabel lab; 133813550Sjoerg char namebuf[BBSIZE]; 133913550Sjoerg int f; 134013550Sjoerg 134113550Sjoerg if (dkname[0] == '/') { 134237773Sbde warnx("\"auto\" requires the usage of a canonical disk name"); 134316431Sbde return (NULL); 134413550Sjoerg } 134513550Sjoerg (void)snprintf(namebuf, BBSIZE, "%sr%s", _PATH_DEV, dkname); 134637773Sbde if ((f = open(namebuf, O_RDONLY)) == -1) { 134737773Sbde warn("cannot open %s", namebuf); 134816431Sbde return (NULL); 134913550Sjoerg } 135013550Sjoerg if (ioctl(f, DIOCGDINFO, &lab) < 0) { 135137773Sbde warn("ioctl DIOCGDINFO"); 135213550Sjoerg close(f); 135316431Sbde return (NULL); 135413550Sjoerg } 135513550Sjoerg close(f); 135637773Sbde lab.d_boot0 = NULL; 135737773Sbde lab.d_boot1 = NULL; 135816431Sbde return (&lab); 135913550Sjoerg} 136013550Sjoerg 136113550Sjoerg/* 13621558Srgrimes * If we are installing a boot program that doesn't fit in d_bbsize 13631558Srgrimes * we need to mark those partitions that the boot overflows into. 13641558Srgrimes * This allows newfs to prevent creation of a filesystem where it might 13651558Srgrimes * clobber bootstrap code. 13661558Srgrimes */ 136713544Sjoergvoid 13681558Srgrimessetbootflag(lp) 13691558Srgrimes register struct disklabel *lp; 13701558Srgrimes{ 13711558Srgrimes register struct partition *pp; 13721558Srgrimes int i, errors = 0; 13731558Srgrimes char part; 13741558Srgrimes u_long boffset; 13751558Srgrimes 13761558Srgrimes if (bootbuf == 0) 13771558Srgrimes return; 13781558Srgrimes boffset = bootsize / lp->d_secsize; 13791558Srgrimes for (i = 0; i < lp->d_npartitions; i++) { 13801558Srgrimes part = 'a' + i; 13811558Srgrimes pp = &lp->d_partitions[i]; 13821558Srgrimes if (pp->p_size == 0) 13831558Srgrimes continue; 13841558Srgrimes if (boffset <= pp->p_offset) { 13851558Srgrimes if (pp->p_fstype == FS_BOOT) 13861558Srgrimes pp->p_fstype = FS_UNUSED; 13871558Srgrimes } else if (pp->p_fstype != FS_BOOT) { 13881558Srgrimes if (pp->p_fstype != FS_UNUSED) { 13891558Srgrimes fprintf(stderr, 13901558Srgrimes "boot overlaps used partition %c\n", 13911558Srgrimes part); 13921558Srgrimes errors++; 13931558Srgrimes } else { 13941558Srgrimes pp->p_fstype = FS_BOOT; 13951558Srgrimes Warning("boot overlaps partition %c, %s", 13961558Srgrimes part, "marked as FS_BOOT"); 13971558Srgrimes } 13981558Srgrimes } 13991558Srgrimes } 140036632Scharnier if (errors) 140136632Scharnier errx(4, "cannot install boot program"); 14021558Srgrimes} 14031558Srgrimes 14041558Srgrimes/*VARARGS1*/ 140513544Sjoergvoid 140613544SjoergWarning(char *fmt, ...) 14071558Srgrimes{ 140813544Sjoerg va_list ap; 14091558Srgrimes 14101558Srgrimes fprintf(stderr, "Warning, "); 141113544Sjoerg va_start(ap, fmt); 141213544Sjoerg vfprintf(stderr, fmt, ap); 14131558Srgrimes fprintf(stderr, "\n"); 141413544Sjoerg va_end(ap); 14151558Srgrimes} 14161558Srgrimes 141713544Sjoergvoid 14181558Srgrimesusage() 14191558Srgrimes{ 14201558Srgrimes#if NUMBOOT > 0 142126542Scharnier 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%s\n%s\n", 142226542Scharnier "usage: disklabel [-r] disk", 142326542Scharnier "\t\t(to read label)", 142426542Scharnier " disklabel -w [-r] disk type [ packid ]", 142526542Scharnier "\t\t(to write label with existing boot program)", 142626542Scharnier " disklabel -e [-r] disk", 142726542Scharnier "\t\t(to edit label)", 142826542Scharnier " disklabel -R [-r] disk protofile", 142926542Scharnier "\t\t(to restore label with existing boot program)", 14301558Srgrimes#if NUMBOOT > 1 143126542Scharnier " disklabel -B [ -b boot1 [ -s boot2 ] ] disk [ type ]", 143226542Scharnier "\t\t(to install boot program with existing label)", 143326542Scharnier " disklabel -w -B [ -b boot1 [ -s boot2 ] ] disk type [ packid ]", 143426542Scharnier "\t\t(to write label and boot program)", 143526542Scharnier " disklabel -R -B [ -b boot1 [ -s boot2 ] ] disk protofile [ type ]", 143626542Scharnier "\t\t(to restore label and boot program)", 14371558Srgrimes#else 143826542Scharnier " disklabel -B [ -b bootprog ] disk [ type ]", 143926542Scharnier "\t\t(to install boot program with existing on-disk label)", 144026542Scharnier " disklabel -w -B [ -b bootprog ] disk type [ packid ]", 144126542Scharnier "\t\t(to write label and install boot program)", 144226542Scharnier " disklabel -R -B [ -b bootprog ] disk protofile [ type ]", 144326542Scharnier "\t\t(to restore label and install boot program)", 14441558Srgrimes#endif 144526542Scharnier " disklabel [-NW] disk", 144626542Scharnier "\t\t(to write disable/enable label)"); 14471558Srgrimes#else 144826542Scharnier fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 144926542Scharnier "usage: disklabel [-r] disk", "(to read label)", 145026542Scharnier " disklabel -w [-r] disk type [ packid ]", 145126542Scharnier "\t\t(to write label)", 145226542Scharnier " disklabel -e [-r] disk", 145326542Scharnier "\t\t(to edit label)", 145426542Scharnier " disklabel -R [-r] disk protofile", 145526542Scharnier "\t\t(to restore label)", 145626542Scharnier " disklabel [-NW] disk", 145726542Scharnier "\t\t(to write disable/enable label)"); 14581558Srgrimes#endif 14591558Srgrimes exit(1); 14601558Srgrimes} 1461