From 3c677f61f4de959d73ab02195eebde3c5bb75f9d Mon Sep 17 00:00:00 2001 From: joerg Date: Tue, 1 Jun 2004 20:32:36 +0000 Subject: Major overhaul of sunlabel(8). . Implement option -c, all partition sizes will be calculated in cylinders as opposed to sectors. Since the Sun label is inherently cylinder-based, this makes the job a little easier. . Implement option -h, print the label in `human readable' size/offset format. . Implement SVR4-compatible VTOC-style elements. They are fully optional, defaulting to the current behaviour where no VTOC-style table will be written to disk. However, if desired, the full functionality of the partitioning menu of Solaris' format(1m) is now offered (and even more). . When editing the label, do not loop around edit_label() where a new template file is generated for each turn, this used to be annoying in that any possible syntax error caused a complaint, but then the template was created anew, so the user had to perform all their editing again. Rather loop inside edit_label(), similar to bsdlabel(8), so in case of errors, the user will be presented their previous template file again. . If VTOC-style elements are present, the overlap checks are made less stringent. Overlaps will still be warned about, but overlaps of `unmountable' partitions against other ones are no longer fatal. That way, e. g. VxVM encapsulated disk labels can be fully edited in FreeBSD (but not in Solaris ;-). . In print_label(), generate the editing hints only if the -e flag is in effect. Additionally, print a hint about the total number of sectors in the (hardware) medium. . When editing a label, allow for changing the geometry emulation (and textual name) by modifying the "text:" line on top. That way, a more effective emulation can be chosen. . When editing/reading a label, additionally allow for the suffixes `s' (512-byte sectors), and `c' (cylinders) in the partition size field. . Finally, turn the stub man page into something that really explains the entire thing. --- sbin/sunlabel/sunlabel.8 | 358 ++++++++++++++++++++++++++++++++++- sbin/sunlabel/sunlabel.c | 471 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 757 insertions(+), 72 deletions(-) (limited to 'sbin/sunlabel') diff --git a/sbin/sunlabel/sunlabel.8 b/sbin/sunlabel/sunlabel.8 index 4e56507..d2d2cff 100644 --- a/sbin/sunlabel/sunlabel.8 +++ b/sbin/sunlabel/sunlabel.8 @@ -1,5 +1,7 @@ .\" Copyright (c) 2004 .\" David E. O'Brien. All rights reserved. +.\" Copyright (c) 2004 +.\" Joerg Wunsch. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -24,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 29, 2004 +.Dd June 1, 2004 .Dt SUNLABEL 8 .Os .Sh NAME @@ -33,6 +35,7 @@ .Sh SYNOPSIS .Nm .Op Fl r +.Op Fl c No \&| Fl h .Ar disk .Nm .Fl B @@ -44,35 +47,378 @@ .Op Fl B Op Fl b Ar boot1 .Op Fl r .Op Fl n -.Ar disk profile +.Op Fl c +.Ar disk protofile .Nm .Fl e .Op Fl B Op Fl b Ar boot1 .Op Fl r .Op Fl n +.Op Fl c .Ar disk .Nm .Fl w .Op Fl B Op Fl b Ar boot1 .Op Fl r .Op Fl n +.Op Fl c .Ar disk type .Sh DESCRIPTION The .Nm utility -installs, examines or modifies the bootable -.Fx -label on a disk partition. +installs, examines or modifies the +.Em Sun OpenBoot PROM +label on a disk. In addition, .Nm can install bootstrap code. +.Ss Introduction +.Pp +The label occupies the first sector (i. e. 512 bytes) of each disk. +It starts with a textual description which by convention also mentions +the disk geometry in textual form (number of cylinders, alternate +cylinders, heads, and sectors per track), optionally followed by a +table of SVR4-compatible VTOC tags and flags per partition, followed +by the partition table itself. +Finally, a checksum is recorded to ensure the label has not been +tampered with. +.Pp +The +.Em Sun OpenBoot PROM +label allows for 8 disk partitions. +The partition table lists the starting cylinder of the partition, +plus the size of the partition in 512-byte sectors. +Thus, partitions in the +.Em Sun OpenBoot PROM +must always start at a cylinder boundary (for whatever geometry +emulation has been chosen). +.Pp +The optional SVR4-compatible VTOC tag and flags table is not used +by the +.Fx +kernel. +It is maintained solely for compatibilty with the +.Em Solaris +operating system that might share disks with +.Fx +on the same hardware platform. +.Pp +The +.Em Sun OpenBoot PROM +label is natively understood by the underlying hardware, which can +bootstrap from a single partition entry, as opposed to the very first +block(s) of the entire disk as on many other hardware platforms. +.Pp +Note that the hardware platform mandates that two cylinders are set +aside as +.Em alternate cylinders +which are not available to user programs (and not even through the +.Ql backup +partition). +.Ss Options +Options are listed in alphabetical order here. +Note that only those option combinations listed under +.Sx SYNOPSIS +are allowable. +.Pp +.Bl -tag -width ".Fl b Ar bootpath" +.It Fl b Ar bootpath +Specify that +.Ar bootpath +is to be used as the boot image, rather than the default of +.Pa /boot/boot1 . +.It Fl B +Install bootstrap code onto the disk. +Note that since the underlying hardware platform bootstraps from +partitions, not disks, this operation is only useful if there is +a partition starting at offset 0. +.It Fl c +Use cylinders for partition size display rather than +(512-byte) sectors. +This also changes the default interpretation of the partition +size entries when editing the label, or reading from a prototype +file. +Thus, prototype files are only compatible when both, obtaining +the file and re-installing it is done using the same +.Fl c +option setting. +.It Fl e +Enter edit mode. +See +.Sx Edit mode +below for a more detailed explanation. +.It Fl h +When displaying the label, make the partition size and offset +values +.Dq human readable . +The displayed numbers will get a suffix of +.Ql B +for bytes, +.Ql K +for 1024 bytes each, +.Ql M +for 1048576 bytes each, or +.Ql G +for 1073741824 bytes each appended. +Note that due to possible rounding errors, prototype files +obtained using the +.Fl h +option are not suited for re-installing using the +.Fl R +option. +.It Fl n +No changes. +All operations, checks etc. are performed normally, but nothing +is written to disk. +.It Fl r +Obsolete option that used to indicate that the operation should +be done directly on disk, as opposed through the respective kernel +services. +Ignored. +.It Fl R +Restore label from the prototype in +.Ar protofile . +A prototype file is simply the textual representation of the +label as printed using the first form of the +.Nm +utility shown in the +.Sx SYNOPSIS . +Note that the +.Fl c +option used to obtain the prototype must match the option used +when restoring the label (both present, or both absent). +.It Fl w +Write mode. +Suitable to write an initial label to disk. +The +.Ar type +argument used to be an entry into a table of predefined labels, +but this functionality is not supported by +.Nm . +Instead, the only allowable +.Ar type +argument is the string +.Dq auto , +indicating that an automatically created label should be written +to disk. +This automatism will try to create an initial label that fits as +best as possible into the available disk capacity. +.El +.Pp +If neither of the +.Fl e , +.Fl R , +or +.Fl w +options is present, the existing label for +.Ar disk +will be printed to standard output. +.Pp +.Ar disk +must be given as a plain disk name, without any leading +.Pa /dev/ . +.Ss Edit mode +In edit mode, the existing label from +.Ar disk +will be read, and put into a template file. +The command referenced by the +.Ev EDITOR +environmental variable will be started to allow the user +to edit the label. +The label is then checked and examined for any errors. +If no errors have been found, the new label is written to disk. +If there were any errors, a message is printed to standard +error output, and the user is asked whether they want to edit +the template file again. +If accepted, editing starts over, if declined, no changes will +be written to disk. +.Pp +The label presented for editing is the same as the standard +printout, with some added hints about the possible options to +specify the sector size and starting cylinder. +There are two areas in the template that can be edited: +.Pp +.Bl -tag -width indent +.It Sy Textual label, geometry emulation +The line +.Dl "text: XXXX cyl CC alt 2 hd HH sec SS" +represents the label text. +It must be retained exactly in the form shown. +The editable text +.Sy XXXX +is a simple (non-whitespace) text describing the disk. +By convention, this text mentions the approximate size of the +disk, as in +.Ql SUN9.0G +for a 9 GB disk shipped by Sun. +.Pp +The values +.Sy CC , +.Sy HH , +and +.Sy SS +describe the number of cylinders, heads (aka. tracks per +cylinder), and sectors per track respectively. +They might be modified to change the geometry emulation. +Each number must be between 1 and 65535. +The product +.D1 Em (CC + 2) * HH * SS +must be less than or equal to the total number of sectors of the +disk (which is given as a hint in a comment field). +.It Sy Partition entries +Partition entries start with a letter from +.Ql a +through +.Ql h , +immediately followed by a colon, followed by the size of this +partition, and the starting cylinder of the partition. +The unit of the size field defaults to sectors, or to cylinders +if the +.Fl c +option is in effect. +Alternatively, a different unit may be specified by appending +.Ql s +for (512-byte) sectors, +.Ql c +for cylinders, +.Ql k +for kilobytes, +.Ql m +for megabytes, or +.Ql g +for gigabytes. +The last partition entry may specify the size as +.Ql \&* +to indicate that this entry should consume the rest of disk not +consumed by any other partition so far. +.Pp +The start of partition is always taken as a cylinder number (starting +at 0) since this is what the underlying hardware uses. +Alternatively, specifying it as +.Ql \&* +will make the computation automatically chose the nearest possible +cylinder boundary. +.Pp +Partition +.Ql c +must always be present, must start at 0, and must cover the entire +disk (without considering the alternate cylinders though). +.Pp +Optionally, each partition entry may be followed by an SVR4-compatible +VTOC tag name, and a flag description. +The following VTOC tag names are known: +.Bl -column -offset indent ".Li unassigned" ".Sy value" ".Sy comment" +.It Sy name Ta Sy value Ta Sy comment +.It Li unassigned Ta No 0x00 +.It Li boot Ta No 0x01 +.It Li root Ta No 0x02 +.It Li swap Ta No 0x03 +.It Li usr Ta No 0x04 +.It Li backup Ta No 0x05 Ta c partition, entire disk +.It Li stand Ta No 0x06 +.It Li var Ta No 0x07 +.It Li home Ta No 0x08 +.It Li altsctr Ta No 0x09 Ta alternate sector partition +.It Li cache Ta No 0x0a Ta Solaris cachefs partition +.It Li VxVM_pub Ta No 0x0e Ta VxVM public region +.It Li VxVM_priv Ta No 0x0f Ta VxVM private region +.El +.Pp +The following VTOC flags are known: +.Bl -column -offset indent ".Sy name" ".Sy value" ".Sy comment" +.It Sy name Ta Sy value Ta Sy comment +.It Li wm Ta No 0x00 Ta read/write, mountable +.It Li wu Ta No 0x01 Ta read/write, unmountable +.It Li rm Ta No 0x10 Ta read/only, mountable +.It Li ru Ta No 0x11 Ta read/only, unmountable +.El +.Pp +Optionally, both the tag and/or the flag name may be specified +numerically, using standard +.Ql C +numerial notation (prefix +.Ql 0x +for hexadecimal numbers, +.Ql 0 +for octal numbers). +If the flag field is omitted, it defaults to +.Ql wm . +If the tag field is also omitted, it defaults to +.Ql unassigned . +If none of the partitions lists any VTOC tag/flags, no +SVR4-compatible VTOC elements will be written to disk. +If VTOC-style elements are present, partition +.Ql c +must be marked as +.Ql backup +(and should be marked +.Ql wu ) . +.El +.Pp +When checking the label, partition +.Ql c +is checked for presence, and for the mentioned restrictions. +All other partitions are checked for possible overlaps, as +well as for not extending past the end of unit. +If VTOC-style elements are present, overlaps of unmountable +partitions against other partitions will be warned still but +do not cause a rejection of the label. +That way, +.Em encapsulated disks +of volume management software are acceptable as long as the +volume management partitions are clearly marked as unmountable. +.Pp +Any other fields in the label template are informational only, +and will not be parsed when reading the label. +.Pp +Note that when changing the geometry emulation by editing the +textual description line, all partition entries will be +considered based on the new geometry emulation. +.Sh ENVIRONMENT +.Bl -tag -width ".Ev EDITOR" -compact +.It Ev EDITOR +Name of the command to edit the template file in edit-mode. +Defaults to +.Xr vi 1 . +.El .Sh FILES .Bl -tag -width ".Pa /boot/boot1" -compact .It Pa /boot/boot1 Default boot image. .El .Sh SEE ALSO +.Xr vi 1 , .Xr geom 4 , -.Xr disktab 5 , .Xr bsdlabel 8 +.Sh HISTORY +The +.Nm +utility appeared in +.Fx 5.1 . +.Sh AUTHORS +The +.Nm +utility was written by +.An Jake Burkholder , +modeling it after the +.Xr bsdlabel 8 +command available on other architectures. +.Pp +.An -nosplit +This man page was initially written by +.An David O'Brien , +and later substantially updated by +.An J\(:org Wunsch . +.Sh BUGS +Installing bootstrap code onto an entire disk is merely pointless. +.Nm +should rather support installing bootstrap code into a partition +instead. +.Pp +The +.Dq auto +layout algorithm could be smarter. +By now, it tends to emulate fairly large cylinders which due to +the two reserved alternate cylinders causes a fair amount of +wasted disk space. diff --git a/sbin/sunlabel/sunlabel.c b/sbin/sunlabel/sunlabel.c index b37c701..ecf2755 100644 --- a/sbin/sunlabel/sunlabel.c +++ b/sbin/sunlabel/sunlabel.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2003 Jake Burkholder. + * Copyright (c) 2004 Joerg Wunsch. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -91,16 +92,26 @@ __FBSDID("$FreeBSD$"); static int bflag; static int Bflag; +static int cflag; static int eflag; +static int hflag; static int nflag; static int Rflag; static int wflag; +static off_t mediasize; +static uint32_t sectorsize; + +struct tags { + const char *name; + unsigned int id; +}; + static int check_label(struct sun_disklabel *sl); static void read_label(struct sun_disklabel *sl, const char *disk); static void write_label(struct sun_disklabel *sl, const char *disk, const char *bootpath); -static int edit_label(struct sun_disklabel *sl, const char *disk, +static void edit_label(struct sun_disklabel *sl, const char *disk, const char *bootpath); static int parse_label(struct sun_disklabel *sl, const char *file); static void print_label(struct sun_disklabel *sl, const char *disk, FILE *out); @@ -108,10 +119,41 @@ static void print_label(struct sun_disklabel *sl, const char *disk, FILE *out); static int parse_size(struct sun_disklabel *sl, int part, char *size); static int parse_offset(struct sun_disklabel *sl, int part, char *offset); +static const char *flagname(unsigned int tag); +static const char *tagname(unsigned int tag); +static unsigned int parse_flag(struct sun_disklabel *sl, int part, + const char *flag); +static unsigned int parse_tag(struct sun_disklabel *sl, int part, + const char *tag); +static const char *make_h_number(uintmax_t u); + static void usage(void); extern char *__progname; +static struct tags knowntags[] = { + { "unassigned", VTOC_UNASSIGNED }, + { "boot", VTOC_BOOT }, + { "root", VTOC_ROOT }, + { "swap", VTOC_SWAP }, + { "usr", VTOC_USR }, + { "backup", VTOC_BACKUP }, + { "stand", VTOC_STAND }, + { "var", VTOC_VAR }, + { "home", VTOC_HOME }, + { "altsctr", VTOC_ALTSCTR }, + { "cache", VTOC_CACHE }, + { "VxVM_pub", VTOC_VXVM_PUB }, + { "VxVM_priv", VTOC_VXVM_PRIV }, +}; + +static struct tags knownflags[] = { + { "wm", 0 }, + { "wu", VTOC_UNMNT }, + { "rm", VTOC_RONLY }, + { "ru", VTOC_UNMNT | VTOC_RONLY }, +}; + /* * Disk label editor for sun disklabels. */ @@ -125,7 +167,7 @@ main(int ac, char **av) int ch; bootpath = _PATH_BOOT; - while ((ch = getopt(ac, av, "b:BenrRw")) != -1) + while ((ch = getopt(ac, av, "b:BcehnrRw")) != -1) switch (ch) { case 'b': bflag = 1; @@ -134,9 +176,15 @@ main(int ac, char **av) case 'B': Bflag = 1; break; + case 'c': + cflag = 1; + break; case 'e': eflag = 1; break; + case 'h': + hflag = 1; + break; case 'n': nflag = 1; break; @@ -159,6 +207,8 @@ main(int ac, char **av) usage(); if (eflag && (Rflag || wflag)) usage(); + if (eflag) + hflag = 0; ac -= optind; av += optind; if (ac == 0) @@ -180,8 +230,7 @@ main(int ac, char **av) read_label(&sl, disk); if (sl.sl_magic != SUN_DKMAGIC) errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk); - while (edit_label(&sl, disk, bootpath) != 0) - ; + edit_label(&sl, disk, bootpath); } else if (Rflag) { if (ac != 2) usage(); @@ -212,9 +261,13 @@ check_label(struct sun_disklabel *sl) uint64_t start; uint64_t oend; uint64_t end; + int havevtoc; + int warnonly; int i; int j; + havevtoc = sl->sl_vtoc_sane == SUN_VTOC_SANE; + nsectors = sl->sl_ncylinders * sl->sl_ntracks * sl->sl_nsectors; if (sl->sl_part[SUN_RAWPART].sdkp_cyloffset != 0 || sl->sl_part[SUN_RAWPART].sdkp_nsectors != nsectors) { @@ -222,6 +275,10 @@ check_label(struct sun_disklabel *sl) "whole disk"); return (1); } + if (havevtoc && sl->sl_vtoc_map[2].svtoc_tag != VTOC_BACKUP) { + warnx("partition c must have tag \"backup\""); + return (1); + } for (i = 0; i < SUN_NPART; i++) { if (i == 2 || sl->sl_part[i].sdkp_nsectors == 0) continue; @@ -233,7 +290,22 @@ check_label(struct sun_disklabel *sl) 'a' + i); return (1); } + if (havevtoc) { + if (sl->sl_vtoc_map[i].svtoc_tag == VTOC_BACKUP) { + warnx("only partition c is allowed to have " + "tag \"backup\""); + return (1); + } + } for (j = 0; j < SUN_NPART; j++) { + /* + * Overlaps for unmountable partitions are + * non-fatal but will be warned anyway. + */ + warnonly = havevtoc && + ((sl->sl_vtoc_map[i].svtoc_flag & VTOC_UNMNT) != 0 || + (sl->sl_vtoc_map[j].svtoc_flag & VTOC_UNMNT) != 0); + if (j == 2 || j == i || sl->sl_part[j].sdkp_nsectors == 0) continue; @@ -245,7 +317,8 @@ check_label(struct sun_disklabel *sl) (end > ostart && end < oend)) { warnx("partition %c overlaps partition %c", 'a' + i, 'a' + j); - return (1); + if (!warnonly) + return (1); } } } @@ -256,10 +329,8 @@ static void read_label(struct sun_disklabel *sl, const char *disk) { char path[MAXPATHLEN]; - uint32_t sectorsize; uint32_t fwsectors; uint32_t fwheads; - off_t mediasize; char buf[SUN_SIZE]; int fd, error; @@ -269,12 +340,17 @@ read_label(struct sun_disklabel *sl, const char *disk) if (read(fd, buf, sizeof(buf)) != sizeof(buf)) err(1, "read"); error = sunlabel_dec(buf, sl); - if (error) { - bzero(sl, sizeof(*sl)); - if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) != 0) + if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) != 0) + if (error) err(1, "%s: ioctl(DIOCGMEDIASIZE) failed", disk); - if (ioctl(fd, DIOCGSECTORSIZE, §orsize) != 0) + if (ioctl(fd, DIOCGSECTORSIZE, §orsize) != 0) { + if (error) err(1, "%s: DIOCGSECTORSIZE failed", disk); + else + sectorsize = 512; + } + if (error) { + bzero(sl, sizeof(*sl)); if (ioctl(fd, DIOCGFWSECTORS, &fwsectors) != 0) fwsectors = 63; if (ioctl(fd, DIOCGFWHEADS, &fwheads) != 0) { @@ -401,7 +477,7 @@ write_label(struct sun_disklabel *sl, const char *disk, const char *bootpath) exit(0); } -static int +static void edit_label(struct sun_disklabel *sl, const char *disk, const char *bootpath) { char tmpfil[] = _PATH_TMPFILE; @@ -419,39 +495,41 @@ edit_label(struct sun_disklabel *sl, const char *disk, const char *bootpath) err(1, "fdopen"); print_label(sl, disk, fp); fflush(fp); - if ((pid = fork()) < 0) - err(1, "fork"); - if (pid == 0) { - if ((editor = getenv("EDITOR")) == NULL) - editor = _PATH_VI; - execlp(editor, editor, tmpfil, (char *)NULL); - err(1, "execlp %s", editor); - } - status = 0; - while ((r = wait(&status)) > 0 && r != pid) - ; - if (WIFEXITED(status)) { - if (parse_label(sl, tmpfil) == 0) { - fclose(fp); - unlink(tmpfil); - write_label(sl, disk, bootpath); - return (0); + for (;;) { + if ((pid = fork()) < 0) + err(1, "fork"); + if (pid == 0) { + if ((editor = getenv("EDITOR")) == NULL) + editor = _PATH_VI; + execlp(editor, editor, tmpfil, (char *)NULL); + err(1, "execlp %s", editor); } - printf("re-edit the label? [y]: "); - fflush(stdout); - c = getchar(); - if (c != EOF && c != '\n') - while (getchar() != '\n') - ; - if (c == 'n') { - fclose(fp); - unlink(tmpfil); - return (0); + status = 0; + while ((r = wait(&status)) > 0 && r != pid) + ; + if (WIFEXITED(status)) { + if (parse_label(sl, tmpfil) == 0) { + fclose(fp); + unlink(tmpfil); + write_label(sl, disk, bootpath); + return; + } + printf("re-edit the label? [y]: "); + fflush(stdout); + c = getchar(); + if (c != EOF && c != '\n') + while (getchar() != '\n') + ; + if (c == 'n') { + fclose(fp); + unlink(tmpfil); + return; + } } } fclose(fp); unlink(tmpfil); - return (1); + return; } static int @@ -459,16 +537,25 @@ parse_label(struct sun_disklabel *sl, const char *file) { char offset[32]; char size[32]; + char flag[32]; + char tag[32]; char buf[128]; + char text[128]; + struct sun_disklabel sl1; char *bp; + const char *what; uint8_t part; FILE *fp; int line; + int rv; + int wantvtoc; + unsigned alt, cyl, hd, nr, sec; - line = 0; + line = wantvtoc = 0; if ((fp = fopen(file, "r")) == NULL) err(1, "fopen"); - bzero(sl->sl_part, sizeof(sl->sl_part)); + sl1 = *sl; + bzero(&sl1.sl_part, sizeof(sl1.sl_part)); while (fgets(buf, sizeof(buf), fp) != NULL) { /* * In order to recognize a partition entry, we search @@ -483,21 +570,104 @@ parse_label(struct sun_disklabel *sl, const char *file) */ for (bp = buf; isspace(*bp); bp++) ; + if (strncmp(bp, "text:", strlen("text:")) == 0) { + bp += strlen("text:"); + rv = sscanf(bp, + " %s cyl %u alt %u hd %u sec %u", + text, &cyl, &alt, &hd, &sec); + if (rv != 5) { + warnx("%s, line %d: text label does not " + "contain required fields", + file, line + 1); + fclose(fp); + return (1); + } + if (alt != 2) { + warnx("%s, line %d: # alt must be equal 2", + file, line + 1); + fclose(fp); + return (1); + } + if (cyl == 0 || cyl > USHRT_MAX) { + what = "cyl"; + nr = cyl; + unreasonable: + warnx("%s, line %d: # %s %d unreasonable", + file, line + 1, what, nr); + fclose(fp); + return (1); + } + if (hd == 0 || hd > USHRT_MAX) { + what = "hd"; + nr = hd; + goto unreasonable; + } + if (sec == 0 || sec > USHRT_MAX) { + what = "sec"; + nr = sec; + goto unreasonable; + } + if (mediasize == 0) + warnx("unit size unknown, no sector count " + "check could be done"); + else if ((uintmax_t)(cyl + alt) * sec * hd > + (uintmax_t)mediasize / sectorsize) { + warnx("%s, line %d: sector count %ju exceeds " + "unit size %ju", + file, line + 1, + (uintmax_t)(cyl + alt) * sec * hd, + (uintmax_t)mediasize / sectorsize); + fclose(fp); + return (1); + } + sl1.sl_pcylinders = cyl + alt; + sl1.sl_ncylinders = cyl; + sl1.sl_acylinders = alt; + sl1.sl_nsectors = sec; + sl1.sl_ntracks = hd; + memset(sl1.sl_text, 0, sizeof(sl1.sl_text)); + snprintf(sl1.sl_text, sizeof(sl1.sl_text), + "%s cyl %u alt %u hd %u sec %u", + text, cyl, alt, hd, sec); + continue; + } if (strlen(bp) < 2 || bp[1] != ':') { line++; continue; } - if (sscanf(bp, "%c: %s %s\n", &part, size, offset) != 3 || - parse_size(sl, part - 'a', size) || - parse_offset(sl, part - 'a', offset)) { + rv = sscanf(bp, "%c: %30s %30s %30s %30s", + &part, size, offset, tag, flag); + if (rv < 3) { + syntaxerr: warnx("%s: syntax error on line %d", file, line + 1); fclose(fp); return (1); } + if (parse_size(&sl1, part - 'a', size) || + parse_offset(&sl1, part - 'a', offset)) + goto syntaxerr; + if (rv > 3) { + wantvtoc = 1; + if (rv == 5 && parse_flag(&sl1, part - 'a', flag)) + goto syntaxerr; + if (parse_tag(&sl1, part - 'a', tag)) + goto syntaxerr; + } line++; } fclose(fp); + if (wantvtoc) { + sl1.sl_vtoc_sane = SUN_VTOC_SANE; + sl1.sl_vtoc_vers = SUN_VTOC_VERSION; + sl1.sl_vtoc_nparts = SUN_NPART; + } else { + sl1.sl_vtoc_sane = 0; + sl1.sl_vtoc_vers = 0; + sl1.sl_vtoc_nparts = 0; + bzero(&sl1.sl_vtoc_map, sizeof(sl1.sl_vtoc_map)); + } + *sl = sl1; return (check_label(sl)); } @@ -522,17 +692,23 @@ parse_size(struct sun_disklabel *sl, int part, char *size) nsectors += sl->sl_part[i].sdkp_nsectors; } n = total - nsectors; + } else if (p[1] == '\0' && (p[0] == 'C' || p[0] == 'c')) { + n = n * sl->sl_ntracks * sl->sl_nsectors; } else if (p[1] == '\0' && (p[0] == 'K' || p[0] == 'k')) { n = roundup((n * 1024) / 512, sl->sl_ntracks * sl->sl_nsectors); } else if (p[1] == '\0' && (p[0] == 'M' || p[0] == 'm')) { n = roundup((n * 1024 * 1024) / 512, sl->sl_ntracks * sl->sl_nsectors); + } else if (p[1] == '\0' && (p[0] == 'S' || p[0] == 's')) { + /* size in sectors, no action neded */ } else if (p[1] == '\0' && (p[0] == 'G' || p[0] == 'g')) { n = roundup((n * 1024 * 1024 * 1024) / 512, sl->sl_ntracks * sl->sl_nsectors); } else return (-1); + } else if (cflag) { + n = n * sl->sl_ntracks * sl->sl_nsectors; } sl->sl_part[part].sdkp_nsectors = n; return (0); @@ -567,34 +743,83 @@ static void print_label(struct sun_disklabel *sl, const char *disk, FILE *out) { int i; + int havevtoc; + uintmax_t secpercyl; + + havevtoc = sl->sl_vtoc_sane == SUN_VTOC_SANE; + secpercyl = sl->sl_nsectors * sl->sl_ntracks; fprintf(out, "# /dev/%s:\n" "text: %s\n" -"bytes/sectors: 512\n" -"sectors/cylinder: %d\n" -"sectors/unit: %d\n" -"\n" -"%d partitions:\n" -"#\n" -"# Size is in sectors, use %%dK, %%dM or %%dG to specify in kilobytes,\n" -"# megabytes or gigabytes respectively, or '*' to specify rest of disk.\n" -"# Offset is in cylinders, use '*' to calculate offsets automatically.\n" -"#\n" -"# size offset\n" -"# ---------- ----------\n", +"bytes/sectors: %d\n" +"sectors/cylinder: %ju\n", disk, sl->sl_text, - sl->sl_nsectors * sl->sl_ntracks, - sl->sl_nsectors * sl->sl_ntracks * sl->sl_ncylinders, + sectorsize, + secpercyl); + if (eflag) + fprintf(out, + "# max sectors/unit (including alt cylinders): %ju\n", + (uintmax_t)mediasize / sectorsize); + fprintf(out, +"sectors/unit: %ju\n" +"\n" +"%d partitions:\n" +"#\n", + secpercyl * sl->sl_ncylinders, SUN_NPART); + if (!hflag) { + fprintf(out, "# Size is in %s.", cflag? "cylinders": "sectors"); + if (eflag) + fprintf(out, +" Use %%d%c, %%dK, %%dM or %%dG to specify in %s,\n" +"# kilobytes, megabytes or gigabytes respectively, or '*' to specify rest of\n" +"# disk.\n", + cflag? 's': 'c', + cflag? "sectors": "cylinders"); + else + putc('\n', out); + fprintf(out, "# Offset is in cylinders."); + if (eflag) + fprintf(out, +" Use '*' to calculate offsets automatically.\n" +"#\n"); + else + putc('\n', out); + } + if (havevtoc) + fprintf(out, +"# size offset tag flag\n" +"# ---------- ---------- ---------- ----\n" + ); + else + fprintf(out, +"# size offset\n" +"# ---------- ----------\n" + ); + for (i = 0; i < SUN_NPART; i++) { if (sl->sl_part[i].sdkp_nsectors == 0) continue; - fprintf(out, " %c: %10u %10u\n", - 'a' + i, - sl->sl_part[i].sdkp_nsectors, - sl->sl_part[i].sdkp_cyloffset); + if (hflag) { + fprintf(out, " %c: %10s", + 'a' + i, + make_h_number(sl->sl_part[i].sdkp_nsectors * 512)); + fprintf(out, " %10s", + make_h_number(sl->sl_part[i].sdkp_cyloffset * + 512 * secpercyl)); + } else { + fprintf(out, " %c: %10ju %10u", + 'a' + i, + sl->sl_part[i].sdkp_nsectors / (cflag? secpercyl: 1), + sl->sl_part[i].sdkp_cyloffset); + } + if (havevtoc) + fprintf(out, " %11s %5s", + tagname(sl->sl_vtoc_map[i].svtoc_tag), + flagname(sl->sl_vtoc_map[i].svtoc_flag)); + putc('\n', out); } } @@ -603,13 +828,13 @@ usage(void) { fprintf(stderr, "usage:" -"\t%s [-r] disk\n" +"\t%s [-r] [-c | -h] disk\n" "\t\t(to read label)\n" "\t%s -B [-b boot1] [-n] disk\n" "\t\t(to install boot program only)\n" -"\t%s -R [-B [-b boot1]] [-r] [-n] disk protofile\n" +"\t%s -R [-B [-b boot1]] [-r] [-n] [-c] disk protofile\n" "\t\t(to restore label)\n" -"\t%s -e [-B [-b boot1]] [-r] [-n] disk\n" +"\t%s -e [-B [-b boot1]] [-r] [-n] [-c] disk\n" "\t\t(to edit label)\n" "\t%s -w [-B [-b boot1]] [-r] [-n] disk type\n" "\t\t(to write default label)\n", @@ -620,3 +845,117 @@ usage(void) __progname); exit(1); } + +/* + * Return VTOC tag and flag names for tag or flag ID, resp. + */ +static const char * +tagname(unsigned int tag) +{ + static char buf[32]; + size_t i; + struct tags *tp; + + for (i = 0, tp = knowntags; + i < sizeof(knowntags) / sizeof(struct tags); + i++, tp++) + if (tp->id == tag) + return (tp->name); + + sprintf(buf, "%u", tag); + + return (buf); +} + +static const char * +flagname(unsigned int flag) +{ + static char buf[32]; + size_t i; + struct tags *tp; + + for (i = 0, tp = knownflags; + i < sizeof(knownflags) / sizeof(struct tags); + i++, tp++) + if (tp->id == flag) + return (tp->name); + + sprintf(buf, "%u", flag); + + return (buf); +} + +static unsigned int +parse_tag(struct sun_disklabel *sl, int part, const char *tag) +{ + struct tags *tp; + char *endp; + size_t i; + unsigned long l; + + for (i = 0, tp = knowntags; + i < sizeof(knowntags) / sizeof(struct tags); + i++, tp++) + if (strcmp(tp->name, tag) == 0) { + sl->sl_vtoc_map[part].svtoc_tag = (uint16_t)tp->id; + return (0); + } + + l = strtoul(tag, &endp, 0); + if (*tag != '\0' && *endp == '\0') { + sl->sl_vtoc_map[part].svtoc_tag = (uint16_t)l; + return (0); + } + + return (-1); +} + +static unsigned int +parse_flag(struct sun_disklabel *sl, int part, const char *flag) +{ + struct tags *tp; + char *endp; + size_t i; + unsigned long l; + + for (i = 0, tp = knownflags; + i < sizeof(knownflags) / sizeof(struct tags); + i++, tp++) + if (strcmp(tp->name, flag) == 0) { + sl->sl_vtoc_map[part].svtoc_flag = (uint16_t)tp->id; + return (0); + } + + l = strtoul(flag, &endp, 0); + if (*flag != '\0' && *endp == '\0') { + sl->sl_vtoc_map[part].svtoc_flag = (uint16_t)l; + return (0); + } + + return (-1); +} + +/* + * Convert argument into `human readable' byte number form. + */ +static const char * +make_h_number(uintmax_t u) +{ + static char buf[32]; + double d; + + if (u == 0) { + strcpy(buf, "0B"); + } else if (u > 2000000000UL) { + d = (double)u / 1e9; + sprintf(buf, "%.1fG", d); + } else if (u > 2000000UL) { + d = (double)u / 1e6; + sprintf(buf, "%.1fM", d); + } else { + d = (double)u / 1e3; + sprintf(buf, "%.1fK", d); + } + + return (buf); +} -- cgit v1.1