Add ELFOSABI_ARM_AEABI ELF OSABI constant
[freebsd-src.git] / sbin / sunlabel / sunlabel.c
blobc79e213b686eb08f09a767ecbd44550e49990cc5
1 /*-
2 * Copyright (c) 2003 Jake Burkholder.
3 * Copyright (c) 2004,2005 Joerg Wunsch.
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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
25 * SUCH DAMAGE.
28 * Copyright (c) 1994, 1995 Gordon W. Ross
29 * Copyright (c) 1994 Theo de Raadt
30 * All rights reserved.
31 * Copyright (c) 1987, 1993
32 * The Regents of the University of California. All rights reserved.
34 * This code is derived from software contributed to Berkeley by
35 * Symmetric Computer Systems.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * This product includes software developed by Theo de Raadt.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
66 * from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $
69 #include <sys/cdefs.h>
70 __FBSDID("$FreeBSD$");
72 #include <sys/types.h>
73 #include <sys/param.h>
74 #include <sys/disk.h>
75 #include <sys/ioctl.h>
76 #include <sys/sun_disklabel.h>
77 #include <sys/wait.h>
79 #include <ctype.h>
80 #include <err.h>
81 #include <fcntl.h>
82 #include <inttypes.h>
83 #include <libgeom.h>
84 #include <paths.h>
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <string.h>
88 #include <unistd.h>
90 #define _PATH_TMPFILE "/tmp/EdDk.XXXXXXXXXX"
91 #define _PATH_BOOT "/boot/boot1"
93 static int bflag;
94 static int Bflag;
95 static int cflag;
96 static int eflag;
97 static int hflag;
98 static int nflag;
99 static int Rflag;
100 static int wflag;
102 static off_t mediasize;
103 static uint32_t sectorsize;
105 struct tags {
106 const char *name;
107 unsigned int id;
110 static int check_label(struct sun_disklabel *sl);
111 static void read_label(struct sun_disklabel *sl, const char *disk);
112 static void write_label(struct sun_disklabel *sl, const char *disk,
113 const char *bootpath);
114 static void edit_label(struct sun_disklabel *sl, const char *disk,
115 const char *bootpath);
116 static int parse_label(struct sun_disklabel *sl, const char *file);
117 static void print_label(struct sun_disklabel *sl, const char *disk, FILE *out);
119 static int parse_size(struct sun_disklabel *sl, int part, char *size);
120 static int parse_offset(struct sun_disklabel *sl, int part, char *offset);
122 static const char *flagname(unsigned int tag);
123 static const char *tagname(unsigned int tag);
124 static unsigned int parse_flag(struct sun_disklabel *sl, int part,
125 const char *flag);
126 static unsigned int parse_tag(struct sun_disklabel *sl, int part,
127 const char *tag);
128 static const char *make_h_number(uintmax_t u);
130 static void usage(void);
132 extern char *__progname;
134 static struct tags knowntags[] = {
135 { "unassigned", VTOC_UNASSIGNED },
136 { "boot", VTOC_BOOT },
137 { "root", VTOC_ROOT },
138 { "swap", VTOC_SWAP },
139 { "usr", VTOC_USR },
140 { "backup", VTOC_BACKUP },
141 { "stand", VTOC_STAND },
142 { "var", VTOC_VAR },
143 { "home", VTOC_HOME },
144 { "altsctr", VTOC_ALTSCTR },
145 { "cache", VTOC_CACHE },
146 { "VxVM_pub", VTOC_VXVM_PUB },
147 { "VxVM_priv", VTOC_VXVM_PRIV },
150 static struct tags knownflags[] = {
151 { "wm", 0 },
152 { "wu", VTOC_UNMNT },
153 { "rm", VTOC_RONLY },
154 { "ru", VTOC_UNMNT | VTOC_RONLY },
158 * Disk label editor for sun disklabels.
161 main(int ac, char **av)
163 struct sun_disklabel sl;
164 const char *bootpath;
165 const char *proto;
166 const char *disk;
167 int ch;
169 bootpath = _PATH_BOOT;
170 while ((ch = getopt(ac, av, "b:BcehnrRw")) != -1)
171 switch (ch) {
172 case 'b':
173 bflag = 1;
174 bootpath = optarg;
175 break;
176 case 'B':
177 Bflag = 1;
178 break;
179 case 'c':
180 cflag = 1;
181 break;
182 case 'e':
183 eflag = 1;
184 break;
185 case 'h':
186 hflag = 1;
187 break;
188 case 'n':
189 nflag = 1;
190 break;
191 case 'r':
192 fprintf(stderr, "Obsolete -r flag ignored\n");
193 break;
194 case 'R':
195 Rflag = 1;
196 break;
197 case 'w':
198 wflag = 1;
199 break;
200 default:
201 usage();
202 break;
204 if (bflag && !Bflag)
205 usage();
206 if (nflag && !(Bflag || eflag || Rflag || wflag))
207 usage();
208 if (eflag && (Rflag || wflag))
209 usage();
210 if (eflag)
211 hflag = 0;
212 ac -= optind;
213 av += optind;
214 if (ac == 0)
215 usage();
216 bzero(&sl, sizeof(sl));
217 disk = av[0];
218 if (wflag) {
219 if (ac != 2 || strcmp(av[1], "auto") != 0)
220 usage();
221 read_label(&sl, disk);
222 bzero(sl.sl_part, sizeof(sl.sl_part));
223 sl.sl_part[SUN_RAWPART].sdkp_cyloffset = 0;
224 sl.sl_part[SUN_RAWPART].sdkp_nsectors = sl.sl_ncylinders *
225 sl.sl_ntracks * sl.sl_nsectors;
226 write_label(&sl, disk, bootpath);
227 } else if (eflag) {
228 if (ac != 1)
229 usage();
230 read_label(&sl, disk);
231 if (sl.sl_magic != SUN_DKMAGIC)
232 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk);
233 edit_label(&sl, disk, bootpath);
234 } else if (Rflag) {
235 if (ac != 2)
236 usage();
237 proto = av[1];
238 read_label(&sl, disk);
239 if (parse_label(&sl, proto) != 0)
240 errx(1, "%s: invalid label", proto);
241 write_label(&sl, disk, bootpath);
242 } else if (Bflag) {
243 read_label(&sl, disk);
244 if (sl.sl_magic != SUN_DKMAGIC)
245 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk);
246 write_label(&sl, disk, bootpath);
247 } else {
248 read_label(&sl, disk);
249 if (sl.sl_magic != SUN_DKMAGIC)
250 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk);
251 print_label(&sl, disk, stdout);
253 return (0);
256 static int
257 check_label(struct sun_disklabel *sl)
259 uint64_t nsectors;
260 uint64_t ostart;
261 uint64_t start;
262 uint64_t oend;
263 uint64_t end;
264 int havevtoc;
265 int warnonly;
266 int i;
267 int j;
269 havevtoc = sl->sl_vtoc_sane == SUN_VTOC_SANE;
271 nsectors = sl->sl_ncylinders * sl->sl_ntracks * sl->sl_nsectors;
272 if (sl->sl_part[SUN_RAWPART].sdkp_cyloffset != 0 ||
273 sl->sl_part[SUN_RAWPART].sdkp_nsectors != nsectors) {
274 warnx("partition c is incorrect, must start at 0 and cover "
275 "whole disk");
276 return (1);
278 if (havevtoc && sl->sl_vtoc_map[2].svtoc_tag != VTOC_BACKUP) {
279 warnx("partition c must have tag \"backup\"");
280 return (1);
282 for (i = 0; i < SUN_NPART; i++) {
283 if (i == 2 || sl->sl_part[i].sdkp_nsectors == 0)
284 continue;
285 start = (uint64_t)sl->sl_part[i].sdkp_cyloffset *
286 sl->sl_ntracks * sl->sl_nsectors;
287 end = start + sl->sl_part[i].sdkp_nsectors;
288 if (end > nsectors) {
289 warnx("partition %c extends past end of disk",
290 'a' + i);
291 return (1);
293 if (havevtoc) {
294 if (sl->sl_vtoc_map[i].svtoc_tag == VTOC_BACKUP) {
295 warnx("only partition c is allowed to have "
296 "tag \"backup\"");
297 return (1);
300 for (j = 0; j < SUN_NPART; j++) {
302 * Overlaps for unmountable partitions are
303 * non-fatal but will be warned anyway.
305 warnonly = havevtoc &&
306 ((sl->sl_vtoc_map[i].svtoc_flag & VTOC_UNMNT) != 0 ||
307 (sl->sl_vtoc_map[j].svtoc_flag & VTOC_UNMNT) != 0);
309 if (j == 2 || j == i ||
310 sl->sl_part[j].sdkp_nsectors == 0)
311 continue;
312 ostart = (uint64_t)sl->sl_part[j].sdkp_cyloffset *
313 sl->sl_ntracks * sl->sl_nsectors;
314 oend = ostart + sl->sl_part[j].sdkp_nsectors;
315 if ((start <= ostart && end >= oend) ||
316 (start > ostart && start < oend) ||
317 (end > ostart && end < oend)) {
318 warnx("partition %c overlaps partition %c",
319 'a' + i, 'a' + j);
320 if (!warnonly)
321 return (1);
325 return (0);
328 static void
329 read_label(struct sun_disklabel *sl, const char *disk)
331 char path[MAXPATHLEN];
332 uint32_t fwsectors;
333 uint32_t fwheads;
334 char buf[SUN_SIZE];
335 int fd, error;
337 snprintf(path, sizeof(path), "%s%s", _PATH_DEV, disk);
338 if ((fd = open(path, O_RDONLY)) < 0)
339 err(1, "open %s", path);
340 if (read(fd, buf, sizeof(buf)) != sizeof(buf))
341 err(1, "read");
342 error = sunlabel_dec(buf, sl);
343 if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) != 0)
344 if (error)
345 err(1, "%s: ioctl(DIOCGMEDIASIZE) failed", disk);
346 if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) != 0) {
347 if (error)
348 err(1, "%s: DIOCGSECTORSIZE failed", disk);
349 else
350 sectorsize = 512;
352 if (error) {
353 bzero(sl, sizeof(*sl));
354 if (ioctl(fd, DIOCGFWSECTORS, &fwsectors) != 0)
355 fwsectors = 63;
356 if (ioctl(fd, DIOCGFWHEADS, &fwheads) != 0) {
357 if (mediasize <= 63 * 1024 * sectorsize)
358 fwheads = 1;
359 else if (mediasize <= 63 * 16 * 1024 * sectorsize)
360 fwheads = 16;
361 else
362 fwheads = 255;
364 sl->sl_rpm = 3600;
365 sl->sl_pcylinders = mediasize / (fwsectors * fwheads *
366 sectorsize);
367 sl->sl_sparespercyl = 0;
368 sl->sl_interleave = 1;
369 sl->sl_ncylinders = sl->sl_pcylinders - 2;
370 sl->sl_acylinders = 2;
371 sl->sl_nsectors = fwsectors;
372 sl->sl_ntracks = fwheads;
373 sl->sl_part[SUN_RAWPART].sdkp_cyloffset = 0;
374 sl->sl_part[SUN_RAWPART].sdkp_nsectors = sl->sl_ncylinders *
375 sl->sl_ntracks * sl->sl_nsectors;
376 if (mediasize > (off_t)4999L * 1024L * 1024L) {
377 sprintf(sl->sl_text,
378 "FreeBSD%jdG cyl %u alt %u hd %u sec %u",
379 (intmax_t)(mediasize + 512 * 1024 * 1024) /
380 (1024 * 1024 * 1024),
381 sl->sl_ncylinders, sl->sl_acylinders,
382 sl->sl_ntracks, sl->sl_nsectors);
383 } else {
384 sprintf(sl->sl_text,
385 "FreeBSD%jdM cyl %u alt %u hd %u sec %u",
386 (intmax_t)(mediasize + 512 * 1024) / (1024 * 1024),
387 sl->sl_ncylinders, sl->sl_acylinders,
388 sl->sl_ntracks, sl->sl_nsectors);
391 close(fd);
394 static void
395 write_label(struct sun_disklabel *sl, const char *disk, const char *bootpath)
397 char path[MAXPATHLEN];
398 char boot[SUN_BOOTSIZE];
399 char buf[SUN_SIZE];
400 const char *errstr;
401 off_t off;
402 int bfd;
403 int fd;
404 int i;
405 struct gctl_req *grq;
407 sl->sl_magic = SUN_DKMAGIC;
409 if (check_label(sl) != 0)
410 errx(1, "invalid label");
412 bzero(buf, sizeof(buf));
413 sunlabel_enc(buf, sl);
415 if (nflag) {
416 print_label(sl, disk, stdout);
417 return;
419 if (Bflag) {
420 if ((bfd = open(bootpath, O_RDONLY)) < 0)
421 err(1, "open %s", bootpath);
422 i = read(bfd, boot, sizeof(boot));
423 if (i < 0)
424 err(1, "read");
425 else if (i != sizeof (boot))
426 errx(1, "read wrong size boot code (%d)", i);
427 close(bfd);
429 snprintf(path, sizeof(path), "%s%s", _PATH_DEV, disk);
430 fd = open(path, O_RDWR);
431 if (fd < 0) {
432 grq = gctl_get_handle();
433 gctl_ro_param(grq, "verb", -1, "write label");
434 gctl_ro_param(grq, "class", -1, "SUN");
435 gctl_ro_param(grq, "geom", -1, disk);
436 gctl_ro_param(grq, "label", sizeof buf, buf);
437 errstr = gctl_issue(grq);
438 if (errstr != NULL)
439 errx(1, "%s", errstr);
440 gctl_free(grq);
441 if (Bflag) {
442 grq = gctl_get_handle();
443 gctl_ro_param(grq, "verb", -1, "write bootcode");
444 gctl_ro_param(grq, "class", -1, "SUN");
445 gctl_ro_param(grq, "geom", -1, disk);
446 gctl_ro_param(grq, "bootcode", sizeof boot, boot);
447 errstr = gctl_issue(grq);
448 if (errstr != NULL)
449 errx(1, "%s", errstr);
450 gctl_free(grq);
452 } else {
453 if (lseek(fd, 0, SEEK_SET) < 0)
454 err(1, "lseek");
455 if (write(fd, buf, sizeof(buf)) != sizeof(buf))
456 err (1, "write");
457 if (Bflag) {
458 for (i = 0; i < SUN_NPART; i++) {
459 if (sl->sl_part[i].sdkp_nsectors == 0)
460 continue;
461 off = sl->sl_part[i].sdkp_cyloffset *
462 sl->sl_ntracks * sl->sl_nsectors * 512;
464 * Ignore first SUN_SIZE bytes of boot code to
465 * avoid overwriting the label.
467 if (lseek(fd, off + SUN_SIZE, SEEK_SET) < 0)
468 err(1, "lseek");
469 if (write(fd, boot + SUN_SIZE,
470 sizeof(boot) - SUN_SIZE) !=
471 sizeof(boot) - SUN_SIZE)
472 err(1, "write");
475 close(fd);
477 exit(0);
480 static void
481 edit_label(struct sun_disklabel *sl, const char *disk, const char *bootpath)
483 char tmpfil[] = _PATH_TMPFILE;
484 const char *editor;
485 int status;
486 FILE *fp;
487 pid_t pid;
488 pid_t r;
489 int fd;
490 int c;
492 if ((fd = mkstemp(tmpfil)) < 0)
493 err(1, "mkstemp");
494 if ((fp = fdopen(fd, "w")) == NULL)
495 err(1, "fdopen");
496 print_label(sl, disk, fp);
497 fflush(fp);
498 for (;;) {
499 if ((pid = fork()) < 0)
500 err(1, "fork");
501 if (pid == 0) {
502 if ((editor = getenv("EDITOR")) == NULL)
503 editor = _PATH_VI;
504 execlp(editor, editor, tmpfil, (char *)NULL);
505 err(1, "execlp %s", editor);
507 status = 0;
508 while ((r = wait(&status)) > 0 && r != pid)
510 if (WIFEXITED(status)) {
511 if (parse_label(sl, tmpfil) == 0) {
512 fclose(fp);
513 unlink(tmpfil);
514 write_label(sl, disk, bootpath);
515 return;
517 printf("re-edit the label? [y]: ");
518 fflush(stdout);
519 c = getchar();
520 if (c != EOF && c != '\n')
521 while (getchar() != '\n')
523 if (c == 'n') {
524 fclose(fp);
525 unlink(tmpfil);
526 return;
530 fclose(fp);
531 unlink(tmpfil);
532 return;
535 static int
536 parse_label(struct sun_disklabel *sl, const char *file)
538 char offset[32];
539 char size[32];
540 char flag[32];
541 char tag[32];
542 char buf[128];
543 char text[128];
544 char volname[SUN_VOLNAME_LEN + 1];
545 struct sun_disklabel sl1;
546 char *bp;
547 const char *what;
548 uint8_t part;
549 FILE *fp;
550 int line;
551 int rv;
552 int wantvtoc;
553 unsigned alt, cyl, hd, nr, sec;
555 line = wantvtoc = 0;
556 if ((fp = fopen(file, "r")) == NULL)
557 err(1, "fopen");
558 sl1 = *sl;
559 bzero(&sl1.sl_part, sizeof(sl1.sl_part));
560 while (fgets(buf, sizeof(buf), fp) != NULL) {
562 * In order to recognize a partition entry, we search
563 * for lines starting with a single letter followed by
564 * a colon as their first non-white characters. We
565 * silently ignore any other lines, so any comment etc.
566 * lines in the label template will be ignored.
568 * XXX We should probably also recognize the geometry
569 * fields on top, and allow changing the geometry
570 * emulated by this disk.
572 for (bp = buf; isspace(*bp); bp++)
574 if (strncmp(bp, "text:", strlen("text:")) == 0) {
575 bp += strlen("text:");
576 rv = sscanf(bp,
577 " %s cyl %u alt %u hd %u sec %u",
578 text, &cyl, &alt, &hd, &sec);
579 if (rv != 5) {
580 warnx("%s, line %d: text label does not "
581 "contain required fields",
582 file, line + 1);
583 fclose(fp);
584 return (1);
586 if (alt != 2) {
587 warnx("%s, line %d: # alt must be equal 2",
588 file, line + 1);
589 fclose(fp);
590 return (1);
592 if (cyl == 0 || cyl > USHRT_MAX) {
593 what = "cyl";
594 nr = cyl;
595 unreasonable:
596 warnx("%s, line %d: # %s %d unreasonable",
597 file, line + 1, what, nr);
598 fclose(fp);
599 return (1);
601 if (hd == 0 || hd > USHRT_MAX) {
602 what = "hd";
603 nr = hd;
604 goto unreasonable;
606 if (sec == 0 || sec > USHRT_MAX) {
607 what = "sec";
608 nr = sec;
609 goto unreasonable;
611 if (mediasize == 0)
612 warnx("unit size unknown, no sector count "
613 "check could be done");
614 else if ((uintmax_t)(cyl + alt) * sec * hd >
615 (uintmax_t)mediasize / sectorsize) {
616 warnx("%s, line %d: sector count %ju exceeds "
617 "unit size %ju",
618 file, line + 1,
619 (uintmax_t)(cyl + alt) * sec * hd,
620 (uintmax_t)mediasize / sectorsize);
621 fclose(fp);
622 return (1);
624 sl1.sl_pcylinders = cyl + alt;
625 sl1.sl_ncylinders = cyl;
626 sl1.sl_acylinders = alt;
627 sl1.sl_nsectors = sec;
628 sl1.sl_ntracks = hd;
629 memset(sl1.sl_text, 0, sizeof(sl1.sl_text));
630 snprintf(sl1.sl_text, sizeof(sl1.sl_text),
631 "%s cyl %u alt %u hd %u sec %u",
632 text, cyl, alt, hd, sec);
633 continue;
635 if (strncmp(bp, "volume name:", strlen("volume name:")) == 0) {
636 wantvtoc = 1; /* Volume name requires VTOC. */
637 bp += strlen("volume name:");
638 #if SUN_VOLNAME_LEN != 8
639 # error "scanf field width does not match SUN_VOLNAME_LEN"
640 #endif
642 * We set the field length to one more than
643 * SUN_VOLNAME_LEN to allow detecting an
644 * overflow.
646 memset(volname, 0, sizeof volname);
647 rv = sscanf(bp, " %9[^\n]", volname);
648 if (rv != 1) {
649 /* Clear the volume name. */
650 memset(sl1.sl_vtoc_volname, 0,
651 SUN_VOLNAME_LEN);
652 } else {
653 memcpy(sl1.sl_vtoc_volname, volname,
654 SUN_VOLNAME_LEN);
655 if (volname[SUN_VOLNAME_LEN] != '\0')
656 warnx(
657 "%s, line %d: volume name longer than %d characters, truncating",
658 file, line + 1, SUN_VOLNAME_LEN);
660 continue;
662 if (strlen(bp) < 2 || bp[1] != ':') {
663 line++;
664 continue;
666 rv = sscanf(bp, "%c: %30s %30s %30s %30s",
667 &part, size, offset, tag, flag);
668 if (rv < 3) {
669 syntaxerr:
670 warnx("%s: syntax error on line %d",
671 file, line + 1);
672 fclose(fp);
673 return (1);
675 if (parse_size(&sl1, part - 'a', size) ||
676 parse_offset(&sl1, part - 'a', offset))
677 goto syntaxerr;
678 if (rv > 3) {
679 wantvtoc = 1;
680 if (rv == 5 && parse_flag(&sl1, part - 'a', flag))
681 goto syntaxerr;
682 if (parse_tag(&sl1, part - 'a', tag))
683 goto syntaxerr;
685 line++;
687 fclose(fp);
688 if (wantvtoc) {
689 sl1.sl_vtoc_sane = SUN_VTOC_SANE;
690 sl1.sl_vtoc_vers = SUN_VTOC_VERSION;
691 sl1.sl_vtoc_nparts = SUN_NPART;
692 } else {
693 sl1.sl_vtoc_sane = 0;
694 sl1.sl_vtoc_vers = 0;
695 sl1.sl_vtoc_nparts = 0;
696 bzero(&sl1.sl_vtoc_map, sizeof(sl1.sl_vtoc_map));
698 *sl = sl1;
699 return (check_label(sl));
702 static int
703 parse_size(struct sun_disklabel *sl, int part, char *size)
705 uintmax_t nsectors;
706 uintmax_t total;
707 uintmax_t n;
708 char *p;
709 int i;
711 nsectors = 0;
712 n = strtoumax(size, &p, 10);
713 if (*p != '\0') {
714 if (strcmp(size, "*") == 0) {
715 total = sl->sl_ncylinders * sl->sl_ntracks *
716 sl->sl_nsectors;
717 for (i = 0; i < part; i++) {
718 if (i == 2)
719 continue;
720 nsectors += sl->sl_part[i].sdkp_nsectors;
722 n = total - nsectors;
723 } else if (p[1] == '\0' && (p[0] == 'C' || p[0] == 'c')) {
724 n = n * sl->sl_ntracks * sl->sl_nsectors;
725 } else if (p[1] == '\0' && (p[0] == 'K' || p[0] == 'k')) {
726 n = roundup((n * 1024) / 512,
727 sl->sl_ntracks * sl->sl_nsectors);
728 } else if (p[1] == '\0' && (p[0] == 'M' || p[0] == 'm')) {
729 n = roundup((n * 1024 * 1024) / 512,
730 sl->sl_ntracks * sl->sl_nsectors);
731 } else if (p[1] == '\0' && (p[0] == 'S' || p[0] == 's')) {
732 /* size in sectors, no action neded */
733 } else if (p[1] == '\0' && (p[0] == 'G' || p[0] == 'g')) {
734 n = roundup((n * 1024 * 1024 * 1024) / 512,
735 sl->sl_ntracks * sl->sl_nsectors);
736 } else
737 return (-1);
738 } else if (cflag) {
739 n = n * sl->sl_ntracks * sl->sl_nsectors;
741 sl->sl_part[part].sdkp_nsectors = n;
742 return (0);
745 static int
746 parse_offset(struct sun_disklabel *sl, int part, char *offset)
748 uintmax_t nsectors;
749 uintmax_t n;
750 char *p;
751 int i;
753 nsectors = 0;
754 n = strtoumax(offset, &p, 10);
755 if (*p != '\0') {
756 if (strcmp(offset, "*") == 0) {
757 for (i = 0; i < part; i++) {
758 if (i == 2)
759 continue;
760 nsectors += sl->sl_part[i].sdkp_nsectors;
762 n = nsectors / (sl->sl_nsectors * sl->sl_ntracks);
763 } else
764 return (-1);
766 sl->sl_part[part].sdkp_cyloffset = n;
767 return (0);
770 static void
771 print_label(struct sun_disklabel *sl, const char *disk, FILE *out)
773 int i, j;
774 int havevtoc;
775 uintmax_t secpercyl;
776 /* Long enough to hex-encode each character. */
777 char volname[4 * SUN_VOLNAME_LEN + 1];
779 havevtoc = sl->sl_vtoc_sane == SUN_VTOC_SANE;
780 secpercyl = sl->sl_nsectors * sl->sl_ntracks;
782 fprintf(out,
783 "# /dev/%s:\n"
784 "text: %s\n"
785 "bytes/sector: %d\n"
786 "sectors/cylinder: %ju\n",
787 disk,
788 sl->sl_text,
789 sectorsize,
790 secpercyl);
791 if (eflag)
792 fprintf(out,
793 "# max sectors/unit (including alt cylinders): %ju\n",
794 (uintmax_t)mediasize / sectorsize);
795 fprintf(out,
796 "sectors/unit: %ju\n",
797 secpercyl * sl->sl_ncylinders);
798 if (havevtoc && sl->sl_vtoc_volname[0] != '\0') {
799 for (i = j = 0; i < SUN_VOLNAME_LEN; i++) {
800 if (sl->sl_vtoc_volname[i] == '\0')
801 break;
802 if (isprint(sl->sl_vtoc_volname[i]))
803 volname[j++] = sl->sl_vtoc_volname[i];
804 else
805 j += sprintf(volname + j, "\\x%02X",
806 sl->sl_vtoc_volname[i]);
808 volname[j] = '\0';
809 fprintf(out, "volume name: %s\n", volname);
811 fprintf(out,
812 "\n"
813 "%d partitions:\n"
814 "#\n",
815 SUN_NPART);
816 if (!hflag) {
817 fprintf(out, "# Size is in %s.", cflag? "cylinders": "sectors");
818 if (eflag)
819 fprintf(out,
820 " Use %%d%c, %%dK, %%dM or %%dG to specify in %s,\n"
821 "# kilobytes, megabytes or gigabytes respectively, or '*' to specify rest of\n"
822 "# disk.\n",
823 cflag? 's': 'c',
824 cflag? "sectors": "cylinders");
825 else
826 putc('\n', out);
827 fprintf(out, "# Offset is in cylinders.");
828 if (eflag)
829 fprintf(out,
830 " Use '*' to calculate offsets automatically.\n"
831 "#\n");
832 else
833 putc('\n', out);
835 if (havevtoc)
836 fprintf(out,
837 "# size offset tag flag\n"
838 "# ---------- ---------- ---------- ----\n"
840 else
841 fprintf(out,
842 "# size offset\n"
843 "# ---------- ----------\n"
846 for (i = 0; i < SUN_NPART; i++) {
847 if (sl->sl_part[i].sdkp_nsectors == 0)
848 continue;
849 if (hflag) {
850 fprintf(out, " %c: %10s",
851 'a' + i,
852 make_h_number((uintmax_t)
853 sl->sl_part[i].sdkp_nsectors * 512));
854 fprintf(out, " %10s",
855 make_h_number((uintmax_t)
856 sl->sl_part[i].sdkp_cyloffset * 512
857 * secpercyl));
858 } else {
859 fprintf(out, " %c: %10ju %10u",
860 'a' + i,
861 sl->sl_part[i].sdkp_nsectors / (cflag? secpercyl: 1),
862 sl->sl_part[i].sdkp_cyloffset);
864 if (havevtoc)
865 fprintf(out, " %11s %5s",
866 tagname(sl->sl_vtoc_map[i].svtoc_tag),
867 flagname(sl->sl_vtoc_map[i].svtoc_flag));
868 putc('\n', out);
872 static void
873 usage(void)
876 fprintf(stderr, "usage:"
877 "\t%s [-r] [-c | -h] disk\n"
878 "\t\t(to read label)\n"
879 "\t%s -B [-b boot1] [-n] disk\n"
880 "\t\t(to install boot program only)\n"
881 "\t%s -R [-B [-b boot1]] [-r] [-n] [-c] disk protofile\n"
882 "\t\t(to restore label)\n"
883 "\t%s -e [-B [-b boot1]] [-r] [-n] [-c] disk\n"
884 "\t\t(to edit label)\n"
885 "\t%s -w [-B [-b boot1]] [-r] [-n] disk type\n"
886 "\t\t(to write default label)\n",
887 __progname,
888 __progname,
889 __progname,
890 __progname,
891 __progname);
892 exit(1);
896 * Return VTOC tag and flag names for tag or flag ID, resp.
898 static const char *
899 tagname(unsigned int tag)
901 static char buf[32];
902 size_t i;
903 struct tags *tp;
905 for (i = 0, tp = knowntags; i < nitems(knowntags); i++, tp++)
906 if (tp->id == tag)
907 return (tp->name);
909 sprintf(buf, "%u", tag);
911 return (buf);
914 static const char *
915 flagname(unsigned int flag)
917 static char buf[32];
918 size_t i;
919 struct tags *tp;
921 for (i = 0, tp = knownflags; i < nitems(knownflags); i++, tp++)
922 if (tp->id == flag)
923 return (tp->name);
925 sprintf(buf, "%u", flag);
927 return (buf);
930 static unsigned int
931 parse_tag(struct sun_disklabel *sl, int part, const char *tag)
933 struct tags *tp;
934 char *endp;
935 size_t i;
936 unsigned long l;
938 for (i = 0, tp = knowntags; i < nitems(knowntags); i++, tp++)
939 if (strcmp(tp->name, tag) == 0) {
940 sl->sl_vtoc_map[part].svtoc_tag = (uint16_t)tp->id;
941 return (0);
944 l = strtoul(tag, &endp, 0);
945 if (*tag != '\0' && *endp == '\0') {
946 sl->sl_vtoc_map[part].svtoc_tag = (uint16_t)l;
947 return (0);
950 return (-1);
953 static unsigned int
954 parse_flag(struct sun_disklabel *sl, int part, const char *flag)
956 struct tags *tp;
957 char *endp;
958 size_t i;
959 unsigned long l;
961 for (i = 0, tp = knownflags; i < nitems(knownflags); i++, tp++)
962 if (strcmp(tp->name, flag) == 0) {
963 sl->sl_vtoc_map[part].svtoc_flag = (uint16_t)tp->id;
964 return (0);
967 l = strtoul(flag, &endp, 0);
968 if (*flag != '\0' && *endp == '\0') {
969 sl->sl_vtoc_map[part].svtoc_flag = (uint16_t)l;
970 return (0);
973 return (-1);
977 * Convert argument into `human readable' byte number form.
979 static const char *
980 make_h_number(uintmax_t u)
982 static char buf[32];
983 double d;
985 if (u == 0) {
986 strcpy(buf, "0B");
987 } else if (u > 2000000000UL) {
988 d = (double)u / 1e9;
989 sprintf(buf, "%.1fG", d);
990 } else if (u > 2000000UL) {
991 d = (double)u / 1e6;
992 sprintf(buf, "%.1fM", d);
993 } else {
994 d = (double)u / 1e3;
995 sprintf(buf, "%.1fK", d);
998 return (buf);