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