xref: /freebsd-12.1/sbin/sunlabel/sunlabel.c (revision 8a16b7a1)
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
main(int ac,char ** av)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
check_label(struct sun_disklabel * sl)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
read_label(struct sun_disklabel * sl,const char * disk)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
write_label(struct sun_disklabel * sl,const char * disk,const char * bootpath)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
edit_label(struct sun_disklabel * sl,const char * disk,const char * bootpath)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
parse_label(struct sun_disklabel * sl,const char * file)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
parse_size(struct sun_disklabel * sl,int part,char * size)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
parse_offset(struct sun_disklabel * sl,int part,char * offset)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
print_label(struct sun_disklabel * sl,const char * disk,FILE * out)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
usage(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 *
tagname(unsigned int tag)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 *
flagname(unsigned int flag)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
parse_tag(struct sun_disklabel * sl,int part,const char * tag)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
parse_flag(struct sun_disklabel * sl,int part,const char * flag)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 *
make_h_number(uintmax_t u)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 }
1002