* Copyright (c) 1987 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Symmetric Computer Systems.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
"@(#) Copyright (c) 1987 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)disklabel.c 5.14 (Berkeley) %G%";
/* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */
#include <sys/disklabel.h>
* Disklabel: read and write disklabels.
* The label is usually placed on one of the first sectors of the disk.
* Many machines (VAX 11/750) also place a bootstrap in the same area,
* in which case the label is embedded in the bootstrap.
* The bootstrap source must leave space at the proper offset
* for the label on such machines.
#define BBSIZE 8192 /* size of boot area, with label */
#define BOOT /* also have bootstrap in "boot area" */
#define BOOTDIR "/usr/mdec" /* source of boot binaries */
#define DEFEDITOR "/usr/ucb/vi"
#define streq(a,b) (strcmp(a,b) == 0)
char tmpfil
[] = "/tmp/EdDk.aXXXXXX";
char namebuf
[BBSIZE
], *np
= namebuf
;
struct disklabel
*readlabel(), *makebootarea();
enum { UNSPEC
, EDIT
, NOWRITE
, READ
, RESTORE
, WRITE
, WRITEABLE
} op
= UNSPEC
;
register struct disklabel
*lp
;
while ((ch
= getopt(argc
, argv
, "NRWerw")) != EOF
)
(void)sprintf(np
, "/dev/r%s%c", dkname
, RAWPARTITION
);
np
+= strlen(specname
) + 1;
f
= open(specname
, op
== READ
? O_RDONLY
: O_RDWR
);
if (f
< 0 && errno
== ENOENT
&& dkname
[0] != '/') {
(void)sprintf(specname
, "/dev/r%s", dkname
);
np
= namebuf
+ strlen(specname
) + 1;
f
= open(specname
, op
== READ
? O_RDONLY
: O_RDWR
);
if (ioctl(f
, DIOCWLABEL
, (char *)&flag
) < 0)
Perror("ioctl DIOCWLABEL");
if (argc
== 4) { /* [ priboot secboot ] */
lab
.d_secsize
= DEV_BSIZE
; /* XXX */
lab
.d_bbsize
= BBSIZE
; /* XXX */
else if (argc
== 3) /* [ disktype ] */
makelabel(argv
[2], (char *)NULL
, &lab
);
"Must specify either disktype or bootfiles with -r flag of RESTORE option\n");
lp
= makebootarea(bootarea
, &lab
);
if (!(t
= fopen(argv
[1],"r")))
if (getasciilabel(t
, lp
))
error
= writelabel(f
, bootarea
, lp
);
if (argc
> 5 || argc
< 2)
if (argc
> 3 || argc
< 2)
makelabel(type
, name
, &lab
);
lp
= makebootarea(bootarea
, &lab
);
error
= writelabel(f
, bootarea
, lp
);
if (ioctl(f
, DIOCWLABEL
, (char *)&flag
) < 0)
Perror("ioctl DIOCWLABEL");
* Construct a prototype disklabel from /etc/disktab. As a side
* effect, set the names of the primary and secondary boot files
makelabel(type
, name
, lp
)
register struct disklabel
*lp
;
register struct disklabel
*dp
;
dp
= getdiskbyname(type
);
fprintf(stderr
, "%s: unknown disk type\n", type
);
* Check if disktab specifies the bootstraps (b0 or b1).
if (!xxboot
&& lp
->d_boot0
) {
(void)sprintf(boot0
, "%s/%s", BOOTDIR
, lp
->d_boot0
);
(void)strcpy(boot0
, lp
->d_boot0
);
if (!bootxx
&& lp
->d_boot1
) {
(void)sprintf(boot1
, "%s/%s", BOOTDIR
, lp
->d_boot1
);
(void)strcpy(boot1
, lp
->d_boot1
);
* If bootstraps not specified anywhere, makebootarea()
* will choose ones based on the name of the disk special
* file. E.g. /dev/ra0 -> raboot, bootra
/* d_packname is union d_boot[01], so zero */
bzero(lp
->d_packname
, sizeof(lp
->d_packname
));
(void)strncpy(lp
->d_packname
, name
, sizeof(lp
->d_packname
));
register struct disklabel
*lp
;
lp
->d_magic2
= DISKMAGIC
;
lp
->d_checksum
= dkcksum(lp
);
* 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)
if (ioctl(f
, DIOCSDINFO
, lp
) < 0 &&
errno
!= ENODEV
&& errno
!= ENOTTY
) {
l_perror("ioctl DIOCSDINFO");
(void)lseek(f
, (off_t
)0, L_SET
);
* write enable label sector before write (if necessary),
if (ioctl(f
, DIOCWLABEL
, &flag
) < 0)
perror("ioctl DIOCWLABEL");
if (write(f
, boot
, lp
->d_bbsize
) != lp
->d_bbsize
) {
(void) ioctl(f
, DIOCWLABEL
, &flag
);
} else if (ioctl(f
, DIOCWDINFO
, lp
) < 0) {
l_perror("ioctl DIOCWDINFO");
if (lp
->d_type
== DTYPE_SMD
&& lp
->d_flags
& D_BADSECT
) {
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
), L_SET
);
if (write(f
, boot
, lp
->d_secsize
) < lp
->d_secsize
) {
fprintf(stderr
, "alternate label %d ", i
/2);
fprintf(stderr
, "disklabel: %s: ", s
);
fprintf(stderr
, "No disk label on disk;\n");
"use \"disklabel -r\" to install initial label\n");
fprintf(stderr
, "Label magic number or checksum is wrong!\n");
fprintf(stderr
, "(disklabel or kernel is out of date?)\n");
fprintf(stderr
, "Open partition would move or shrink\n");
"Labeled partition or 'a' partition must start at beginning of disk\n");
* Fetch disklabel for disk.
* Use ioctl to get label unless -r flag is given.
register struct disklabel
*lp
;
if (read(f
, bootarea
, BBSIZE
) < BBSIZE
)
for (lp
= (struct disklabel
*)bootarea
;
lp
<= (struct disklabel
*)(bootarea
+ BBSIZE
- sizeof(*lp
));
lp
= (struct disklabel
*)((char *)lp
+ 16))
if (lp
->d_magic
== DISKMAGIC
&&
lp
->d_magic2
== DISKMAGIC
)
if (lp
> (struct disklabel
*)(bootarea
+BBSIZE
-sizeof(*lp
)) ||
lp
->d_magic
!= DISKMAGIC
|| lp
->d_magic2
!= DISKMAGIC
||
"Bad pack magic number (label is damaged, or pack is unlabeled)\n");
/* lp = (struct disklabel *)(bootarea + LABELOFFSET); */
if (ioctl(f
, DIOCGDINFO
, lp
) < 0)
Perror("ioctl DIOCGDINFO");
register struct disklabel
*dp
;
lp
= (struct disklabel
*)(boot
+ (LABELSECTOR
* dp
->d_secsize
) +
if (xxboot
== NULL
|| bootxx
== NULL
) {
if ((p
= rindex(dkname
, '/')) == NULL
)
while (*p
&& !isdigit(*p
))
(void)sprintf(np
, "%s/%sboot", BOOTDIR
, dkbasename
);
if (access(np
, F_OK
) < 0 && dkbasename
[0] == 'r')
(void)sprintf(xxboot
, "%s/%sboot", BOOTDIR
, dkbasename
);
np
+= strlen(xxboot
) + 1;
(void)sprintf(np
, "%s/boot%s", BOOTDIR
, dkbasename
);
if (access(np
, F_OK
) < 0 && dkbasename
[0] == 'r')
(void)sprintf(bootxx
, "%s/boot%s", BOOTDIR
, dkbasename
);
np
+= strlen(bootxx
) + 1;
fprintf(stderr
, "bootstraps: xxboot = %s, bootxx = %s\n",
b
= open(xxboot
, O_RDONLY
);
if (read(b
, boot
, (int)dp
->d_secsize
) < 0)
b
= open(bootxx
, O_RDONLY
);
if (read(b
, &boot
[dp
->d_secsize
], (int)(dp
->d_bbsize
-dp
->d_secsize
)) < 0)
for (p
= (char *)lp
; p
< (char *)lp
+ sizeof(struct disklabel
); p
++)
"Bootstrap doesn't leave room for disk label\n");
register struct disklabel
*lp
;
register struct partition
*pp
;
fprintf(f
, "# %s:\n", specname
);
if ((unsigned) lp
->d_type
< DKMAXTYPES
)
fprintf(f
, "type: %s\n", dktypenames
[lp
->d_type
]);
fprintf(f
, "type: %d\n", lp
->d_type
);
fprintf(f
, "disk: %.*s\n", sizeof(lp
->d_typename
), lp
->d_typename
);
fprintf(f
, "label: %.*s\n", sizeof(lp
->d_packname
), lp
->d_packname
);
if (lp
->d_flags
& D_REMOVABLE
)
fprintf(f
, " removeable");
if (lp
->d_flags
& D_BADSECT
)
fprintf(f
, "bytes/sector: %d\n", lp
->d_secsize
);
fprintf(f
, "sectors/track: %d\n", lp
->d_nsectors
);
fprintf(f
, "tracks/cylinder: %d\n", lp
->d_ntracks
);
fprintf(f
, "sectors/cylinder: %d\n", lp
->d_secpercyl
);
fprintf(f
, "cylinders: %d\n", lp
->d_ncylinders
);
fprintf(f
, "rpm: %d\n", lp
->d_rpm
);
fprintf(f
, "interleave: %d\n", lp
->d_interleave
);
fprintf(f
, "trackskew: %d\n", lp
->d_trackskew
);
fprintf(f
, "cylinderskew: %d\n", lp
->d_cylskew
);
fprintf(f
, "headswitch: %d\t\t# milliseconds\n", lp
->d_headswitch
);
fprintf(f
, "track-to-track seek: %d\t# milliseconds\n", lp
->d_trkseek
);
fprintf(f
, "drivedata: ");
for (i
= NDDATA
- 1; i
>= 0; i
--)
fprintf(f
, "%d ", lp
->d_drivedata
[j
]);
fprintf(f
, "\n\n%d partitions:\n", lp
->d_npartitions
);
"# size offset fstype [fsize bsize cpg]\n");
for (i
= 0; i
< lp
->d_npartitions
; i
++, pp
++) {
fprintf(f
, " %c: %8d %8d ", 'a' + i
,
pp
->p_size
, pp
->p_offset
);
if ((unsigned) pp
->p_fstype
< FSMAXTYPES
)
fprintf(f
, "%8.8s", fstypenames
[pp
->p_fstype
]);
fprintf(f
, "%8d", pp
->p_fstype
);
case FS_UNUSED
: /* XXX */
fprintf(f
, " %5d %5d %5.5s ",
pp
->p_fsize
, pp
->p_fsize
* pp
->p_frag
, "");
fprintf(f
, " %5d %5d %5d ",
pp
->p_fsize
, pp
->p_fsize
* pp
->p_frag
,
fprintf(f
, "%20.20s", "");
fprintf(f
, "\t# (Cyl. %4d",
pp
->p_offset
/ lp
->d_secpercyl
);
if (pp
->p_offset
% lp
->d_secpercyl
)
pp
->p_size
+ lp
->d_secpercyl
- 1) /
if (pp
->p_size
% lp
->d_secpercyl
)
fprintf(stderr
, "%s: Can't create\n", tmpfil
);
fprintf(stderr
, "%s: Can't reopen for reading\n",
bzero((char *)&label
, sizeof(label
));
if (getasciilabel(fd
, &label
)) {
if (writelabel(f
, bootarea
, lp
) == 0) {
printf("re-edit the label? [y]: "); fflush(stdout
);
if (c
!= EOF
&& c
!= (int)'\n')
while (getchar() != (int)'\n')
omask
= sigblock(sigmask(SIGINT
)|sigmask(SIGQUIT
)|sigmask(SIGHUP
));
while ((pid
= fork()) < 0) {
fprintf(stderr
, "You have too many processes\n");
if ((ed
= getenv("EDITOR")) == (char *)0)
execlp(ed
, ed
, tmpfil
, 0);
while ((xpid
= wait(&stat
)) >= 0)
while (*cp
!= '\0' && isspace(*cp
))
if (*cp
== '\0' || *cp
== '#')
while (*cp
!= '\0' && !isspace(*cp
) && *cp
!= '#')
* Read an ascii label in from fd f,
* in the same format as that put out by display(),
register struct disklabel
*lp
;
register char **cpp
, *cp
;
register struct partition
*pp
;
char *tp
, *s
, line
[BUFSIZ
];
int v
, lineno
= 0, errors
= 0;
lp
->d_bbsize
= BBSIZE
; /* XXX */
lp
->d_sbsize
= SBSIZE
; /* XXX */
while (fgets(line
, sizeof(line
) - 1, f
)) {
if (cp
= index(line
,'\n'))
fprintf(stderr
, "line %d: syntax error\n", lineno
);
*tp
++ = '\0', tp
= skip(tp
);
for (; cpp
< &dktypenames
[DKMAXTYPES
]; cpp
++)
if ((s
= *cpp
) && streq(s
, tp
)) {
lp
->d_type
= cpp
- dktypenames
;
if ((unsigned)v
>= DKMAXTYPES
)
fprintf(stderr
, "line %d:%s %d\n", lineno
,
"Warning, unknown disk type", v
);
if (streq(cp
, "flags")) {
for (v
= 0; (cp
= tp
) && *cp
!= '\0';) {
if (streq(cp
, "removeable"))
else if (streq(cp
, "ecc"))
else if (streq(cp
, "badsect"))
"line %d: %s: bad flag\n",
if (streq(cp
, "drivedata")) {
for (i
= 0; (cp
= tp
) && *cp
!= '\0' && i
< NDDATA
;) {
lp
->d_drivedata
[i
++] = atoi(cp
);
if (sscanf(cp
, "%d partitions", &v
) == 1) {
if (v
== 0 || (unsigned)v
> MAXPARTITIONS
) {
"line %d: bad # of partitions\n", lineno
);
lp
->d_npartitions
= MAXPARTITIONS
;
strncpy(lp
->d_typename
, tp
, sizeof (lp
->d_typename
));
if (streq(cp
, "label")) {
strncpy(lp
->d_packname
, tp
, sizeof (lp
->d_packname
));
if (streq(cp
, "bytes/sector")) {
if (v
<= 0 || (v
% 512) != 0) {
"line %d: %s: bad sector size\n",
if (streq(cp
, "sectors/track")) {
fprintf(stderr
, "line %d: %s: bad %s\n",
if (streq(cp
, "sectors/cylinder")) {
fprintf(stderr
, "line %d: %s: bad %s\n",
if (streq(cp
, "tracks/cylinder")) {
fprintf(stderr
, "line %d: %s: bad %s\n",
if (streq(cp
, "cylinders")) {
fprintf(stderr
, "line %d: %s: bad %s\n",
fprintf(stderr
, "line %d: %s: bad %s\n",
if (streq(cp
, "interleave")) {
fprintf(stderr
, "line %d: %s: bad %s\n",
if (streq(cp
, "trackskew")) {
fprintf(stderr
, "line %d: %s: bad %s\n",
if (streq(cp
, "cylinderskew")) {
fprintf(stderr
, "line %d: %s: bad %s\n",
if (streq(cp
, "headswitch")) {
fprintf(stderr
, "line %d: %s: bad %s\n",
if (streq(cp
, "track-to-track seek")) {
fprintf(stderr
, "line %d: %s: bad %s\n",
if ('a' <= *cp
&& *cp
<= 'z' && cp
[1] == '\0') {
unsigned part
= *cp
- 'a';
if (part
> lp
->d_npartitions
) {
"line %d: bad partition name\n", lineno
);
pp
= &lp
->d_partitions
[part
];
cp = tp, tp = word(cp); \
"line %d: %s: bad partition size\n",
"line %d: %s: bad partition offset\n",
for (; cpp
< &fstypenames
[FSMAXTYPES
]; cpp
++)
if ((s
= *cpp
) && streq(s
, cp
)) {
pp
->p_fstype
= cpp
- fstypenames
;
if ((unsigned)v
>= FSMAXTYPES
) {
fprintf(stderr
, "line %d: %s %s\n", lineno
,
"Warning, unknown filesystem type", cp
);
case FS_UNUSED
: /* XXX */
pp
->p_frag
= v
/ pp
->p_fsize
;
pp
->p_frag
= v
/ pp
->p_fsize
;
fprintf(stderr
, "line %d: %s: Unknown disklabel field\n",
errors
+= checklabel(lp
);
* Check disklabel for errors and fill in
* derived fields according to supplied values.
register struct disklabel
*lp
;
register struct partition
*pp
;
if (lp
->d_secsize
== 0) {
fprintf(stderr
, "sector size %d\n", lp
->d_secsize
);
if (lp
->d_nsectors
== 0) {
fprintf(stderr
, "sectors/track %d\n", lp
->d_nsectors
);
if (lp
->d_ntracks
== 0) {
fprintf(stderr
, "tracks/cylinder %d\n", lp
->d_ntracks
);
if (lp
->d_ncylinders
== 0) {
fprintf(stderr
, "cylinders/unit %d\n", lp
->d_ncylinders
);
Warning("revolutions/minute %d\n", lp
->d_rpm
);
if (lp
->d_secpercyl
== 0)
lp
->d_secpercyl
= lp
->d_nsectors
* lp
->d_ntracks
;
if (lp
->d_secperunit
== 0)
lp
->d_secperunit
= lp
->d_secpercyl
* lp
->d_ncylinders
;
fprintf(stderr
, "boot block size %d\n", lp
->d_bbsize
);
} else if (lp
->d_bbsize
% lp
->d_secsize
)
Warning("boot block size %% sector-size != 0\n");
fprintf(stderr
, "super block size %d\n", lp
->d_sbsize
);
} else if (lp
->d_sbsize
% lp
->d_secsize
)
Warning("super block size %% sector-size != 0\n");
if (lp
->d_npartitions
> MAXPARTITIONS
)
Warning("number of partitions (%d) > MAXPARTITIONS (%d)\n",
lp
->d_npartitions
, MAXPARTITIONS
);
for (i
= 0; i
< lp
->d_npartitions
; i
++) {
pp
= &lp
->d_partitions
[i
];
if (pp
->p_size
== 0 && pp
->p_offset
!= 0)
Warning("partition %c: size 0, but offset %d\n",
if (pp
->p_size
% lp
->d_secpercyl
)
Warning("partition %c: size %% cylinder-size != 0\n",
if (pp
->p_offset
% lp
->d_secpercyl
)
Warning("partition %c: offset %% cylinder-size != 0\n",
if (pp
->p_offset
> lp
->d_secperunit
) {
"partition %c: offset past end of unit\n", part
);
if (pp
->p_offset
+ pp
->p_size
> lp
->d_secperunit
) {
"partition %c: partition extends past end of unit\n",
for (; i
< MAXPARTITIONS
; i
++) {
pp
= &lp
->d_partitions
[i
];
if (pp
->p_size
|| pp
->p_offset
)
Warning("unused partition %c: size %d offset %d\n",
'a' + i
, pp
->p_size
, pp
->p_offset
);
Warning(fmt
, a1
, a2
, a3
, a4
, a5
)
fprintf(stderr
, "Warning, ");
fprintf(stderr
, fmt
, a1
, a2
, a3
, a4
, a5
);
fputs("disklabel: ", stderr
); perror(str
);
fprintf(stderr
, "%-62s%s\n%-62s%s\n%-62s%s\n%-62s%s\n%-62s%s\n",
"usage: disklabel [-r] disk", "(to read label)",
"or disklabel -w [-r] disk type [ packid ] [ xxboot bootxx ]", "(to write label)",
"or disklabel -e [-r] disk", "(to edit label)",
"or disklabel -R [-r] disk protofile [ type | xxboot bootxx ]", "(to restore label)",
"or disklabel [-NW] disk", "(to write disable/enable label)");
fprintf(stderr
, "%-43s%s\n%-43s%s\n%-43s%s\n%-43s%s\n%-43s%s\n",
"usage: disklabel [-r] disk", "(to read label)",
"or disklabel -w [-r] disk type [ packid ]", "(to write label)",
"or disklabel -e [-r] disk", "(to edit label)",
"or disklabel -R [-r] disk protofile", "(to restore label)",
"or disklabel [-NW] disk", "(to write disable/enable label)");