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