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.
This commit is contained in:
parent
5b4075da93
commit
3c677f61f4
@ -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.
|
||||
|
@ -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 (ioctl(fd, DIOCGMEDIASIZE, &mediasize) != 0)
|
||||
if (error)
|
||||
err(1, "%s: ioctl(DIOCGMEDIASIZE) failed", disk);
|
||||
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, DIOCGMEDIASIZE, &mediasize) != 0)
|
||||
err(1, "%s: ioctl(DIOCGMEDIASIZE) failed", disk);
|
||||
if (ioctl(fd, DIOCGSECTORSIZE, §orsize) != 0)
|
||||
err(1, "%s: DIOCGSECTORSIZE failed", disk);
|
||||
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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user