sunlabel.c revision 113538
1110130Sjake/*-
2110130Sjake * Copyright (c) 2003 Jake Burkholder.
3110130Sjake * All rights reserved.
4110130Sjake *
5110130Sjake * Redistribution and use in source and binary forms, with or without
6110130Sjake * modification, are permitted provided that the following conditions
7110130Sjake * are met:
8110130Sjake * 1. Redistributions of source code must retain the above copyright
9110130Sjake *    notice, this list of conditions and the following disclaimer.
10110130Sjake * 2. Redistributions in binary form must reproduce the above copyright
11110130Sjake *    notice, this list of conditions and the following disclaimer in the
12110130Sjake *    documentation and/or other materials provided with the distribution.
13110130Sjake *
14110130Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15110130Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16110130Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17110130Sjake * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18110130Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19110130Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20110130Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21110130Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22110130Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23110130Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24110130Sjake * SUCH DAMAGE.
25110130Sjake */
26110130Sjake/*
27110130Sjake * Copyright (c) 1994, 1995 Gordon W. Ross
28110130Sjake * Copyright (c) 1994 Theo de Raadt
29110130Sjake * All rights reserved.
30110130Sjake * Copyright (c) 1987, 1993
31110130Sjake *	The Regents of the University of California.  All rights reserved.
32110130Sjake *
33110130Sjake * This code is derived from software contributed to Berkeley by
34110130Sjake * Symmetric Computer Systems.
35110130Sjake *
36110130Sjake * Redistribution and use in source and binary forms, with or without
37110130Sjake * modification, are permitted provided that the following conditions
38110130Sjake * are met:
39110130Sjake * 1. Redistributions of source code must retain the above copyright
40110130Sjake *    notice, this list of conditions and the following disclaimer.
41110130Sjake * 2. Redistributions in binary form must reproduce the above copyright
42110130Sjake *    notice, this list of conditions and the following disclaimer in the
43110130Sjake *    documentation and/or other materials provided with the distribution.
44110130Sjake * 3. All advertising materials mentioning features or use of this software
45110130Sjake *    must display the following acknowledgement:
46110130Sjake *	This product includes software developed by the University of
47110130Sjake *	California, Berkeley and its contributors.
48110130Sjake *      This product includes software developed by Theo de Raadt.
49110130Sjake * 4. Neither the name of the University nor the names of its contributors
50110130Sjake *    may be used to endorse or promote products derived from this software
51110130Sjake *    without specific prior written permission.
52110130Sjake *
53110130Sjake * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54110130Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55110130Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56110130Sjake * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57110130Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58110130Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59110130Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60110130Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61110130Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62110130Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63110130Sjake * SUCH DAMAGE.
64110130Sjake *
65110130Sjake *	from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $
66110130Sjake */
67110130Sjake
68110130Sjake#include <sys/cdefs.h>
69110130Sjake__FBSDID("$FreeBSD: head/sbin/sunlabel/sunlabel.c 113538 2003-04-15 23:46:19Z jake $");
70110130Sjake
71110130Sjake#include <sys/types.h>
72110130Sjake#include <sys/param.h>
73113538Sjake#include <sys/disk.h>
74113538Sjake#include <sys/ioctl.h>
75110130Sjake#include <sys/sun_disklabel.h>
76110130Sjake#include <sys/wait.h>
77110130Sjake
78110130Sjake#include <err.h>
79110130Sjake#include <fcntl.h>
80110130Sjake#include <inttypes.h>
81110130Sjake#include <paths.h>
82110130Sjake#include <stdio.h>
83110130Sjake#include <stdlib.h>
84110130Sjake#include <string.h>
85110130Sjake#include <unistd.h>
86110130Sjake
87110130Sjake#define	_PATH_TMPFILE	"/tmp/EdDk.XXXXXXXXXX"
88110130Sjake#define	_PATH_BOOT	"/boot/boot1"
89110130Sjake
90110130Sjakestatic int bflag;
91110130Sjakestatic int Bflag;
92110130Sjakestatic int eflag;
93110130Sjakestatic int nflag;
94110130Sjakestatic int rflag = 1;
95110130Sjakestatic int Rflag;
96110130Sjakestatic int wflag;
97110130Sjake
98110130Sjakestatic int check_label(struct sun_disklabel *sl);
99110130Sjakestatic void read_label(struct sun_disklabel *sl, const char *disk);
100110130Sjakestatic void write_label(struct sun_disklabel *sl, const char *disk,
101110130Sjake    const char *bootpath);
102110130Sjakestatic int edit_label(struct sun_disklabel *sl, const char *disk,
103110130Sjake    const char *bootpath);
104110130Sjakestatic int parse_label(struct sun_disklabel *sl, const char *file);
105110130Sjakestatic void print_label(struct sun_disklabel *sl, const char *disk, FILE *out);
106110130Sjake
107113538Sjakestatic uint16_t checksum(struct sun_disklabel *sl);
108113538Sjake
109110130Sjakestatic int parse_size(struct sun_disklabel *sl, int part, char *size);
110110130Sjakestatic int parse_offset(struct sun_disklabel *sl, int part, char *offset);
111110130Sjake
112110130Sjakestatic void usage(void);
113110130Sjake
114110130Sjakeextern char *__progname;
115110130Sjake
116110130Sjake/*
117110130Sjake * Disk label editor for sun disklabels.
118110130Sjake */
119110130Sjakeint
120110130Sjakemain(int ac, char **av)
121110130Sjake{
122110130Sjake	struct sun_disklabel sl;
123110130Sjake	const char *bootpath;
124110130Sjake	const char *proto;
125110130Sjake	const char *disk;
126110130Sjake	int ch;
127110130Sjake
128110130Sjake	bootpath = _PATH_BOOT;
129110130Sjake	while ((ch = getopt(ac, av, "b:BenrRw")) != -1)
130110130Sjake		switch (ch) {
131110130Sjake		case 'b':
132110130Sjake			bflag = 1;
133110130Sjake			bootpath = optarg;
134110130Sjake			break;
135110130Sjake		case 'B':
136110130Sjake			Bflag = 1;
137110130Sjake			break;
138110130Sjake		case 'e':
139110130Sjake			eflag = 1;
140110130Sjake			break;
141110130Sjake		case 'n':
142110130Sjake			nflag = 1;
143110130Sjake			break;
144110130Sjake		case 'r':
145110130Sjake			rflag = 1;
146110130Sjake			break;
147110130Sjake		case 'R':
148110130Sjake			Rflag = 1;
149110130Sjake			break;
150110130Sjake		case 'w':
151110130Sjake			wflag = 1;
152110130Sjake			break;
153110130Sjake		default:
154110130Sjake			usage();
155110130Sjake			break;
156110130Sjake		}
157110130Sjake	if (bflag && !Bflag)
158110130Sjake		usage();
159110130Sjake	if (nflag && !(Bflag || eflag || Rflag || wflag))
160110130Sjake		usage();
161110130Sjake	if (eflag && (Rflag || wflag))
162110130Sjake		usage();
163110130Sjake	ac -= optind;
164110130Sjake	av += optind;
165110130Sjake	if (ac == 0)
166110130Sjake		usage();
167110130Sjake	bzero(&sl, sizeof(sl));
168110130Sjake	disk = av[0];
169110130Sjake	if (wflag) {
170110130Sjake		if (ac != 2 || strcmp(av[1], "auto") != 0)
171110130Sjake			usage();
172110130Sjake		read_label(&sl, disk);
173110130Sjake		bzero(sl.sl_part, sizeof(sl.sl_part));
174110130Sjake		sl.sl_part[2].sdkp_cyloffset = 0;
175110130Sjake		sl.sl_part[2].sdkp_nsectors = sl.sl_ncylinders *
176110130Sjake		    sl.sl_ntracks * sl.sl_nsectors;
177110130Sjake		write_label(&sl, disk, bootpath);
178110130Sjake	} else if (eflag) {
179110130Sjake		if (ac != 1)
180110130Sjake			usage();
181110130Sjake		read_label(&sl, disk);
182110130Sjake		if (sl.sl_magic != SUN_DKMAGIC)
183110130Sjake			errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk);
184110130Sjake		while (edit_label(&sl, disk, bootpath) != 0)
185110130Sjake			;
186110130Sjake	} else if (Rflag) {
187110130Sjake		if (ac != 2)
188110130Sjake			usage();
189110130Sjake		proto = av[1];
190110130Sjake		read_label(&sl, disk);
191113538Sjake		if (parse_label(&sl, proto) != 0)
192113538Sjake			errx(1, "%s: invalid label", proto);
193110130Sjake		write_label(&sl, disk, bootpath);
194110130Sjake	} else if (Bflag) {
195110130Sjake		read_label(&sl, disk);
196110130Sjake		if (sl.sl_magic != SUN_DKMAGIC)
197110130Sjake			errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk);
198110130Sjake		write_label(&sl, disk, bootpath);
199110130Sjake	} else {
200110130Sjake		read_label(&sl, disk);
201110130Sjake		if (sl.sl_magic != SUN_DKMAGIC)
202110130Sjake			errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk);
203110130Sjake		print_label(&sl, disk, stdout);
204110130Sjake	}
205110130Sjake	return (0);
206110130Sjake}
207110130Sjake
208110130Sjakestatic int
209110130Sjakecheck_label(struct sun_disklabel *sl)
210110130Sjake{
211110130Sjake	uint64_t nsectors;
212110130Sjake	uint64_t ostart;
213110130Sjake	uint64_t start;
214110130Sjake	uint64_t oend;
215110130Sjake	uint64_t end;
216110130Sjake	int i;
217110130Sjake	int j;
218110130Sjake
219110130Sjake	nsectors = sl->sl_ncylinders * sl->sl_ntracks * sl->sl_nsectors;
220113538Sjake	if (sl->sl_part[2].sdkp_cyloffset != 0 ||
221113538Sjake	    sl->sl_part[2].sdkp_nsectors != nsectors) {
222113538Sjake		warnx("partition c is incorrect, must start at 0 and cover "
223113538Sjake		    "whole disk");
224113538Sjake		return (1);
225113538Sjake	}
226110130Sjake	for (i = 0; i < 8; i++) {
227110130Sjake		if (i == 2 || sl->sl_part[i].sdkp_nsectors == 0)
228110130Sjake			continue;
229110130Sjake		start = (uint64_t)sl->sl_part[i].sdkp_cyloffset *
230110130Sjake		    sl->sl_ntracks * sl->sl_nsectors;
231110130Sjake		end = start + sl->sl_part[i].sdkp_nsectors;
232110130Sjake		if (end > nsectors) {
233110130Sjake			warnx("partition %c extends past end of disk",
234110130Sjake			    'a' + i);
235110130Sjake			return (1);
236110130Sjake		}
237110130Sjake		for (j = 0; j < 8; j++) {
238110130Sjake			if (j == 2 || j == i ||
239110130Sjake			    sl->sl_part[j].sdkp_nsectors == 0)
240110130Sjake				continue;
241110130Sjake			ostart = (uint64_t)sl->sl_part[j].sdkp_cyloffset *
242110130Sjake			    sl->sl_ntracks * sl->sl_nsectors;
243110130Sjake			oend = ostart + sl->sl_part[j].sdkp_nsectors;
244110130Sjake			if ((start <= ostart && end >= oend) ||
245110130Sjake			    (start > ostart && start < oend) ||
246110130Sjake			    (end > ostart && end < oend)) {
247110130Sjake				warnx("partition %c overlaps partition %c",
248110130Sjake				    'a' + i, 'a' + j);
249110130Sjake				return (1);
250110130Sjake			}
251110130Sjake		}
252110130Sjake	}
253110130Sjake	return (0);
254110130Sjake}
255110130Sjake
256110130Sjakestatic void
257110130Sjakeread_label(struct sun_disklabel *sl, const char *disk)
258110130Sjake{
259113538Sjake	char path[MAXPATHLEN];
260113538Sjake	uint32_t sectorsize;
261113538Sjake	uint32_t fwsectors;
262113538Sjake	uint32_t fwheads;
263113538Sjake	off_t mediasize;
264113538Sjake	int fd;
265110130Sjake
266113538Sjake	snprintf(path, sizeof(path), "%s%s", _PATH_DEV, disk);
267113538Sjake	if ((fd = open(path, O_RDONLY)) < 0)
268113538Sjake		err(1, "open %s", path);
269113538Sjake	if (read(fd, sl, sizeof(*sl)) != sizeof(*sl))
270113538Sjake		err(1, "read");
271113538Sjake	if (sl->sl_magic != SUN_DKMAGIC || checksum(sl) != sl->sl_cksum) {
272113538Sjake		bzero(sl, sizeof(*sl));
273113538Sjake		if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) != 0)
274113538Sjake			err(1, "%s: ioctl(DIOCGMEDIASIZE) failed", disk);
275113538Sjake		if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) != 0)
276113538Sjake			err(1, "%s: DIOCGSECTORSIZE failed", disk);
277113538Sjake		if (ioctl(fd, DIOCGFWSECTORS, &fwsectors) != 0)
278113538Sjake			fwsectors = 63;
279113538Sjake		if (ioctl(fd, DIOCGFWHEADS, &fwheads) != 0) {
280113538Sjake			if (mediasize <= 63 * 1024 * sectorsize)
281113538Sjake				fwheads = 1;
282113538Sjake			else if (mediasize <= 63 * 16 * 1024 * sectorsize)
283113538Sjake				fwheads = 16;
284113538Sjake			else
285113538Sjake				fwheads = 255;
286110130Sjake		}
287113538Sjake		sl->sl_rpm = 3600;
288113538Sjake		sl->sl_pcylinders = mediasize / (fwsectors * fwheads *
289113538Sjake		    sectorsize);
290113538Sjake		sl->sl_sparespercyl = 0;
291113538Sjake		sl->sl_interleave = 1;
292113538Sjake		sl->sl_ncylinders = sl->sl_pcylinders - 2;
293113538Sjake		sl->sl_acylinders = 2;
294113538Sjake		sl->sl_nsectors = fwsectors;
295113538Sjake		sl->sl_ntracks = fwheads;
296113538Sjake		sl->sl_part[2].sdkp_cyloffset = 0;
297113538Sjake		sl->sl_part[2].sdkp_nsectors = sl->sl_ncylinders *
298113538Sjake		    sl->sl_ntracks * sl->sl_nsectors;
299113538Sjake		if (mediasize > 4999L * 1024L * 1024L) {
300113538Sjake			sprintf(sl->sl_text,
301113538Sjake			    "FreeBSD%luG cyl %u alt %u hd %u sec %u",
302113538Sjake			    (mediasize + 512 * 1024 * 1024) /
303113538Sjake			        (1024 * 1024 * 1024),
304113538Sjake			    sl->sl_ncylinders, sl->sl_acylinders,
305113538Sjake			    sl->sl_ntracks, sl->sl_nsectors);
306113538Sjake		} else {
307113538Sjake			sprintf(sl->sl_text,
308113538Sjake			    "FreeBSD%luM cyl %u alt %u hd %u sec %u",
309113538Sjake			    (mediasize + 512 * 1024) / (1024 * 1024),
310113538Sjake			    sl->sl_ncylinders, sl->sl_acylinders,
311113538Sjake			    sl->sl_ntracks, sl->sl_nsectors);
312110130Sjake		}
313110130Sjake	}
314113538Sjake	close(fd);
315110130Sjake}
316110130Sjake
317110130Sjakestatic void
318110130Sjakewrite_label(struct sun_disklabel *sl, const char *disk, const char *bootpath)
319110130Sjake{
320110130Sjake	char path[MAXPATHLEN];
321110130Sjake	char boot[16 * 512];
322110130Sjake	off_t off;
323110130Sjake	int bfd;
324110130Sjake	int fd;
325110130Sjake	int i;
326110130Sjake
327110130Sjake	sl->sl_magic = SUN_DKMAGIC;
328113538Sjake	sl->sl_cksum = checksum(sl);
329110130Sjake
330110130Sjake	if (check_label(sl) != 0)
331110130Sjake		errx(1, "invalid label");
332110130Sjake
333110130Sjake	if (nflag) {
334110130Sjake		print_label(sl, disk, stdout);
335110130Sjake	} else if (rflag) {
336110130Sjake		snprintf(path, sizeof(path), "%s%s", _PATH_DEV, disk);
337110130Sjake		if ((fd = open(path, O_RDWR)) < 0)
338110130Sjake			err(1, "open %s", path);
339110130Sjake		if (Bflag) {
340110130Sjake			if ((bfd = open(bootpath, O_RDONLY)) < 0)
341110130Sjake				err(1, "open %s", bootpath);
342110130Sjake			if (read(bfd, boot, sizeof(boot)) != sizeof(boot))
343110130Sjake				err(1, "read");
344110130Sjake			close(bfd);
345110130Sjake			for (i = 0; i < 8; i++) {
346110130Sjake				if (sl->sl_part[i].sdkp_nsectors == 0)
347110130Sjake					continue;
348110130Sjake				off = sl->sl_part[i].sdkp_cyloffset *
349110130Sjake				    sl->sl_ntracks * sl->sl_nsectors * 512;
350110130Sjake				if (lseek(fd, off, SEEK_SET) < 0)
351110130Sjake					err(1, "lseek");
352110130Sjake				if (write(fd, boot, sizeof(boot)) !=
353110130Sjake				    sizeof(boot))
354110130Sjake					err(1, "write");
355110130Sjake			}
356110130Sjake		}
357110130Sjake		if (lseek(fd, 0, SEEK_SET) < 0)
358110130Sjake			err(1, "lseek");
359110130Sjake		if (write(fd, sl, sizeof(*sl)) != sizeof(*sl))
360110130Sjake			err(1, "write");
361110130Sjake		close(fd);
362110130Sjake	} else
363110130Sjake		err(1, "implement!");
364110130Sjake}
365110130Sjake
366110130Sjakestatic int
367110130Sjakeedit_label(struct sun_disklabel *sl, const char *disk, const char *bootpath)
368110130Sjake{
369110130Sjake	char tmpfil[] = _PATH_TMPFILE;
370110130Sjake	const char *editor;
371110130Sjake	int status;
372110130Sjake	FILE *fp;
373110130Sjake	pid_t pid;
374110130Sjake	pid_t r;
375110130Sjake	int fd;
376110130Sjake	int c;
377110130Sjake
378110130Sjake	if ((fd = mkstemp(tmpfil)) < 0)
379110130Sjake		err(1, "mkstemp");
380110130Sjake	if ((fp = fdopen(fd, "w")) == NULL)
381110130Sjake		err(1, "fdopen");
382110130Sjake	print_label(sl, disk, fp);
383110130Sjake	fflush(fp);
384110130Sjake	if ((pid = fork()) < 0)
385110130Sjake		err(1, "fork");
386110130Sjake	if (pid == 0) {
387110130Sjake		if ((editor = getenv("EDITOR")) == NULL)
388110130Sjake			editor = _PATH_VI;
389110130Sjake		execlp(editor, editor, tmpfil, NULL);
390110130Sjake		err(1, "execlp %s", editor);
391110130Sjake	}
392110130Sjake	status = 0;
393110130Sjake	while ((r = wait(&status)) > 0 && r != pid)
394110130Sjake		;
395110130Sjake	if (WIFEXITED(status)) {
396110130Sjake		if (parse_label(sl, tmpfil) == 0) {
397110130Sjake			fclose(fp);
398110130Sjake			unlink(tmpfil);
399110130Sjake			write_label(sl, disk, bootpath);
400110130Sjake			return (0);
401110130Sjake		}
402110130Sjake		printf("re-edit the label? [y]: ");
403110130Sjake		fflush(stdout);
404110130Sjake		c = getchar();
405110130Sjake		if (c != EOF && c != '\n')
406110130Sjake			while (getchar() != '\n')
407110130Sjake				;
408110130Sjake		if  (c == 'n') {
409110130Sjake			fclose(fp);
410110130Sjake			unlink(tmpfil);
411110130Sjake			return (0);
412110130Sjake		}
413110130Sjake	}
414110130Sjake	fclose(fp);
415110130Sjake	unlink(tmpfil);
416110130Sjake	return (1);
417110130Sjake}
418110130Sjake
419110130Sjakestatic int
420110130Sjakeparse_label(struct sun_disklabel *sl, const char *file)
421110130Sjake{
422110130Sjake	char offset[32];
423110130Sjake	char size[32];
424110130Sjake	char buf[128];
425110130Sjake	uint8_t part;
426110130Sjake	FILE *fp;
427110130Sjake	int line;
428110130Sjake
429110130Sjake	line = 0;
430110130Sjake	if ((fp = fopen(file, "r")) == NULL)
431110130Sjake		err(1, "fopen");
432110130Sjake	bzero(sl->sl_part, sizeof(sl->sl_part));
433110130Sjake	while (fgets(buf, sizeof(buf), fp) != NULL) {
434110130Sjake		if (buf[0] != ' ' || buf[1] != ' ')
435110130Sjake			continue;
436110130Sjake		if (sscanf(buf, "  %c: %s %s\n", &part, size, offset) != 3 ||
437110130Sjake		    parse_size(sl, part - 'a', size) ||
438110130Sjake		    parse_offset(sl, part - 'a', offset)) {
439110130Sjake			warnx("%s: syntex error on line %d",
440110130Sjake			    file, line);
441110130Sjake			fclose(fp);
442110130Sjake			return (1);
443110130Sjake		}
444110130Sjake		line++;
445110130Sjake	}
446110130Sjake	fclose(fp);
447110130Sjake	return (check_label(sl));
448110130Sjake}
449110130Sjake
450110130Sjakestatic int
451110130Sjakeparse_size(struct sun_disklabel *sl, int part, char *size)
452110130Sjake{
453110130Sjake	uintmax_t nsectors;
454110130Sjake	uintmax_t total;
455110130Sjake	uintmax_t n;
456110130Sjake	char *p;
457110130Sjake	int i;
458110130Sjake
459110130Sjake	nsectors = 0;
460110130Sjake	n = strtoumax(size, &p, 10);
461110130Sjake	if (*p != '\0') {
462110130Sjake		if (strcmp(size, "*") == 0) {
463110130Sjake			total = sl->sl_ncylinders * sl->sl_ntracks *
464110130Sjake			    sl->sl_nsectors;
465110130Sjake			for (i = 0; i < part; i++) {
466110130Sjake				if (i == 2)
467110130Sjake					continue;
468110130Sjake				nsectors += sl->sl_part[i].sdkp_nsectors;
469110130Sjake			}
470110130Sjake			n = total - nsectors;
471110130Sjake		} else if (p[1] == '\0' && (p[0] == 'K' || p[0] == 'k')) {
472110130Sjake			n = roundup((n * 1024) / 512,
473110130Sjake			    sl->sl_ntracks * sl->sl_nsectors);
474110130Sjake		} else if (p[1] == '\0' && (p[0] == 'M' || p[0] == 'm')) {
475110130Sjake			n = roundup((n * 1024 * 1024) / 512,
476110130Sjake			    sl->sl_ntracks * sl->sl_nsectors);
477110130Sjake		} else if (p[1] == '\0' && (p[0] == 'G' || p[0] == 'g')) {
478110130Sjake			n = roundup((n * 1024 * 1024 * 1024) / 512,
479110130Sjake			    sl->sl_ntracks * sl->sl_nsectors);
480110130Sjake		} else
481110130Sjake			return (-1);
482110130Sjake	}
483110130Sjake	sl->sl_part[part].sdkp_nsectors = n;
484110130Sjake	return (0);
485110130Sjake}
486110130Sjake
487113538Sjakestatic uint16_t
488113538Sjakechecksum(struct sun_disklabel *sl)
489113538Sjake{
490113538Sjake	uint16_t cksum;
491113538Sjake	uint16_t *sp1;
492113538Sjake	uint16_t *sp2;
493113538Sjake
494113538Sjake	sp1 = (u_short *)sl;
495113538Sjake	sp2 = (u_short *)(sl + 1) - 1;
496113538Sjake	cksum = 0;
497113538Sjake	while (sp1 < sp2)
498113538Sjake		cksum ^= *sp1++;
499113538Sjake	return (cksum);
500113538Sjake}
501113538Sjake
502110130Sjakestatic int
503110130Sjakeparse_offset(struct sun_disklabel *sl, int part, char *offset)
504110130Sjake{
505110130Sjake	uintmax_t nsectors;
506110130Sjake	uintmax_t n;
507110130Sjake	char *p;
508110130Sjake	int i;
509110130Sjake
510110130Sjake	nsectors = 0;
511110130Sjake	n = strtoumax(offset, &p, 10);
512110130Sjake	if (*p != '\0') {
513110130Sjake		if (strcmp(offset, "*") == 0) {
514110130Sjake			for (i = 0; i < part; i++) {
515110130Sjake				if (i == 2)
516110130Sjake					continue;
517110130Sjake				nsectors += sl->sl_part[i].sdkp_nsectors;
518110130Sjake			}
519110130Sjake			n = nsectors / (sl->sl_nsectors * sl->sl_ntracks);
520110130Sjake		} else
521110130Sjake			return (-1);
522110130Sjake	}
523110130Sjake	sl->sl_part[part].sdkp_cyloffset = n;
524110130Sjake	return (0);
525110130Sjake}
526110130Sjake
527110130Sjakestatic void
528110130Sjakeprint_label(struct sun_disklabel *sl, const char *disk, FILE *out)
529110130Sjake{
530110130Sjake	int i;
531110130Sjake
532110130Sjake	fprintf(out,
533110130Sjake"# /dev/%s:\n"
534110130Sjake"text: %s\n"
535110130Sjake"bytes/sectors: 512\n"
536110130Sjake"sectors/cylinder: %d\n"
537110130Sjake"sectors/unit: %d\n"
538110130Sjake"\n"
539110130Sjake"8 partitions:\n"
540110130Sjake"#\n"
541110130Sjake"# Size is in sectors, use %%dK, %%dM or %%dG to specify in kilobytes,\n"
542110130Sjake"# megabytes or gigabytes respectively, or '*' to specify rest of disk.\n"
543110130Sjake"# Offset is in cylinders, use '*' to calculate offsets automatically.\n"
544110130Sjake"#\n"
545110130Sjake"#    size       offset\n"
546110130Sjake"#    ---------- ----------\n",
547110130Sjake	    disk,
548110130Sjake	    sl->sl_text,
549110130Sjake	    sl->sl_nsectors * sl->sl_ntracks,
550110130Sjake	    sl->sl_nsectors * sl->sl_ntracks * sl->sl_ncylinders);
551110130Sjake	for (i = 0; i < 8; i++) {
552110130Sjake		if (sl->sl_part[i].sdkp_nsectors == 0)
553110130Sjake			continue;
554110130Sjake		fprintf(out, "  %c: %10u %10u\n",
555110130Sjake		    'a' + i,
556110130Sjake		    sl->sl_part[i].sdkp_nsectors,
557110130Sjake		    sl->sl_part[i].sdkp_cyloffset);
558110130Sjake	}
559110130Sjake}
560110130Sjake
561110130Sjakestatic void
562110130Sjakeusage(void)
563110130Sjake{
564110130Sjake
565110130Sjake	fprintf(stderr, "usage:"
566110130Sjake"\t%s [-r] disk\n"
567110130Sjake"\t\t(to read label)\n"
568110130Sjake"\t%s -B [-b boot1] [-n] disk\n"
569110130Sjake"\t\t(to install boot program only)\n"
570110130Sjake"\t%s -R [-B [-b boot1]] [-r] [-n] disk protofile\n"
571110130Sjake"\t\t(to restore label)\n"
572110130Sjake"\t%s -e [-B [-b boot1]] [-r] [-n] disk\n"
573110130Sjake"\t\t(to edit label)\n"
574110130Sjake"\t%s -w [-B [-b boot1]] [-r] [-n] disk type\n"
575110130Sjake"\t\t(to write default label)\n",
576110130Sjake	     __progname,
577110130Sjake	     __progname,
578110130Sjake	     __progname,
579110130Sjake	     __progname,
580110130Sjake	     __progname);
581110130Sjake	exit(1);
582110130Sjake}
583