1 /* $NetBSD: sunlabel.c,v 1.22 2008/04/28 20:24:17 martin Exp $ */
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
36 #include <sys/cdefs.h>
37 #if defined(__RCSID) && !defined(lint)
38 __RCSID("$NetBSD: sunlabel.c,v 1.22 2008/04/28 20:24:17 martin Exp $");
47 #ifndef NO_TERMCAP_WIDTH
55 #include <sys/ioctl.h>
57 /* If neither S_COMMAND nor NO_S_COMMAND is defined, guess. */
58 #if !defined(S_COMMAND) && !defined(NO_S_COMMAND)
61 #include <sys/disklabel.h>
65 * NPART is the total number of partitions. This must be <= 43, given the
66 * amount of space available to store extended partitions. It also must be
67 * <=26, given the use of single letters to name partitions. The 8 is the
68 * number of `standard' partitions; this arguably should be a #define, since
69 * it occurs not only here but scattered throughout the code.
72 #define NXPART (NPART - 8)
73 #define PARTLETTER(i) ((i) + 'a')
74 #define LETTERPART(i) ((i) - 'a')
77 * A partition. We keep redundant information around, making sure
78 * that whenever we change one, we keep another constant and update
79 * the third. Which one is which depends. Arguably a partition
80 * should also know its partition number; here, if we need that we
81 * cheat, using (effectively) ptr-&label.partitions[0].
90 * A label. As the embedded comments indicate, much of this structure
91 * corresponds directly to Sun's struct dk_label. Some of the values
92 * here are historical holdovers. Apparently really old Suns did
93 * their own sparing in software, so a sector or two per cylinder,
94 * plus a whole cylinder or two at the end, got set aside as spares.
95 * acyl and apc count those spares, and this is also why ncyl and pcyl
96 * both exist. These days the spares generally are hidden from the
97 * host by the disk, and there's no reason not to set
98 * ncyl=pcyl=ceil(device size/spc) and acyl=apc=0.
100 * Note also that the geometry assumptions behind having nhead and
101 * nsect assume that the sect/trk and trk/cyl values are constant
102 * across the whole drive. The latter is still usually true; the
103 * former isn't. In my experience, you can just put fixed values
104 * here; the basis for software knowing the drive geometry is also
105 * mostly invalid these days anyway. (I just use nhead=32 nsect=64,
106 * which gives me 1M "cylinders", a convenient size.)
109 /* BEGIN fields taken directly from struct dk_label */
110 char asciilabel
[128];
111 uint32_t rpm
; /* Spindle rotation speed - useless now */
112 uint32_t pcyl
; /* Physical cylinders */
113 uint32_t apc
; /* Alternative sectors per cylinder */
114 uint32_t obs1
; /* Obsolete? */
115 uint32_t obs2
; /* Obsolete? */
116 uint32_t intrlv
; /* Interleave - never anything but 1 IME */
117 uint32_t ncyl
; /* Number of usable cylinders */
118 uint32_t acyl
; /* Alternative cylinders - pcyl minus ncyl */
119 uint32_t nhead
; /* Tracks-per-cylinder (usually # of heads) */
120 uint32_t nsect
; /* Sectors-per-track */
121 uint32_t obs3
; /* Obsolete? */
122 uint32_t obs4
; /* Obsolete? */
123 /* END fields taken directly from struct dk_label */
124 uint32_t spc
; /* Sectors per cylinder - nhead*nsect */
125 uint32_t dirty
:1;/* Modified since last read */
126 struct part partitions
[NPART
];/* The partitions themselves */
130 * Describes a field in the label.
132 * tag is a short name for the field, like "apc" or "nsect". loc is a
133 * pointer to the place in the label where it's stored. print is a
134 * function to print the value; the second argument is the current
135 * column number, and the return value is the new current column
136 * number. (This allows print functions to do proper line wrapping.)
137 * chval is called to change a field; the first argument is the
138 * command line portion that contains the new value (in text form).
139 * The chval function is responsible for parsing and error-checking as
140 * well as doing the modification. changed is a function which does
141 * field-specific actions necessary when the field has been changed.
142 * This could be rolled into the chval function, but I believe this
143 * way provides better code sharing.
145 * Note that while the fields in the label vary in size (8, 16, or 32
146 * bits), we store everything as ints in the label struct, above, and
147 * convert when packing and unpacking. This allows us to have only
148 * one numeric chval function.
153 int (*print
)(struct field
*, int);
154 void (*chval
)(const char *, struct field
*);
155 void (*changed
)(void);
159 /* LABEL_MAGIC was chosen by Sun and cannot be trivially changed. */
160 #define LABEL_MAGIC 0xdabe
162 * LABEL_XMAGIC needs to agree between here and any other code that uses
163 * extended partitions (mainly the kernel).
165 #define LABEL_XMAGIC (0x199d1fe2+8)
167 static int diskfd
; /* fd on the disk */
168 static const char *diskname
; /* name of the disk, for messages */
169 static int readonly
; /* true iff it's open RO */
170 static unsigned char labelbuf
[512]; /* Buffer holding the label sector */
171 static struct label label
; /* The label itself. */
172 static int fixmagic
; /* -m, ignore bad magic #s */
173 static int fixcksum
; /* -s, ignore bad cksums */
174 static int newlabel
; /* -n, ignore all on-disk values */
175 static int quiet
; /* -q, don't print chatter */
178 * The various functions that go in the field function pointers. The
179 * _ascii functions are for 128-byte string fields (the ASCII label);
180 * the _int functions are for int-valued fields (everything else).
181 * update_spc is a `changed' function for updating the spc value when
182 * changing one of the two values that make it up.
184 static int print_ascii(struct field
*, int);
185 static void chval_ascii(const char *, struct field
*);
186 static int print_int(struct field
*, int);
187 static void chval_int(const char *, struct field
*);
188 static void update_spc(void);
190 int main(int, char **);
192 /* The fields themselves. */
193 static struct field fields
[] =
195 {"ascii", &label
.asciilabel
[0], print_ascii
, chval_ascii
, 0, 0 },
196 {"rpm", &label
.rpm
, print_int
, chval_int
, 0, 0 },
197 {"pcyl", &label
.pcyl
, print_int
, chval_int
, 0, 0 },
198 {"apc", &label
.apc
, print_int
, chval_int
, 0, 0 },
199 {"obs1", &label
.obs1
, print_int
, chval_int
, 0, 0 },
200 {"obs2", &label
.obs2
, print_int
, chval_int
, 0, 0 },
201 {"intrlv", &label
.intrlv
, print_int
, chval_int
, 0, 0 },
202 {"ncyl", &label
.ncyl
, print_int
, chval_int
, 0, 0 },
203 {"acyl", &label
.acyl
, print_int
, chval_int
, 0, 0 },
204 {"nhead", &label
.nhead
, print_int
, chval_int
, update_spc
, 0 },
205 {"nsect", &label
.nsect
, print_int
, chval_int
, update_spc
, 0 },
206 {"obs3", &label
.obs3
, print_int
, chval_int
, 0, 0 },
207 {"obs4", &label
.obs4
, print_int
, chval_int
, 0, 0 },
208 {NULL
, NULL
, NULL
, NULL
, 0, 0 }
212 * We'd _like_ to use howmany() from the include files, but can't count
213 * on its being present or working.
215 static inline uint32_t how_many(uint32_t amt
, uint32_t unit
)
216 __attribute__((const));
217 static inline uint32_t
218 how_many(uint32_t amt
, uint32_t unit
)
220 return ((amt
+ unit
- 1) / unit
);
224 * Try opening the disk, given a name. If mustsucceed is true, we
225 * "cannot fail"; failures produce gripe-and-exit, and if we return,
226 * our return value is 1. Otherwise, we return 1 on success and 0 on
230 trydisk(const char *s
, int mustsucceed
)
235 if ((diskfd
= open(s
, O_RDWR
)) == -1 ||
236 (diskfd
= open(s
, O_RDWR
| O_NONBLOCK
)) == -1) {
237 if ((diskfd
= open(s
, O_RDONLY
)) == -1) {
239 err(1, "Cannot open `%s'", s
);
246 warnx("No write access, label is readonly");
252 * Set the disk device, given the user-supplied string. Note that even
253 * if we malloc, we never free, because either trydisk eventually
254 * succeeds, in which case the string is saved in diskname, or it
255 * fails, in which case we exit and freeing is irrelevant.
258 setdisk(const char *s
)
262 if (strchr(s
, '/')) {
268 #ifndef DISTRIB /* native tool: search in /dev */
269 asprintf(&tmp
, "/dev/%s", s
);
272 if (trydisk(tmp
, 0)) {
277 asprintf(&tmp
, "/dev/%s%c", s
, getrawpartition() + 'a');
280 if (trydisk(tmp
, 0)) {
285 errx(1, "Can't find device for disk `%s'", s
);
288 static void usage(void) __dead
;
292 (void)fprintf(stderr
, "usage: %s [-mnqs] disk\n", getprogname());
297 * Command-line arguments. We can have at most one non-flag
298 * argument, which is the disk name; we can also have flags
301 * Turns on fixmagic, which causes bad magic numbers to be
302 * ignored (though a complaint is still printed), rather
303 * than being fatal errors.
306 * Turns on fixcksum, which causes bad checksums to be
307 * ignored (though a complaint is still printed), rather
308 * than being fatal errors.
311 * Turns on newlabel, which means we're creating a new
312 * label and anything in the label sector should be
313 * ignored. This is a bit like -m -s, except that it
314 * doesn't print complaints and it ignores possible
318 * Turns on quiet, which suppresses printing of prompts
319 * and other irrelevant chatter. If you're trying to use
320 * sunlabel in an automated way, you probably want this.
323 handleargs(int ac
, char **av
)
327 while ((c
= getopt(ac
, av
, "mnqs")) != -1) {
342 warnx("Illegal option `%c'", c
);
354 * Sets the ending cylinder for a partition. This exists mainly to
355 * centralize the check. (If spc is zero, cylinder numbers make
356 * little sense, and the code would otherwise die on divide-by-0 if we
357 * barged blindly ahead.) We need to call this on a partition
358 * whenever we change it; we need to call it on all partitions
359 * whenever we change spc.
362 set_endcyl(struct part
*p
)
364 if (label
.spc
== 0) {
365 p
->endcyl
= p
->startcyl
;
367 p
->endcyl
= p
->startcyl
+ how_many(p
->nblk
, label
.spc
);
372 * Unpack a label from disk into the in-core label structure. If
373 * newlabel is set, we don't actually do so; we just synthesize a
374 * blank label instead. This is where knowledge of the Sun label
375 * format is kept for read; pack_label is the corresponding routine
376 * for write. We are careful to use labelbuf, l_s, or l_l as
377 * appropriate to avoid byte-sex issues, so we can work on
378 * little-endian machines.
380 * Note that a bad magic number for the extended partition information
381 * is not considered an error; it simply indicates there is no
382 * extended partition information. Arguably this is the Wrong Thing,
383 * and we should take zero as meaning no info, and anything other than
384 * zero or LABEL_XMAGIC as reason to gripe.
389 unsigned short int l_s
[256];
390 unsigned long int l_l
[128];
392 unsigned long int sum
;
396 bzero(&label
.asciilabel
[0], 128);
409 for (i
= 0; i
< NPART
; i
++) {
410 label
.partitions
[i
].startcyl
= 0;
411 label
.partitions
[i
].nblk
= 0;
412 set_endcyl(&label
.partitions
[i
]);
418 for (i
= 0; i
< 256; i
++)
419 l_s
[i
] = (labelbuf
[i
+ i
] << 8) | labelbuf
[i
+ i
+ 1];
420 for (i
= 0; i
< 128; i
++)
421 l_l
[i
] = (l_s
[i
+ i
] << 16) | l_s
[i
+ i
+ 1];
422 if (l_s
[254] != LABEL_MAGIC
) {
425 warnx("ignoring incorrect magic number.");
427 return "bad magic number";
431 for (i
= 0; i
< 256; i
++)
437 warnx("ignoring incorrect checksum.");
439 return "checksum wrong";
442 (void)memcpy(&label
.asciilabel
[0], &labelbuf
[0], 128);
443 label
.rpm
= l_s
[210];
444 label
.pcyl
= l_s
[211];
445 label
.apc
= l_s
[212];
446 label
.obs1
= l_s
[213];
447 label
.obs2
= l_s
[214];
448 label
.intrlv
= l_s
[215];
449 label
.ncyl
= l_s
[216];
450 label
.acyl
= l_s
[217];
451 label
.nhead
= l_s
[218];
452 label
.nsect
= l_s
[219];
453 label
.obs3
= l_s
[220];
454 label
.obs4
= l_s
[221];
455 label
.spc
= label
.nhead
* label
.nsect
;
456 for (i
= 0; i
< 8; i
++) {
457 label
.partitions
[i
].startcyl
= (uint32_t)l_l
[i
+ i
+ 111];
458 label
.partitions
[i
].nblk
= (uint32_t)l_l
[i
+ i
+ 112];
459 set_endcyl(&label
.partitions
[i
]);
462 if (l_l
[33] == LABEL_XMAGIC
) {
464 for (i
= 0; i
< ((NXPART
* 2) + 1); i
++)
466 if (sum
!= l_l
[32]) {
469 warnx("Ignoring incorrect extended-partition checksum.");
472 warnx("Extended-partition magic right but checksum wrong.");
479 for (i
= 0; i
< NXPART
; i
++) {
481 label
.partitions
[i
+ 8].startcyl
= (uint32_t)l_l
[j
++];
482 label
.partitions
[i
+ 8].nblk
= (uint32_t)l_l
[j
++];
483 set_endcyl(&label
.partitions
[i
+ 8]);
486 for (i
= 0; i
< NXPART
; i
++) {
487 label
.partitions
[i
+ 8].startcyl
= 0;
488 label
.partitions
[i
+ 8].nblk
= 0;
489 set_endcyl(&label
.partitions
[i
+ 8]);
496 * Pack a label from the in-core label structure into on-disk format.
497 * This is where knowledge of the Sun label format is kept for write;
498 * unpack_label is the corresponding routine for read. If all
499 * partitions past the first 8 are size=0 cyl=0, we store all-0s in
500 * the extended partition space, to be fully compatible with Sun
501 * labels. Since AFIAK nothing works in that case that would break if
502 * we put extended partition info there in the same format we'd use if
503 * there were real info there, this is arguably unnecessary, but it's
506 * We are careful to avoid endianness issues by constructing everything
507 * in an array of shorts. We do this rather than using chars or longs
508 * because the checksum is defined in terms of shorts; using chars or
509 * longs would simplify small amounts of code at the price of
515 unsigned short int l_s
[256];
517 unsigned short int sum
;
519 memset(&l_s
[0], 0, 512);
520 memcpy(&labelbuf
[0], &label
.asciilabel
[0], 128);
521 for (i
= 0; i
< 64; i
++)
522 l_s
[i
] = (labelbuf
[i
+ i
] << 8) | labelbuf
[i
+ i
+ 1];
523 l_s
[210] = label
.rpm
;
524 l_s
[211] = label
.pcyl
;
525 l_s
[212] = label
.apc
;
526 l_s
[213] = label
.obs1
;
527 l_s
[214] = label
.obs2
;
528 l_s
[215] = label
.intrlv
;
529 l_s
[216] = label
.ncyl
;
530 l_s
[217] = label
.acyl
;
531 l_s
[218] = label
.nhead
;
532 l_s
[219] = label
.nsect
;
533 l_s
[220] = label
.obs3
;
534 l_s
[221] = label
.obs4
;
535 for (i
= 0; i
< 8; i
++) {
536 l_s
[(i
* 4) + 222] = label
.partitions
[i
].startcyl
>> 16;
537 l_s
[(i
* 4) + 223] = label
.partitions
[i
].startcyl
& 0xffff;
538 l_s
[(i
* 4) + 224] = label
.partitions
[i
].nblk
>> 16;
539 l_s
[(i
* 4) + 225] = label
.partitions
[i
].nblk
& 0xffff;
541 for (i
= 0; i
< NXPART
; i
++) {
542 if (label
.partitions
[i
+ 8].startcyl
||
543 label
.partitions
[i
+ 8].nblk
)
547 unsigned long int xsum
;
548 l_s
[66] = LABEL_XMAGIC
>> 16;
549 l_s
[67] = LABEL_XMAGIC
& 0xffff;
550 for (i
= 0; i
< NXPART
; i
++) {
551 int j
= (i
* 4) + 68;
552 l_s
[j
++] = label
.partitions
[i
+ 8].startcyl
>> 16;
553 l_s
[j
++] = label
.partitions
[i
+ 8].startcyl
& 0xffff;
554 l_s
[j
++] = label
.partitions
[i
+ 8].nblk
>> 16;
555 l_s
[j
++] = label
.partitions
[i
+ 8].nblk
& 0xffff;
558 for (i
= 0; i
< ((NXPART
* 2) + 1); i
++)
559 xsum
+= (l_s
[i
+ i
+ 66] << 16) | l_s
[i
+ i
+ 67];
560 l_s
[64] = (int32_t)(xsum
>> 16);
561 l_s
[65] = (int32_t)(xsum
& 0xffff);
563 l_s
[254] = LABEL_MAGIC
;
565 for (i
= 0; i
< 255; i
++)
568 for (i
= 0; i
< 256; i
++) {
569 labelbuf
[i
+ i
] = ((uint32_t)l_s
[i
]) >> 8;
570 labelbuf
[i
+ i
+ 1] = l_s
[i
] & 0xff;
575 * Get the label. Read it off the disk and unpack it. This function
576 * is nothing but lseek, read, unpack_label, and error checking.
584 if (lseek(diskfd
, (off_t
)0, SEEK_SET
) == (off_t
)-1)
585 err(1, "lseek to 0 on `%s' failed", diskname
);
587 if ((rv
= read(diskfd
, &labelbuf
[0], 512)) == -1)
588 err(1, "read label from `%s' failed", diskname
);
591 errx(1, "short read from `%s' wanted %d, got %d.", diskname
,
594 lerr
= unpack_label();
596 errx(1, "bogus label on `%s' (%s)", diskname
, lerr
);
600 * Put the label. Pack it and write it to the disk. This function is
601 * little more than pack_label, lseek, write, and error checking.
609 warnx("No write access to `%s'", diskname
);
613 if (lseek(diskfd
, (off_t
)0, SEEK_SET
) < (off_t
)-1)
614 err(1, "lseek to 0 on `%s' failed", diskname
);
618 if ((rv
= write(diskfd
, &labelbuf
[0], 512)) == -1) {
619 err(1, "write label to `%s' failed", diskname
);
624 errx(1, "short write to `%s': wanted %d, got %d",
631 * Skip whitespace. Used several places in the command-line parsing
635 skipspaces(const char **cpp
)
637 const char *cp
= *cpp
;
638 while (*cp
&& isspace((unsigned char)*cp
))
644 * Scan a number. The first arg points to the char * that's moving
645 * along the string. The second arg points to where we should store
646 * the result. The third arg says what we're scanning, for errors.
647 * The return value is 0 on error, or nonzero if all goes well.
650 scannum(const char **cpp
, uint32_t *np
, const char *tag
)
661 while (*cp
&& isdigit((unsigned char)*cp
)) {
662 v
= (10 * v
) + (*cp
++ - '0');
668 printf("Missing/invalid %s: %s\n", tag
, cp
);
676 * Change a partition. pno is the number of the partition to change;
677 * numbers is a pointer to the string containing the specification for
678 * the new start and size. This always takes the form "start size",
682 * The partition starts at the beginning of that cylinder.
685 * The partition starts at the same place partition X does.
688 * The partition starts at the place partition X ends. If
689 * partition X does not exactly on a cylinder boundary, it
690 * is effectively rounded up.
695 * The partition is that many sectors long.
698 * The three numbers are cyl/trk/sect counts. n1/n2/n3 is
699 * equivalent to specifying a single number
700 * ((n1*label.nhead)+n2)*label.nsect)+n3. In particular,
701 * if label.nhead or label.nsect is zero, this has limited
705 * The partition ends where partition X ends. It is an
706 * error for partition X to end before the specified start
707 * point. This always goes to exactly where partition X
708 * ends, even if that's partway through a cylinder.
711 * The partition extends to end exactly where partition X
712 * begins. It is an error for partition X to begin before
713 * the specified start point.
716 * The partition has the same size as partition X.
718 * If label.spc is nonzero but the partition size is not a multiple of
719 * it, a warning is printed, since you usually don't want this. Most
720 * often, in my experience, this comes from specifying a cylinder
721 * count as a single number N instead of N/0/0.
724 chpart(int pno
, const char *numbers
)
732 skipspaces(&numbers
);
733 if (!memcmp(numbers
, "end-", 4) && numbers
[4]) {
734 int epno
= LETTERPART(numbers
[4]);
735 if ((epno
>= 0) && (epno
< NPART
)) {
736 cyl0
= label
.partitions
[epno
].endcyl
;
739 if (!scannum(&numbers
, &cyl0
, "starting cylinder"))
742 } else if (!memcmp(numbers
, "start-", 6) && numbers
[6]) {
743 int spno
= LETTERPART(numbers
[6]);
744 if ((spno
>= 0) && (spno
< NPART
)) {
745 cyl0
= label
.partitions
[spno
].startcyl
;
748 if (!scannum(&numbers
, &cyl0
, "starting cylinder"))
752 if (!scannum(&numbers
, &cyl0
, "starting cylinder"))
755 skipspaces(&numbers
);
756 if (!memcmp(numbers
, "end-", 4) && numbers
[4]) {
757 int epno
= LETTERPART(numbers
[4]);
758 if ((epno
>= 0) && (epno
< NPART
)) {
759 if (label
.partitions
[epno
].endcyl
<= cyl0
) {
760 warnx("Partition %c ends before cylinder %u",
761 PARTLETTER(epno
), cyl0
);
764 size
= label
.partitions
[epno
].nblk
;
765 /* Be careful of unsigned arithmetic */
766 if (cyl0
> label
.partitions
[epno
].startcyl
) {
767 size
-= (cyl0
- label
.partitions
[epno
].startcyl
)
769 } else if (cyl0
< label
.partitions
[epno
].startcyl
) {
770 size
+= (label
.partitions
[epno
].startcyl
- cyl0
)
775 if (!scannum(&numbers
, &size
, "partition size"))
778 } else if (!memcmp(numbers
, "start-", 6) && numbers
[6]) {
779 int spno
= LETTERPART(numbers
[6]);
780 if ((spno
>= 0) && (spno
< NPART
)) {
781 if (label
.partitions
[spno
].startcyl
<= cyl0
) {
782 warnx("Partition %c starts before cylinder %u",
783 PARTLETTER(spno
), cyl0
);
786 size
= (label
.partitions
[spno
].startcyl
- cyl0
)
790 if (!scannum(&numbers
, &size
, "partition size"))
793 } else if (!memcmp(numbers
, "size-", 5) && numbers
[5]) {
794 int spno
= LETTERPART(numbers
[5]);
795 if ((spno
>= 0) && (spno
< NPART
)) {
796 size
= label
.partitions
[spno
].nblk
;
799 if (!scannum(&numbers
, &size
, "partition size"))
803 if (!scannum(&numbers
, &size
, "partition size"))
805 skipspaces(&numbers
);
806 if (*numbers
== '/') {
809 if (!scannum(&numbers
, &sizet
,
810 "partition size track value"))
812 skipspaces(&numbers
);
813 if (*numbers
!= '/') {
814 warnx("Invalid c/t/s syntax - no second slash");
818 if (!scannum(&numbers
, &sizes
,
819 "partition size sector value"))
821 size
= sizes
+ (label
.nsect
* (sizet
822 + (label
.nhead
* sizec
)));
825 if (label
.spc
&& (size
% label
.spc
)) {
826 warnx("Size is not a multiple of cylinder size (is %u/%u/%u)",
828 (size
% label
.spc
) / label
.nsect
, size
% label
.nsect
);
830 label
.partitions
[pno
].startcyl
= cyl0
;
831 label
.partitions
[pno
].nblk
= size
;
832 set_endcyl(&label
.partitions
[pno
]);
833 if ((label
.partitions
[pno
].startcyl
* label
.spc
)
834 + label
.partitions
[pno
].nblk
> label
.spc
* label
.ncyl
) {
835 warnx("Partition extends beyond end of disk");
841 * Change a 128-byte-string field. There's currently only one such,
842 * the ASCII label field.
845 chval_ascii(const char *cp
, struct field
*f
)
850 if ((nl
= strchr(cp
, '\n')) == NULL
)
851 nl
= cp
+ strlen(cp
);
853 warnx("Ascii label string too long - max 128 characters");
855 memset(f
->loc
, 0, 128);
856 memcpy(f
->loc
, cp
, (size_t)(nl
- cp
));
861 * Change an int-valued field. As noted above, there's only one
862 * function, regardless of the field size in the on-disk label.
865 chval_int(const char *cp
, struct field
*f
)
869 if (!scannum(&cp
, &v
, "value"))
871 *(uint32_t *)f
->loc
= v
;
875 * Change a field's value. The string argument contains the field name
876 * and the new value in text form. Look up the field and call its
877 * chval and changed functions.
880 chvalue(const char *str
)
886 if (fields
[0].taglen
< 1) {
887 for (i
= 0; fields
[i
].tag
; i
++)
888 fields
[i
].taglen
= strlen(fields
[i
].tag
);
892 while (*cp
&& !isspace((unsigned char)*cp
))
895 for (i
= 0; fields
[i
].tag
; i
++) {
896 if (((int)n
== fields
[i
].taglen
) && !memcmp(str
, fields
[i
].tag
, n
)) {
897 (*fields
[i
].chval
) (cp
, &fields
[i
]);
898 if (fields
[i
].changed
)
899 (*fields
[i
].changed
)();
904 warnx("Bad name %.*s - see L output for names", (int)n
, str
);
908 * `changed' function for the ntrack and nsect fields; update label.spc
909 * and call set_endcyl on all partitions.
916 label
.spc
= label
.nhead
* label
.nsect
;
917 for (i
= 0; i
< NPART
; i
++)
918 set_endcyl(&label
.partitions
[i
]);
922 * Print function for 128-byte-string fields. Currently only the ASCII
923 * label, but we don't depend on that.
926 print_ascii(struct field
*f
, int sofar
)
928 printf("%s: %.128s\n", f
->tag
, (char *)f
->loc
);
934 * Print an int-valued field. We are careful to do proper line wrap,
935 * making each value occupy 16 columns.
938 print_int(struct field
*f
, int sofar
)
944 printf("%s: %-*u", f
->tag
, 14 - (int)strlen(f
->tag
),
945 *(uint32_t *)f
->loc
);
950 * Print the whole label. Just call the print function for each field,
951 * then append a newline if necessary.
960 for (i
= 0; fields
[i
].tag
; i
++)
961 c
= (*fields
[i
].print
) (&fields
[i
], c
);
967 * Figure out how many columns wide the screen is. We impose a minimum
968 * width of 20 columns; I suspect the output code has some issues if
969 * we have fewer columns than partitions.
975 #ifndef NO_TERMCAP_WIDTH
979 #if defined(TIOCGWINSZ)
981 #elif defined(TIOCGSIZE)
986 #ifndef NO_TERMCAP_WIDTH
987 term
= getenv("TERM");
988 if (term
&& (tgetent(&tbuf
[0], term
) == 1)) {
989 int n
= tgetnum("co");
994 #if defined(TIOCGWINSZ)
995 if ((ioctl(1, TIOCGWINSZ
, &wsz
) == 0) && (wsz
.ws_col
> 0)) {
998 #elif defined(TIOCGSIZE)
999 if ((ioctl(1, TIOCGSIZE
, &tsz
) == 0) && (tsz
.ts_cols
> 0)) {
1000 ncols
= tsz
.ts_cols
;
1009 * Print the partitions. The argument is true iff we should print all
1010 * partitions, even those set start=0 size=0. We generate one line
1011 * per partition (or, if all==0, per `interesting' partition), plus a
1012 * visually graphic map of partition letters. Most of the hair in the
1013 * visual display lies in ensuring that nothing takes up less than one
1014 * character column, that if two boundaries appear visually identical,
1015 * they _are_ identical. Within that constraint, we try to make the
1016 * number of character columns proportional to the size....
1021 int i
, j
, k
, n
, r
, c
;
1023 uint32_t edges
[2 * NPART
];
1026 unsigned char table
[2 * NPART
][NPART
];
1028 struct part
*p
= label
.partitions
;
1030 for (i
= 0; i
< NPART
; i
++) {
1031 if (all
|| p
[i
].startcyl
|| p
[i
].nblk
) {
1032 printf("%c: start cyl = %6u, size = %8u (",
1033 PARTLETTER(i
), p
[i
].startcyl
, p
[i
].nblk
);
1035 printf("%u/%u/%u - ", p
[i
].nblk
/ label
.spc
,
1036 (p
[i
].nblk
% label
.spc
) / label
.nsect
,
1037 p
[i
].nblk
% label
.nsect
);
1039 printf("%gMb)\n", p
[i
].nblk
/ 2048.0);
1044 for (i
= 0; i
< NPART
; i
++) {
1045 if (p
[i
].nblk
> 0) {
1046 edges
[j
++] = p
[i
].startcyl
;
1047 edges
[j
++] = p
[i
].endcyl
;
1053 for (i
= 1; i
< j
; i
++) {
1054 if (edges
[i
] < edges
[i
- 1]) {
1057 edges
[i
] = edges
[i
- 1];
1064 for (i
= 1; i
< j
; i
++) {
1065 if (edges
[i
] != edges
[n
]) {
1068 edges
[n
] = edges
[i
];
1073 for (i
= 0; i
< NPART
; i
++) {
1074 if (p
[i
].nblk
> 0) {
1075 for (j
= 0; j
< n
; j
++) {
1076 if ((p
[i
].startcyl
<= edges
[j
]) &&
1077 (p
[i
].endcyl
> edges
[j
])) {
1086 ncols
= screen_columns() - 2;
1087 for (i
= 0; i
< n
; i
++)
1088 ce
[i
] = (edges
[i
] * ncols
) / (double) edges
[n
- 1];
1090 for (i
= 1; i
< n
; i
++)
1091 if (ce
[i
] <= ce
[i
- 1])
1092 ce
[i
] = ce
[i
- 1] + 1;
1094 if ((size_t)ce
[n
- 1] > ncols
) {
1096 for (i
= n
- 1; (i
> 0) && (ce
[i
] <= ce
[i
- 1]); i
--)
1097 ce
[i
- 1] = ce
[i
] - 1;
1099 for (i
= 0; i
< n
; i
++)
1104 for (i
= 0; i
< NPART
; i
++) {
1105 if (p
[i
].nblk
> 0) {
1109 for (j
= i
- 1; j
>= 0; j
--) {
1112 for (k
= 0; k
< n
; k
++)
1113 if (table
[k
][i
] && table
[k
][j
])
1125 for (i
= 1; i
< NPART
; i
++)
1129 if ((line
= malloc(ncols
+ 1)) == NULL
)
1130 err(1, "Can't allocate memory");
1132 for (i
= 0; i
<= r
; i
++) {
1133 for (j
= 0; (size_t)j
< ncols
; j
++)
1135 for (j
= 0; j
< NPART
; j
++) {
1139 for (k
= 0; k
< n
; k
++) {
1141 for (c
= ce
[k
]; c
< ce
[k
+ 1]; c
++)
1146 for (j
= ncols
- 1; (j
>= 0) && (line
[j
] == ' '); j
--);
1147 printf("%.*s\n", j
+ 1, line
);
1154 * This computes an appropriate checksum for an in-core label. It's
1155 * not really related to the S command, except that it's needed only
1156 * by setlabel(), which is #ifdef S_COMMAND.
1158 static unsigned short int
1159 dkcksum(const struct disklabel
*lp
)
1161 const unsigned short int *start
;
1162 const unsigned short int *end
;
1163 unsigned short int sum
;
1164 const unsigned short int *p
;
1166 start
= (const void *)lp
;
1167 end
= (const void *)&lp
->d_partitions
[lp
->d_npartitions
];
1169 for (p
= start
; p
< end
; p
++)
1175 * Set the in-core label. This is basically putlabel, except it builds
1176 * a struct disklabel instead of a Sun label buffer, and uses
1177 * DIOCSDINFO instead of lseek-and-write.
1184 char pad
[sizeof(struct disklabel
) -
1185 (MAXPARTITIONS
* sizeof(struct partition
)) +
1186 (16 * sizeof(struct partition
))];
1189 struct part
*p
= label
.partitions
;
1191 if (ioctl(diskfd
, DIOCGDINFO
, &u
.l
) == -1) {
1192 warn("ioctl DIOCGDINFO failed");
1195 if (u
.l
.d_secsize
!= 512) {
1196 warnx("Disk claims %d-byte sectors", (int)u
.l
.d_secsize
);
1198 u
.l
.d_nsectors
= label
.nsect
;
1199 u
.l
.d_ntracks
= label
.nhead
;
1200 u
.l
.d_ncylinders
= label
.ncyl
;
1201 u
.l
.d_secpercyl
= label
.nsect
* label
.nhead
;
1202 u
.l
.d_rpm
= label
.rpm
;
1203 u
.l
.d_interleave
= label
.intrlv
;
1204 u
.l
.d_npartitions
= getmaxpartitions();
1205 memset(&u
.l
.d_partitions
[0], 0,
1206 u
.l
.d_npartitions
* sizeof(struct partition
));
1207 for (i
= 0; i
< u
.l
.d_npartitions
; i
++) {
1208 u
.l
.d_partitions
[i
].p_size
= p
[i
].nblk
;
1209 u
.l
.d_partitions
[i
].p_offset
= p
[i
].startcyl
1210 * label
.nsect
* label
.nhead
;
1211 u
.l
.d_partitions
[i
].p_fsize
= 0;
1212 u
.l
.d_partitions
[i
].p_fstype
= (i
== 1) ? FS_SWAP
:
1213 (i
== 2) ? FS_UNUSED
: FS_BSDFFS
;
1214 u
.l
.d_partitions
[i
].p_frag
= 0;
1215 u
.l
.d_partitions
[i
].p_cpg
= 0;
1218 u
.l
.d_checksum
= dkcksum(&u
.l
);
1219 if (ioctl(diskfd
, DIOCSDINFO
, &u
.l
) == -1) {
1220 warn("ioctl DIOCSDINFO failed");
1226 static const char *help
[] = {
1227 "?\t- print this help",
1228 "L\t- print label, except for partition table",
1229 "P\t- print partition table",
1230 "PP\t- print partition table including size=0 offset=0 entries",
1231 "[abcdefghijklmnop] <cylno> <size> - change partition",
1232 "V <name> <value> - change a non-partition label value",
1233 "W\t- write (possibly modified) label out",
1235 "S\t- set label in the kernel (orthogonal to W)",
1237 "Q\t- quit program (error if no write since last change)",
1238 "Q!\t- quit program (unconditionally) [EOF also quits]",
1243 * Read and execute one command line from the user.
1252 printf("sunlabel> ");
1253 if (fgets(&cmdline
[0], sizeof(cmdline
), stdin
) != &cmdline
[0])
1255 switch (cmdline
[0]) {
1257 for (i
= 0; help
[i
]; i
++)
1258 printf("%s\n", help
[i
]);
1264 print_part(cmdline
[1] == 'P');
1273 printf("This compilation doesn't support S.\n");
1277 if ((cmdline
[1] == '!') || !label
.dirty
)
1279 printf("Label is dirty - use w to write it\n");
1280 printf("Use Q! to quit anyway.\n");
1298 chpart(LETTERPART(cmdline
[0]), &cmdline
[1]);
1301 chvalue(&cmdline
[1]);
1306 printf("(Unrecognized command character %c ignored.)\n",
1313 * main() (duh!). Pretty boring.
1316 main(int ac
, char **av
)