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