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