This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / sbin / disklabel / disklabel.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1987 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Symmetric Computer Systems.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
37 * -------------------- ----- ----------------------
38 * CURRENT PATCH LEVEL: 1 00034
39 * -------------------- ----- ----------------------
40 *
41 * 18 Sep 92 Gary A Browning Fix expectation of active partition
42 */
43
44#ifndef lint
45char copyright[] =
46"@(#) Copyright (c) 1987 The Regents of the University of California.\n\
47 All rights reserved.\n";
48#endif /* not lint */
49
50#ifndef lint
51static char sccsid[] = "@(#)disklabel.c 5.20 (Berkeley) 2/9/91";
52/* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */
53#endif /* not lint */
54
55#include <sys/param.h>
56#include <sys/signal.h>
57#include <sys/errno.h>
58#include <sys/file.h>
59#include <sys/ioctl.h>
60#include <ufs/fs.h>
61#include <string.h>
62#define DKTYPENAMES
63#include <sys/disklabel.h>
64#include <stdio.h>
65#include <ctype.h>
66#include "pathnames.h"
67
68/*
69 * Disklabel: read and write disklabels.
70 * The label is usually placed on one of the first sectors of the disk.
71 * Many machines (VAX 11/750) also place a bootstrap in the same area,
72 * in which case the label is embedded in the bootstrap.
73 * The bootstrap source must leave space at the proper offset
74 * for the label on such machines.
75 *
76 * On 386BSD, the disklabel may either be at the start of the disk, or, at
77 * the start of an MS/DOS partition. In this way, it can be used either
78 * in concert with other operating systems sharing a disk, or with the
79 * disk dedicated to 386BSD. In shared mode, the DOS disk geometry must be
80 * identical to that which disklabel uses, and the disklabel must solely
81 * describe the space within the partition selected. Otherwise, the disk
82 * must be dedicated to 386BSD. -wfj
83 */
84
85#if defined(vax)
86#define RAWPARTITION 'c'
87#endif
88
89#if defined(i386)
90/* with 386BSD, 'c' maps the portion of the disk given over to 386BSD,
91 and 'd' maps the entire drive, ignoring any partition tables */
92#define RAWPARTITION 'd'
93#endif
94
95#if defined(vax)==0 && defined(i386)==0
96#define RAWPARTITION 'a'
97#endif
98
99#ifndef BBSIZE
100#define BBSIZE 8192 /* size of boot area, with label */
101#endif
102
103#if defined(vax) || defined(i386)
104#define BOOT /* also have bootstrap in "boot area" */
105#define BOOTDIR _PATH_BOOTDIR /* source of boot binaries */
106#else
107#ifdef lint
108#define BOOT
109#endif
110#endif
111
112#define DEFEDITOR _PATH_VI
113#define streq(a,b) (strcmp(a,b) == 0)
114
115#ifdef BOOT
116char *xxboot;
117char *bootxx;
118#endif
119
120char *dkname;
121char *specname;
122char tmpfil[] = _PATH_TMP;
123
124extern int errno;
125char namebuf[BBSIZE], *np = namebuf;
126struct disklabel lab;
127struct disklabel *readlabel(), *makebootarea();
128char bootarea[BBSIZE];
129char boot0[MAXPATHLEN];
130char boot1[MAXPATHLEN];
131
132enum { UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE } op = UNSPEC;
133
134int rflag;
135
136#ifdef DEBUG
137int debug;
138#endif
139
140#ifdef __386BSD__
141struct dos_partition *dosdp; /* 386BSD DOS partition, if found */
142struct dos_partition *readmbr(int);
143#endif
144
145main(argc, argv)
146 int argc;
147 char *argv[];
148{
149 extern int optind;
150 register struct disklabel *lp;
151 FILE *t;
152 int ch, f, error = 0;
153 char *name = 0, *type;
154
155 while ((ch = getopt(argc, argv, "NRWerw")) != EOF)
156 switch (ch) {
157 case 'N':
158 if (op != UNSPEC)
159 usage();
160 op = NOWRITE;
161 break;
162 case 'R':
163 if (op != UNSPEC)
164 usage();
165 op = RESTORE;
166 break;
167 case 'W':
168 if (op != UNSPEC)
169 usage();
170 op = WRITEABLE;
171 break;
172 case 'e':
173 if (op != UNSPEC)
174 usage();
175 op = EDIT;
176 break;
177 case 'r':
178 ++rflag;
179 break;
180 case 'w':
181 if (op != UNSPEC)
182 usage();
183 op = WRITE;
184 break;
185#ifdef DEBUG
186 case 'd':
187 debug++;
188 break;
189#endif
190 case '?':
191 default:
192 usage();
193 }
194 argc -= optind;
195 argv += optind;
196 if (op == UNSPEC)
197 op = READ;
198 if (argc < 1)
199 usage();
200
201 dkname = argv[0];
202 if (dkname[0] != '/') {
203 (void)sprintf(np, "%sr%s%c", _PATH_DEV, dkname, RAWPARTITION);
204 specname = np;
205 np += strlen(specname) + 1;
206 } else
207 specname = dkname;
208 f = open(specname, op == READ ? O_RDONLY : O_RDWR);
209 if (f < 0 && errno == ENOENT && dkname[0] != '/') {
210 (void)sprintf(specname, "%sr%s", _PATH_DEV, dkname);
211 np = namebuf + strlen(specname) + 1;
212 f = open(specname, op == READ ? O_RDONLY : O_RDWR);
213 }
214 if (f < 0)
215 Perror(specname);
216
217#ifdef __386BSD__
218 /*
219 * Check for presence of DOS partition table in
220 * master boot record. Return pointer to 386BSD
221 * partition, if present. If no valid partition table,
222 * return 0. If valid partition table present, but no
223 * partition to use, return a pointer to a non-386bsd
224 * partition.
225 */
226 dosdp = readmbr(f);
227 { int mfd; unsigned char params[0x10];
228 /* sleezy, but we need it fast! */
229 mfd = open("/dev/mem", 0);
230 lseek(mfd, 0x300, 0);
231 read (mfd, params, 0x10);
232 }
233
234#endif
235
236 switch(op) {
237 case EDIT:
238 if (argc != 1)
239 usage();
240 lp = readlabel(f);
241 error = edit(lp, f);
242 break;
243 case NOWRITE: {
244 int flag = 0;
245 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
246 Perror("ioctl DIOCWLABEL");
247 break;
248 }
249 case READ:
250 if (argc != 1)
251 usage();
252
253 lp = readlabel(f);
254 display(stdout, lp);
255 error = checklabel(lp);
256 break;
257 case RESTORE:
258#ifdef BOOT
259 if (rflag) {
260 if (argc == 4) { /* [ priboot secboot ] */
261 xxboot = argv[2];
262 bootxx = argv[3];
263 lab.d_secsize = DEV_BSIZE; /* XXX */
264 lab.d_bbsize = BBSIZE; /* XXX */
265 }
266 else if (argc == 3) /* [ disktype ] */
267 makelabel(argv[2], (char *)NULL, &lab);
268 else {
269 fprintf(stderr,
270"Must specify either disktype or bootfiles with -r flag of RESTORE option\n");
271 exit(1);
272 }
273 }
274 else
275#endif
276 if (argc != 2)
277 usage();
278 lp = makebootarea(bootarea, &lab);
279 if (!(t = fopen(argv[1],"r")))
280 Perror(argv[1]);
281 if (getasciilabel(t, lp))
282 error = writelabel(f, bootarea, lp);
283 break;
284 case WRITE:
285 type = argv[1];
286#ifdef BOOT
287 if (argc > 5 || argc < 2)
288 usage();
289 if (argc > 3) {
290 bootxx = argv[--argc];
291 xxboot = argv[--argc];
292 }
293#else
294 if (argc > 3 || argc < 2)
295 usage();
296#endif
297 if (argc > 2)
298 name = argv[--argc];
299 makelabel(type, name, &lab);
300 lp = makebootarea(bootarea, &lab);
301 *lp = lab;
302 if (checklabel(lp) == 0)
303 error = writelabel(f, bootarea, lp);
304 break;
305 case WRITEABLE: {
306 int flag = 1;
307 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
308 Perror("ioctl DIOCWLABEL");
309 break;
310 }
311 }
312 exit(error);
313}
314
315/*
316 * Construct a prototype disklabel from /etc/disktab. As a side
317 * effect, set the names of the primary and secondary boot files
318 * if specified.
319 */
320makelabel(type, name, lp)
321 char *type, *name;
322 register struct disklabel *lp;
323{
324 register struct disklabel *dp;
325 char *strcpy();
326
327 dp = getdiskbyname(type);
328 if (dp == NULL) {
329 fprintf(stderr, "%s: unknown disk type\n", type);
330 exit(1);
331 }
332 *lp = *dp;
333#ifdef BOOT
334 /*
335 * Check if disktab specifies the bootstraps (b0 or b1).
336 */
337 if (!xxboot && lp->d_boot0) {
338 if (*lp->d_boot0 != '/')
339 (void)sprintf(boot0, "%s/%s", BOOTDIR, lp->d_boot0);
340 else
341 (void)strcpy(boot0, lp->d_boot0);
342 xxboot = boot0;
343 }
344 if (!bootxx && lp->d_boot1) {
345 if (*lp->d_boot1 != '/')
346 (void)sprintf(boot1, "%s/%s", BOOTDIR, lp->d_boot1);
347 else
348 (void)strcpy(boot1, lp->d_boot1);
349 bootxx = boot1;
350 }
351 /*
352 * If bootstraps not specified anywhere, makebootarea()
353 * will choose ones based on the name of the disk special
354 * file. E.g. /dev/ra0 -> raboot, bootra
355 */
356#endif /*BOOT*/
357 /* d_packname is union d_boot[01], so zero */
358 bzero(lp->d_packname, sizeof(lp->d_packname));
359 if (name)
360 (void)strncpy(lp->d_packname, name, sizeof(lp->d_packname));
361}
362
363writelabel(f, boot, lp)
364 int f;
365 char *boot;
366 register struct disklabel *lp;
367{
368 register int i;
369 int flag;
370 off_t lseek();
371#ifdef __386BSD__
372 off_t lbl_off; struct partition *pp = lp->d_partitions;
373#endif
374
375 lp->d_magic = DISKMAGIC;
376 lp->d_magic2 = DISKMAGIC;
377 lp->d_checksum = 0;
378 lp->d_checksum = dkcksum(lp);
379 if (rflag) {
380
381#ifdef __386BSD__
382 /*
383 * If 386BSD DOS partition is missing, or if
384 * the label to be written is not within partition,
385 * prompt first. Need to allow this in case operator
386 * wants to convert the drive for dedicated use.
387 * In this case, partition 'a' had better start at 0,
388 * otherwise we reject the request as meaningless. -wfj
389 */
390
391 if (dosdp && dosdp->dp_typ == DOSPTYP_386BSD && pp->p_size &&
392 dosdp->dp_start == pp->p_offset) {
393 lbl_off = pp->p_offset;
394 } else {
395 if (dosdp) {
396 char c;
397
398 printf("overwriting disk with DOS partition table? (n):");
399 fflush(stdout);
400 c = getchar();
401 if (c != EOF && c != (int)'\n')
402 while (getchar() != (int)'\n')
403 ;
404 if (c == (int)'n')
405 exit(0);
406 }
407 lbl_off = 0;
408 }
409 (void)lseek(f, (off_t)(lbl_off * lp->d_secsize), L_SET);
410#endif
411 /*
412 * First set the kernel disk label,
413 * then write a label to the raw disk.
414 * If the SDINFO ioctl fails because it is unimplemented,
415 * keep going; otherwise, the kernel consistency checks
416 * may prevent us from changing the current (in-core)
417 * label.
418 */
419 if (ioctl(f, DIOCSDINFO, lp) < 0 &&
420 errno != ENODEV && errno != ENOTTY) {
421 l_perror("ioctl DIOCSDINFO");
422 /*return (1);*/
423 }
424
425 /*
426 * write enable label sector before write (if necessary),
427 * disable after writing.
428 */
429 flag = 1;
430 if (ioctl(f, DIOCWLABEL, &flag) < 0)
431 perror("ioctl DIOCWLABEL");
432 if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) {
433 perror("write");
434 return (1);
435 }
436 flag = 0;
437 (void) ioctl(f, DIOCWLABEL, &flag);
438 } else if (ioctl(f, DIOCWDINFO, lp) < 0) {
439 l_perror("ioctl DIOCWDINFO");
440 return (1);
441 }
442
443 if (lp->d_type != DTYPE_SCSI && lp->d_flags & D_BADSECT) {
444 daddr_t alt;
445
446 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
447 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
448 (void)lseek(f, (off_t)((alt + i) * lp->d_secsize), L_SET);
449 if (write(f, boot, lp->d_secsize) < lp->d_secsize) {
450 int oerrno = errno;
451 fprintf(stderr, "alternate label %d ", i/2);
452 errno = oerrno;
453 perror("write");
454 }
455 }
456 }
457
458 return (0);
459}
460
461l_perror(s)
462 char *s;
463{
464 int saverrno = errno;
465
466 fprintf(stderr, "disklabel: %s: ", s);
467
468 switch (saverrno) {
469
470 case ESRCH:
471 fprintf(stderr, "No disk label on disk;\n");
472 fprintf(stderr,
473 "use \"disklabel -r\" to install initial label\n");
474 break;
475
476 case EINVAL:
477 fprintf(stderr, "Label magic number or checksum is wrong!\n");
478 fprintf(stderr, "(disklabel or kernel is out of date?)\n");
479 break;
480
481 case EBUSY:
482 fprintf(stderr, "Open partition would move or shrink\n");
483 break;
484
485 case EXDEV:
486 fprintf(stderr,
487 "Labeled partition or 'a' partition must start at beginning of disk\n");
488 fprintf(stderr, "or DOS partition\n");
489 break;
490
491 default:
492 errno = saverrno;
493 perror((char *)NULL);
494 break;
495 }
496}
497
498#ifdef __386BSD__
499/*
500 * Fetch DOS partition table from disk.
501 */
502struct dos_partition *
503readmbr(f)
504 int f;
505{
506 static struct dos_partition dos_partitions[NDOSPART];
507 struct dos_partition *dp, *bsdp;
508 char mbr[DEV_BSIZE];
509 int i, npart, nboot, njunk;
510
511 (void)lseek(f, (off_t)DOSBBSECTOR, L_SET);
512 if (read(f, mbr, sizeof(mbr)) < sizeof(mbr))
513 Perror("can't read master boot record");
514
515 bcopy(mbr + DOSPARTOFF, dos_partitions, sizeof(dos_partitions));
516
517 /*
518 * Don't (yet) know disk geometry (BIOS), use
519 * partition table to find 386BSD partition, and obtain
520 * disklabel from there.
521 */
522 dp = dos_partitions;
523 npart = njunk = nboot = 0;
78ed81a3 524 bsdp = NULL;
15637ed4
RG
525 for (i = 0; i < NDOSPART; i++, dp++) {
526 if (dp->dp_flag != 0x80 && dp->dp_flag != 0) njunk++;
527 else
528 if (dp->dp_size > 0) npart++;
529 if (dp->dp_flag == 0x80) nboot++;
530 if (dp->dp_size && dp->dp_typ == DOSPTYP_386BSD)
531 bsdp = dp;
532 }
533
534 /* valid partition table? */
535 if (npart == 0 || njunk) /* 18 Sep 92*/
536/* was: if (nboot != 1 || npart == 0 || njunk)*/
537 return (0);
538 /* if no bsd partition, pass back first one */
539 if (!bsdp) {
540 Warning("DOS partition table with no valid 386BSD partition");
541 return (dos_partitions);
542 }
543 return (bsdp);
544}
545#endif
546
547/*
548 * Fetch disklabel for disk.
549 * Use ioctl to get label unless -r flag is given.
550 */
551struct disklabel *
552readlabel(f)
553 int f;
554{
555 register struct disklabel *lp;
556
557 if (rflag) {
558#ifdef __386BSD__
559 off_t sectoffset;
560
561 if (dosdp && dosdp->dp_size && dosdp->dp_typ == DOSPTYP_386BSD)
562 sectoffset = dosdp->dp_start * DEV_BSIZE;
563 else
564 sectoffset = 0;
565 (void)lseek(f, sectoffset, L_SET);
566#endif
567
568 if (read(f, bootarea, BBSIZE) < BBSIZE)
569 Perror(specname);
570 for (lp = (struct disklabel *)bootarea;
571 lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp));
572 lp = (struct disklabel *)((char *)lp + 16))
573 if (lp->d_magic == DISKMAGIC &&
574 lp->d_magic2 == DISKMAGIC)
575 break;
576 if (lp > (struct disklabel *)(bootarea+BBSIZE-sizeof(*lp)) ||
577 lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC ||
578 dkcksum(lp) != 0) {
579 fprintf(stderr,
580 "Bad pack magic number (label is damaged, or pack is unlabeled)\n");
581 /* lp = (struct disklabel *)(bootarea + LABELOFFSET);
582 exit (1); */
583 goto tryioctl;
584 }
585 } else {
586tryioctl:
587 lp = &lab;
588 if (ioctl(f, DIOCGDINFO, lp) < 0)
589 Perror("ioctl DIOCGDINFO");
590 }
591 return (lp);
592}
593
594struct disklabel *
595makebootarea(boot, dp)
596 char *boot;
597 register struct disklabel *dp;
598{
599 struct disklabel *lp;
600 register char *p;
601 int b;
602#ifdef BOOT
603 char *dkbasename;
604#endif /*BOOT*/
605
606 lp = (struct disklabel *)(boot + (LABELSECTOR * dp->d_secsize) +
607 LABELOFFSET);
608#ifdef BOOT
609 if (!rflag)
610 return (lp);
611
612 if (xxboot == NULL || bootxx == NULL) {
613 dkbasename = np;
614 if ((p = rindex(dkname, '/')) == NULL)
615 p = dkname;
616 else
617 p++;
618 while (*p && !isdigit(*p))
619 *np++ = *p++;
620 *np++ = '\0';
621
622 if (xxboot == NULL) {
623 (void)sprintf(np, "%s/%sboot", BOOTDIR, dkbasename);
624 if (access(np, F_OK) < 0 && dkbasename[0] == 'r')
625 dkbasename++;
626 xxboot = np;
627 (void)sprintf(xxboot, "%s/%sboot", BOOTDIR, dkbasename);
628 np += strlen(xxboot) + 1;
629 }
630 if (bootxx == NULL) {
631 (void)sprintf(np, "%s/boot%s", BOOTDIR, dkbasename);
632 if (access(np, F_OK) < 0 && dkbasename[0] == 'r')
633 dkbasename++;
634 bootxx = np;
635 (void)sprintf(bootxx, "%s/boot%s", BOOTDIR, dkbasename);
636 np += strlen(bootxx) + 1;
637 }
638 }
639#ifdef DEBUG
640 if (debug)
641 fprintf(stderr, "bootstraps: xxboot = %s, bootxx = %s\n",
642 xxboot, bootxx);
643#endif
644
645 b = open(xxboot, O_RDONLY);
646 if (b < 0)
647 Perror(xxboot);
648 if (read(b, boot, (int)dp->d_secsize) < 0)
649 Perror(xxboot);
650 close(b);
651 b = open(bootxx, O_RDONLY);
652 if (b < 0)
653 Perror(bootxx);
654 if (read(b, &boot[dp->d_secsize], (int)(dp->d_bbsize-dp->d_secsize)) < 0)
655 Perror(bootxx);
656 (void)close(b);
657#endif /*BOOT*/
658
659 for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++)
660 if (*p) {
661 fprintf(stderr,
662 "Bootstrap doesn't leave room for disk label\n");
663 exit(2);
664 }
665 return (lp);
666}
667
668display(f, lp)
669 FILE *f;
670 register struct disklabel *lp;
671{
672 register int i, j;
673 register struct partition *pp;
674
675 fprintf(f, "# %s:\n", specname);
676 if ((unsigned) lp->d_type < DKMAXTYPES)
677 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
678 else
679 fprintf(f, "type: %d\n", lp->d_type);
680 fprintf(f, "disk: %.*s\n", sizeof(lp->d_typename), lp->d_typename);
681 fprintf(f, "label: %.*s\n", sizeof(lp->d_packname), lp->d_packname);
682 fprintf(f, "flags:");
683 if (lp->d_flags & D_REMOVABLE)
684 fprintf(f, " removeable");
685 if (lp->d_flags & D_ECC)
686 fprintf(f, " ecc");
687 if (lp->d_flags & D_BADSECT)
688 fprintf(f, " badsect");
689 fprintf(f, "\n");
690 fprintf(f, "bytes/sector: %d\n", lp->d_secsize);
691 fprintf(f, "sectors/track: %d\n", lp->d_nsectors);
692 fprintf(f, "tracks/cylinder: %d\n", lp->d_ntracks);
693 fprintf(f, "sectors/cylinder: %d\n", lp->d_secpercyl);
694 fprintf(f, "cylinders: %d\n", lp->d_ncylinders);
695 fprintf(f, "rpm: %d\n", lp->d_rpm);
696 fprintf(f, "interleave: %d\n", lp->d_interleave);
697 fprintf(f, "trackskew: %d\n", lp->d_trackskew);
698 fprintf(f, "cylinderskew: %d\n", lp->d_cylskew);
699 fprintf(f, "headswitch: %d\t\t# milliseconds\n", lp->d_headswitch);
700 fprintf(f, "track-to-track seek: %d\t# milliseconds\n", lp->d_trkseek);
701 fprintf(f, "drivedata: ");
702 for (i = NDDATA - 1; i >= 0; i--)
703 if (lp->d_drivedata[i])
704 break;
705 if (i < 0)
706 i = 0;
707 for (j = 0; j <= i; j++)
708 fprintf(f, "%d ", lp->d_drivedata[j]);
709 fprintf(f, "\n\n%d partitions:\n", lp->d_npartitions);
710 fprintf(f,
711 "# size offset fstype [fsize bsize cpg]\n");
712 pp = lp->d_partitions;
713 for (i = 0; i < lp->d_npartitions; i++, pp++) {
714 if (pp->p_size) {
715 fprintf(f, " %c: %8d %8d ", 'a' + i,
716 pp->p_size, pp->p_offset);
717 if ((unsigned) pp->p_fstype < FSMAXTYPES)
718 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
719 else
720 fprintf(f, "%8d", pp->p_fstype);
721 switch (pp->p_fstype) {
722
723 case FS_UNUSED: /* XXX */
724 fprintf(f, " %5d %5d %5.5s ",
725 pp->p_fsize, pp->p_fsize * pp->p_frag, "");
726 break;
727
728 case FS_BSDFFS:
729 fprintf(f, " %5d %5d %5d ",
730 pp->p_fsize, pp->p_fsize * pp->p_frag,
731 pp->p_cpg);
732 break;
733
734 default:
735 fprintf(f, "%20.20s", "");
736 break;
737 }
738 fprintf(f, "\t# (Cyl. %4d",
739 pp->p_offset / lp->d_secpercyl);
740 if (pp->p_offset % lp->d_secpercyl)
741 putc('*', f);
742 else
743 putc(' ', f);
744 fprintf(f, "- %d",
745 (pp->p_offset +
746 pp->p_size + lp->d_secpercyl - 1) /
747 lp->d_secpercyl - 1);
748 if (pp->p_size % lp->d_secpercyl)
749 putc('*', f);
750 fprintf(f, ")\n");
751 }
752 }
753 fflush(f);
754}
755
756edit(lp, f)
757 struct disklabel *lp;
758 int f;
759{
760 register int c;
761 struct disklabel label;
762 FILE *fd;
763 char *mktemp();
764
765 (void) mktemp(tmpfil);
766 fd = fopen(tmpfil, "w");
767 if (fd == NULL) {
768 fprintf(stderr, "%s: Can't create\n", tmpfil);
769 return (1);
770 }
771 (void)fchmod(fd, 0600);
772 display(fd, lp);
773 fclose(fd);
774 for (;;) {
775 if (!editit())
776 break;
777 fd = fopen(tmpfil, "r");
778 if (fd == NULL) {
779 fprintf(stderr, "%s: Can't reopen for reading\n",
780 tmpfil);
781 break;
782 }
783 bzero((char *)&label, sizeof(label));
784 if (getasciilabel(fd, &label)) {
785 *lp = label;
786 if (writelabel(f, bootarea, lp) == 0) {
787 (void) unlink(tmpfil);
788 return (0);
789 }
790 }
791 printf("re-edit the label? [y]: "); fflush(stdout);
792 c = getchar();
793 if (c != EOF && c != (int)'\n')
794 while (getchar() != (int)'\n')
795 ;
796 if (c == (int)'n')
797 break;
798 }
799 (void) unlink(tmpfil);
800 return (1);
801}
802
803editit()
804{
805 register int pid, xpid;
806 int stat, omask;
807 extern char *getenv();
808
809 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
810 while ((pid = fork()) < 0) {
811 extern int errno;
812
813 if (errno == EPROCLIM) {
814 fprintf(stderr, "You have too many processes\n");
815 return(0);
816 }
817 if (errno != EAGAIN) {
818 perror("fork");
819 return(0);
820 }
821 sleep(1);
822 }
823 if (pid == 0) {
824 register char *ed;
825
826 sigsetmask(omask);
827 setgid(getgid());
828 setuid(getuid());
829 if ((ed = getenv("EDITOR")) == (char *)0)
830 ed = DEFEDITOR;
831 execlp(ed, ed, tmpfil, 0);
832 perror(ed);
833 exit(1);
834 }
835 while ((xpid = wait(&stat)) >= 0)
836 if (xpid == pid)
837 break;
838 sigsetmask(omask);
839 return(!stat);
840}
841
842char *
843skip(cp)
844 register char *cp;
845{
846
847 while (*cp != '\0' && isspace(*cp))
848 cp++;
849 if (*cp == '\0' || *cp == '#')
850 return ((char *)NULL);
851 return (cp);
852}
853
854char *
855word(cp)
856 register char *cp;
857{
858 register char c;
859
860 while (*cp != '\0' && !isspace(*cp) && *cp != '#')
861 cp++;
862 if ((c = *cp) != '\0') {
863 *cp++ = '\0';
864 if (c != '#')
865 return (skip(cp));
866 }
867 return ((char *)NULL);
868}
869
870/*
871 * Read an ascii label in from fd f,
872 * in the same format as that put out by display(),
873 * and fill in lp.
874 */
875getasciilabel(f, lp)
876 FILE *f;
877 register struct disklabel *lp;
878{
879 register char **cpp, *cp;
880 register struct partition *pp;
881 char *tp, *s, line[BUFSIZ];
882 int v, lineno = 0, errors = 0;
883
884 lp->d_bbsize = BBSIZE; /* XXX */
885 lp->d_sbsize = SBSIZE; /* XXX */
886 while (fgets(line, sizeof(line) - 1, f)) {
887 lineno++;
888 if (cp = index(line,'\n'))
889 *cp = '\0';
890 cp = skip(line);
891 if (cp == NULL)
892 continue;
893 tp = index(cp, ':');
894 if (tp == NULL) {
895 fprintf(stderr, "line %d: syntax error\n", lineno);
896 errors++;
897 continue;
898 }
899 *tp++ = '\0', tp = skip(tp);
900 if (streq(cp, "type")) {
901 if (tp == NULL)
902 tp = "unknown";
903 cpp = dktypenames;
904 for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
905 if ((s = *cpp) && streq(s, tp)) {
906 lp->d_type = cpp - dktypenames;
907 goto next;
908 }
909 v = atoi(tp);
910 if ((unsigned)v >= DKMAXTYPES)
911 fprintf(stderr, "line %d:%s %d\n", lineno,
912 "Warning, unknown disk type", v);
913 lp->d_type = v;
914 continue;
915 }
916 if (streq(cp, "flags")) {
917 for (v = 0; (cp = tp) && *cp != '\0';) {
918 tp = word(cp);
919 if (streq(cp, "removeable"))
920 v |= D_REMOVABLE;
921 else if (streq(cp, "ecc"))
922 v |= D_ECC;
923 else if (streq(cp, "badsect"))
924 v |= D_BADSECT;
925 else {
926 fprintf(stderr,
927 "line %d: %s: bad flag\n",
928 lineno, cp);
929 errors++;
930 }
931 }
932 lp->d_flags = v;
933 continue;
934 }
935 if (streq(cp, "drivedata")) {
936 register int i;
937
938 for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
939 lp->d_drivedata[i++] = atoi(cp);
940 tp = word(cp);
941 }
942 continue;
943 }
944 if (sscanf(cp, "%d partitions", &v) == 1) {
945 if (v == 0 || (unsigned)v > MAXPARTITIONS) {
946 fprintf(stderr,
947 "line %d: bad # of partitions\n", lineno);
948 lp->d_npartitions = MAXPARTITIONS;
949 errors++;
950 } else
951 lp->d_npartitions = v;
952 continue;
953 }
954 if (tp == NULL)
955 tp = "";
956 if (streq(cp, "disk")) {
957 strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
958 continue;
959 }
960 if (streq(cp, "label")) {
961 strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
962 continue;
963 }
964 if (streq(cp, "bytes/sector")) {
965 v = atoi(tp);
966 if (v <= 0 || (v % 512) != 0) {
967 fprintf(stderr,
968 "line %d: %s: bad sector size\n",
969 lineno, tp);
970 errors++;
971 } else
972 lp->d_secsize = v;
973 continue;
974 }
975 if (streq(cp, "sectors/track")) {
976 v = atoi(tp);
977 if (v <= 0) {
978 fprintf(stderr, "line %d: %s: bad %s\n",
979 lineno, tp, cp);
980 errors++;
981 } else
982 lp->d_nsectors = v;
983 continue;
984 }
985 if (streq(cp, "sectors/cylinder")) {
986 v = atoi(tp);
987 if (v <= 0) {
988 fprintf(stderr, "line %d: %s: bad %s\n",
989 lineno, tp, cp);
990 errors++;
991 } else
992 lp->d_secpercyl = v;
993 continue;
994 }
995 if (streq(cp, "tracks/cylinder")) {
996 v = atoi(tp);
997 if (v <= 0) {
998 fprintf(stderr, "line %d: %s: bad %s\n",
999 lineno, tp, cp);
1000 errors++;
1001 } else
1002 lp->d_ntracks = v;
1003 continue;
1004 }
1005 if (streq(cp, "cylinders")) {
1006 v = atoi(tp);
1007 if (v <= 0) {
1008 fprintf(stderr, "line %d: %s: bad %s\n",
1009 lineno, tp, cp);
1010 errors++;
1011 } else
1012 lp->d_ncylinders = v;
1013 continue;
1014 }
1015 if (streq(cp, "rpm")) {
1016 v = atoi(tp);
1017 if (v <= 0) {
1018 fprintf(stderr, "line %d: %s: bad %s\n",
1019 lineno, tp, cp);
1020 errors++;
1021 } else
1022 lp->d_rpm = v;
1023 continue;
1024 }
1025 if (streq(cp, "interleave")) {
1026 v = atoi(tp);
1027 if (v <= 0) {
1028 fprintf(stderr, "line %d: %s: bad %s\n",
1029 lineno, tp, cp);
1030 errors++;
1031 } else
1032 lp->d_interleave = v;
1033 continue;
1034 }
1035 if (streq(cp, "trackskew")) {
1036 v = atoi(tp);
1037 if (v < 0) {
1038 fprintf(stderr, "line %d: %s: bad %s\n",
1039 lineno, tp, cp);
1040 errors++;
1041 } else
1042 lp->d_trackskew = v;
1043 continue;
1044 }
1045 if (streq(cp, "cylinderskew")) {
1046 v = atoi(tp);
1047 if (v < 0) {
1048 fprintf(stderr, "line %d: %s: bad %s\n",
1049 lineno, tp, cp);
1050 errors++;
1051 } else
1052 lp->d_cylskew = v;
1053 continue;
1054 }
1055 if (streq(cp, "headswitch")) {
1056 v = atoi(tp);
1057 if (v < 0) {
1058 fprintf(stderr, "line %d: %s: bad %s\n",
1059 lineno, tp, cp);
1060 errors++;
1061 } else
1062 lp->d_headswitch = v;
1063 continue;
1064 }
1065 if (streq(cp, "track-to-track seek")) {
1066 v = atoi(tp);
1067 if (v < 0) {
1068 fprintf(stderr, "line %d: %s: bad %s\n",
1069 lineno, tp, cp);
1070 errors++;
1071 } else
1072 lp->d_trkseek = v;
1073 continue;
1074 }
1075 if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') {
1076 unsigned part = *cp - 'a';
1077
1078 if (part > lp->d_npartitions) {
1079 fprintf(stderr,
1080 "line %d: bad partition name\n", lineno);
1081 errors++;
1082 continue;
1083 }
1084 pp = &lp->d_partitions[part];
1085#define NXTNUM(n) { \
1086 cp = tp, tp = word(cp); \
1087 if (tp == NULL) \
1088 tp = cp; \
1089 (n) = atoi(cp); \
1090 }
1091
1092 NXTNUM(v);
1093 if (v < 0) {
1094 fprintf(stderr,
1095 "line %d: %s: bad partition size\n",
1096 lineno, cp);
1097 errors++;
1098 } else
1099 pp->p_size = v;
1100 NXTNUM(v);
1101 if (v < 0) {
1102 fprintf(stderr,
1103 "line %d: %s: bad partition offset\n",
1104 lineno, cp);
1105 errors++;
1106 } else
1107 pp->p_offset = v;
1108 cp = tp, tp = word(cp);
1109 cpp = fstypenames;
1110 for (; cpp < &fstypenames[FSMAXTYPES]; cpp++)
1111 if ((s = *cpp) && streq(s, cp)) {
1112 pp->p_fstype = cpp - fstypenames;
1113 goto gottype;
1114 }
1115 if (isdigit(*cp))
1116 v = atoi(cp);
1117 else
1118 v = FSMAXTYPES;
1119 if ((unsigned)v >= FSMAXTYPES) {
1120 fprintf(stderr, "line %d: %s %s\n", lineno,
1121 "Warning, unknown filesystem type", cp);
1122 v = FS_UNUSED;
1123 }
1124 pp->p_fstype = v;
1125 gottype:
1126
1127 switch (pp->p_fstype) {
1128
1129 case FS_UNUSED: /* XXX */
1130 NXTNUM(pp->p_fsize);
1131 if (pp->p_fsize == 0)
1132 break;
1133 NXTNUM(v);
1134 pp->p_frag = v / pp->p_fsize;
1135 break;
1136
1137 case FS_BSDFFS:
1138 NXTNUM(pp->p_fsize);
1139 if (pp->p_fsize == 0)
1140 break;
1141 NXTNUM(v);
1142 pp->p_frag = v / pp->p_fsize;
1143 NXTNUM(pp->p_cpg);
1144 break;
1145
1146 default:
1147 break;
1148 }
1149 continue;
1150 }
1151 fprintf(stderr, "line %d: %s: Unknown disklabel field\n",
1152 lineno, cp);
1153 errors++;
1154 next:
1155 ;
1156 }
1157 errors += checklabel(lp);
1158 return (errors == 0);
1159}
1160
1161/*
1162 * Check disklabel for errors and fill in
1163 * derived fields according to supplied values.
1164 */
1165checklabel(lp)
1166 register struct disklabel *lp;
1167{
1168 register struct partition *pp;
1169 int i, errors = 0;
1170 char part;
1171
1172 if (lp->d_secsize == 0) {
1173 fprintf(stderr, "sector size %d\n", lp->d_secsize);
1174 return (1);
1175 }
1176 if (lp->d_nsectors == 0) {
1177 fprintf(stderr, "sectors/track %d\n", lp->d_nsectors);
1178 return (1);
1179 }
1180 if (lp->d_ntracks == 0) {
1181 fprintf(stderr, "tracks/cylinder %d\n", lp->d_ntracks);
1182 return (1);
1183 }
1184 if (lp->d_ncylinders == 0) {
1185 fprintf(stderr, "cylinders/unit %d\n", lp->d_ncylinders);
1186 errors++;
1187 }
1188 if (lp->d_rpm == 0)
1189 Warning("revolutions/minute %d\n", lp->d_rpm);
1190 if (lp->d_secpercyl == 0)
1191 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1192 if (lp->d_secperunit == 0)
1193 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
1194#ifdef __386BSD__notyet
1195 if (dosdp && dosdp->dp_size && dosdp->dp_typ == DOSPTYP_386BSD
1196 && lp->d_secperunit > dosdp->dp_start + dosdp->dp_size) {
1197 fprintf(stderr, "exceeds DOS partition size\n");
1198 errors++;
1199 lp->d_secperunit = dosdp->dp_start + dosdp->dp_size;
1200 }
1201 /* XXX should also check geometry against BIOS's idea */
1202#endif
1203 if (lp->d_bbsize == 0) {
1204 fprintf(stderr, "boot block size %d\n", lp->d_bbsize);
1205 errors++;
1206 } else if (lp->d_bbsize % lp->d_secsize)
1207 Warning("boot block size %% sector-size != 0\n");
1208 if (lp->d_sbsize == 0) {
1209 fprintf(stderr, "super block size %d\n", lp->d_sbsize);
1210 errors++;
1211 } else if (lp->d_sbsize % lp->d_secsize)
1212 Warning("super block size %% sector-size != 0\n");
1213 if (lp->d_npartitions > MAXPARTITIONS)
1214 Warning("number of partitions (%d) > MAXPARTITIONS (%d)\n",
1215 lp->d_npartitions, MAXPARTITIONS);
1216 for (i = 0; i < lp->d_npartitions; i++) {
1217 part = 'a' + i;
1218 pp = &lp->d_partitions[i];
1219 if (pp->p_size == 0 && pp->p_offset != 0)
1220 Warning("partition %c: size 0, but offset %d\n",
1221 part, pp->p_offset);
1222#ifdef notdef
1223 if (pp->p_size % lp->d_secpercyl)
1224 Warning("partition %c: size %% cylinder-size != 0\n",
1225 part);
1226 if (pp->p_offset % lp->d_secpercyl)
1227 Warning("partition %c: offset %% cylinder-size != 0\n",
1228 part);
1229#endif
1230 if (pp->p_offset > lp->d_secperunit) {
1231 fprintf(stderr,
1232 "partition %c: offset past end of unit\n", part);
1233 errors++;
1234 }
1235 if (pp->p_offset + pp->p_size > lp->d_secperunit) {
1236 fprintf(stderr,
1237 "partition %c: partition extends past end of unit\n",
1238 part);
1239 errors++;
1240 }
1241 }
1242 for (; i < MAXPARTITIONS; i++) {
1243 part = 'a' + i;
1244 pp = &lp->d_partitions[i];
1245 if (pp->p_size || pp->p_offset)
1246 Warning("unused partition %c: size %d offset %d\n",
1247 'a' + i, pp->p_size, pp->p_offset);
1248 }
1249 return (errors);
1250}
1251
1252/*VARARGS1*/
1253Warning(fmt, a1, a2, a3, a4, a5)
1254 char *fmt;
1255{
1256
1257 fprintf(stderr, "Warning, ");
1258 fprintf(stderr, fmt, a1, a2, a3, a4, a5);
1259 fprintf(stderr, "\n");
1260}
1261
1262Perror(str)
1263 char *str;
1264{
1265 fputs("disklabel: ", stderr); perror(str);
1266 exit(4);
1267}
1268
1269usage()
1270{
1271#ifdef BOOT
1272 fprintf(stderr, "%-62s%s\n%-62s%s\n%-62s%s\n%-62s%s\n%-62s%s\n",
1273"usage: disklabel [-r] disk", "(to read label)",
1274"or disklabel -w [-r] disk type [ packid ] [ xxboot bootxx ]", "(to write label)",
1275"or disklabel -e [-r] disk", "(to edit label)",
1276"or disklabel -R [-r] disk protofile [ type | xxboot bootxx ]", "(to restore label)",
1277"or disklabel [-NW] disk", "(to write disable/enable label)");
1278#else
1279 fprintf(stderr, "%-43s%s\n%-43s%s\n%-43s%s\n%-43s%s\n%-43s%s\n",
1280"usage: disklabel [-r] disk", "(to read label)",
1281"or disklabel -w [-r] disk type [ packid ]", "(to write label)",
1282"or disklabel -e [-r] disk", "(to edit label)",
1283"or disklabel -R [-r] disk protofile", "(to restore label)",
1284"or disklabel [-NW] disk", "(to write disable/enable label)");
1285#endif
1286 exit(1);
1287}