diff options
-rw-r--r-- | sbin/bsdlabel/bsdlabel.8 | 157 | ||||
-rw-r--r-- | sbin/bsdlabel/bsdlabel.c | 560 | ||||
-rw-r--r-- | sbin/disklabel/disklabel.8 | 157 | ||||
-rw-r--r-- | sbin/disklabel/disklabel.c | 560 |
4 files changed, 1116 insertions, 318 deletions
diff --git a/sbin/bsdlabel/bsdlabel.8 b/sbin/bsdlabel/bsdlabel.8 index fb16eab..0486c52 100644 --- a/sbin/bsdlabel/bsdlabel.8 +++ b/sbin/bsdlabel/bsdlabel.8 @@ -48,15 +48,18 @@ .Nm .Fl w .Op Fl r +.Op Fl n .Ar disk Ar disktype/auto .Oo Ar packid Oc .Nm .Fl e .Op Fl r +.Op Fl n .Ar disk .Nm .Fl R .Op Fl r +.Op Fl n .Ar disk Ar protofile .Nm .Op Fl NW @@ -73,6 +76,7 @@ .Nm .Fl w .Fl B +.Op Fl n .Oo .Fl b Ar boot1 .Fl s Ar boot2 @@ -82,6 +86,7 @@ .Nm .Fl R .Fl B +.Op Fl n .Oo .Fl b Ar boot1 .Fl s Ar boot2 @@ -170,12 +175,14 @@ To write a standard label, use the form .Nm .Fl w .Op Fl r +.Op Fl n .Ar disk Ar disktype/auto .Oo Ar packid Oc .Pp .Nm .Fl w .Op Fl r +.Op Fl n .Ar disk auto .Pp @@ -188,7 +195,14 @@ different disks of the same physical type are to have different partitions, it will be necessary to have separate disktab entries describing each, or to edit the label after installation as described below. The optional argument is a pack identification string, up to 16 characters long. The pack id must be -quoted if it contains blanks. If the +quoted if it contains blanks. +.Pp +If the +.Fl n +flag is given, no data will be written to the device, and instead the +disklabel that would have been written will be printed to stdout. +.Pp +If the .Fl r flag is given, the disk sectors containing the label and bootstrap will be written directly. @@ -220,6 +234,9 @@ disk is the only supported operation, and the itself must be provided as the canonical name, i.e. not as a full path name. .Pp +For most harddisks, a label based on percentages for most partitions (and +one partition with a size of '*') will produce a reasonable configuration. +.Pp PC-based systems have special requirements in order for the BIOS to properly recognize a .Fx @@ -244,6 +261,7 @@ To edit an existing disk label, use the form .Nm .Fl e .Op Fl r +.Op Fl n .Ar disk .Pp This command reads the label from the in-core kernel copy, or directly from the @@ -257,7 +275,11 @@ environment variable, is used. When the editor terminates, the label file is used to rewrite the disk label. Existing bootstrap code is unchanged regardless of whether .Fl r -was specified. +was specified. If +.Fl n +is specified, no data will be written to the device, and instead the +disklabel that would have been written will be printed to stdout. This is +useful to see how a partitioning scheme will work out for a specific disk. .Ss Restoring a disk label from a file .Pp To restore a disk label from a file, use the form @@ -265,6 +287,7 @@ To restore a disk label from a file, use the form .Nm .Fl R .Op Fl r +.Op Fl n .Ar disk Ar protofile .Pp .Nm @@ -277,6 +300,11 @@ clobbered if .Fl r is specified and will be unaffected otherwise. See the boot options below for a method of restoring the label and writing the bootstrap at the same time. +If +.Fl n +is used, no data will be written to the device, and instead the +disklabel that would have been written will be printed to stdout. This is +useful to see how a partitioning scheme will work out for a specific disk. .Ss Enabling and disabling writing to the disk label area .Pp By default, it is not possible to write to the disk label area at the beginning @@ -331,6 +359,7 @@ This command is typically run on a slice such as .Nm .Fl w .Fl B +.Op Fl n .Oo .Fl b Ar boot1 .Fl s Ar boot2 @@ -345,10 +374,15 @@ In addition to writing a new volume label, it also installs the bootstrap. If run on a base disk this command will create a .Dq dangerously-dedicated label. This command is normally run on a slice rather than a base disk. +If +.Fl n +is used, no data will be written to the device, and instead the +disklabel that would have been written will be printed to stdout. .Pp .Nm .Fl R .Fl B +.Op Fl n .Oo .Fl b Ar boot1 .Fl s Ar boot2 @@ -367,7 +401,10 @@ label. This command is normally run on a slice rather than a base disk. The bootstrap commands always access the disk directly, so it is not necessary to specify the .Fl r -flag. +flag. If +.Fl n +is used, no data will be written to the device, and instead the +disklabel that would have been written will be printed to stdout. .Pp The bootstrap code is comprised of two boot programs. Specify the name of the boot programs to be installed in one of these ways: @@ -548,21 +585,63 @@ By convention, partition .Nm c is reserved to describe the entire disk. .It size -is the size of the partition in sectors. +is the size of the partition in sectors, +.Nm K +(kilobytes - 1024), +.Nm M +(megabytes - 1024*1024), +.Nm G +(gigabytes - 1024*1024*1024), +.Nm % +(percentage of free space AFTER removing any fixed-size partitions other +than partition +.Nm c +), or * (all remaining free space AFTER fixed-size and percentage +partitions). For partition +.Nm c , +a size of * indicates the entire disk. Lowercase versions of K, M, and G +are allowed. +Size and type should be specifed without any spaces between them. +.Pp +Example: 2097152, 1g, 1024m and 1048576k are all the same size +(assuming 512-byte sectors). .It offset -is the offset of the start of the partition from the beginning of the drive. +is the offset of the start of the partition from the beginning of the +drive in sectors, or * to have +.Nm +calculate the correct offset to use (the end of the previous partition plus +one, ignoring partition +.Nm c . +For partition +.Nm c , +* will be interpreted as an offset of 0. .It fstype describes the purpose of the partition. The example shows most normal usages. -For UFS file systems, use type 4.2BSD. See +For UFS file systems, use type +.Nm 4.2BSD . +Other common types are +.Nm unused +and +.Nm swap . +See .Pa /usr/include/sys/disklabel.h for a complete list. .It fsize -For file systems only, the fragment size. +For +.Nm 4.2BSD +and LFS file systems only, the fragment size. Defaults to 8192 for +partitions smaller than 1 GB, 16384 for partitions 1GB or larger. .It bsize -For file systems only, the block size. +For +.Nm 4.2BSD +and LFS file systems only, the block size. Defaults to 1024 for +partitions smaller than 1 GB, 4096 for partitions 1GB or larger. .It bps/cpg -For UFS file systems, the number of cylinders in a cylinder group. For LFS file -systems, the segment shift value. +For +.Nm 4.2BSD +file systems, the number of cylinders in a cylinder group. For LFS file +systems, the segment shift value. Defaults to 16 for +partitions smaller than 1 GB, 64 for partitions 1GB or larger. .El .Pp The remainder of the line is a comment and shows the cylinder allocations based @@ -611,6 +690,13 @@ Read the on-disk label for edit it and reinstall in-core as well as on-disk. Existing bootstrap code is unaffected. .Pp +.Dl disklabel -e -r -n da0s1 +.Pp +Read the on-disk label for +.Pa da0s1 , +edit it, and display what the new label would be (in sectors). It does +NOT install the new label either in-core or on-disk. +.Pp .Dl disklabel -r -w da0s1 auto .Pp Try to auto-detect the required information from @@ -626,6 +712,15 @@ from information in .Pa savedlabel . Existing bootstrap code is unaffected. .Pp +.Dl disklabel -R -n da0s1 label_layout +.Pp +Display what the label would be for +.Pa da0s1 +using the partition layout in +.Pa label_layout . +This is useful for determining how much space would be alloted for various +partitions with a labelling scheme using %-based or * partition sizes. +.Pp .Dl disklabel -B da0s1 .Pp Install a new bootstrap on @@ -661,6 +756,40 @@ initialize the slice, then edit it to your needs. The .Pa dd commands are optional, but may be necessary for some BIOSes to properly recognize the disk. +.Pp +This is an example disklabel that uses some of the new partition size types +such as %, M, G, and *, which could be used as a source file for +.Pp +.Dl disklabel -R ad0s1c new_label_file +.Bd -literal -offset 4n +# /dev/ad0s1c: +type: ESDI +disk: ad0s1 +label: +flags: +bytes/sector: 512 +sectors/track: 63 +tracks/cylinder: 16 +sectors/cylinder: 1008 +cylinders: 40633 +sectors/unit: 40959009 +rpm: 3600 +interleave: 1 +trackskew: 0 +cylinderskew: 0 +headswitch: 0 # milliseconds +track-to-track seek: 0 # milliseconds +drivedata: 0 + +8 partitions: +# size offset fstype [fsize bsize bps/cpg] + a: 400M 0 4.2BSD 4096 16384 75 # (Cyl. 0 - 812*) + b: 1G * swap + c: * * unused + e: 204800 * 4.2BSD + f: 5g * 4.2BSD + g: * * 4.2BSD +.Ed .Sh SEE ALSO .Xr disklabel 5 , .Xr disktab 5 , @@ -723,5 +852,9 @@ concern if the disk is fully dedicated, so that the BSD disklabel starts at absolute block 0 on the disk. .Pp .Nm -does not perform adequate error checking. No warning is given if partitions -overlap, nor if space remains unused. +does not perform all possible error checking. Warning *is* given if partitions +overlap; if an absolute offset doesn't match the expected offset; if the +.Nm c +partition doesn't start at 0 or doesn't cover the entire slice; if a +partition runs past the end of the device; and a number of other errors; but +no warning is given if space remains unused. diff --git a/sbin/bsdlabel/bsdlabel.c b/sbin/bsdlabel/bsdlabel.c index 484f073..cec9cc0 100644 --- a/sbin/bsdlabel/bsdlabel.c +++ b/sbin/bsdlabel/bsdlabel.c @@ -80,6 +80,15 @@ static const char rcsid[] = #define BBSIZE 8192 /* size of boot area, with label */ #endif +/* FIX! These are too low, but are traditional */ +#define DEFAULT_NEWFS_BLOCK 8192U +#define DEFAULT_NEWFS_FRAG 1024U +#define DEFAULT_NEWFS_CPG 16U + +#define BIG_NEWFS_BLOCK 16384U +#define BIG_NEWFS_FRAG 4096U +#define BIG_NEWFS_CPG 64U + #ifdef tahoe #define NUMBOOT 0 #else @@ -118,6 +127,14 @@ char namebuf[BBSIZE], *np = namebuf; struct disklabel lab; char bootarea[BBSIZE]; +/* partition 'c' is the full disk and is special */ +#define FULL_DISK_PART 2 +#define MAX_PART ('z') +#define MAX_NUM_PARTS (1 + MAX_PART - 'a') +char part_size_type[MAX_NUM_PARTS]; +char part_offset_type[MAX_NUM_PARTS]; +int part_set[MAX_NUM_PARTS]; + #if NUMBOOT > 0 int installboot; /* non-zero if we should install a boot program */ char *bootbuf; /* pointer to buffer with remainder of boot prog */ @@ -133,12 +150,13 @@ enum { } op = UNSPEC; int rflag; +int disable_write; /* set to disable writing to disk label */ #ifdef DEBUG int debug; -#define OPTIONS "BNRWb:ders:w" +#define OPTIONS "BNRWb:denrs:w" #else -#define OPTIONS "BNRWb:ers:w" +#define OPTIONS "BNRWb:enrs:w" #endif int @@ -171,6 +189,9 @@ main(argc, argv) usage(); op = NOWRITE; break; + case 'n': + disable_write = 1; + break; case 'R': if (op != UNSPEC) usage(); @@ -397,75 +418,81 @@ writelabel(f, boot, lp) register int i; #endif - setbootflag(lp); - lp->d_magic = DISKMAGIC; - lp->d_magic2 = DISKMAGIC; - lp->d_checksum = 0; - lp->d_checksum = dkcksum(lp); - if (rflag) { - /* - * First set the kernel disk label, - * then write a label to the raw disk. - * If the SDINFO ioctl fails because it is unimplemented, - * keep going; otherwise, the kernel consistency checks - * may prevent us from changing the current (in-core) - * label. - */ - if (ioctl(f, DIOCSDINFO, lp) < 0 && - errno != ENODEV && errno != ENOTTY) { - l_perror("ioctl DIOCSDINFO"); - return (1); - } - (void)lseek(f, (off_t)0, SEEK_SET); - + if (disable_write) { + Warning("write to disk label supressed - label was as follows:"); + display(stdout, lp); + return (0); + } else { + setbootflag(lp); + lp->d_magic = DISKMAGIC; + lp->d_magic2 = DISKMAGIC; + lp->d_checksum = 0; + lp->d_checksum = dkcksum(lp); + if (rflag) { + /* + * First set the kernel disk label, + * then write a label to the raw disk. + * If the SDINFO ioctl fails because it is unimplemented, + * keep going; otherwise, the kernel consistency checks + * may prevent us from changing the current (in-core) + * label. + */ + if (ioctl(f, DIOCSDINFO, lp) < 0 && + errno != ENODEV && errno != ENOTTY) { + l_perror("ioctl DIOCSDINFO"); + return (1); + } + (void)lseek(f, (off_t)0, SEEK_SET); + #ifdef __alpha__ - /* - * Generate the bootblock checksum for the SRM console. - */ - for (p = (u_long *)boot, i = 0, sum = 0; i < 63; i++) - sum += p[i]; - p[63] = sum; + /* + * Generate the bootblock checksum for the SRM console. + */ + for (p = (u_long *)boot, i = 0, sum = 0; i < 63; i++) + sum += p[i]; + p[63] = sum; #endif - - /* - * write enable label sector before write (if necessary), - * disable after writing. - */ - flag = 1; - if (ioctl(f, DIOCWLABEL, &flag) < 0) - warn("ioctl DIOCWLABEL"); - if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) { - warn("write"); - return (1); - } + + /* + * write enable label sector before write (if necessary), + * disable after writing. + */ + flag = 1; + if (ioctl(f, DIOCWLABEL, &flag) < 0) + warn("ioctl DIOCWLABEL"); + if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) { + warn("write"); + return (1); + } #if NUMBOOT > 0 - /* - * Output the remainder of the disklabel - */ - if (bootbuf && write(f, bootbuf, bootsize) != bootsize) { - warn("write"); - return(1); - } + /* + * Output the remainder of the disklabel + */ + if (bootbuf && write(f, bootbuf, bootsize) != bootsize) { + warn("write"); + return(1); + } #endif - flag = 0; - (void) ioctl(f, DIOCWLABEL, &flag); - } else if (ioctl(f, DIOCWDINFO, lp) < 0) { - l_perror("ioctl DIOCWDINFO"); - return (1); - } + flag = 0; + (void) ioctl(f, DIOCWLABEL, &flag); + } else if (ioctl(f, DIOCWDINFO, lp) < 0) { + l_perror("ioctl DIOCWDINFO"); + return (1); + } #ifdef vax - if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { - daddr_t alt; - - alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; - for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { - (void)lseek(f, (off_t)((alt + i) * lp->d_secsize), - SEEK_SET); - if (write(f, boot, lp->d_secsize) < lp->d_secsize) - warn("alternate label %d write", i/2); + if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { + daddr_t alt; + + alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; + for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { + (void)lseek(f, (off_t)((alt + i) * lp->d_secsize), + SEEK_SET); + if (write(f, boot, lp->d_secsize) < lp->d_secsize) + warn("alternate label %d write", i/2); + } } - } #endif + } return (0); } @@ -933,6 +960,8 @@ getasciilabel(f, lp) { register char **cpp, *cp; register struct partition *pp; + int i; + unsigned int part; char *tp, *s, line[BUFSIZ]; int v, lineno = 0, errors = 0; @@ -1137,16 +1166,18 @@ getasciilabel(f, lp) lp->d_trkseek = v; continue; } - if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') { - unsigned part = *cp - 'a'; - - if (part > lp->d_npartitions) { + /* the ':' was removed above */ + if ('a' <= *cp && *cp <= MAX_PART && cp[1] == '\0') { + part = *cp - 'a'; + if (part >= lp->d_npartitions) { fprintf(stderr, - "line %d: bad partition name\n", lineno); + "line %d: partition name out of range a-%c: %s\n", + lineno, 'a' + lp->d_npartitions - 1, cp); errors++; continue; } pp = &lp->d_partitions[part]; + part_set[part] = 1; #define NXTNUM(n) { \ if (tp == NULL) { \ fprintf(stderr, "line %d: too few numeric fields\n", lineno); \ @@ -1159,80 +1190,131 @@ getasciilabel(f, lp) (n) = atoi(cp); \ } \ } - - NXTNUM(v); - if (v < 0) { +/* retain 1 character following number */ +#define NXTWORD(w,n) { \ + if (tp == NULL) { \ + fprintf(stderr, "line %d: too few numeric fields\n", lineno); \ + errors++; \ + break; \ + } else { \ + char *tmp; \ + cp = tp, tp = word(cp); \ + if (tp == NULL) \ + tp = cp; \ + (n) = strtol(cp,&tmp,10); \ + if (tmp) (w) = *tmp; \ + } \ + } + v = 0; + NXTWORD(part_size_type[part],v); + if (v < 0 || (v == 0 && part_size_type[part] != '*')) { fprintf(stderr, "line %d: %s: bad partition size\n", lineno, cp); errors++; - } else - pp->p_size = v; - NXTNUM(v); - if (v < 0) { - fprintf(stderr, - "line %d: %s: bad partition offset\n", - lineno, cp); - errors++; - } else - pp->p_offset = v; - cp = tp, tp = word(cp); - cpp = fstypenames; - for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) - if ((s = *cpp) && streq(s, cp)) { - pp->p_fstype = cpp - fstypenames; - goto gottype; - } - if (isdigit(*cp)) - v = atoi(cp); - else - v = FSMAXTYPES; - if ((unsigned)v >= FSMAXTYPES) { - fprintf(stderr, "line %d: %s %s\n", lineno, - "Warning, unknown filesystem type", cp); - v = FS_UNUSED; - } - pp->p_fstype = v; - gottype: - - switch (pp->p_fstype) { - - case FS_UNUSED: /* XXX */ - NXTNUM(pp->p_fsize); - if (pp->p_fsize == 0) - break; - NXTNUM(v); - pp->p_frag = v / pp->p_fsize; - break; - - case FS_BSDFFS: - NXTNUM(pp->p_fsize); - if (pp->p_fsize == 0) - break; - NXTNUM(v); - pp->p_frag = v / pp->p_fsize; - NXTNUM(pp->p_cpg); break; + } else { + pp->p_size = v; - case FS_BSDLFS: - NXTNUM(pp->p_fsize); - if (pp->p_fsize == 0) + v = 0; + NXTWORD(part_offset_type[part],v); + if (v < 0 || (v == 0 && + part_offset_type[part] != '*' && + part_offset_type[part] != '\0')) { + fprintf(stderr, + "line %d: %s: bad partition offset\n", + lineno, cp); + errors++; break; - NXTNUM(v); - pp->p_frag = v / pp->p_fsize; - NXTNUM(pp->p_cpg); - break; - - default: - break; + } else { + pp->p_offset = v; + cp = tp, tp = word(cp); + cpp = fstypenames; + for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) + if ((s = *cpp) && streq(s, cp)) { + pp->p_fstype = cpp - + fstypenames; + goto gottype; + } + if (isdigit(*cp)) + v = atoi(cp); + else + v = FSMAXTYPES; + if ((unsigned)v >= FSMAXTYPES) { + fprintf(stderr, + "line %d: Warning, unknown " + "filesystem type %s\n", + lineno, cp); + v = FS_UNUSED; + } + pp->p_fstype = v; + gottype:; + /* + * Note: NXTNUM will break us out of the + * switch only! + */ + switch (pp->p_fstype) { + case FS_UNUSED: + /* + * allow us to accept defaults for + * fsize/frag/cpg + */ + if (tp) { + NXTNUM(pp->p_fsize); + if (pp->p_fsize == 0) + break; + NXTNUM(v); + pp->p_frag = v / pp->p_fsize; + } + /* else default to 0's */ + break; + + /* These happen to be the same */ + case FS_BSDFFS: + case FS_BSDLFS: + if (tp) { + NXTNUM(pp->p_fsize); + if (pp->p_fsize == 0) + break; + NXTNUM(v); + pp->p_frag = v / pp->p_fsize; + NXTNUM(pp->p_cpg); + } else { + /* + * FIX! poor attempt at + * adaptive + */ + /* 1 GB */ + if (pp->p_size < 1*1024*1024*1024/lp->d_secsize) { +/* FIX! These are too low, but are traditional */ + pp->p_fsize = DEFAULT_NEWFS_BLOCK; + pp->p_frag = (unsigned char) DEFAULT_NEWFS_FRAG; + pp->p_cpg = DEFAULT_NEWFS_CPG; + } else { + pp->p_fsize = BIG_NEWFS_BLOCK; + pp->p_frag = (unsigned char) BIG_NEWFS_FRAG; + pp->p_cpg = BIG_NEWFS_CPG; + } + } + break; + default: + break; + } + + /* + * note: we may not have + * gotten all the entries for + * the fs though if we didn't, + * errors will be set. + */ + } } continue; } fprintf(stderr, "line %d: %s: Unknown disklabel field\n", lineno, cp); errors++; - next: - ; + next:; } errors += checklabel(lp); return (errors == 0); @@ -1249,6 +1331,11 @@ checklabel(lp) register struct partition *pp; int i, errors = 0; char part; + unsigned long total_size,total_percent,current_offset; + int seen_default_offset; + int hog_part; + int j; + struct partition *pp2; if (lp->d_secsize == 0) { fprintf(stderr, "sector size 0\n"); @@ -1285,6 +1372,153 @@ checklabel(lp) if (lp->d_npartitions > MAXPARTITIONS) Warning("number of partitions (%lu) > MAXPARTITIONS (%d)", (u_long)lp->d_npartitions, MAXPARTITIONS); + + /* first allocate space to the partitions, then offsets */ + total_size = 0; /* in sectors */ + total_percent = 0; /* in percent */ + hog_part = -1; + /* find all fixed partitions */ + for (i = 0; i < lp->d_npartitions; i++) { + pp = &lp->d_partitions[i]; + if (part_set[i]) { + if (part_size_type[i] == '*') { + /* partition 2 ('c') is special */ + if (i == FULL_DISK_PART) { + pp->p_size = lp->d_secperunit; + } else { + if (hog_part != -1) + Warning("Too many '*' partitions (%c and %c)", + hog_part + 'a',i + 'a'); + else + hog_part = i; + } + } else { + char *type; + unsigned long size; + + size = pp->p_size; + switch (part_size_type[i]) { + case '%': + total_percent += size; + break; + case 'k': + case 'K': + size *= 1024UL; + break; + case 'm': + case 'M': + size *= ((unsigned long) 1024*1024); + break; + case 'g': + case 'G': + size *= ((unsigned long) 1024*1024*1024); + break; + case '\0': + break; + default: + Warning("unknown size specifier '%c' (K/M/G are valid)",part_size_type[i]); + break; + } + /* don't count %'s yet */ + if (part_size_type[i] != '%') { + /* + * for all not in sectors, convert to + * sectors + */ + if (part_size_type[i] != '\0') { + if (size % lp->d_secsize != 0) + Warning("partition %c not an integer number of sectors", + i + 'a'); + size /= lp->d_secsize; + pp->p_size = size; + } + /* else already in sectors */ + /* partition 2 ('c') is special */ + if (i != FULL_DISK_PART) + total_size += size; + } + } + } + } + /* handle % partitions - note %'s don't need to add up to 100! */ + if (total_percent != 0) { + long free_space = lp->d_secperunit - total_size; + if (total_percent > 100) { + fprintf(stderr,"total percentage %d is greater than 100\n", + total_percent); + errors++; + } + + if (free_space > 0) { + for (i = 0; i < lp->d_npartitions; i++) { + pp = &lp->d_partitions[i]; + if (part_set[i] && part_size_type[i] == '%') { + unsigned long old_size = pp->p_size; + /* careful of overflows! and integer roundoff */ + pp->p_size = ((double)pp->p_size/100) * free_space; + total_size += pp->p_size; + + /* FIX we can lose a sector or so due to roundoff per + partition. A more complex algorithm could avoid that */ + } + } + } else { + fprintf(stderr, + "%ld sectors available to give to '*' and '%' partitions\n", + free_space); + errors++; + /* fix? set all % partitions to size 0? */ + } + } + /* give anything remaining to the hog partition */ + if (hog_part != -1) { + lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size; + total_size = lp->d_secperunit; + } + + /* Now set the offsets for each partition */ + current_offset = 0; /* in sectors */ + seen_default_offset = 0; + for (i = 0; i < lp->d_npartitions; i++) { + part = 'a' + i; + pp = &lp->d_partitions[i]; + if (part_set[i]) { + if (part_offset_type[i] == '*') { + /* partition 2 ('c') is special */ + if (i == FULL_DISK_PART) { + pp->p_offset = 0; + } else { + pp->p_offset = current_offset; + seen_default_offset = 1; + } + } else { + /* allow them to be out of order for old-style tables */ + /* partition 2 ('c') is special */ + if (pp->p_offset < current_offset && + seen_default_offset && i != FULL_DISK_PART) { + fprintf(stderr, +"Offset %ld for partition %c overlaps previous partition which ends at %ld\n", + pp->p_offset,i+'a',current_offset); + fprintf(stderr, +"Labels with any *'s for offset must be in ascending order by sector\n"); + errors++; + } else if (pp->p_offset != current_offset && + i != FULL_DISK_PART && seen_default_offset) { + /* + * this may give unneeded warnings if + * partitions are out-of-order + */ + Warning( +"Offset %ld for partition %c doesn't match expected value %ld", + pp->p_offset, i + 'a', current_offset); + } + } + /* partition 2 ('c') is special */ + if (i != FULL_DISK_PART) + current_offset = pp->p_offset + pp->p_size; + } + } + for (i = 0; i < lp->d_npartitions; i++) { part = 'a' + i; pp = &lp->d_partitions[i]; @@ -1310,6 +1544,38 @@ checklabel(lp) part); errors++; } + if (i == FULL_DISK_PART) + { + if (pp->p_fstype != FS_UNUSED) + Warning("partition %c is not marked as unused!",part); + if (pp->p_offset != 0) + Warning("partition %c doesn't start at 0!",part); + if (pp->p_size != lp->d_secperunit) + Warning("partition %c doesn't cover the whole unit!",part); + + if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) || + (pp->p_size != lp->d_secperunit)) { + Warning("An incorrect partition %c may cause problems for " + "standard system utilities",part); + } + } + + /* check for overlaps */ + /* this will check for all possible overlaps once and only once */ + for (j = 0; j < i; j++) { + /* partition 2 ('c') is special */ + if (j != FULL_DISK_PART && i != FULL_DISK_PART && + part_set[i] && part_set[j]) { + pp2 = &lp->d_partitions[j]; + if (pp2->p_offset < pp->p_offset + pp->p_size && + (pp2->p_offset + pp2->p_size > pp->p_offset || + pp2->p_offset >= pp->p_offset)) { + fprintf(stderr,"partitions %c and %c overlap!\n", + j + 'a', i + 'a'); + errors++; + } + } + } } for (; i < MAXPARTITIONS; i++) { part = 'a' + i; @@ -1352,11 +1618,11 @@ getvirginlabel(void) * fallback to the old get-disdk-info ioctl. */ if (ioctl(f, DIOCGDVIRGIN, &lab) < 0) { - if (ioctl(f, DIOCGDINFO, &lab) < 0) { - warn("ioctl DIOCGDINFO"); - close(f); - return (NULL); - } + if (ioctl(f, DIOCGDINFO, &lab) < 0) { + warn("ioctl DIOCGDINFO"); + close(f); + return (NULL); + } } close(f); lab.d_boot0 = NULL; @@ -1427,25 +1693,25 @@ usage() 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", "usage: disklabel [-r] disk", "\t\t(to read label)", - " disklabel -w [-r] disk type [ packid ]", + " disklabel -w [-r] [-n] disk type [ packid ]", "\t\t(to write label with existing boot program)", - " disklabel -e [-r] disk", + " disklabel -e [-r] [-n] disk", "\t\t(to edit label)", - " disklabel -R [-r] disk protofile", + " disklabel -R [-r] [-n] disk protofile", "\t\t(to restore label with existing boot program)", #if NUMBOOT > 1 - " disklabel -B [ -b boot1 [ -s boot2 ] ] disk [ type ]", + " disklabel -B [-n] [ -b boot1 [ -s boot2 ] ] disk [ type ]", "\t\t(to install boot program with existing label)", - " disklabel -w -B [ -b boot1 [ -s boot2 ] ] disk type [ packid ]", + " disklabel -w -B [-n] [ -b boot1 [ -s boot2 ] ] disk type [ packid ]", "\t\t(to write label and boot program)", - " disklabel -R -B [ -b boot1 [ -s boot2 ] ] disk protofile [ type ]", + " disklabel -R -B [-n] [ -b boot1 [ -s boot2 ] ] disk protofile [ type ]", "\t\t(to restore label and boot program)", #else - " disklabel -B [ -b bootprog ] disk [ type ]", + " disklabel -B [-n] [ -b bootprog ] disk [ type ]", "\t\t(to install boot program with existing on-disk label)", - " disklabel -w -B [ -b bootprog ] disk type [ packid ]", + " disklabel -w -B [-n] [ -b bootprog ] disk type [ packid ]", "\t\t(to write label and install boot program)", - " disklabel -R -B [ -b bootprog ] disk protofile [ type ]", + " disklabel -R -B [-n] [ -b bootprog ] disk protofile [ type ]", "\t\t(to restore label and install boot program)", #endif " disklabel [-NW] disk", @@ -1453,11 +1719,11 @@ usage() #else fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", "usage: disklabel [-r] disk", "(to read label)", - " disklabel -w [-r] disk type [ packid ]", + " disklabel -w [-r] [-n] disk type [ packid ]", "\t\t(to write label)", - " disklabel -e [-r] disk", + " disklabel -e [-r] [-n] disk", "\t\t(to edit label)", - " disklabel -R [-r] disk protofile", + " disklabel -R [-r] [-n] disk protofile", "\t\t(to restore label)", " disklabel [-NW] disk", "\t\t(to write disable/enable label)"); diff --git a/sbin/disklabel/disklabel.8 b/sbin/disklabel/disklabel.8 index fb16eab..0486c52 100644 --- a/sbin/disklabel/disklabel.8 +++ b/sbin/disklabel/disklabel.8 @@ -48,15 +48,18 @@ .Nm .Fl w .Op Fl r +.Op Fl n .Ar disk Ar disktype/auto .Oo Ar packid Oc .Nm .Fl e .Op Fl r +.Op Fl n .Ar disk .Nm .Fl R .Op Fl r +.Op Fl n .Ar disk Ar protofile .Nm .Op Fl NW @@ -73,6 +76,7 @@ .Nm .Fl w .Fl B +.Op Fl n .Oo .Fl b Ar boot1 .Fl s Ar boot2 @@ -82,6 +86,7 @@ .Nm .Fl R .Fl B +.Op Fl n .Oo .Fl b Ar boot1 .Fl s Ar boot2 @@ -170,12 +175,14 @@ To write a standard label, use the form .Nm .Fl w .Op Fl r +.Op Fl n .Ar disk Ar disktype/auto .Oo Ar packid Oc .Pp .Nm .Fl w .Op Fl r +.Op Fl n .Ar disk auto .Pp @@ -188,7 +195,14 @@ different disks of the same physical type are to have different partitions, it will be necessary to have separate disktab entries describing each, or to edit the label after installation as described below. The optional argument is a pack identification string, up to 16 characters long. The pack id must be -quoted if it contains blanks. If the +quoted if it contains blanks. +.Pp +If the +.Fl n +flag is given, no data will be written to the device, and instead the +disklabel that would have been written will be printed to stdout. +.Pp +If the .Fl r flag is given, the disk sectors containing the label and bootstrap will be written directly. @@ -220,6 +234,9 @@ disk is the only supported operation, and the itself must be provided as the canonical name, i.e. not as a full path name. .Pp +For most harddisks, a label based on percentages for most partitions (and +one partition with a size of '*') will produce a reasonable configuration. +.Pp PC-based systems have special requirements in order for the BIOS to properly recognize a .Fx @@ -244,6 +261,7 @@ To edit an existing disk label, use the form .Nm .Fl e .Op Fl r +.Op Fl n .Ar disk .Pp This command reads the label from the in-core kernel copy, or directly from the @@ -257,7 +275,11 @@ environment variable, is used. When the editor terminates, the label file is used to rewrite the disk label. Existing bootstrap code is unchanged regardless of whether .Fl r -was specified. +was specified. If +.Fl n +is specified, no data will be written to the device, and instead the +disklabel that would have been written will be printed to stdout. This is +useful to see how a partitioning scheme will work out for a specific disk. .Ss Restoring a disk label from a file .Pp To restore a disk label from a file, use the form @@ -265,6 +287,7 @@ To restore a disk label from a file, use the form .Nm .Fl R .Op Fl r +.Op Fl n .Ar disk Ar protofile .Pp .Nm @@ -277,6 +300,11 @@ clobbered if .Fl r is specified and will be unaffected otherwise. See the boot options below for a method of restoring the label and writing the bootstrap at the same time. +If +.Fl n +is used, no data will be written to the device, and instead the +disklabel that would have been written will be printed to stdout. This is +useful to see how a partitioning scheme will work out for a specific disk. .Ss Enabling and disabling writing to the disk label area .Pp By default, it is not possible to write to the disk label area at the beginning @@ -331,6 +359,7 @@ This command is typically run on a slice such as .Nm .Fl w .Fl B +.Op Fl n .Oo .Fl b Ar boot1 .Fl s Ar boot2 @@ -345,10 +374,15 @@ In addition to writing a new volume label, it also installs the bootstrap. If run on a base disk this command will create a .Dq dangerously-dedicated label. This command is normally run on a slice rather than a base disk. +If +.Fl n +is used, no data will be written to the device, and instead the +disklabel that would have been written will be printed to stdout. .Pp .Nm .Fl R .Fl B +.Op Fl n .Oo .Fl b Ar boot1 .Fl s Ar boot2 @@ -367,7 +401,10 @@ label. This command is normally run on a slice rather than a base disk. The bootstrap commands always access the disk directly, so it is not necessary to specify the .Fl r -flag. +flag. If +.Fl n +is used, no data will be written to the device, and instead the +disklabel that would have been written will be printed to stdout. .Pp The bootstrap code is comprised of two boot programs. Specify the name of the boot programs to be installed in one of these ways: @@ -548,21 +585,63 @@ By convention, partition .Nm c is reserved to describe the entire disk. .It size -is the size of the partition in sectors. +is the size of the partition in sectors, +.Nm K +(kilobytes - 1024), +.Nm M +(megabytes - 1024*1024), +.Nm G +(gigabytes - 1024*1024*1024), +.Nm % +(percentage of free space AFTER removing any fixed-size partitions other +than partition +.Nm c +), or * (all remaining free space AFTER fixed-size and percentage +partitions). For partition +.Nm c , +a size of * indicates the entire disk. Lowercase versions of K, M, and G +are allowed. +Size and type should be specifed without any spaces between them. +.Pp +Example: 2097152, 1g, 1024m and 1048576k are all the same size +(assuming 512-byte sectors). .It offset -is the offset of the start of the partition from the beginning of the drive. +is the offset of the start of the partition from the beginning of the +drive in sectors, or * to have +.Nm +calculate the correct offset to use (the end of the previous partition plus +one, ignoring partition +.Nm c . +For partition +.Nm c , +* will be interpreted as an offset of 0. .It fstype describes the purpose of the partition. The example shows most normal usages. -For UFS file systems, use type 4.2BSD. See +For UFS file systems, use type +.Nm 4.2BSD . +Other common types are +.Nm unused +and +.Nm swap . +See .Pa /usr/include/sys/disklabel.h for a complete list. .It fsize -For file systems only, the fragment size. +For +.Nm 4.2BSD +and LFS file systems only, the fragment size. Defaults to 8192 for +partitions smaller than 1 GB, 16384 for partitions 1GB or larger. .It bsize -For file systems only, the block size. +For +.Nm 4.2BSD +and LFS file systems only, the block size. Defaults to 1024 for +partitions smaller than 1 GB, 4096 for partitions 1GB or larger. .It bps/cpg -For UFS file systems, the number of cylinders in a cylinder group. For LFS file -systems, the segment shift value. +For +.Nm 4.2BSD +file systems, the number of cylinders in a cylinder group. For LFS file +systems, the segment shift value. Defaults to 16 for +partitions smaller than 1 GB, 64 for partitions 1GB or larger. .El .Pp The remainder of the line is a comment and shows the cylinder allocations based @@ -611,6 +690,13 @@ Read the on-disk label for edit it and reinstall in-core as well as on-disk. Existing bootstrap code is unaffected. .Pp +.Dl disklabel -e -r -n da0s1 +.Pp +Read the on-disk label for +.Pa da0s1 , +edit it, and display what the new label would be (in sectors). It does +NOT install the new label either in-core or on-disk. +.Pp .Dl disklabel -r -w da0s1 auto .Pp Try to auto-detect the required information from @@ -626,6 +712,15 @@ from information in .Pa savedlabel . Existing bootstrap code is unaffected. .Pp +.Dl disklabel -R -n da0s1 label_layout +.Pp +Display what the label would be for +.Pa da0s1 +using the partition layout in +.Pa label_layout . +This is useful for determining how much space would be alloted for various +partitions with a labelling scheme using %-based or * partition sizes. +.Pp .Dl disklabel -B da0s1 .Pp Install a new bootstrap on @@ -661,6 +756,40 @@ initialize the slice, then edit it to your needs. The .Pa dd commands are optional, but may be necessary for some BIOSes to properly recognize the disk. +.Pp +This is an example disklabel that uses some of the new partition size types +such as %, M, G, and *, which could be used as a source file for +.Pp +.Dl disklabel -R ad0s1c new_label_file +.Bd -literal -offset 4n +# /dev/ad0s1c: +type: ESDI +disk: ad0s1 +label: +flags: +bytes/sector: 512 +sectors/track: 63 +tracks/cylinder: 16 +sectors/cylinder: 1008 +cylinders: 40633 +sectors/unit: 40959009 +rpm: 3600 +interleave: 1 +trackskew: 0 +cylinderskew: 0 +headswitch: 0 # milliseconds +track-to-track seek: 0 # milliseconds +drivedata: 0 + +8 partitions: +# size offset fstype [fsize bsize bps/cpg] + a: 400M 0 4.2BSD 4096 16384 75 # (Cyl. 0 - 812*) + b: 1G * swap + c: * * unused + e: 204800 * 4.2BSD + f: 5g * 4.2BSD + g: * * 4.2BSD +.Ed .Sh SEE ALSO .Xr disklabel 5 , .Xr disktab 5 , @@ -723,5 +852,9 @@ concern if the disk is fully dedicated, so that the BSD disklabel starts at absolute block 0 on the disk. .Pp .Nm -does not perform adequate error checking. No warning is given if partitions -overlap, nor if space remains unused. +does not perform all possible error checking. Warning *is* given if partitions +overlap; if an absolute offset doesn't match the expected offset; if the +.Nm c +partition doesn't start at 0 or doesn't cover the entire slice; if a +partition runs past the end of the device; and a number of other errors; but +no warning is given if space remains unused. diff --git a/sbin/disklabel/disklabel.c b/sbin/disklabel/disklabel.c index 484f073..cec9cc0 100644 --- a/sbin/disklabel/disklabel.c +++ b/sbin/disklabel/disklabel.c @@ -80,6 +80,15 @@ static const char rcsid[] = #define BBSIZE 8192 /* size of boot area, with label */ #endif +/* FIX! These are too low, but are traditional */ +#define DEFAULT_NEWFS_BLOCK 8192U +#define DEFAULT_NEWFS_FRAG 1024U +#define DEFAULT_NEWFS_CPG 16U + +#define BIG_NEWFS_BLOCK 16384U +#define BIG_NEWFS_FRAG 4096U +#define BIG_NEWFS_CPG 64U + #ifdef tahoe #define NUMBOOT 0 #else @@ -118,6 +127,14 @@ char namebuf[BBSIZE], *np = namebuf; struct disklabel lab; char bootarea[BBSIZE]; +/* partition 'c' is the full disk and is special */ +#define FULL_DISK_PART 2 +#define MAX_PART ('z') +#define MAX_NUM_PARTS (1 + MAX_PART - 'a') +char part_size_type[MAX_NUM_PARTS]; +char part_offset_type[MAX_NUM_PARTS]; +int part_set[MAX_NUM_PARTS]; + #if NUMBOOT > 0 int installboot; /* non-zero if we should install a boot program */ char *bootbuf; /* pointer to buffer with remainder of boot prog */ @@ -133,12 +150,13 @@ enum { } op = UNSPEC; int rflag; +int disable_write; /* set to disable writing to disk label */ #ifdef DEBUG int debug; -#define OPTIONS "BNRWb:ders:w" +#define OPTIONS "BNRWb:denrs:w" #else -#define OPTIONS "BNRWb:ers:w" +#define OPTIONS "BNRWb:enrs:w" #endif int @@ -171,6 +189,9 @@ main(argc, argv) usage(); op = NOWRITE; break; + case 'n': + disable_write = 1; + break; case 'R': if (op != UNSPEC) usage(); @@ -397,75 +418,81 @@ writelabel(f, boot, lp) register int i; #endif - setbootflag(lp); - lp->d_magic = DISKMAGIC; - lp->d_magic2 = DISKMAGIC; - lp->d_checksum = 0; - lp->d_checksum = dkcksum(lp); - if (rflag) { - /* - * First set the kernel disk label, - * then write a label to the raw disk. - * If the SDINFO ioctl fails because it is unimplemented, - * keep going; otherwise, the kernel consistency checks - * may prevent us from changing the current (in-core) - * label. - */ - if (ioctl(f, DIOCSDINFO, lp) < 0 && - errno != ENODEV && errno != ENOTTY) { - l_perror("ioctl DIOCSDINFO"); - return (1); - } - (void)lseek(f, (off_t)0, SEEK_SET); - + if (disable_write) { + Warning("write to disk label supressed - label was as follows:"); + display(stdout, lp); + return (0); + } else { + setbootflag(lp); + lp->d_magic = DISKMAGIC; + lp->d_magic2 = DISKMAGIC; + lp->d_checksum = 0; + lp->d_checksum = dkcksum(lp); + if (rflag) { + /* + * First set the kernel disk label, + * then write a label to the raw disk. + * If the SDINFO ioctl fails because it is unimplemented, + * keep going; otherwise, the kernel consistency checks + * may prevent us from changing the current (in-core) + * label. + */ + if (ioctl(f, DIOCSDINFO, lp) < 0 && + errno != ENODEV && errno != ENOTTY) { + l_perror("ioctl DIOCSDINFO"); + return (1); + } + (void)lseek(f, (off_t)0, SEEK_SET); + #ifdef __alpha__ - /* - * Generate the bootblock checksum for the SRM console. - */ - for (p = (u_long *)boot, i = 0, sum = 0; i < 63; i++) - sum += p[i]; - p[63] = sum; + /* + * Generate the bootblock checksum for the SRM console. + */ + for (p = (u_long *)boot, i = 0, sum = 0; i < 63; i++) + sum += p[i]; + p[63] = sum; #endif - - /* - * write enable label sector before write (if necessary), - * disable after writing. - */ - flag = 1; - if (ioctl(f, DIOCWLABEL, &flag) < 0) - warn("ioctl DIOCWLABEL"); - if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) { - warn("write"); - return (1); - } + + /* + * write enable label sector before write (if necessary), + * disable after writing. + */ + flag = 1; + if (ioctl(f, DIOCWLABEL, &flag) < 0) + warn("ioctl DIOCWLABEL"); + if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) { + warn("write"); + return (1); + } #if NUMBOOT > 0 - /* - * Output the remainder of the disklabel - */ - if (bootbuf && write(f, bootbuf, bootsize) != bootsize) { - warn("write"); - return(1); - } + /* + * Output the remainder of the disklabel + */ + if (bootbuf && write(f, bootbuf, bootsize) != bootsize) { + warn("write"); + return(1); + } #endif - flag = 0; - (void) ioctl(f, DIOCWLABEL, &flag); - } else if (ioctl(f, DIOCWDINFO, lp) < 0) { - l_perror("ioctl DIOCWDINFO"); - return (1); - } + flag = 0; + (void) ioctl(f, DIOCWLABEL, &flag); + } else if (ioctl(f, DIOCWDINFO, lp) < 0) { + l_perror("ioctl DIOCWDINFO"); + return (1); + } #ifdef vax - if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { - daddr_t alt; - - alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; - for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { - (void)lseek(f, (off_t)((alt + i) * lp->d_secsize), - SEEK_SET); - if (write(f, boot, lp->d_secsize) < lp->d_secsize) - warn("alternate label %d write", i/2); + if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { + daddr_t alt; + + alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; + for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { + (void)lseek(f, (off_t)((alt + i) * lp->d_secsize), + SEEK_SET); + if (write(f, boot, lp->d_secsize) < lp->d_secsize) + warn("alternate label %d write", i/2); + } } - } #endif + } return (0); } @@ -933,6 +960,8 @@ getasciilabel(f, lp) { register char **cpp, *cp; register struct partition *pp; + int i; + unsigned int part; char *tp, *s, line[BUFSIZ]; int v, lineno = 0, errors = 0; @@ -1137,16 +1166,18 @@ getasciilabel(f, lp) lp->d_trkseek = v; continue; } - if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') { - unsigned part = *cp - 'a'; - - if (part > lp->d_npartitions) { + /* the ':' was removed above */ + if ('a' <= *cp && *cp <= MAX_PART && cp[1] == '\0') { + part = *cp - 'a'; + if (part >= lp->d_npartitions) { fprintf(stderr, - "line %d: bad partition name\n", lineno); + "line %d: partition name out of range a-%c: %s\n", + lineno, 'a' + lp->d_npartitions - 1, cp); errors++; continue; } pp = &lp->d_partitions[part]; + part_set[part] = 1; #define NXTNUM(n) { \ if (tp == NULL) { \ fprintf(stderr, "line %d: too few numeric fields\n", lineno); \ @@ -1159,80 +1190,131 @@ getasciilabel(f, lp) (n) = atoi(cp); \ } \ } - - NXTNUM(v); - if (v < 0) { +/* retain 1 character following number */ +#define NXTWORD(w,n) { \ + if (tp == NULL) { \ + fprintf(stderr, "line %d: too few numeric fields\n", lineno); \ + errors++; \ + break; \ + } else { \ + char *tmp; \ + cp = tp, tp = word(cp); \ + if (tp == NULL) \ + tp = cp; \ + (n) = strtol(cp,&tmp,10); \ + if (tmp) (w) = *tmp; \ + } \ + } + v = 0; + NXTWORD(part_size_type[part],v); + if (v < 0 || (v == 0 && part_size_type[part] != '*')) { fprintf(stderr, "line %d: %s: bad partition size\n", lineno, cp); errors++; - } else - pp->p_size = v; - NXTNUM(v); - if (v < 0) { - fprintf(stderr, - "line %d: %s: bad partition offset\n", - lineno, cp); - errors++; - } else - pp->p_offset = v; - cp = tp, tp = word(cp); - cpp = fstypenames; - for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) - if ((s = *cpp) && streq(s, cp)) { - pp->p_fstype = cpp - fstypenames; - goto gottype; - } - if (isdigit(*cp)) - v = atoi(cp); - else - v = FSMAXTYPES; - if ((unsigned)v >= FSMAXTYPES) { - fprintf(stderr, "line %d: %s %s\n", lineno, - "Warning, unknown filesystem type", cp); - v = FS_UNUSED; - } - pp->p_fstype = v; - gottype: - - switch (pp->p_fstype) { - - case FS_UNUSED: /* XXX */ - NXTNUM(pp->p_fsize); - if (pp->p_fsize == 0) - break; - NXTNUM(v); - pp->p_frag = v / pp->p_fsize; - break; - - case FS_BSDFFS: - NXTNUM(pp->p_fsize); - if (pp->p_fsize == 0) - break; - NXTNUM(v); - pp->p_frag = v / pp->p_fsize; - NXTNUM(pp->p_cpg); break; + } else { + pp->p_size = v; - case FS_BSDLFS: - NXTNUM(pp->p_fsize); - if (pp->p_fsize == 0) + v = 0; + NXTWORD(part_offset_type[part],v); + if (v < 0 || (v == 0 && + part_offset_type[part] != '*' && + part_offset_type[part] != '\0')) { + fprintf(stderr, + "line %d: %s: bad partition offset\n", + lineno, cp); + errors++; break; - NXTNUM(v); - pp->p_frag = v / pp->p_fsize; - NXTNUM(pp->p_cpg); - break; - - default: - break; + } else { + pp->p_offset = v; + cp = tp, tp = word(cp); + cpp = fstypenames; + for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) + if ((s = *cpp) && streq(s, cp)) { + pp->p_fstype = cpp - + fstypenames; + goto gottype; + } + if (isdigit(*cp)) + v = atoi(cp); + else + v = FSMAXTYPES; + if ((unsigned)v >= FSMAXTYPES) { + fprintf(stderr, + "line %d: Warning, unknown " + "filesystem type %s\n", + lineno, cp); + v = FS_UNUSED; + } + pp->p_fstype = v; + gottype:; + /* + * Note: NXTNUM will break us out of the + * switch only! + */ + switch (pp->p_fstype) { + case FS_UNUSED: + /* + * allow us to accept defaults for + * fsize/frag/cpg + */ + if (tp) { + NXTNUM(pp->p_fsize); + if (pp->p_fsize == 0) + break; + NXTNUM(v); + pp->p_frag = v / pp->p_fsize; + } + /* else default to 0's */ + break; + + /* These happen to be the same */ + case FS_BSDFFS: + case FS_BSDLFS: + if (tp) { + NXTNUM(pp->p_fsize); + if (pp->p_fsize == 0) + break; + NXTNUM(v); + pp->p_frag = v / pp->p_fsize; + NXTNUM(pp->p_cpg); + } else { + /* + * FIX! poor attempt at + * adaptive + */ + /* 1 GB */ + if (pp->p_size < 1*1024*1024*1024/lp->d_secsize) { +/* FIX! These are too low, but are traditional */ + pp->p_fsize = DEFAULT_NEWFS_BLOCK; + pp->p_frag = (unsigned char) DEFAULT_NEWFS_FRAG; + pp->p_cpg = DEFAULT_NEWFS_CPG; + } else { + pp->p_fsize = BIG_NEWFS_BLOCK; + pp->p_frag = (unsigned char) BIG_NEWFS_FRAG; + pp->p_cpg = BIG_NEWFS_CPG; + } + } + break; + default: + break; + } + + /* + * note: we may not have + * gotten all the entries for + * the fs though if we didn't, + * errors will be set. + */ + } } continue; } fprintf(stderr, "line %d: %s: Unknown disklabel field\n", lineno, cp); errors++; - next: - ; + next:; } errors += checklabel(lp); return (errors == 0); @@ -1249,6 +1331,11 @@ checklabel(lp) register struct partition *pp; int i, errors = 0; char part; + unsigned long total_size,total_percent,current_offset; + int seen_default_offset; + int hog_part; + int j; + struct partition *pp2; if (lp->d_secsize == 0) { fprintf(stderr, "sector size 0\n"); @@ -1285,6 +1372,153 @@ checklabel(lp) if (lp->d_npartitions > MAXPARTITIONS) Warning("number of partitions (%lu) > MAXPARTITIONS (%d)", (u_long)lp->d_npartitions, MAXPARTITIONS); + + /* first allocate space to the partitions, then offsets */ + total_size = 0; /* in sectors */ + total_percent = 0; /* in percent */ + hog_part = -1; + /* find all fixed partitions */ + for (i = 0; i < lp->d_npartitions; i++) { + pp = &lp->d_partitions[i]; + if (part_set[i]) { + if (part_size_type[i] == '*') { + /* partition 2 ('c') is special */ + if (i == FULL_DISK_PART) { + pp->p_size = lp->d_secperunit; + } else { + if (hog_part != -1) + Warning("Too many '*' partitions (%c and %c)", + hog_part + 'a',i + 'a'); + else + hog_part = i; + } + } else { + char *type; + unsigned long size; + + size = pp->p_size; + switch (part_size_type[i]) { + case '%': + total_percent += size; + break; + case 'k': + case 'K': + size *= 1024UL; + break; + case 'm': + case 'M': + size *= ((unsigned long) 1024*1024); + break; + case 'g': + case 'G': + size *= ((unsigned long) 1024*1024*1024); + break; + case '\0': + break; + default: + Warning("unknown size specifier '%c' (K/M/G are valid)",part_size_type[i]); + break; + } + /* don't count %'s yet */ + if (part_size_type[i] != '%') { + /* + * for all not in sectors, convert to + * sectors + */ + if (part_size_type[i] != '\0') { + if (size % lp->d_secsize != 0) + Warning("partition %c not an integer number of sectors", + i + 'a'); + size /= lp->d_secsize; + pp->p_size = size; + } + /* else already in sectors */ + /* partition 2 ('c') is special */ + if (i != FULL_DISK_PART) + total_size += size; + } + } + } + } + /* handle % partitions - note %'s don't need to add up to 100! */ + if (total_percent != 0) { + long free_space = lp->d_secperunit - total_size; + if (total_percent > 100) { + fprintf(stderr,"total percentage %d is greater than 100\n", + total_percent); + errors++; + } + + if (free_space > 0) { + for (i = 0; i < lp->d_npartitions; i++) { + pp = &lp->d_partitions[i]; + if (part_set[i] && part_size_type[i] == '%') { + unsigned long old_size = pp->p_size; + /* careful of overflows! and integer roundoff */ + pp->p_size = ((double)pp->p_size/100) * free_space; + total_size += pp->p_size; + + /* FIX we can lose a sector or so due to roundoff per + partition. A more complex algorithm could avoid that */ + } + } + } else { + fprintf(stderr, + "%ld sectors available to give to '*' and '%' partitions\n", + free_space); + errors++; + /* fix? set all % partitions to size 0? */ + } + } + /* give anything remaining to the hog partition */ + if (hog_part != -1) { + lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size; + total_size = lp->d_secperunit; + } + + /* Now set the offsets for each partition */ + current_offset = 0; /* in sectors */ + seen_default_offset = 0; + for (i = 0; i < lp->d_npartitions; i++) { + part = 'a' + i; + pp = &lp->d_partitions[i]; + if (part_set[i]) { + if (part_offset_type[i] == '*') { + /* partition 2 ('c') is special */ + if (i == FULL_DISK_PART) { + pp->p_offset = 0; + } else { + pp->p_offset = current_offset; + seen_default_offset = 1; + } + } else { + /* allow them to be out of order for old-style tables */ + /* partition 2 ('c') is special */ + if (pp->p_offset < current_offset && + seen_default_offset && i != FULL_DISK_PART) { + fprintf(stderr, +"Offset %ld for partition %c overlaps previous partition which ends at %ld\n", + pp->p_offset,i+'a',current_offset); + fprintf(stderr, +"Labels with any *'s for offset must be in ascending order by sector\n"); + errors++; + } else if (pp->p_offset != current_offset && + i != FULL_DISK_PART && seen_default_offset) { + /* + * this may give unneeded warnings if + * partitions are out-of-order + */ + Warning( +"Offset %ld for partition %c doesn't match expected value %ld", + pp->p_offset, i + 'a', current_offset); + } + } + /* partition 2 ('c') is special */ + if (i != FULL_DISK_PART) + current_offset = pp->p_offset + pp->p_size; + } + } + for (i = 0; i < lp->d_npartitions; i++) { part = 'a' + i; pp = &lp->d_partitions[i]; @@ -1310,6 +1544,38 @@ checklabel(lp) part); errors++; } + if (i == FULL_DISK_PART) + { + if (pp->p_fstype != FS_UNUSED) + Warning("partition %c is not marked as unused!",part); + if (pp->p_offset != 0) + Warning("partition %c doesn't start at 0!",part); + if (pp->p_size != lp->d_secperunit) + Warning("partition %c doesn't cover the whole unit!",part); + + if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) || + (pp->p_size != lp->d_secperunit)) { + Warning("An incorrect partition %c may cause problems for " + "standard system utilities",part); + } + } + + /* check for overlaps */ + /* this will check for all possible overlaps once and only once */ + for (j = 0; j < i; j++) { + /* partition 2 ('c') is special */ + if (j != FULL_DISK_PART && i != FULL_DISK_PART && + part_set[i] && part_set[j]) { + pp2 = &lp->d_partitions[j]; + if (pp2->p_offset < pp->p_offset + pp->p_size && + (pp2->p_offset + pp2->p_size > pp->p_offset || + pp2->p_offset >= pp->p_offset)) { + fprintf(stderr,"partitions %c and %c overlap!\n", + j + 'a', i + 'a'); + errors++; + } + } + } } for (; i < MAXPARTITIONS; i++) { part = 'a' + i; @@ -1352,11 +1618,11 @@ getvirginlabel(void) * fallback to the old get-disdk-info ioctl. */ if (ioctl(f, DIOCGDVIRGIN, &lab) < 0) { - if (ioctl(f, DIOCGDINFO, &lab) < 0) { - warn("ioctl DIOCGDINFO"); - close(f); - return (NULL); - } + if (ioctl(f, DIOCGDINFO, &lab) < 0) { + warn("ioctl DIOCGDINFO"); + close(f); + return (NULL); + } } close(f); lab.d_boot0 = NULL; @@ -1427,25 +1693,25 @@ usage() 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", "usage: disklabel [-r] disk", "\t\t(to read label)", - " disklabel -w [-r] disk type [ packid ]", + " disklabel -w [-r] [-n] disk type [ packid ]", "\t\t(to write label with existing boot program)", - " disklabel -e [-r] disk", + " disklabel -e [-r] [-n] disk", "\t\t(to edit label)", - " disklabel -R [-r] disk protofile", + " disklabel -R [-r] [-n] disk protofile", "\t\t(to restore label with existing boot program)", #if NUMBOOT > 1 - " disklabel -B [ -b boot1 [ -s boot2 ] ] disk [ type ]", + " disklabel -B [-n] [ -b boot1 [ -s boot2 ] ] disk [ type ]", "\t\t(to install boot program with existing label)", - " disklabel -w -B [ -b boot1 [ -s boot2 ] ] disk type [ packid ]", + " disklabel -w -B [-n] [ -b boot1 [ -s boot2 ] ] disk type [ packid ]", "\t\t(to write label and boot program)", - " disklabel -R -B [ -b boot1 [ -s boot2 ] ] disk protofile [ type ]", + " disklabel -R -B [-n] [ -b boot1 [ -s boot2 ] ] disk protofile [ type ]", "\t\t(to restore label and boot program)", #else - " disklabel -B [ -b bootprog ] disk [ type ]", + " disklabel -B [-n] [ -b bootprog ] disk [ type ]", "\t\t(to install boot program with existing on-disk label)", - " disklabel -w -B [ -b bootprog ] disk type [ packid ]", + " disklabel -w -B [-n] [ -b bootprog ] disk type [ packid ]", "\t\t(to write label and install boot program)", - " disklabel -R -B [ -b bootprog ] disk protofile [ type ]", + " disklabel -R -B [-n] [ -b bootprog ] disk protofile [ type ]", "\t\t(to restore label and install boot program)", #endif " disklabel [-NW] disk", @@ -1453,11 +1719,11 @@ usage() #else fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", "usage: disklabel [-r] disk", "(to read label)", - " disklabel -w [-r] disk type [ packid ]", + " disklabel -w [-r] [-n] disk type [ packid ]", "\t\t(to write label)", - " disklabel -e [-r] disk", + " disklabel -e [-r] [-n] disk", "\t\t(to edit label)", - " disklabel -R [-r] disk protofile", + " disklabel -R [-r] [-n] disk protofile", "\t\t(to restore label)", " disklabel [-NW] disk", "\t\t(to write disable/enable label)"); |