2 * Copyright (c) 1987, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Symmetric Computer Systems.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 static const char copyright[] =
39 "@(#) Copyright (c) 1987, 1993\n\
40 The Regents of the University of California. All rights reserved.\n";
45 static char sccsid[] = "@(#)disklabel.c 8.2 (Berkeley) 1/7/94";
46 /* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */
48 static const char rcsid[] =
49 "$FreeBSD: src/sbin/disklabel/disklabel.c,v 1.28.2.15 2003/01/24 16:18:16 des Exp $";
52 #include <sys/param.h>
57 #include <sys/disklabel.h>
58 #include <ufs/ffs/fs.h>
68 #include "pathnames.h"
71 * Disklabel: read and write disklabels.
72 * The label is usually placed on one of the first sectors of the disk.
73 * Many machines also place a bootstrap in the same area,
74 * in which case the label is embedded in the bootstrap.
75 * The bootstrap source must leave space at the proper offset
76 * for the label on such machines.
80 #define BBSIZE 8192 /* size of boot area, with label */
83 /* FIX! These are too low, but are traditional */
84 #define DEFAULT_NEWFS_BLOCK 8192U
85 #define DEFAULT_NEWFS_FRAG 1024U
86 #define DEFAULT_NEWFS_CPG 16U
88 #define BIG_NEWFS_BLOCK 16384U
89 #define BIG_NEWFS_FRAG 2048U
90 #define BIG_NEWFS_CPG 64U
95 #if defined(__alpha__) || defined(hp300) || defined(hp800)
102 void makelabel(const char *, const char *, struct disklabel *);
103 int writelabel(int, const char *, struct disklabel *);
104 void l_perror(const char *);
105 struct disklabel *readlabel(int);
106 struct disklabel *makebootarea(char *, struct disklabel *, int);
107 void display(FILE *, const struct disklabel *);
108 int edit(struct disklabel *, int);
112 int getasciilabel(FILE *, struct disklabel *);
113 int getasciipartspec(char *, struct disklabel *, int, int);
114 int checklabel(struct disklabel *);
115 void setbootflag(struct disklabel *);
116 void Warning(const char *, ...) __printflike(1, 2);
118 struct disklabel *getvirginlabel(void);
120 #define DEFEDITOR _PATH_VI
121 #define streq(a,b) (strcmp(a,b) == 0)
125 char tmpfil[] = PATH_TMPFILE;
127 char namebuf[BBSIZE], *np = namebuf;
128 struct disklabel lab;
129 char bootarea[BBSIZE];
131 #define MAX_PART ('z')
132 #define MAX_NUM_PARTS (1 + MAX_PART - 'a')
133 char part_size_type[MAX_NUM_PARTS];
134 char part_offset_type[MAX_NUM_PARTS];
135 int part_set[MAX_NUM_PARTS];
138 int installboot; /* non-zero if we should install a boot program */
139 char *bootbuf; /* pointer to buffer with remainder of boot prog */
140 int bootsize; /* size of remaining boot program */
141 char *xxboot; /* primary boot */
142 char *bootxx; /* secondary boot */
143 char boot0[MAXPATHLEN];
144 char boot1[MAXPATHLEN];
148 UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT
152 int disable_write; /* set to disable writing to disk label */
156 #define OPTIONS "BNRWb:denrs:w"
158 #define OPTIONS "BNRWb:enrs:w"
162 main(int argc, char *argv[])
164 struct disklabel *lp;
166 int ch, f = 0, flag, error = 0;
169 while ((ch = getopt(argc, argv, OPTIONS)) != -1)
244 if (dkname[0] != '/') {
245 (void)sprintf(np, "%s%s%c", _PATH_DEV, dkname, 'a' + RAW_PART);
247 np += strlen(specname) + 1;
250 f = open(specname, op == READ ? O_RDONLY : O_RDWR);
251 if (f < 0 && errno == ENOENT && dkname[0] != '/') {
252 (void)sprintf(specname, "%s%s", _PATH_DEV, dkname);
253 np = namebuf + strlen(specname) + 1;
254 f = open(specname, op == READ ? O_RDONLY : O_RDWR);
257 err(4, "%s", specname);
273 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
274 err(4, "ioctl DIOCWLABEL");
282 error = checklabel(lp);
287 if (installboot && argc == 3) {
288 makelabel(argv[2], 0, &lab);
292 * We only called makelabel() for its side effect
293 * of setting the bootstrap file names. Discard
294 * all changes to `lab' so that all values in the
295 * final label come from the ASCII label.
297 bzero((char *)&lab, sizeof(lab));
302 if (!(t = fopen(argv[1], "r")))
303 err(4, "%s", argv[1]);
304 if (!getasciilabel(t, &lab))
306 lp = makebootarea(bootarea, &lab, f);
308 error = writelabel(f, bootarea, lp);
318 makelabel(argv[1], name, &lab);
319 lp = makebootarea(bootarea, &lab, f);
321 if (checklabel(lp) == 0)
322 error = writelabel(f, bootarea, lp);
327 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
328 err(4, "ioctl DIOCWLABEL");
334 struct disklabel tlab;
339 makelabel(argv[1], 0, &lab);
340 lp = makebootarea(bootarea, &lab, f);
342 if (checklabel(lp) == 0)
343 error = writelabel(f, bootarea, lp);
352 * Construct a prototype disklabel from /etc/disktab. As a side
353 * effect, set the names of the primary and secondary boot files
357 makelabel(const char *type, const char *name, struct disklabel *lp)
359 struct disklabel *dp;
361 if (strcmp(type, "auto") == 0)
362 dp = getvirginlabel();
364 dp = getdiskbyname(type);
366 errx(1, "%s: unknown disk type", type);
370 * Set bootstrap name(s).
371 * 1. If set from command line, use those,
372 * 2. otherwise, check if disktab specifies them (b0 or b1),
373 * 3. otherwise, makebootarea() will choose ones based on the name
374 * of the disk special file. E.g. /dev/ra0 -> raboot, bootra
376 if (!xxboot && lp->d_boot0) {
377 if (*lp->d_boot0 != '/')
378 (void)sprintf(boot0, "%s/%s",
379 _PATH_BOOTDIR, lp->d_boot0);
381 (void)strcpy(boot0, lp->d_boot0);
385 if (!bootxx && lp->d_boot1) {
386 if (*lp->d_boot1 != '/')
387 (void)sprintf(boot1, "%s/%s",
388 _PATH_BOOTDIR, lp->d_boot1);
390 (void)strcpy(boot1, lp->d_boot1);
395 /* d_packname is union d_boot[01], so zero */
396 bzero(lp->d_packname, sizeof(lp->d_packname));
398 (void)strncpy(lp->d_packname, name, sizeof(lp->d_packname));
402 writelabel(int f, const char *boot, struct disklabel *lp)
414 Warning("write to disk label supressed - label was as follows:");
419 lp->d_magic = DISKMAGIC;
420 lp->d_magic2 = DISKMAGIC;
422 lp->d_checksum = dkcksum(lp);
425 * First set the kernel disk label,
426 * then write a label to the raw disk.
427 * If the SDINFO ioctl fails because it is unimplemented,
428 * keep going; otherwise, the kernel consistency checks
429 * may prevent us from changing the current (in-core)
432 if (ioctl(f, DIOCSDINFO, lp) < 0 &&
433 errno != ENODEV && errno != ENOTTY) {
434 l_perror("ioctl DIOCSDINFO");
437 (void)lseek(f, (off_t)0, SEEK_SET);
441 * Generate the bootblock checksum for the SRM console.
443 for (p = (u_long *)boot, i = 0, sum = 0; i < 63; i++)
449 * write enable label sector before write (if necessary),
450 * disable after writing.
453 if (ioctl(f, DIOCWLABEL, &flag) < 0)
454 warn("ioctl DIOCWLABEL");
455 if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) {
461 * Output the remainder of the disklabel
463 if (bootbuf && write(f, bootbuf, bootsize) != bootsize) {
469 (void) ioctl(f, DIOCWLABEL, &flag);
470 } else if (ioctl(f, DIOCWDINFO, lp) < 0) {
471 l_perror("ioctl DIOCWDINFO");
475 if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
478 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
479 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
480 (void)lseek(f, (off_t)((alt + i) * lp->d_secsize),
482 if (write(f, boot, lp->d_secsize) < lp->d_secsize)
483 warn("alternate label %d write", i/2);
492 l_perror(const char *s)
497 warnx("%s: no disk label on disk;", s);
498 fprintf(stderr, "add \"-r\" to install initial label\n");
502 warnx("%s: label magic number or checksum is wrong!", s);
503 fprintf(stderr, "(disklabel or kernel is out of date?)\n");
507 warnx("%s: open partition would move or shrink", s);
511 warnx("%s: '%c' partition must start at beginning of disk",
522 * Fetch disklabel for disk.
523 * Use ioctl to get label unless -r flag is given.
528 struct disklabel *lp;
531 if (read(f, bootarea, BBSIZE) < BBSIZE)
532 err(4, "%s", specname);
533 for (lp = (struct disklabel *)bootarea;
534 lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp));
535 lp = (struct disklabel *)((char *)lp + 16))
536 if (lp->d_magic == DISKMAGIC &&
537 lp->d_magic2 == DISKMAGIC)
539 if (lp > (struct disklabel *)(bootarea+BBSIZE-sizeof(*lp)) ||
540 lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC ||
543 "bad pack magic number (label is damaged, or pack is unlabeled)");
546 if (ioctl(f, DIOCGDINFO, lp) < 0)
547 err(4, "ioctl DIOCGDINFO");
553 * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot''
554 * Returns a pointer to the disklabel portion of the bootarea.
557 makebootarea(char *boot, struct disklabel *dp, int f)
559 struct disklabel *lp;
576 if (dp->d_secsize == 0) {
577 dp->d_secsize = DEV_BSIZE;
578 dp->d_bbsize = BBSIZE;
580 lp = (struct disklabel *)
581 (boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET);
582 bzero((char *)lp, sizeof *lp);
585 * If we are not installing a boot program but we are installing a
586 * label on disk then we must read the current bootarea so we don't
587 * clobber the existing boot.
591 if (read(f, boot, BBSIZE) < BBSIZE)
592 err(4, "%s", specname);
593 bzero((char *)lp, sizeof *lp);
598 * We are installing a boot program. Determine the name(s) and
599 * read them into the appropriate places in the boot area.
601 if (!xxboot || !bootxx) {
603 if ((p = rindex(dkname, '/')) == NULL)
607 while (*p && !isdigit(*p))
612 (void)sprintf(boot0, "%s/boot1", _PATH_BOOTDIR);
617 (void)sprintf(boot1, "%s/boot2", _PATH_BOOTDIR);
624 fprintf(stderr, "bootstraps: xxboot = %s, bootxx = %s\n",
625 xxboot, bootxx ? bootxx : "NONE");
630 * 1. One-piece bootstrap (hp300/hp800)
631 * up to d_bbsize bytes of ``xxboot'' go in bootarea, the rest
632 * is remembered and written later following the bootarea.
633 * 2. Two-piece bootstraps (vax/i386?/mips?)
634 * up to d_secsize bytes of ``xxboot'' go in first d_secsize
635 * bytes of bootarea, remaining d_bbsize-d_secsize filled
638 b = open(xxboot, O_RDONLY);
640 err(4, "%s", xxboot);
645 * The i386 has the so-called fdisk table embedded into the
646 * primary bootstrap. We take care to not clobber it, but
647 * only if it does already contain some data. (Otherwise,
648 * the xxboot provides a template.)
650 if ((tmpbuf = (char *)malloc((int)dp->d_secsize)) == 0)
651 err(4, "%s", xxboot);
652 memcpy((void *)tmpbuf, (void *)boot, (int)dp->d_secsize);
654 if (read(b, boot, (int)dp->d_secsize) < 0)
655 err(4, "%s", xxboot);
658 for (i = DOSPARTOFF, found = 0;
659 !found && i < DOSPARTOFF + NDOSPART*sizeof(struct dos_partition);
661 found = tmpbuf[i] != 0;
663 memcpy((void *)&boot[DOSPARTOFF],
664 (void *)&tmpbuf[DOSPARTOFF],
665 NDOSPART * sizeof(struct dos_partition));
668 b = open(bootxx, O_RDONLY);
670 err(4, "%s", bootxx);
671 if (fstat(b, &sb) != 0)
672 err(4, "%s", bootxx);
673 if (dp->d_secsize + sb.st_size > dp->d_bbsize)
674 errx(4, "%s too large", bootxx);
675 if (read(b, &boot[dp->d_secsize],
676 (int)(dp->d_bbsize-dp->d_secsize)) < 0)
677 err(4, "%s", bootxx);
678 #else /* !(NUMBOOT > 1) */
681 * On the alpha, the primary bootstrap starts at the
682 * second sector of the boot area. The first sector
683 * contains the label and must be edited to contain the
684 * size and location of the primary bootstrap.
686 n = read(b, boot + dp->d_secsize, (int)dp->d_bbsize);
688 err(4, "%s", xxboot);
689 bootinfo = (u_long *)(boot + 480);
690 bootinfo[0] = (n + dp->d_secsize - 1) / dp->d_secsize;
691 bootinfo[1] = 1; /* start at sector 1 */
692 bootinfo[2] = 0; /* flags (must be zero) */
693 #else /* !__alpha__ */
694 if (read(b, boot, (int)dp->d_bbsize) < 0)
695 err(4, "%s", xxboot);
696 #endif /* __alpha__ */
697 if (fstat(b, &sb) != 0)
698 err(4, "%s", xxboot);
699 bootsize = (int)sb.st_size - dp->d_bbsize;
701 /* XXX assume d_secsize is a power of two */
702 bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1);
703 bootbuf = (char *)malloc((size_t)bootsize);
705 err(4, "%s", xxboot);
706 if (read(b, bootbuf, bootsize) < 0) {
708 err(4, "%s", xxboot);
711 #endif /* NUMBOOT > 1 */
713 #endif /* NUMBOOT > 0 */
715 * Make sure no part of the bootstrap is written in the area
716 * reserved for the label.
718 for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++)
720 errx(2, "bootstrap doesn't leave room for disk label");
725 display(FILE *f, const struct disklabel *lp)
728 const struct partition *pp;
730 fprintf(f, "# %s:\n", specname);
731 if (lp->d_type < DKMAXTYPES)
732 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
734 fprintf(f, "type: %u\n", lp->d_type);
735 fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
737 fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
739 fprintf(f, "flags:");
740 if (lp->d_flags & D_REMOVABLE)
741 fprintf(f, " removeable");
742 if (lp->d_flags & D_ECC)
744 if (lp->d_flags & D_BADSECT)
745 fprintf(f, " badsect");
747 fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
748 fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
749 fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
750 fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
751 fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
752 fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
753 fprintf(f, "rpm: %u\n", lp->d_rpm);
754 fprintf(f, "interleave: %u\n", lp->d_interleave);
755 fprintf(f, "trackskew: %u\n", lp->d_trackskew);
756 fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
757 fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
758 (u_long)lp->d_headswitch);
759 fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
760 (u_long)lp->d_trkseek);
761 fprintf(f, "drivedata: ");
762 for (i = NDDATA - 1; i >= 0; i--)
763 if (lp->d_drivedata[i])
767 for (j = 0; j <= i; j++)
768 fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
769 fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
771 "# size offset fstype [fsize bsize bps/cpg]\n");
772 pp = lp->d_partitions;
773 for (i = 0; i < lp->d_npartitions; i++, pp++) {
775 fprintf(f, " %c: %8lu %8lu ", 'a' + i,
776 (u_long)pp->p_size, (u_long)pp->p_offset);
777 if (pp->p_fstype < FSMAXTYPES)
778 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
780 fprintf(f, "%8d", pp->p_fstype);
781 switch (pp->p_fstype) {
783 case FS_UNUSED: /* XXX */
784 fprintf(f, " %5lu %5lu %5.5s ",
786 (u_long)(pp->p_fsize * pp->p_frag), "");
790 fprintf(f, " %5lu %5lu %5u ",
792 (u_long)(pp->p_fsize * pp->p_frag),
797 fprintf(f, " %5lu %5lu %5d",
799 (u_long)(pp->p_fsize * pp->p_frag),
804 fprintf(f, "%20.20s", "");
807 fprintf(f, "\t# (Cyl. %4lu",
808 (u_long)(pp->p_offset / lp->d_secpercyl));
809 if (pp->p_offset % lp->d_secpercyl)
814 (u_long)((pp->p_offset + pp->p_size +
815 lp->d_secpercyl - 1) /
816 lp->d_secpercyl - 1));
817 if (pp->p_size % lp->d_secpercyl)
826 edit(struct disklabel *lp, int f)
829 struct disklabel label;
832 if ((fd = mkstemp(tmpfil)) == -1 ||
833 (fp = fdopen(fd, "w")) == NULL) {
834 warnx("can't create %s", tmpfil);
842 fp = fopen(tmpfil, "r");
844 warnx("can't reopen %s for reading", tmpfil);
847 bzero((char *)&label, sizeof(label));
848 if (getasciilabel(fp, &label)) {
850 if (writelabel(f, bootarea, lp) == 0) {
852 (void) unlink(tmpfil);
857 printf("re-edit the label? [y]: "); fflush(stdout);
859 if (c != EOF && c != (int)'\n')
860 while (getchar() != (int)'\n')
865 (void) unlink(tmpfil);
876 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
877 while ((pid = fork()) < 0) {
878 if (errno == EPROCLIM) {
879 warnx("you have too many processes");
882 if (errno != EAGAIN) {
892 if ((ed = getenv("EDITOR")) == (char *)0)
894 execlp(ed, ed, tmpfil, (char *)0);
897 while ((xpid = wait(&stat)) >= 0)
908 while (*cp != '\0' && isspace(*cp))
910 if (*cp == '\0' || *cp == '#')
920 while (*cp != '\0' && !isspace(*cp) && *cp != '#')
922 if ((c = *cp) != '\0') {
931 * Read an ascii label in from fd f,
932 * in the same format as that put out by display(),
936 getasciilabel(FILE *f, struct disklabel *lp)
941 char *tp, line[BUFSIZ];
943 int lineno = 0, errors = 0;
946 bzero(&part_set, sizeof(part_set));
947 bzero(&part_size_type, sizeof(part_size_type));
948 bzero(&part_offset_type, sizeof(part_offset_type));
949 lp->d_bbsize = BBSIZE; /* XXX */
950 lp->d_sbsize = SBSIZE; /* XXX */
951 while (fgets(line, sizeof(line) - 1, f)) {
953 if ((cp = index(line,'\n')) != 0)
960 fprintf(stderr, "line %d: syntax error\n", lineno);
964 *tp++ = '\0', tp = skip(tp);
965 if (streq(cp, "type")) {
969 for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
970 if (*cpp && streq(*cpp, tp)) {
971 lp->d_type = cpp - dktypenames;
974 if (cpp < &dktypenames[DKMAXTYPES])
976 v = strtoul(tp, NULL, 10);
978 fprintf(stderr, "line %d:%s %lu\n", lineno,
979 "Warning, unknown disk type", v);
983 if (streq(cp, "flags")) {
984 for (v = 0; (cp = tp) && *cp != '\0';) {
986 if (streq(cp, "removeable"))
988 else if (streq(cp, "ecc"))
990 else if (streq(cp, "badsect"))
994 "line %d: %s: bad flag\n",
1002 if (streq(cp, "drivedata")) {
1003 for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
1004 lp->d_drivedata[i++] = strtoul(cp, NULL, 10);
1009 if (sscanf(cp, "%lu partitions", &v) == 1) {
1010 if (v == 0 || v > MAXPARTITIONS) {
1012 "line %d: bad # of partitions\n", lineno);
1013 lp->d_npartitions = MAXPARTITIONS;
1016 lp->d_npartitions = v;
1021 if (streq(cp, "disk")) {
1022 strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
1025 if (streq(cp, "label")) {
1026 strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
1029 if (streq(cp, "bytes/sector")) {
1030 v = strtoul(tp, NULL, 10);
1031 if (v == 0 || (v % DEV_BSIZE) != 0) {
1033 "line %d: %s: bad sector size\n",
1040 if (streq(cp, "sectors/track")) {
1041 v = strtoul(tp, NULL, 10);
1042 #if (ULONG_MAX != 0xffffffffUL)
1043 if (v == 0 || v > 0xffffffff) {
1047 fprintf(stderr, "line %d: %s: bad %s\n",
1054 if (streq(cp, "sectors/cylinder")) {
1055 v = strtoul(tp, NULL, 10);
1057 fprintf(stderr, "line %d: %s: bad %s\n",
1061 lp->d_secpercyl = v;
1064 if (streq(cp, "tracks/cylinder")) {
1065 v = strtoul(tp, NULL, 10);
1067 fprintf(stderr, "line %d: %s: bad %s\n",
1074 if (streq(cp, "cylinders")) {
1075 v = strtoul(tp, NULL, 10);
1077 fprintf(stderr, "line %d: %s: bad %s\n",
1081 lp->d_ncylinders = v;
1084 if (streq(cp, "sectors/unit")) {
1085 v = strtoul(tp, NULL, 10);
1087 fprintf(stderr, "line %d: %s: bad %s\n",
1091 lp->d_secperunit = v;
1094 if (streq(cp, "rpm")) {
1095 v = strtoul(tp, NULL, 10);
1096 if (v == 0 || v > USHRT_MAX) {
1097 fprintf(stderr, "line %d: %s: bad %s\n",
1104 if (streq(cp, "interleave")) {
1105 v = strtoul(tp, NULL, 10);
1106 if (v == 0 || v > USHRT_MAX) {
1107 fprintf(stderr, "line %d: %s: bad %s\n",
1111 lp->d_interleave = v;
1114 if (streq(cp, "trackskew")) {
1115 v = strtoul(tp, NULL, 10);
1116 if (v > USHRT_MAX) {
1117 fprintf(stderr, "line %d: %s: bad %s\n",
1121 lp->d_trackskew = v;
1124 if (streq(cp, "cylinderskew")) {
1125 v = strtoul(tp, NULL, 10);
1126 if (v > USHRT_MAX) {
1127 fprintf(stderr, "line %d: %s: bad %s\n",
1134 if (streq(cp, "headswitch")) {
1135 v = strtoul(tp, NULL, 10);
1136 lp->d_headswitch = v;
1139 if (streq(cp, "track-to-track seek")) {
1140 v = strtoul(tp, NULL, 10);
1144 /* the ':' was removed above */
1145 if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') {
1147 "line %d: %s: Unknown disklabel field\n", lineno,
1153 /* Process a partition specification line. */
1155 if (part >= lp->d_npartitions) {
1157 "line %d: partition name out of range a-%c: %s\n",
1158 lineno, 'a' + lp->d_npartitions - 1, cp);
1164 if (getasciipartspec(tp, lp, part, lineno) != 0) {
1169 errors += checklabel(lp);
1170 return (errors == 0);
1173 #define NXTNUM(n) do { \
1175 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
1178 cp = tp, tp = word(cp); \
1179 (n) = strtoul(cp, NULL, 10); \
1183 /* retain 1 character following number */
1184 #define NXTWORD(w,n) do { \
1186 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
1190 cp = tp, tp = word(cp); \
1191 (n) = strtoul(cp, &tmp, 10); \
1192 if (tmp) (w) = *tmp; \
1197 * Read a partition line into partition `part' in the specified disklabel.
1198 * Return 0 on success, 1 on failure.
1201 getasciipartspec(char *tp, struct disklabel *lp, int part, int lineno)
1203 struct partition *pp;
1208 pp = &lp->d_partitions[part];
1212 NXTWORD(part_size_type[part],v);
1213 if (v == 0 && part_size_type[part] != '*') {
1215 "line %d: %s: bad partition size\n", lineno, cp);
1221 NXTWORD(part_offset_type[part],v);
1222 if (v == 0 && part_offset_type[part] != '*' &&
1223 part_offset_type[part] != '\0') {
1225 "line %d: %s: bad partition offset\n", lineno, cp);
1229 cp = tp, tp = word(cp);
1230 for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++)
1231 if (*cpp && streq(*cpp, cp))
1234 pp->p_fstype = cpp - fstypenames;
1237 v = strtoul(cp, NULL, 10);
1240 if (v >= FSMAXTYPES) {
1242 "line %d: Warning, unknown filesystem type %s\n",
1249 switch (pp->p_fstype) {
1252 * allow us to accept defaults for
1256 NXTNUM(pp->p_fsize);
1257 if (pp->p_fsize == 0)
1260 pp->p_frag = v / pp->p_fsize;
1262 /* else default to 0's */
1265 /* These happen to be the same */
1269 NXTNUM(pp->p_fsize);
1270 if (pp->p_fsize == 0)
1273 pp->p_frag = v / pp->p_fsize;
1277 * FIX! poor attempt at adaptive
1280 if (pp->p_size < 1024*1024*1024 / lp->d_secsize) {
1282 * FIX! These are too low, but are traditional
1284 pp->p_fsize = DEFAULT_NEWFS_FRAG;
1285 pp->p_frag = DEFAULT_NEWFS_BLOCK /
1287 pp->p_cpg = DEFAULT_NEWFS_CPG;
1289 pp->p_fsize = BIG_NEWFS_FRAG;
1290 pp->p_frag = BIG_NEWFS_BLOCK /
1292 pp->p_cpg = BIG_NEWFS_CPG;
1302 * Check disklabel for errors and fill in
1303 * derived fields according to supplied values.
1306 checklabel(struct disklabel *lp)
1308 struct partition *pp;
1311 u_long total_size, total_percent, current_offset;
1312 int seen_default_offset;
1315 struct partition *pp2;
1317 if (lp->d_secsize == 0) {
1318 fprintf(stderr, "sector size 0\n");
1321 if (lp->d_nsectors == 0) {
1322 fprintf(stderr, "sectors/track 0\n");
1325 if (lp->d_ntracks == 0) {
1326 fprintf(stderr, "tracks/cylinder 0\n");
1329 if (lp->d_ncylinders == 0) {
1330 fprintf(stderr, "cylinders/unit 0\n");
1334 Warning("revolutions/minute 0");
1335 if (lp->d_secpercyl == 0)
1336 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1337 if (lp->d_secperunit == 0)
1338 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
1339 if (lp->d_bbsize == 0) {
1340 fprintf(stderr, "boot block size 0\n");
1342 } else if (lp->d_bbsize % lp->d_secsize)
1343 Warning("boot block size %% sector-size != 0");
1344 if (lp->d_sbsize == 0) {
1345 fprintf(stderr, "super block size 0\n");
1347 } else if (lp->d_sbsize % lp->d_secsize)
1348 Warning("super block size %% sector-size != 0");
1349 if (lp->d_npartitions > MAXPARTITIONS)
1350 Warning("number of partitions (%lu) > MAXPARTITIONS (%d)",
1351 (u_long)lp->d_npartitions, MAXPARTITIONS);
1353 /* first allocate space to the partitions, then offsets */
1354 total_size = 0; /* in sectors */
1355 total_percent = 0; /* in percent */
1357 /* find all fixed partitions */
1358 for (i = 0; i < lp->d_npartitions; i++) {
1359 pp = &lp->d_partitions[i];
1361 if (part_size_type[i] == '*') {
1362 if (i == RAW_PART) {
1363 pp->p_size = lp->d_secperunit;
1366 Warning("Too many '*' partitions (%c and %c)",
1367 hog_part + 'a',i + 'a');
1375 switch (part_size_type[i]) {
1377 total_percent += size;
1385 size *= 1024ULL * 1024ULL;
1389 size *= 1024ULL * 1024ULL * 1024ULL;
1394 Warning("unknown size specifier '%c' (K/M/G are valid)",part_size_type[i]);
1397 /* don't count %'s yet */
1398 if (part_size_type[i] != '%') {
1400 * for all not in sectors, convert to
1403 if (part_size_type[i] != '\0') {
1404 if (size % lp->d_secsize != 0)
1405 Warning("partition %c not an integer number of sectors",
1407 size /= lp->d_secsize;
1410 /* else already in sectors */
1417 /* handle % partitions - note %'s don't need to add up to 100! */
1418 if (total_percent != 0) {
1419 long free_space = lp->d_secperunit - total_size;
1420 if (total_percent > 100) {
1421 fprintf(stderr,"total percentage %lu is greater than 100\n",
1426 if (free_space > 0) {
1427 for (i = 0; i < lp->d_npartitions; i++) {
1428 pp = &lp->d_partitions[i];
1429 if (part_set[i] && part_size_type[i] == '%') {
1430 /* careful of overflows! and integer roundoff */
1431 pp->p_size = ((double)pp->p_size/100) * free_space;
1432 total_size += pp->p_size;
1434 /* FIX we can lose a sector or so due to roundoff per
1435 partition. A more complex algorithm could avoid that */
1440 "%ld sectors available to give to '*' and '%%' partitions\n",
1443 /* fix? set all % partitions to size 0? */
1446 /* give anything remaining to the hog partition */
1447 if (hog_part != -1) {
1448 lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size;
1449 total_size = lp->d_secperunit;
1452 /* Now set the offsets for each partition */
1453 current_offset = 0; /* in sectors */
1454 seen_default_offset = 0;
1455 for (i = 0; i < lp->d_npartitions; i++) {
1457 pp = &lp->d_partitions[i];
1459 if (part_offset_type[i] == '*') {
1460 if (i == RAW_PART) {
1463 pp->p_offset = current_offset;
1464 seen_default_offset = 1;
1467 /* allow them to be out of order for old-style tables */
1468 if (pp->p_offset < current_offset &&
1469 seen_default_offset && i != RAW_PART &&
1470 pp->p_fstype != FS_VINUM) {
1472 "Offset %ld for partition %c overlaps previous partition which ends at %lu\n",
1473 (long)pp->p_offset,i+'a',current_offset);
1475 "Labels with any *'s for offset must be in ascending order by sector\n");
1477 } else if (pp->p_offset != current_offset &&
1478 i != RAW_PART && seen_default_offset) {
1480 * this may give unneeded warnings if
1481 * partitions are out-of-order
1484 "Offset %ld for partition %c doesn't match expected value %ld",
1485 (long)pp->p_offset, i + 'a', current_offset);
1489 current_offset = pp->p_offset + pp->p_size;
1493 for (i = 0; i < lp->d_npartitions; i++) {
1495 pp = &lp->d_partitions[i];
1496 if (pp->p_size == 0 && pp->p_offset != 0)
1497 Warning("partition %c: size 0, but offset %lu",
1498 part, (u_long)pp->p_offset);
1500 if (pp->p_size % lp->d_secpercyl)
1501 Warning("partition %c: size %% cylinder-size != 0",
1503 if (pp->p_offset % lp->d_secpercyl)
1504 Warning("partition %c: offset %% cylinder-size != 0",
1507 if (pp->p_offset > lp->d_secperunit) {
1509 "partition %c: offset past end of unit\n", part);
1512 if (pp->p_offset + pp->p_size > lp->d_secperunit) {
1514 "partition %c: partition extends past end of unit\n",
1520 if (pp->p_fstype != FS_UNUSED)
1521 Warning("partition %c is not marked as unused!",part);
1522 if (pp->p_offset != 0)
1523 Warning("partition %c doesn't start at 0!",part);
1524 if (pp->p_size != lp->d_secperunit)
1525 Warning("partition %c doesn't cover the whole unit!",part);
1527 if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) ||
1528 (pp->p_size != lp->d_secperunit)) {
1529 Warning("An incorrect partition %c may cause problems for "
1530 "standard system utilities",part);
1534 /* check for overlaps */
1535 /* this will check for all possible overlaps once and only once */
1536 for (j = 0; j < i; j++) {
1537 pp2 = &lp->d_partitions[j];
1538 if (j != RAW_PART && i != RAW_PART &&
1539 pp->p_fstype != FS_VINUM &&
1540 pp2->p_fstype != FS_VINUM &&
1541 part_set[i] && part_set[j]) {
1542 if (pp2->p_offset < pp->p_offset + pp->p_size &&
1543 (pp2->p_offset + pp2->p_size > pp->p_offset ||
1544 pp2->p_offset >= pp->p_offset)) {
1545 fprintf(stderr,"partitions %c and %c overlap!\n",
1552 for (; i < MAXPARTITIONS; i++) {
1554 pp = &lp->d_partitions[i];
1555 if (pp->p_size || pp->p_offset)
1556 Warning("unused partition %c: size %d offset %lu",
1557 'a' + i, pp->p_size, (u_long)pp->p_offset);
1563 * When operating on a "virgin" disk, try getting an initial label
1564 * from the associated device driver. This might work for all device
1565 * drivers that are able to fetch some initial device parameters
1566 * without even having access to a (BSD) disklabel, like SCSI disks,
1567 * most IDE drives, or vn devices.
1569 * The device name must be given in its "canonical" form.
1572 getvirginlabel(void)
1574 static struct disklabel lab;
1575 char namebuf[BBSIZE];
1578 if (dkname[0] == '/') {
1579 warnx("\"auto\" requires the usage of a canonical disk name");
1582 (void)snprintf(namebuf, BBSIZE, "%s%s", _PATH_DEV, dkname);
1583 if ((f = open(namebuf, O_RDONLY)) == -1) {
1584 warn("cannot open %s", namebuf);
1589 * Try to use the new get-virgin-label ioctl. If it fails,
1590 * fallback to the old get-disdk-info ioctl.
1592 if (ioctl(f, DIOCGDVIRGIN, &lab) < 0) {
1593 if (ioctl(f, DIOCGDINFO, &lab) < 0) {
1594 warn("ioctl DIOCGDINFO");
1606 * If we are installing a boot program that doesn't fit in d_bbsize
1607 * we need to mark those partitions that the boot overflows into.
1608 * This allows newfs to prevent creation of a filesystem where it might
1609 * clobber bootstrap code.
1612 setbootflag(struct disklabel *lp)
1614 struct partition *pp;
1621 boffset = bootsize / lp->d_secsize;
1622 for (i = 0; i < lp->d_npartitions; i++) {
1624 pp = &lp->d_partitions[i];
1625 if (pp->p_size == 0)
1627 if (boffset <= pp->p_offset) {
1628 if (pp->p_fstype == FS_BOOT)
1629 pp->p_fstype = FS_UNUSED;
1630 } else if (pp->p_fstype != FS_BOOT) {
1631 if (pp->p_fstype != FS_UNUSED) {
1633 "boot overlaps used partition %c\n",
1637 pp->p_fstype = FS_BOOT;
1638 Warning("boot overlaps partition %c, %s",
1639 part, "marked as FS_BOOT");
1644 errx(4, "cannot install boot program");
1649 Warning(const char *fmt, ...)
1653 fprintf(stderr, "Warning, ");
1655 vfprintf(stderr, fmt, ap);
1656 fprintf(stderr, "\n");
1664 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",
1665 "usage: disklabel [-r] disk",
1666 "\t\t(to read label)",
1667 " disklabel -w [-r] [-n] disk type [ packid ]",
1668 "\t\t(to write label with existing boot program)",
1669 " disklabel -e [-r] [-n] disk",
1670 "\t\t(to edit label)",
1671 " disklabel -R [-r] [-n] disk protofile",
1672 "\t\t(to restore label with existing boot program)",
1674 " disklabel -B [-n] [ -b boot1 [ -s boot2 ] ] disk [ type ]",
1675 "\t\t(to install boot program with existing label)",
1676 " disklabel -w -B [-n] [ -b boot1 [ -s boot2 ] ] disk type [ packid ]",
1677 "\t\t(to write label and boot program)",
1678 " disklabel -R -B [-n] [ -b boot1 [ -s boot2 ] ] disk protofile [ type ]",
1679 "\t\t(to restore label and boot program)",
1681 " disklabel -B [-n] [ -b bootprog ] disk [ type ]",
1682 "\t\t(to install boot program with existing on-disk label)",
1683 " disklabel -w -B [-n] [ -b bootprog ] disk type [ packid ]",
1684 "\t\t(to write label and install boot program)",
1685 " disklabel -R -B [-n] [ -b bootprog ] disk protofile [ type ]",
1686 "\t\t(to restore label and install boot program)",
1688 " disklabel [-NW] disk",
1689 "\t\t(to write disable/enable label)");
1691 fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
1692 "usage: disklabel [-r] disk", "(to read label)",
1693 " disklabel -w [-r] [-n] disk type [ packid ]",
1694 "\t\t(to write label)",
1695 " disklabel -e [-r] [-n] disk",
1696 "\t\t(to edit label)",
1697 " disklabel -R [-r] [-n] disk protofile",
1698 "\t\t(to restore label)",
1699 " disklabel [-NW] disk",
1700 "\t\t(to write disable/enable label)");