2 * Copyright (c) 2003 Jake Burkholder.
3 * Copyright (c) 2004,2005 Joerg Wunsch.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SPDX-License-Identifier: BSD-4-Clause
30 * Copyright (c) 1994, 1995 Gordon W. Ross
31 * Copyright (c) 1994 Theo de Raadt
32 * All rights reserved.
33 * Copyright (c) 1987, 1993
34 * The Regents of the University of California. All rights reserved.
36 * This code is derived from software contributed to Berkeley by
37 * Symmetric Computer Systems.
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. All advertising materials mentioning features or use of this software
48 * must display the following acknowledgement:
49 * This product includes software developed by the University of
50 * California, Berkeley and its contributors.
51 * This product includes software developed by Theo de Raadt.
52 * 4. Neither the name of the University nor the names of its contributors
53 * may be used to endorse or promote products derived from this software
54 * without specific prior written permission.
56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $
71 #include <sys/cdefs.h>
72 __FBSDID("$FreeBSD$");
74 #include <sys/types.h>
75 #include <sys/param.h>
77 #include <sys/ioctl.h>
91 #include "sun_disklabel.h"
93 #define _PATH_TMPFILE "/tmp/EdDk.XXXXXXXXXX"
94 #define _PATH_BOOT "/boot/boot1"
105 static off_t mediasize;
106 static uint32_t sectorsize;
113 static int check_label(struct sun_disklabel *sl);
114 static void read_label(struct sun_disklabel *sl, const char *disk);
115 static void write_label(struct sun_disklabel *sl, const char *disk,
116 const char *bootpath);
117 static void edit_label(struct sun_disklabel *sl, const char *disk,
118 const char *bootpath);
119 static int parse_label(struct sun_disklabel *sl, const char *file);
120 static void print_label(struct sun_disklabel *sl, const char *disk, FILE *out);
122 static int parse_size(struct sun_disklabel *sl, int part, char *size);
123 static int parse_offset(struct sun_disklabel *sl, int part, char *offset);
125 static const char *flagname(unsigned int tag);
126 static const char *tagname(unsigned int tag);
127 static unsigned int parse_flag(struct sun_disklabel *sl, int part,
129 static unsigned int parse_tag(struct sun_disklabel *sl, int part,
131 static const char *make_h_number(uintmax_t u);
133 static void usage(void);
135 extern char *__progname;
137 static struct tags knowntags[] = {
138 { "unassigned", VTOC_UNASSIGNED },
139 { "boot", VTOC_BOOT },
140 { "root", VTOC_ROOT },
141 { "swap", VTOC_SWAP },
143 { "backup", VTOC_BACKUP },
144 { "stand", VTOC_STAND },
146 { "home", VTOC_HOME },
147 { "altsctr", VTOC_ALTSCTR },
148 { "cache", VTOC_CACHE },
149 { "VxVM_pub", VTOC_VXVM_PUB },
150 { "VxVM_priv", VTOC_VXVM_PRIV },
153 static struct tags knownflags[] = {
155 { "wu", VTOC_UNMNT },
156 { "rm", VTOC_RONLY },
157 { "ru", VTOC_UNMNT | VTOC_RONLY },
161 * Disk label editor for sun disklabels.
164 main(int ac, char **av)
166 struct sun_disklabel sl;
167 const char *bootpath;
172 bootpath = _PATH_BOOT;
173 while ((ch = getopt(ac, av, "b:BcehnrRw")) != -1)
195 fprintf(stderr, "Obsolete -r flag ignored\n");
209 if (nflag && !(Bflag || eflag || Rflag || wflag))
211 if (eflag && (Rflag || wflag))
219 bzero(&sl, sizeof(sl));
222 if (ac != 2 || strcmp(av[1], "auto") != 0)
224 read_label(&sl, disk);
225 bzero(sl.sl_part, sizeof(sl.sl_part));
226 sl.sl_part[SUN_RAWPART].sdkp_cyloffset = 0;
227 sl.sl_part[SUN_RAWPART].sdkp_nsectors = sl.sl_ncylinders *
228 sl.sl_ntracks * sl.sl_nsectors;
229 write_label(&sl, disk, bootpath);
233 read_label(&sl, disk);
234 if (sl.sl_magic != SUN_DKMAGIC)
235 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk);
236 edit_label(&sl, disk, bootpath);
241 read_label(&sl, disk);
242 if (parse_label(&sl, proto) != 0)
243 errx(1, "%s: invalid label", proto);
244 write_label(&sl, disk, bootpath);
246 read_label(&sl, disk);
247 if (sl.sl_magic != SUN_DKMAGIC)
248 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk);
249 write_label(&sl, disk, bootpath);
251 read_label(&sl, disk);
252 if (sl.sl_magic != SUN_DKMAGIC)
253 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk);
254 print_label(&sl, disk, stdout);
260 check_label(struct sun_disklabel *sl)
272 havevtoc = sl->sl_vtoc_sane == SUN_VTOC_SANE;
274 nsectors = sl->sl_ncylinders * sl->sl_ntracks * sl->sl_nsectors;
275 if (sl->sl_part[SUN_RAWPART].sdkp_cyloffset != 0 ||
276 sl->sl_part[SUN_RAWPART].sdkp_nsectors != nsectors) {
277 warnx("partition c is incorrect, must start at 0 and cover "
281 if (havevtoc && sl->sl_vtoc_map[2].svtoc_tag != VTOC_BACKUP) {
282 warnx("partition c must have tag \"backup\"");
285 for (i = 0; i < SUN_NPART; i++) {
286 if (i == 2 || sl->sl_part[i].sdkp_nsectors == 0)
288 start = (uint64_t)sl->sl_part[i].sdkp_cyloffset *
289 sl->sl_ntracks * sl->sl_nsectors;
290 end = start + sl->sl_part[i].sdkp_nsectors;
291 if (end > nsectors) {
292 warnx("partition %c extends past end of disk",
297 if (sl->sl_vtoc_map[i].svtoc_tag == VTOC_BACKUP) {
298 warnx("only partition c is allowed to have "
303 for (j = 0; j < SUN_NPART; j++) {
305 * Overlaps for unmountable partitions are
306 * non-fatal but will be warned anyway.
308 warnonly = havevtoc &&
309 ((sl->sl_vtoc_map[i].svtoc_flag & VTOC_UNMNT) != 0 ||
310 (sl->sl_vtoc_map[j].svtoc_flag & VTOC_UNMNT) != 0);
312 if (j == 2 || j == i ||
313 sl->sl_part[j].sdkp_nsectors == 0)
315 ostart = (uint64_t)sl->sl_part[j].sdkp_cyloffset *
316 sl->sl_ntracks * sl->sl_nsectors;
317 oend = ostart + sl->sl_part[j].sdkp_nsectors;
318 if ((start <= ostart && end >= oend) ||
319 (start > ostart && start < oend) ||
320 (end > ostart && end < oend)) {
321 warnx("partition %c overlaps partition %c",
332 read_label(struct sun_disklabel *sl, const char *disk)
334 char path[MAXPATHLEN];
340 snprintf(path, sizeof(path), "%s%s", _PATH_DEV, disk);
341 if ((fd = open(path, O_RDONLY)) < 0)
342 err(1, "open %s", path);
343 if (read(fd, buf, sizeof(buf)) != sizeof(buf))
345 error = sunlabel_dec(buf, sl);
346 if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) != 0)
348 err(1, "%s: ioctl(DIOCGMEDIASIZE) failed", disk);
349 if (ioctl(fd, DIOCGSECTORSIZE, §orsize) != 0) {
351 err(1, "%s: DIOCGSECTORSIZE failed", disk);
356 bzero(sl, sizeof(*sl));
357 if (ioctl(fd, DIOCGFWSECTORS, &fwsectors) != 0)
359 if (ioctl(fd, DIOCGFWHEADS, &fwheads) != 0) {
360 if (mediasize <= 63 * 1024 * sectorsize)
362 else if (mediasize <= 63 * 16 * 1024 * sectorsize)
368 sl->sl_pcylinders = mediasize / (fwsectors * fwheads *
370 sl->sl_sparespercyl = 0;
371 sl->sl_interleave = 1;
372 sl->sl_ncylinders = sl->sl_pcylinders - 2;
373 sl->sl_acylinders = 2;
374 sl->sl_nsectors = fwsectors;
375 sl->sl_ntracks = fwheads;
376 sl->sl_part[SUN_RAWPART].sdkp_cyloffset = 0;
377 sl->sl_part[SUN_RAWPART].sdkp_nsectors = sl->sl_ncylinders *
378 sl->sl_ntracks * sl->sl_nsectors;
379 if (mediasize > (off_t)4999L * 1024L * 1024L) {
381 "FreeBSD%jdG cyl %u alt %u hd %u sec %u",
382 (intmax_t)(mediasize + 512 * 1024 * 1024) /
383 (1024 * 1024 * 1024),
384 sl->sl_ncylinders, sl->sl_acylinders,
385 sl->sl_ntracks, sl->sl_nsectors);
388 "FreeBSD%jdM cyl %u alt %u hd %u sec %u",
389 (intmax_t)(mediasize + 512 * 1024) / (1024 * 1024),
390 sl->sl_ncylinders, sl->sl_acylinders,
391 sl->sl_ntracks, sl->sl_nsectors);
398 write_label(struct sun_disklabel *sl, const char *disk, const char *bootpath)
400 char path[MAXPATHLEN];
401 char boot[SUN_BOOTSIZE];
408 struct gctl_req *grq;
410 sl->sl_magic = SUN_DKMAGIC;
412 if (check_label(sl) != 0)
413 errx(1, "invalid label");
415 bzero(buf, sizeof(buf));
416 sunlabel_enc(buf, sl);
419 print_label(sl, disk, stdout);
423 if ((bfd = open(bootpath, O_RDONLY)) < 0)
424 err(1, "open %s", bootpath);
425 i = read(bfd, boot, sizeof(boot));
428 else if (i != sizeof (boot))
429 errx(1, "read wrong size boot code (%d)", i);
432 snprintf(path, sizeof(path), "%s%s", _PATH_DEV, disk);
433 fd = open(path, O_RDWR);
435 grq = gctl_get_handle();
436 gctl_ro_param(grq, "verb", -1, "write label");
437 gctl_ro_param(grq, "class", -1, "SUN");
438 gctl_ro_param(grq, "geom", -1, disk);
439 gctl_ro_param(grq, "label", sizeof buf, buf);
440 errstr = gctl_issue(grq);
442 errx(1, "%s", errstr);
445 grq = gctl_get_handle();
446 gctl_ro_param(grq, "verb", -1, "write bootcode");
447 gctl_ro_param(grq, "class", -1, "SUN");
448 gctl_ro_param(grq, "geom", -1, disk);
449 gctl_ro_param(grq, "bootcode", sizeof boot, boot);
450 errstr = gctl_issue(grq);
452 errx(1, "%s", errstr);
456 if (lseek(fd, 0, SEEK_SET) < 0)
458 if (write(fd, buf, sizeof(buf)) != sizeof(buf))
461 for (i = 0; i < SUN_NPART; i++) {
462 if (sl->sl_part[i].sdkp_nsectors == 0)
464 off = sl->sl_part[i].sdkp_cyloffset *
465 sl->sl_ntracks * sl->sl_nsectors * 512;
467 * Ignore first SUN_SIZE bytes of boot code to
468 * avoid overwriting the label.
470 if (lseek(fd, off + SUN_SIZE, SEEK_SET) < 0)
472 if (write(fd, boot + SUN_SIZE,
473 sizeof(boot) - SUN_SIZE) !=
474 sizeof(boot) - SUN_SIZE)
484 edit_label(struct sun_disklabel *sl, const char *disk, const char *bootpath)
486 char tmpfil[] = _PATH_TMPFILE;
495 if ((fd = mkstemp(tmpfil)) < 0)
497 if ((fp = fdopen(fd, "w")) == NULL)
499 print_label(sl, disk, fp);
502 if ((pid = fork()) < 0)
505 if ((editor = getenv("EDITOR")) == NULL)
507 execlp(editor, editor, tmpfil, (char *)NULL);
508 err(1, "execlp %s", editor);
511 while ((r = wait(&status)) > 0 && r != pid)
513 if (WIFEXITED(status)) {
514 if (parse_label(sl, tmpfil) == 0) {
517 write_label(sl, disk, bootpath);
520 printf("re-edit the label? [y]: ");
523 if (c != EOF && c != '\n')
524 while (getchar() != '\n')
539 parse_label(struct sun_disklabel *sl, const char *file)
547 char volname[SUN_VOLNAME_LEN + 1];
548 struct sun_disklabel sl1;
556 unsigned alt, cyl, hd, nr, sec;
559 if ((fp = fopen(file, "r")) == NULL)
562 bzero(&sl1.sl_part, sizeof(sl1.sl_part));
563 while (fgets(buf, sizeof(buf), fp) != NULL) {
565 * In order to recognize a partition entry, we search
566 * for lines starting with a single letter followed by
567 * a colon as their first non-white characters. We
568 * silently ignore any other lines, so any comment etc.
569 * lines in the label template will be ignored.
571 * XXX We should probably also recognize the geometry
572 * fields on top, and allow changing the geometry
573 * emulated by this disk.
575 for (bp = buf; isspace(*bp); bp++)
577 if (strncmp(bp, "text:", strlen("text:")) == 0) {
578 bp += strlen("text:");
580 " %s cyl %u alt %u hd %u sec %u",
581 text, &cyl, &alt, &hd, &sec);
583 warnx("%s, line %d: text label does not "
584 "contain required fields",
590 warnx("%s, line %d: # alt must be equal 2",
595 if (cyl == 0 || cyl > USHRT_MAX) {
599 warnx("%s, line %d: # %s %d unreasonable",
600 file, line + 1, what, nr);
604 if (hd == 0 || hd > USHRT_MAX) {
609 if (sec == 0 || sec > USHRT_MAX) {
615 warnx("unit size unknown, no sector count "
616 "check could be done");
617 else if ((uintmax_t)(cyl + alt) * sec * hd >
618 (uintmax_t)mediasize / sectorsize) {
619 warnx("%s, line %d: sector count %ju exceeds "
622 (uintmax_t)(cyl + alt) * sec * hd,
623 (uintmax_t)mediasize / sectorsize);
627 sl1.sl_pcylinders = cyl + alt;
628 sl1.sl_ncylinders = cyl;
629 sl1.sl_acylinders = alt;
630 sl1.sl_nsectors = sec;
632 memset(sl1.sl_text, 0, sizeof(sl1.sl_text));
633 snprintf(sl1.sl_text, sizeof(sl1.sl_text),
634 "%s cyl %u alt %u hd %u sec %u",
635 text, cyl, alt, hd, sec);
638 if (strncmp(bp, "volume name:", strlen("volume name:")) == 0) {
639 wantvtoc = 1; /* Volume name requires VTOC. */
640 bp += strlen("volume name:");
641 #if SUN_VOLNAME_LEN != 8
642 # error "scanf field width does not match SUN_VOLNAME_LEN"
645 * We set the field length to one more than
646 * SUN_VOLNAME_LEN to allow detecting an
649 memset(volname, 0, sizeof volname);
650 rv = sscanf(bp, " %9[^\n]", volname);
652 /* Clear the volume name. */
653 memset(sl1.sl_vtoc_volname, 0,
656 memcpy(sl1.sl_vtoc_volname, volname,
658 if (volname[SUN_VOLNAME_LEN] != '\0')
660 "%s, line %d: volume name longer than %d characters, truncating",
661 file, line + 1, SUN_VOLNAME_LEN);
665 if (strlen(bp) < 2 || bp[1] != ':') {
669 rv = sscanf(bp, "%c: %30s %30s %30s %30s",
670 &part, size, offset, tag, flag);
673 warnx("%s: syntax error on line %d",
678 if (parse_size(&sl1, part - 'a', size) ||
679 parse_offset(&sl1, part - 'a', offset))
683 if (rv == 5 && parse_flag(&sl1, part - 'a', flag))
685 if (parse_tag(&sl1, part - 'a', tag))
692 sl1.sl_vtoc_sane = SUN_VTOC_SANE;
693 sl1.sl_vtoc_vers = SUN_VTOC_VERSION;
694 sl1.sl_vtoc_nparts = SUN_NPART;
696 sl1.sl_vtoc_sane = 0;
697 sl1.sl_vtoc_vers = 0;
698 sl1.sl_vtoc_nparts = 0;
699 bzero(&sl1.sl_vtoc_map, sizeof(sl1.sl_vtoc_map));
702 return (check_label(sl));
706 parse_size(struct sun_disklabel *sl, int part, char *size)
715 n = strtoumax(size, &p, 10);
717 if (strcmp(size, "*") == 0) {
718 total = sl->sl_ncylinders * sl->sl_ntracks *
720 for (i = 0; i < part; i++) {
723 nsectors += sl->sl_part[i].sdkp_nsectors;
725 n = total - nsectors;
726 } else if (p[1] == '\0' && (p[0] == 'C' || p[0] == 'c')) {
727 n = n * sl->sl_ntracks * sl->sl_nsectors;
728 } else if (p[1] == '\0' && (p[0] == 'K' || p[0] == 'k')) {
729 n = roundup((n * 1024) / 512,
730 sl->sl_ntracks * sl->sl_nsectors);
731 } else if (p[1] == '\0' && (p[0] == 'M' || p[0] == 'm')) {
732 n = roundup((n * 1024 * 1024) / 512,
733 sl->sl_ntracks * sl->sl_nsectors);
734 } else if (p[1] == '\0' && (p[0] == 'S' || p[0] == 's')) {
735 /* size in sectors, no action neded */
736 } else if (p[1] == '\0' && (p[0] == 'G' || p[0] == 'g')) {
737 n = roundup((n * 1024 * 1024 * 1024) / 512,
738 sl->sl_ntracks * sl->sl_nsectors);
742 n = n * sl->sl_ntracks * sl->sl_nsectors;
744 sl->sl_part[part].sdkp_nsectors = n;
749 parse_offset(struct sun_disklabel *sl, int part, char *offset)
757 n = strtoumax(offset, &p, 10);
759 if (strcmp(offset, "*") == 0) {
760 for (i = 0; i < part; i++) {
763 nsectors += sl->sl_part[i].sdkp_nsectors;
765 n = nsectors / (sl->sl_nsectors * sl->sl_ntracks);
769 sl->sl_part[part].sdkp_cyloffset = n;
774 print_label(struct sun_disklabel *sl, const char *disk, FILE *out)
779 /* Long enough to hex-encode each character. */
780 char volname[4 * SUN_VOLNAME_LEN + 1];
782 havevtoc = sl->sl_vtoc_sane == SUN_VTOC_SANE;
783 secpercyl = sl->sl_nsectors * sl->sl_ntracks;
789 "sectors/cylinder: %ju\n",
796 "# max sectors/unit (including alt cylinders): %ju\n",
797 (uintmax_t)mediasize / sectorsize);
799 "sectors/unit: %ju\n",
800 secpercyl * sl->sl_ncylinders);
801 if (havevtoc && sl->sl_vtoc_volname[0] != '\0') {
802 for (i = j = 0; i < SUN_VOLNAME_LEN; i++) {
803 if (sl->sl_vtoc_volname[i] == '\0')
805 if (isprint(sl->sl_vtoc_volname[i]))
806 volname[j++] = sl->sl_vtoc_volname[i];
808 j += sprintf(volname + j, "\\x%02X",
809 sl->sl_vtoc_volname[i]);
812 fprintf(out, "volume name: %s\n", volname);
820 fprintf(out, "# Size is in %s.", cflag? "cylinders": "sectors");
823 " Use %%d%c, %%dK, %%dM or %%dG to specify in %s,\n"
824 "# kilobytes, megabytes or gigabytes respectively, or '*' to specify rest of\n"
827 cflag? "sectors": "cylinders");
830 fprintf(out, "# Offset is in cylinders.");
833 " Use '*' to calculate offsets automatically.\n"
840 "# size offset tag flag\n"
841 "# ---------- ---------- ---------- ----\n"
846 "# ---------- ----------\n"
849 for (i = 0; i < SUN_NPART; i++) {
850 if (sl->sl_part[i].sdkp_nsectors == 0)
853 fprintf(out, " %c: %10s",
855 make_h_number((uintmax_t)
856 sl->sl_part[i].sdkp_nsectors * 512));
857 fprintf(out, " %10s",
858 make_h_number((uintmax_t)
859 sl->sl_part[i].sdkp_cyloffset * 512
862 fprintf(out, " %c: %10ju %10u",
864 sl->sl_part[i].sdkp_nsectors / (cflag? secpercyl: 1),
865 sl->sl_part[i].sdkp_cyloffset);
868 fprintf(out, " %11s %5s",
869 tagname(sl->sl_vtoc_map[i].svtoc_tag),
870 flagname(sl->sl_vtoc_map[i].svtoc_flag));
879 fprintf(stderr, "usage:"
880 "\t%s [-r] [-c | -h] disk\n"
881 "\t\t(to read label)\n"
882 "\t%s -B [-b boot1] [-n] disk\n"
883 "\t\t(to install boot program only)\n"
884 "\t%s -R [-B [-b boot1]] [-r] [-n] [-c] disk protofile\n"
885 "\t\t(to restore label)\n"
886 "\t%s -e [-B [-b boot1]] [-r] [-n] [-c] disk\n"
887 "\t\t(to edit label)\n"
888 "\t%s -w [-B [-b boot1]] [-r] [-n] disk type\n"
889 "\t\t(to write default label)\n",
899 * Return VTOC tag and flag names for tag or flag ID, resp.
902 tagname(unsigned int tag)
908 for (i = 0, tp = knowntags; i < nitems(knowntags); i++, tp++)
912 sprintf(buf, "%u", tag);
918 flagname(unsigned int flag)
924 for (i = 0, tp = knownflags; i < nitems(knownflags); i++, tp++)
928 sprintf(buf, "%u", flag);
934 parse_tag(struct sun_disklabel *sl, int part, const char *tag)
941 for (i = 0, tp = knowntags; i < nitems(knowntags); i++, tp++)
942 if (strcmp(tp->name, tag) == 0) {
943 sl->sl_vtoc_map[part].svtoc_tag = (uint16_t)tp->id;
947 l = strtoul(tag, &endp, 0);
948 if (*tag != '\0' && *endp == '\0') {
949 sl->sl_vtoc_map[part].svtoc_tag = (uint16_t)l;
957 parse_flag(struct sun_disklabel *sl, int part, const char *flag)
964 for (i = 0, tp = knownflags; i < nitems(knownflags); i++, tp++)
965 if (strcmp(tp->name, flag) == 0) {
966 sl->sl_vtoc_map[part].svtoc_flag = (uint16_t)tp->id;
970 l = strtoul(flag, &endp, 0);
971 if (*flag != '\0' && *endp == '\0') {
972 sl->sl_vtoc_map[part].svtoc_flag = (uint16_t)l;
980 * Convert argument into `human readable' byte number form.
983 make_h_number(uintmax_t u)
990 } else if (u > 2000000000UL) {
992 sprintf(buf, "%.1fG", d);
993 } else if (u > 2000000UL) {
995 sprintf(buf, "%.1fM", d);
998 sprintf(buf, "%.1fK", d);