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