1 /** $MirOS: src/sbin/disklabel/disklabel.c,v 1.9 2013/09/15 11:01:26 tg Exp $ */
2 /* $OpenBSD: disklabel.c,v 1.95 2005/04/30 07:09:37 deraadt Exp $ */
3
4 /*
5 * Copyright (c) 1987, 1993
6 * The Regents of the University of California. All rights reserved.
7 * Copyright (c) 2004, 2010
8 * Thorsten "mirabilos" Glaser <tg@mirbsd.org>
9 *
10 * This code is derived from software contributed to Berkeley by
11 * Symmetric Computer Systems.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38 #include <sys/param.h>
39 #include <sys/ioctl.h>
40 #include <sys/stat.h>
41 #include <sys/wait.h>
42 #define DKTYPENAMES
43 #include <sys/disklabel.h>
44
45 #include <ufs/ffs/fs.h>
46
47 #include <ctype.h>
48 #include <err.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <limits.h>
52 #include <mbfun.h>
53 #include <signal.h>
54 #include <string.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <unistd.h>
58 #include <util.h>
59 #include "pathnames.h"
60 #include "extern.h"
61
62 __COPYRIGHT("@(#) Copyright (c) 1987, 1993\n\
63 The Regents of the University of California. All rights reserved.\n");
64 __RCSID("$MirOS: src/sbin/disklabel/disklabel.c,v 1.9 2013/09/15 11:01:26 tg Exp $");
65
66 /*
67 * Disklabel: read and write disklabels.
68 * The label is usually placed on one of the first sectors of the disk.
69 * Many machines also place a bootstrap in the same area,
70 * in which case the label is embedded in the bootstrap.
71 * The bootstrap source must leave space at the proper offset
72 * for the label on such machines.
73 */
74
75 #ifndef BBSIZE
76 #define BBSIZE 8192 /* size of boot area, with label */
77 #endif
78
79 #ifndef NUMBOOT
80 #define NUMBOOT 0
81 #endif
82
83 char *dkname, *specname;
84 char tmpfil[] = _PATH_TMPFILE;
85 char namebuf[BBSIZE], *np = namebuf;
86 struct disklabel lab;
87 char bootarea[BBSIZE];
88
89 #if NUMBOOT > 0
90 int installboot; /* non-zero if we should install a boot program */
91 char *bootbuf; /* pointer to buffer with remainder of boot prog */
92 int bootsize; /* size of remaining boot program */
93 char *xxboot; /* primary boot */
94 char *bootxx; /* secondary boot */
95 char boot0[MAXPATHLEN];
96 #if NUMBOOT > 1
97 char boot1[MAXPATHLEN];
98 #endif
99 #endif
100
101 enum {
102 UNSPEC, EDIT, EDITOR, READ, RESTORE, SETWRITEABLE, WRITE, WRITEBOOT
103 } op = UNSPEC;
104
105 int cflag;
106 int dflag;
107 int rflag;
108 int tflag;
109 int nwflag;
110 int verbose;
111 int donothing;
112
113 #ifdef DOSLABEL
114 struct dos_partition *dosdp; /* DOS partition, if found */
115 struct dos_partition *readmbr(int);
116 #endif
117
118 void makedisktab(FILE *, struct disklabel *);
119 void makelabel(char *, char *, struct disklabel *);
120 void l_perror(char *);
121 int edit(struct disklabel *, int);
122 int editit(void);
123 char *skip(char *);
124 char *word(char *);
125 int getasciilabel(FILE *, struct disklabel *);
126 int cmplabel(struct disklabel *, struct disklabel *);
127 void setbootflag(struct disklabel *);
128 void usage(void);
129 u_int32_t getnum(char *, u_int32_t, u_int32_t, const char **);
130
131 int
main(int argc,char * argv[])132 main(int argc, char *argv[])
133 {
134 int ch, f, writeable, error = 0;
135 char *fstabfile = NULL;
136 struct disklabel *lp;
137 char print_unit = 0;
138 FILE *t;
139
140 while ((ch = getopt(argc, argv, "BEf:NRWb:cdenp:rs:tvw")) != -1)
141 switch (ch) {
142 #if NUMBOOT > 0
143 case 'B':
144 ++installboot;
145 break;
146 case 'b':
147 xxboot = optarg;
148 break;
149 #if NUMBOOT > 1
150 case 's':
151 bootxx = optarg;
152 break;
153 #endif
154 #endif
155 case 'N':
156 if (op != UNSPEC)
157 usage();
158 writeable = 0;
159 op = SETWRITEABLE;
160 break;
161 case 'R':
162 if (op != UNSPEC)
163 usage();
164 op = RESTORE;
165 break;
166 case 'W':
167 if (op != UNSPEC)
168 usage();
169 writeable = 1;
170 op = SETWRITEABLE;
171 break;
172 case 'c':
173 ++cflag;
174 break;
175 case 'd':
176 ++dflag;
177 break;
178 case 'e':
179 if (op != UNSPEC)
180 usage();
181 op = EDIT;
182 break;
183 case 'E':
184 if (op != UNSPEC)
185 usage();
186 op = EDITOR;
187 break;
188 case 'f':
189 fstabfile = optarg;
190 break;
191 case 'r':
192 ++rflag;
193 break;
194 case 't':
195 ++tflag;
196 break;
197 case 'w':
198 if (op != UNSPEC)
199 usage();
200 op = WRITE;
201 break;
202 case 'p':
203 if (strchr("bckmg", optarg[0]) == NULL ||
204 optarg[1] != '\0')
205 usage();
206 print_unit = optarg[0];
207 break;
208 case 'n':
209 donothing++;
210 break;
211 case 'v':
212 verbose++;
213 break;
214 case '?':
215 default:
216 usage();
217 }
218 argc -= optind;
219 argv += optind;
220
221 #if NUMBOOT > 0
222 if (installboot) {
223 rflag++;
224 if (op == UNSPEC)
225 op = WRITEBOOT;
226 } else {
227 if (op == UNSPEC)
228 op = READ;
229 }
230 #else
231 if (op == UNSPEC)
232 op = READ;
233 #endif
234
235 if (argc < 1 || (rflag && cflag + dflag > 0) ||
236 (fstabfile && op != EDITOR))
237 usage();
238
239 dkname = argv[0];
240 f = opendev(dkname, (op == READ ? O_RDONLY : O_RDWR), OPENDEV_PART,
241 &specname);
242 if (f < 0)
243 err(4, "%s", specname);
244
245 #ifdef DOSLABEL
246 /*
247 * Check for presence of DOS partition table in
248 * master boot record. Return pointer to MirBSD
249 * partition, if present. If no valid partition table,
250 * return 0. If valid partition table present, but no
251 * partition to use, return a pointer to a non-386bsd
252 * partition.
253 */
254 dosdp = readmbr(f);
255 #endif
256
257 switch (op) {
258 case EDIT:
259 if (argc != 1)
260 usage();
261 if ((lp = readlabel(f)) == NULL)
262 exit(1);
263 error = edit(lp, f);
264 break;
265 case EDITOR:
266 if (argc != 1)
267 usage();
268 if ((lp = readlabel(f)) == NULL)
269 exit(1);
270 error = editor(lp, f, specname, fstabfile);
271 break;
272 case READ:
273 if (argc != 1)
274 usage();
275 if ((lp = readlabel(f)) == NULL)
276 exit(1);
277 if (tflag)
278 makedisktab(stdout, lp);
279 else
280 display(stdout, lp, NULL, print_unit, 0, 0);
281 error = checklabel(lp);
282 break;
283 case RESTORE:
284 if (argc < 2 || argc > 3)
285 usage();
286 #if NUMBOOT > 0
287 if (installboot && argc == 3)
288 makelabel(argv[2], NULL, &lab);
289 #endif
290 lp = makebootarea(bootarea, &lab, f);
291 if (!(t = fopen(argv[1], "r")))
292 err(4, "%s", argv[1]);
293 if (getasciilabel(t, lp))
294 error = writelabel(f, bootarea, lp);
295 else
296 error = 1;
297 break;
298 case SETWRITEABLE:
299 if (!donothing) {
300 if (ioctl(f, DIOCWLABEL, (char *)&writeable) < 0)
301 err(4, "ioctl DIOCWLABEL");
302 }
303 break;
304 case WRITE:
305 if (argc < 2 || argc > 3)
306 usage();
307 makelabel(argv[1], argc == 3 ? argv[2] : NULL, &lab);
308 lp = makebootarea(bootarea, &lab, f);
309 *lp = lab;
310 if (checklabel(lp) == 0)
311 error = writelabel(f, bootarea, lp);
312 break;
313 #if NUMBOOT > 0
314 case WRITEBOOT:
315 {
316 struct disklabel tlab;
317
318 if ((lp = readlabel(f)) == NULL)
319 exit(1);
320 tlab = *lp;
321 if (argc == 2)
322 makelabel(argv[1], NULL, &lab);
323 lp = makebootarea(bootarea, &lab, f);
324 *lp = tlab;
325 if (checklabel(lp) == 0)
326 error = writelabel(f, bootarea, lp);
327 break;
328 }
329 #endif
330 default:
331 break;
332 }
333 exit(error);
334 }
335
336 /*
337 * Construct a prototype disklabel from /etc/disktab. As a side
338 * effect, set the names of the primary and secondary boot files
339 * if specified.
340 */
341 void
makelabel(char * type,char * name,struct disklabel * lp)342 makelabel(char *type, char *name, struct disklabel *lp)
343 {
344 struct disklabel *dp;
345
346 dp = getdiskbyname(type);
347 if (dp == NULL)
348 errx(1, "unknown disk type: %s", type);
349 *lp = *dp;
350 #if NUMBOOT > 0
351 /*
352 * Set bootstrap name(s).
353 * 1. If set from command line, use those,
354 * 2. otherwise, check if disktab specifies them (b0 or b1),
355 * 3. otherwise, makebootarea() will choose ones based on the name
356 * of the disk special file. E.g. /dev/ra0 -> raboot, bootra
357 */
358 if (!xxboot && lp->d_boot0) {
359 if (*lp->d_boot0 != '/')
360 (void)snprintf(boot0, sizeof boot0, "%s%s",
361 _PATH_BOOTDIR, lp->d_boot0);
362 else
363 (void)strlcpy(boot0, lp->d_boot0, sizeof boot0);
364 xxboot = boot0;
365 }
366 #if NUMBOOT > 1
367 if (!bootxx && lp->d_boot1) {
368 if (*lp->d_boot1 != '/')
369 (void)snprintf(boot1, sizeof boot1, "%s%s",
370 _PATH_BOOTDIR, lp->d_boot1);
371 else
372 (void)strlcpy(boot1, lp->d_boot1, sizeof boot1);
373 bootxx = boot1;
374 }
375 #endif
376 #endif
377 /* d_packname is union d_boot[01], so zero */
378 memset(lp->d_packname, 0, sizeof(lp->d_packname));
379 if (name)
380 (void)strncpy(lp->d_packname, name, sizeof(lp->d_packname));
381 }
382
383 int
writelabel(int f,char * boot,struct disklabel * lp)384 writelabel(int f, char *boot, struct disklabel *lp)
385 {
386 int writeable;
387 off_t sectoffset = 0;
388
389 if (nwflag) {
390 warnx("DANGER! The disklabel was not found at the correct location!");
391 #ifndef SMALL
392 warnx("To repair this situation, use 'disklabel %s > file' to",
393 dkname);
394 warnx("save it, then use 'disklabel -R %s file' to replace it.",
395 dkname);
396 #endif /* !SMALL */
397 warnx("A new disklabel is not being installed now.");
398 return(0); /* Actually 1 but we want to exit */
399 }
400 #if NUMBOOT > 0
401 setbootflag(lp);
402 #endif
403 lp->d_magic = DISKMAGIC;
404 lp->d_magic2 = DISKMAGIC;
405 lp->d_checksum = 0;
406 lp->d_checksum = dkcksum(lp);
407 if (rflag) {
408 #ifdef DOSLABEL
409 struct partition *pp = &lp->d_partitions[2];
410
411 /*
412 * If MirBSD BIOS partition is missing, or if
413 * the label to be written is not within partition,
414 * prompt first. Need to allow this in case operator
415 * wants to convert the drive for dedicated use.
416 * In this case, partition 'a' had better start at 0,
417 * otherwise we reject the request as meaningless. -wfj
418 */
419 if (dosdp && pp->p_size &&
420 (dosdp->dp_typ == DOSPTYP_MIRBSD ||
421 dosdp->dp_typ == DOSPTYP_OPENBSD ||
422 dosdp->dp_typ == DOSPTYP_FREEBSD ||
423 dosdp->dp_typ == DOSPTYP_NETBSD)) {
424 sectoffset = (off_t)get_le(&dosdp->dp_start) *
425 lp->d_secsize;
426 } else {
427 if (dosdp) {
428 int first, ch;
429
430 printf("Erase the previous contents of the disk? [n]: ");
431 fflush(stdout);
432 first = ch = getchar();
433 while (ch != '\n' && ch != EOF)
434 ch = getchar();
435 if (first != 'y' && first != 'Y')
436 exit(0);
437 }
438 sectoffset = 0;
439 }
440
441 #if NUMBOOT > 0
442 /*
443 * If we are not installing a boot program
444 * we must read the current bootarea so we don't
445 * clobber the existing boot.
446 */
447 if (!installboot) {
448 struct disklabel tlab;
449
450 tlab = *lp;
451 if (cdblockedread(f, boot, tlab.d_bbsize,
452 sectoffset) == -1) {
453 perror("lseek+read");
454 return (1);
455 }
456 *lp =tlab;
457 }
458 #endif
459 #endif
460
461 /*
462 * First set the kernel disk label,
463 * then write a label to the raw disk.
464 * If the SDINFO ioctl fails because it is unimplemented,
465 * keep going; otherwise, the kernel consistency checks
466 * may prevent us from changing the current (in-core)
467 * label.
468 */
469 if (!donothing) {
470 if (ioctl(f, DIOCSDINFO, lp) < 0 &&
471 errno != ENODEV && errno != ENOTTY) {
472 l_perror("ioctl DIOCSDINFO");
473 return (1);
474 }
475 }
476 if (verbose)
477 printf("writing label to block %lld (0x%qx)\n",
478 (long long)sectoffset/DEV_BSIZE,
479 (long long)sectoffset/DEV_BSIZE);
480 if (!donothing) {
481 if (lseek(f, sectoffset, SEEK_SET) < 0) {
482 perror("lseek");
483 return (1);
484 }
485 /*
486 * write enable label sector before write (if necessary),
487 * disable after writing.
488 */
489 writeable = 1;
490
491 if (ioctl(f, DIOCWLABEL, &writeable) < 0)
492 perror("ioctl DIOCWLABEL");
493 #ifdef __alpha__
494 /*
495 * The Alpha requires that the boot block be checksummed.
496 * The first 63 8-byte quantites are summed into the 64th.
497 */
498 {
499 int i;
500 u_int64_t *dp, sum;
501
502 dp = (u_int64_t *)boot;
503 sum = 0;
504 for (i = 0; i < 63; i++)
505 sum += dp[i];
506 dp[63] = sum;
507 }
508 #endif
509 if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) {
510 perror("write");
511 return (1);
512 }
513 }
514 #if NUMBOOT > 0
515 /*
516 * Output the remainder of the disklabel
517 */
518 if (!donothing && bootbuf && write(f, bootbuf, bootsize) != bootsize) {
519 perror("write");
520 return(1);
521 }
522 #endif
523 writeable = 0;
524 if (!donothing)
525 if (ioctl(f, DIOCWLABEL, &writeable) < 0)
526 perror("ioctl DIOCWLABEL");
527 } else {
528 if (!donothing) {
529 if (ioctl(f, DIOCWDINFO, lp) < 0) {
530 l_perror("ioctl DIOCWDINFO");
531 return (1);
532 }
533 }
534 }
535 return (0);
536 }
537
538 void
l_perror(char * s)539 l_perror(char *s)
540 {
541
542 switch (errno) {
543 case ESRCH:
544 warnx("%s: No disk label on disk;\n"
545 "use \"disklabel -r\" to install initial label", s);
546 break;
547 case EINVAL:
548 warnx("%s: Label magic number or checksum is wrong!\n"
549 "(disklabel or kernel is out of date?)", s);
550 break;
551 case EBUSY:
552 warnx("%s: Open partition would move or shrink", s);
553 break;
554 case EXDEV:
555 warnx("%s: Labeled partition or 'a' partition must start "
556 "at beginning of disk", s);
557 break;
558 default:
559 warn("%s", s);
560 break;
561 }
562 }
563
564 #ifdef DOSLABEL
565 /* read sector containing partition table from the disc */
566 int
read_pt(int f,long offs,int * target)567 read_pt(int f, long offs, int *target)
568 {
569 if (cdblockedread(f, target, DEV_BSIZE, (off_t)offs * DEV_BSIZE) == -1)
570 return (-1);
571 return (0);
572 }
573
574 /* scan partition table for BIOS partition of given type */
575 int
scan_pt(struct dos_partition * dp,u_int8_t what)576 scan_pt(struct dos_partition *dp, u_int8_t what)
577 {
578 int part;
579
580 for (part = 0; part < NDOSPART; ++part) {
581 if ((!get_le(&dp[part].dp_size)) || (dp[part].dp_typ != what))
582 continue;
583 fprintf(stderr, "# Inside MBR partition %d: "
584 "type %02X start %u (0x%X) size %u (0x%X)%s\n",
585 part, dp[part].dp_typ,
586 get_le(&dp[part].dp_start), get_le(&dp[part].dp_start),
587 get_le(&dp[part].dp_size), get_le(&dp[part].dp_size),
588 ( ((what == DOSPTYP_EXTENDL) || (what == DOSPTYP_EXTENDLX)
589 || (what == DOSPTYP_EXTEND)) ? ", chaining..." : "."));
590 return part;
591 }
592 return NDOSPART;
593 }
594
595 /*
596 * Fetch DOS partition table from disk.
597 */
598 struct dos_partition *
readmbr(int f)599 readmbr(int f)
600 {
601 static int mbr[DEV_BSIZE / sizeof(int)];
602 long mbrofs;
603 struct dos_partition *dp;
604 u_int16_t signature;
605 int part;
606
607 mbrofs = DOSBBSECTOR;
608 loop: if (read_pt(f, mbrofs, mbr))
609 err(4, "can't read partition table");
610
611 /*
612 * This must be done this way due to alignment restrictions
613 * in for example mips processors.
614 */
615 dp = (struct dos_partition *)mbr;
616 signature = *((u_char *)mbr + DOSMBR_SIGNATURE_OFF) |
617 (*((u_char *)mbr + DOSMBR_SIGNATURE_OFF + 1) << 8);
618 memmove((char *)mbr, (char *)mbr + DOSPARTOFF, sizeof(*dp) * NDOSPART);
619
620 /*
621 * Don't (yet) know disk geometry (BIOS), use
622 * partition table to find MirBSD partition, and obtain
623 * disklabel from there.
624 */
625 /* Check if table is valid. Adjust offsets of partitions. */
626 for (part = 0; part < NDOSPART; part++) {
627 set_le(&dp[part].dp_start,
628 get_le(&dp[part].dp_start) + mbrofs);
629 if ((dp[part].dp_flag & ~0x80) != 0)
630 return (0);
631 }
632
633 /* scan for MirBSD (or OpenBSD, FreeBSD, NetBSD) partition */
634 if ((part = scan_pt(dp, DOSPTYP_MIRBSD)) < NDOSPART)
635 return (&dp[part]);
636 if ((part = scan_pt(dp, DOSPTYP_OPENBSD)) < NDOSPART)
637 return (&dp[part]);
638 if ((part = scan_pt(dp, DOSPTYP_NETBSD)) < NDOSPART)
639 return (&dp[part]);
640 if ((part = scan_pt(dp, DOSPTYP_FREEBSD)) < NDOSPART)
641 return (&dp[part]);
642
643 /*
644 * If there is no signature and no MirBSD partition, this is probably
645 * not an MBR.
646 */
647 if (signature != DOSMBR_SIGNATURE)
648 return (NULL);
649
650 /*
651 * still not found? scan for extended partition
652 * XXX this code assumes: only one 05, 0F or 85 per partition table
653 */
654 if ((part = scan_pt(dp, DOSPTYP_EXTEND)) == NDOSPART)
655 if ((part = scan_pt(dp, DOSPTYP_EXTENDL)) == NDOSPART)
656 if ((part = scan_pt(dp, DOSPTYP_EXTENDLX)) == NDOSPART) {
657 /* if still none found, find first used partition */
658 if (read_pt(f, DOSBBSECTOR, mbr)) {
659 warn("can't read master boot record");
660 return (NULL);
661 }
662 dp = (struct dos_partition *)mbr;
663 memcpy((char *)mbr, (char *)mbr + DOSPARTOFF,
664 sizeof(*dp) * NDOSPART);
665 for (part = 0; part < NDOSPART; part++) {
666 if (get_le(&dp[part].dp_size)) {
667 warnx("warning, DOS partition table with"
668 " no valid MirBSD partition");
669 return (&dp[part]);
670 }
671 }
672 /* Table appears to be empty. */
673 return (NULL);
674 }
675
676 /* we have an extended partition, loop */
677 mbrofs = get_le(&dp[part].dp_start);
678 goto loop;
679 /* NOTREACHED */
680 }
681 #endif
682
683 /*
684 * Fetch disklabel for disk.
685 * Use ioctl to get label unless -r flag is given.
686 */
687 struct disklabel *
readlabel(int f)688 readlabel(int f)
689 {
690 struct disklabel *lp = NULL;
691
692 if (rflag) {
693 char *msg;
694 off_t sectoffset = 0;
695
696 #ifdef DOSLABEL
697 if (dosdp && get_le(&dosdp->dp_size) &&
698 (dosdp->dp_typ == DOSPTYP_MIRBSD ||
699 dosdp->dp_typ == DOSPTYP_OPENBSD ||
700 dosdp->dp_typ == DOSPTYP_FREEBSD ||
701 dosdp->dp_typ == DOSPTYP_NETBSD))
702 sectoffset = (off_t)get_le(&dosdp->dp_start) *
703 DEV_BSIZE;
704 #endif
705 if (verbose)
706 printf("reading label from block %lld, offset %lld\n",
707 (long long)sectoffset/DEV_BSIZE,
708 sectoffset/DEV_BSIZE +
709 (LABELSECTOR * DEV_BSIZE) + LABELOFFSET);
710 if (cdblockedread(f, bootarea, BBSIZE, sectoffset) == -1)
711 err(4, "%s", specname);
712
713 lp = (struct disklabel *)(bootarea +
714 (LABELSECTOR * DEV_BSIZE) + LABELOFFSET);
715 if (lp->d_magic == DISKMAGIC &&
716 lp->d_magic2 == DISKMAGIC) {
717 if (lp->d_npartitions <= MAXPARTITIONS &&
718 dkcksum(lp) == 0)
719 return (lp);
720
721 msg = "disk label corrupted";
722 }
723 else {
724 warnx("no disklabel found. scanning.");
725 }
726 nwflag++;
727
728 msg = "no disk label";
729 for (lp = (struct disklabel *)bootarea;
730 lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp));
731 lp = (struct disklabel *)((char *)lp + sizeof(long))) {
732 if (lp->d_magic == DISKMAGIC &&
733 lp->d_magic2 == DISKMAGIC) {
734 if (lp->d_npartitions <= MAXPARTITIONS &&
735 dkcksum(lp) == 0) {
736 warnx("found at 0x%lx",
737 (long)((char *)lp - bootarea));
738 return (lp);
739 }
740 msg = "disk label corrupted";
741 }
742 }
743 warnx("%s", msg);
744 return(NULL);
745 } else {
746 if (cflag && ioctl(f, DIOCRLDINFO) < 0)
747 err(4, "ioctl DIOCRLDINFO");
748 if (dflag) {
749 lp = &lab;
750 if (ioctl(f, DIOCGPDINFO, lp) < 0)
751 err(4, "ioctl DIOCGPDINFO");
752 } else {
753 lp = &lab;
754 if (ioctl(f, DIOCGDINFO, lp) < 0)
755 err(4, "ioctl DIOCGDINFO");
756 }
757 }
758 return (lp);
759 }
760
761 /*
762 * Construct a bootarea (d_bbsize bytes) in the specified buffer "boot"
763 * Returns a pointer to the disklabel portion of the bootarea.
764 */
765 struct disklabel *
makebootarea(char * boot,struct disklabel * dp,int f)766 makebootarea(char *boot, struct disklabel *dp, int f)
767 {
768 struct disklabel *lp;
769 char *p;
770 #if NUMBOOT > 0
771 char *dkbasename;
772 int b;
773 #if NUMBOOT == 1
774 struct stat sb;
775 #endif
776 #endif
777
778 /* XXX */
779 if (dp->d_secsize == 0) {
780 dp->d_secsize = DEV_BSIZE;
781 dp->d_bbsize = BBSIZE;
782 }
783 lp = (struct disklabel *)
784 (boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET);
785 memset(lp, 0, sizeof *lp);
786 #if NUMBOOT > 0
787 /*
788 * If we are not installing a boot program but we are installing a
789 * label on disk then we must read the current bootarea so we don't
790 * clobber the existing boot.
791 */
792 if (!installboot) {
793 #ifndef __i386__
794 if (rflag) {
795 if (read(f, boot, BBSIZE) < BBSIZE)
796 err(4, "%s", specname);
797 memset(lp, 0, sizeof *lp);
798 }
799 #endif
800 return (lp);
801 }
802 /*
803 * We are installing a boot program. Determine the name(s) and
804 * read them into the appropriate places in the boot area.
805 */
806 if (!xxboot || !bootxx) {
807 dkbasename = np;
808 if ((p = strrchr(dkname, '/')) == NULL)
809 p = dkname;
810 else
811 p++;
812 while (*p && !isdigit(*p))
813 *np++ = *p++;
814 *np++ = '\0';
815
816 if (!xxboot) {
817 (void)snprintf(np, namebuf + sizeof namebuf - np,
818 "%s%sboot", _PATH_BOOTDIR, dkbasename);
819 if (access(np, F_OK) < 0 && dkbasename[0] == 'r')
820 dkbasename++;
821 xxboot = np;
822 (void)snprintf(xxboot,
823 namebuf + sizeof namebuf - np,
824 "%s%sboot", _PATH_BOOTDIR, dkbasename);
825 np += strlen(xxboot) + 1;
826 }
827 #if NUMBOOT > 1
828 if (!bootxx) {
829 (void)snprintf(np, namebuf + sizeof namebuf - np,
830 "%sboot%s", _PATH_BOOTDIR, dkbasename);
831 if (access(np, F_OK) < 0 && dkbasename[0] == 'r')
832 dkbasename++;
833 bootxx = np;
834 (void)snprintf(bootxx, namebuf + sizeof namebuf - bootxx,
835 "%sboot%s", _PATH_BOOTDIR, dkbasename);
836 np += strlen(bootxx) + 1;
837 }
838 #endif
839 }
840 if (verbose)
841 warnx("bootstraps: xxboot = %s, bootxx = %s", xxboot,
842 bootxx ? bootxx : "NONE");
843
844 /*
845 * Strange rules:
846 * 1. One-piece bootstrap (hp300/hp800)
847 * up to d_bbsize bytes of "xxboot" go in bootarea, the rest
848 * is remembered and written later following the bootarea.
849 * 2. Two-piece bootstraps (vax/i386?/mips?)
850 * up to d_secsize bytes of "xxboot" go in first d_secsize
851 * bytes of bootarea, remaining d_bbsize-d_secsize filled
852 * from "bootxx".
853 */
854 b = open(xxboot, O_RDONLY);
855 if (b < 0)
856 err(4, "%s", xxboot);
857 #if NUMBOOT > 1
858 if (read(b, boot, (int)dp->d_secsize) < 0)
859 err(4, "%s", xxboot);
860 (void)close(b);
861 b = open(bootxx, O_RDONLY);
862 if (b < 0)
863 err(4, "%s", bootxx);
864 if (read(b, &boot[dp->d_secsize], (int)(dp->d_bbsize-dp->d_secsize)) < 0)
865 err(4, "%s", bootxx);
866 #else
867 if (read(b, boot, (int)dp->d_bbsize) < 0)
868 err(4, "%s", xxboot);
869 (void)fstat(b, &sb);
870 bootsize = (int)sb.st_size - dp->d_bbsize;
871 if (bootsize > 0) {
872 /* XXX assume d_secsize is a power of two */
873 bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1);
874 bootbuf = (char *)malloc((size_t)bootsize);
875 if (bootbuf == 0)
876 err(4, "%s", xxboot);
877 if (read(b, bootbuf, bootsize) < 0) {
878 free(bootbuf);
879 err(4, "%s", xxboot);
880 }
881 }
882 #endif
883 (void)close(b);
884 #endif
885 /*
886 * Make sure no part of the bootstrap is written in the area
887 * reserved for the label.
888 */
889 for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++)
890 if (*p)
891 errx(2, "Bootstrap doesn't leave room for disk label");
892 return (lp);
893 }
894
895 void
makedisktab(FILE * f,struct disklabel * lp)896 makedisktab(FILE *f, struct disklabel *lp)
897 {
898 int i;
899 char *did = "\\\n\t:";
900 struct partition *pp;
901
902 if (lp->d_packname[0])
903 (void)fprintf(f, "%.*s|", (int)sizeof(lp->d_packname),
904 lp->d_packname);
905 if (lp->d_typename[0])
906 (void)fprintf(f, "%.*s|", (int)sizeof(lp->d_typename),
907 lp->d_typename);
908 (void)fputs("Automatically generated label:\\\n\t:dt=", f);
909 if ((unsigned) lp->d_type < DKMAXTYPES)
910 (void)fprintf(f, "%s:", dktypenames[lp->d_type]);
911 else
912 (void)fprintf(f, "unknown%d:", lp->d_type);
913
914 (void)fprintf(f, "se#%u:", lp->d_secsize);
915 (void)fprintf(f, "ns#%u:", lp->d_nsectors);
916 (void)fprintf(f, "nt#%u:", lp->d_ntracks);
917 (void)fprintf(f, "nc#%u:", lp->d_ncylinders);
918 (void)fprintf(f, "sc#%u:", lp->d_secpercyl);
919 (void)fprintf(f, "su#%u:", lp->d_secperunit);
920
921 if (lp->d_rpm != 3600) {
922 (void)fprintf(f, "%srm#%hu:", did, lp->d_rpm);
923 did = "";
924 }
925 if (lp->d_interleave != 1) {
926 (void)fprintf(f, "%sil#%hu:", did, lp->d_interleave);
927 did = "";
928 }
929 if (lp->d_trackskew != 0) {
930 (void)fprintf(f, "%ssk#%hu:", did, lp->d_trackskew);
931 did = "";
932 }
933 if (lp->d_cylskew != 0) {
934 (void)fprintf(f, "%scs#%hu:", did, lp->d_cylskew);
935 did = "";
936 }
937 if (lp->d_headswitch != 0) {
938 (void)fprintf(f, "%shs#%u:", did, lp->d_headswitch);
939 did = "";
940 }
941 if (lp->d_trkseek != 0) {
942 (void)fprintf(f, "%sts#%u:", did, lp->d_trkseek);
943 did = "";
944 }
945 for (i = 0; i < NDDATA; i++)
946 if (lp->d_drivedata[i])
947 (void)fprintf(f, "d%d#%u", i, lp->d_drivedata[i]);
948 pp = lp->d_partitions;
949 for (i = 0; i < lp->d_npartitions; i++, pp++) {
950 if (pp->p_size) {
951 char c = 'a' + i;
952
953 (void)fprintf(f, "\\\n\t:");
954 (void)fprintf(f, "p%c#%u:", c, pp->p_size);
955 (void)fprintf(f, "o%c#%u:", c, pp->p_offset);
956 if (pp->p_fstype != FS_UNUSED) {
957 if ((unsigned) pp->p_fstype < FSMAXTYPES)
958 (void)fprintf(f, "t%c=%s:", c,
959 fstypenames[pp->p_fstype]);
960 else
961 (void)fprintf(f, "t%c=unknown%d:",
962 c, pp->p_fstype);
963 }
964 switch (pp->p_fstype) {
965
966 case FS_UNUSED:
967 break;
968
969 case FS_BSDFFS:
970 (void)fprintf(f, "b%c#%u:", c,
971 pp->p_fsize * pp->p_frag);
972 (void)fprintf(f, "f%c#%u:", c, pp->p_fsize);
973 break;
974
975 default:
976 break;
977 }
978 }
979 }
980 (void)fputc('\n', f);
981 (void)fflush(f);
982 }
983
984 double
scale(u_int32_t sz,char unit,struct disklabel * lp)985 scale(u_int32_t sz, char unit, struct disklabel *lp)
986 {
987 double fsz;
988
989 fsz = (double)sz * lp->d_secsize;
990
991 switch (unit) {
992 case 'B':
993 return fsz;
994 case 'C':
995 return fsz / lp->d_secsize / lp->d_secpercyl;
996 case 'K':
997 return fsz / 1024;
998 case 'M':
999 return fsz / (1024 * 1024);
1000 case 'G':
1001 return fsz / (1024 * 1024 * 1024);
1002 default:
1003 return -1.0;
1004 }
1005 }
1006
1007 /*
1008 * Display a particular partition.
1009 */
1010 void
display_partition(FILE * f,struct disklabel * lp,char ** mp,int i,char unit)1011 display_partition(FILE *f, struct disklabel *lp, char **mp, int i,
1012 char unit)
1013 {
1014 volatile struct partition *pp = &lp->d_partitions[i];
1015 double p_size, p_offset;
1016
1017 p_size = scale(pp->p_size, unit, lp);
1018 p_offset = scale(pp->p_offset, unit, lp);
1019 if (pp->p_size) {
1020 if (p_size < 0)
1021 fprintf(f, " %c: %13u %13u ", 'a' + i,
1022 pp->p_size, pp->p_offset);
1023 else
1024 fprintf(f, " %c: %12.*f%c %12.*f%c ", 'a' + i,
1025 unit == 'B' ? 0 : 1, p_size, unit,
1026 unit == 'B' ? 0 : 1, p_offset, unit);
1027 if ((unsigned) pp->p_fstype < FSMAXTYPES)
1028 fprintf(f, "%7.7s", fstypenames[pp->p_fstype]);
1029 else
1030 fprintf(f, "%7d", pp->p_fstype);
1031 switch (pp->p_fstype) {
1032
1033 case FS_UNUSED: /* XXX */
1034 fprintf(f, " %5u %5u %4.4s ",
1035 pp->p_fsize, pp->p_fsize * pp->p_frag, "");
1036 break;
1037
1038 case FS_BSDFFS:
1039 fprintf(f, " %5u %5u %4hu ",
1040 pp->p_fsize, pp->p_fsize * pp->p_frag,
1041 pp->p_cpg);
1042 break;
1043
1044 default:
1045 fprintf(f, "%19.19s", "");
1046 break;
1047 }
1048 if (mp != NULL) {
1049 if (mp[i] != NULL)
1050 fprintf(f, "# %s", mp[i]);
1051 } else if (lp->d_secpercyl) {
1052 fprintf(f, "# Cyl %5u",
1053 pp->p_offset / lp->d_secpercyl);
1054 if (pp->p_offset % lp->d_secpercyl)
1055 putc('*', f);
1056 else
1057 putc(' ', f);
1058 fprintf(f, "-%6u",
1059 (pp->p_offset +
1060 pp->p_size + lp->d_secpercyl - 1) /
1061 lp->d_secpercyl - 1);
1062 if ((pp->p_offset + pp->p_size) % lp->d_secpercyl)
1063 putc('*', f);
1064 else
1065 putc(' ', f);
1066 }
1067 putc('\n', f);
1068 }
1069 }
1070
1071 void
display(FILE * f,struct disklabel * lp,char ** mp,char unit,int edit,u_int32_t fr)1072 display(FILE *f, struct disklabel *lp, char **mp, char unit, int edit,
1073 u_int32_t fr)
1074 {
1075 int i, j;
1076 double d;
1077
1078 unit = toupper(unit);
1079 if (edit)
1080 fprintf(f, "device: %s\n", specname);
1081 else
1082 fprintf(f, "# %s:\n", specname);
1083
1084 if ((unsigned) lp->d_type < DKMAXTYPES)
1085 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
1086 else
1087 fprintf(f, "type: %d\n", lp->d_type);
1088 fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename);
1089 fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname);
1090 if (!edit) {
1091 fprintf(f, "flags:");
1092 if (lp->d_flags & D_REMOVABLE)
1093 fprintf(f, " removable");
1094 if (lp->d_flags & D_ECC)
1095 fprintf(f, " ecc");
1096 if (lp->d_flags & D_BADSECT)
1097 fprintf(f, " badsect");
1098 putc('\n', f);
1099 }
1100 fprintf(f, "bytes/sector: %u\n", lp->d_secsize);
1101 fprintf(f, "sectors/track: %u\n", lp->d_nsectors);
1102 fprintf(f, "tracks/cylinder: %u\n", lp->d_ntracks);
1103 fprintf(f, "sectors/cylinder: %u\n", lp->d_secpercyl);
1104 fprintf(f, "cylinders: %u\n", lp->d_ncylinders);
1105 d = scale(lp->d_secperunit, unit, lp);
1106 if (d < 0)
1107 fprintf(f, "total sectors: %u\n", lp->d_secperunit);
1108 else
1109 fprintf(f, "total bytes: %.*f%c\n", unit == 'B' ? 0 : 1,
1110 d, unit);
1111
1112 if (edit) {
1113 d = scale(fr, unit, lp);
1114 if (d < 0)
1115 fprintf(f, "free sectors: %u\n", fr);
1116 else
1117 fprintf(f, "free bytes: %.*f%c\n", unit == 'B' ? 0 : 1,
1118 d, unit);
1119 }
1120 fprintf(f, "rpm: %hu\n", lp->d_rpm);
1121 if (!edit) {
1122 fprintf(f, "interleave: %hu\n", lp->d_interleave);
1123 fprintf(f, "trackskew: %hu\n", lp->d_trackskew);
1124 fprintf(f, "cylinderskew: %hu\n", lp->d_cylskew);
1125 fprintf(f, "headswitch: %u\t\t# microseconds\n",
1126 lp->d_headswitch);
1127 fprintf(f, "track-to-track seek: %u\t# microseconds\n",
1128 lp->d_trkseek);
1129 fprintf(f, "drivedata: ");
1130 for (i = NDDATA - 1; i >= 0; i--)
1131 if (lp->d_drivedata[i])
1132 break;
1133 if (i < 0)
1134 i = 0;
1135 for (j = 0; j <= i; j++)
1136 fprintf(f, "%d ", lp->d_drivedata[j]);
1137 fprintf(f, "\n");
1138 }
1139 fprintf(f, "\n%hu partitions:\n", lp->d_npartitions);
1140 fprintf(f, "# %13.13s %13.13s fstype [fsize bsize cpg]\n",
1141 "size", "offset");
1142 for (i = 0; i < lp->d_npartitions; i++)
1143 display_partition(f, lp, mp, i, unit);
1144 fflush(f);
1145 }
1146
1147 int
edit(struct disklabel * lp,int f)1148 edit(struct disklabel *lp, int f)
1149 {
1150 int first, ch, fd;
1151 struct disklabel label;
1152 FILE *fp;
1153
1154 if ((fd = mkstemp(tmpfil)) == -1 || (fp = fdopen(fd, "w")) == NULL) {
1155 if (fd != -1)
1156 close(fd);
1157 warn("%s", tmpfil);
1158 return (1);
1159 }
1160 display(fp, lp, NULL, 0, 0, 0);
1161 #ifndef SMALL
1162 fprintf(fp, "\n# Notes:\n");
1163 fprintf(fp,
1164 "# Up to 16 partitions are valid, named from 'a' to 'p'. Partition 'a' is\n"
1165 "# your root filesystem, 'b' is your swap, and 'c' should cover your whole\n"
1166 "# disk. Any other partition is free for any use. 'size' and 'offset' are\n"
1167 "# in 512-byte blocks. fstype should be '4.2BSD', 'swap', or 'none' or some\n"
1168 "# other values. fsize/bsize/cpg should typically be '2048 16384 16' for a\n"
1169 "# 4.2BSD filesystem (or '512 4096 16' except on alpha, sun4, ...)\n");
1170 #endif /* !SMALL */
1171 fclose(fp);
1172 for (;;) {
1173 if (!editit())
1174 break;
1175 fp = fopen(tmpfil, "r");
1176 if (fp == NULL) {
1177 warn("%s", tmpfil);
1178 break;
1179 }
1180 memset(&label, 0, sizeof(label));
1181 if (getasciilabel(fp, &label)) {
1182 if (cmplabel(lp, &label) == 0) {
1183 puts("No changes.");
1184 fclose(fp);
1185 (void) unlink(tmpfil);
1186 return (0);
1187 }
1188 *lp = label;
1189 if (writelabel(f, bootarea, lp) == 0) {
1190 fclose(fp);
1191 (void) unlink(tmpfil);
1192 return (0);
1193 }
1194 }
1195 fclose(fp);
1196 printf("re-edit the label? [y]: ");
1197 fflush(stdout);
1198 first = ch = getchar();
1199 while (ch != '\n' && ch != EOF)
1200 ch = getchar();
1201 if (first == 'n' || first == 'N')
1202 break;
1203 }
1204 (void)unlink(tmpfil);
1205 return (1);
1206 }
1207
1208 int
editit(void)1209 editit(void)
1210 {
1211 pid_t pid;
1212 int stat = 0, len;
1213 char *argp[] = {"sh", "-c", NULL, NULL};
1214 char *ed, *p;
1215
1216 if ((ed = getenv("EDITOR")) == NULL)
1217 ed = _PATH_VI;
1218 len = strlen(ed) + 1 + strlen(tmpfil) + 1;
1219 p = (char *)malloc(len);
1220 if (!p) {
1221 warn("failed to start editor");
1222 return (0);
1223 }
1224 snprintf(p, len, "%s %s", ed, tmpfil);
1225 argp[2] = p;
1226
1227 /* Turn off signals. */
1228 (void)signal(SIGHUP, SIG_IGN);
1229 (void)signal(SIGINT, SIG_IGN);
1230 (void)signal(SIGQUIT, SIG_IGN);
1231 while ((pid = fork()) < 0) {
1232 if (errno != EAGAIN) {
1233 warn("fork");
1234 free(p);
1235 stat = 1;
1236 goto bail;
1237 }
1238 sleep(1);
1239 }
1240 if (pid == 0) {
1241 execv(_PATH_BSHELL, argp);
1242 _exit(127);
1243 }
1244 free(p);
1245 for (;;) {
1246 if (waitpid(pid, (int *)&stat, WUNTRACED) == -1) {
1247 if (errno == EINTR)
1248 continue;
1249 if (errno == ECHILD)
1250 stat = 1;
1251 break;
1252 }
1253 if (WIFSTOPPED(stat))
1254 raise(WSTOPSIG(stat));
1255 else if (WIFEXITED(stat))
1256 break;
1257 }
1258 bail:
1259 (void)signal(SIGHUP, SIG_DFL);
1260 (void)signal(SIGINT, SIG_DFL);
1261 (void)signal(SIGQUIT, SIG_DFL);
1262 return (!stat);
1263 }
1264
1265 char *
skip(char * cp)1266 skip(char *cp)
1267 {
1268
1269 cp += strspn(cp, " \t");
1270 if (*cp == '\0')
1271 return (NULL);
1272 return (cp);
1273 }
1274
1275 char *
word(char * cp)1276 word(char *cp)
1277 {
1278
1279 cp += strcspn(cp, " \t");
1280 if (*cp == '\0')
1281 return (NULL);
1282 *cp++ = '\0';
1283 cp += strspn(cp, " \t");
1284 if (*cp == '\0')
1285 return (NULL);
1286 return (cp);
1287 }
1288
1289 /* Base the max value on the sizeof of the value we are reading */
1290 #define GETNUM(field, nptr, min, errstr) \
1291 getnum((nptr), (min), \
1292 sizeof(field) == 4 ? UINT_MAX : \
1293 (sizeof(field) == 2 ? USHRT_MAX : UCHAR_MAX), (errstr))
1294
1295 u_int32_t
getnum(char * nptr,u_int32_t min,u_int32_t max,const char ** errstr)1296 getnum(char *nptr, u_int32_t min, u_int32_t max, const char **errstr)
1297 {
1298 char *p, c;
1299 u_int32_t ret;
1300
1301 for (p = nptr; *p != '\0' && !isspace(*p); p++)
1302 ;
1303 c = *p;
1304 *p = '\0';
1305 ret = strtonum(nptr, min, max, errstr);
1306 *p = c;
1307 return (ret);
1308 }
1309
1310 /*
1311 * Read an ascii label in from fd f,
1312 * in the same format as that put out by display(),
1313 * and fill in lp.
1314 */
1315 int
getasciilabel(FILE * f,struct disklabel * lp)1316 getasciilabel(FILE *f, struct disklabel *lp)
1317 {
1318 char **cpp, *cp;
1319 const char *errstr;
1320 struct partition *pp;
1321 char *tp, *s, line[BUFSIZ];
1322 int lineno = 0, errors = 0;
1323 u_int32_t v;
1324
1325 lp->d_bbsize = BBSIZE; /* XXX */
1326 lp->d_sbsize = SBSIZE; /* XXX */
1327 while (fgets(line, sizeof(line) - 1, f)) {
1328 lineno++;
1329 if ((cp = strpbrk(line, "#\r\n")))
1330 *cp = '\0';
1331 cp = skip(line);
1332 if (cp == NULL)
1333 continue;
1334 tp = strchr(cp, ':');
1335 if (tp == NULL) {
1336 warnx("line %d: syntax error", lineno);
1337 errors++;
1338 continue;
1339 }
1340 *tp++ = '\0', tp = skip(tp);
1341 if (!strcmp(cp, "type")) {
1342 if (tp == NULL)
1343 tp = "unknown";
1344 else if (strcasecmp(tp, "IDE") == 0)
1345 tp = "ESDI";
1346 cpp = dktypenames;
1347 for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
1348 if ((s = *cpp) && !strcasecmp(s, tp)) {
1349 lp->d_type = cpp - dktypenames;
1350 goto next;
1351 }
1352 v = GETNUM(lp->d_type, tp, 0, &errstr);
1353 if (errstr || v >= DKMAXTYPES)
1354 warnx("line %d: warning, unknown disk type: %s",
1355 lineno, tp);
1356 lp->d_type = v;
1357 continue;
1358 }
1359 if (!strcmp(cp, "flags")) {
1360 for (v = 0; (cp = tp) && *cp != '\0';) {
1361 tp = word(cp);
1362 if (!strcmp(cp, "removable"))
1363 v |= D_REMOVABLE;
1364 else if (!strcmp(cp, "ecc"))
1365 v |= D_ECC;
1366 else if (!strcmp(cp, "badsect"))
1367 v |= D_BADSECT;
1368 else {
1369 warnx("line %d: bad flag: %s",
1370 lineno, cp);
1371 errors++;
1372 }
1373 }
1374 lp->d_flags = v;
1375 continue;
1376 }
1377 if (!strcmp(cp, "drivedata")) {
1378 int i;
1379
1380 for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
1381 v = GETNUM(lp->d_drivedata[i], cp, 0, &errstr);
1382 if (errstr)
1383 warnx("line %d: bad drivedata %s",
1384 lineno, cp);
1385 lp->d_drivedata[i++] = v;
1386 tp = word(cp);
1387 }
1388 continue;
1389 }
1390 if (sscanf(cp, "%d partitions", &v) == 1) {
1391 if (v == 0 || v > MAXPARTITIONS) {
1392 warnx("line %d: bad # of partitions", lineno);
1393 lp->d_npartitions = MAXPARTITIONS;
1394 errors++;
1395 } else
1396 lp->d_npartitions = v;
1397 continue;
1398 }
1399 if (tp == NULL)
1400 tp = "";
1401 if (!strcmp(cp, "disk")) {
1402 strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
1403 continue;
1404 }
1405 if (!strcmp(cp, "label")) {
1406 strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
1407 continue;
1408 }
1409 if (!strcmp(cp, "bytes/sector")) {
1410 v = GETNUM(lp->d_secsize, tp, 1, &errstr);
1411 if (errstr || (v % 512) != 0) {
1412 warnx("line %d: bad %s: %s", lineno, cp, tp);
1413 errors++;
1414 } else
1415 lp->d_secsize = v;
1416 continue;
1417 }
1418 if (!strcmp(cp, "sectors/track")) {
1419 v = GETNUM(lp->d_nsectors, tp, 1, &errstr);
1420 if (errstr) {
1421 warnx("line %d: bad %s: %s", lineno, cp, tp);
1422 errors++;
1423 } else
1424 lp->d_nsectors = v;
1425 continue;
1426 }
1427 if (!strcmp(cp, "sectors/cylinder")) {
1428 v = GETNUM(lp->d_secpercyl, tp, 1, &errstr);
1429 if (errstr) {
1430 warnx("line %d: bad %s: %s", lineno, cp, tp);
1431 errors++;
1432 } else
1433 lp->d_secpercyl = v;
1434 continue;
1435 }
1436 if (!strcmp(cp, "tracks/cylinder")) {
1437 v = GETNUM(lp->d_ntracks, tp, 1, &errstr);
1438 if (errstr) {
1439 warnx("line %d: bad %s: %s", lineno, cp, tp);
1440 errors++;
1441 } else
1442 lp->d_ntracks = v;
1443 continue;
1444 }
1445 if (!strcmp(cp, "cylinders")) {
1446 v = GETNUM(lp->d_ncylinders, tp, 1, &errstr);
1447 if (errstr) {
1448 warnx("line %d: bad %s: %s", lineno, cp, tp);
1449 errors++;
1450 } else
1451 lp->d_ncylinders = v;
1452 continue;
1453 }
1454 if (!strcmp(cp, "total sectors")) {
1455 v = GETNUM(lp->d_secperunit, tp, 1, &errstr);
1456 if (errstr) {
1457 warnx("line %d: bad %s: %s", lineno, cp, tp);
1458 errors++;
1459 } else
1460 lp->d_secperunit = v;
1461 continue;
1462 }
1463 if (!strcmp(cp, "rpm")) {
1464 v = GETNUM(lp->d_rpm, tp, 1, &errstr);
1465 if (errstr) {
1466 warnx("line %d: bad %s: %s", lineno, cp, tp);
1467 errors++;
1468 } else
1469 lp->d_rpm = v;
1470 continue;
1471 }
1472 if (!strcmp(cp, "interleave")) {
1473 v = GETNUM(lp->d_interleave, tp, 1, &errstr);
1474 if (errstr) {
1475 warnx("line %d: bad %s: %s", lineno, cp, tp);
1476 errors++;
1477 } else
1478 lp->d_interleave = v;
1479 continue;
1480 }
1481 if (!strcmp(cp, "trackskew")) {
1482 v = GETNUM(lp->d_trackskew, tp, 0, &errstr);
1483 if (errstr) {
1484 warnx("line %d: bad %s: %s", lineno, cp, tp);
1485 errors++;
1486 } else
1487 lp->d_trackskew = v;
1488 continue;
1489 }
1490 if (!strcmp(cp, "cylinderskew")) {
1491 v = GETNUM(lp->d_cylskew, tp, 0, &errstr);
1492 if (errstr) {
1493 warnx("line %d: bad %s: %s", lineno, cp, tp);
1494 errors++;
1495 } else
1496 lp->d_cylskew = v;
1497 continue;
1498 }
1499 if (!strcmp(cp, "headswitch")) {
1500 v = GETNUM(lp->d_headswitch, tp, 0, &errstr);
1501 if (errstr) {
1502 warnx("line %d: bad %s: %s", lineno, cp, tp);
1503 errors++;
1504 } else
1505 lp->d_headswitch = v;
1506 continue;
1507 }
1508 if (!strcmp(cp, "track-to-track seek")) {
1509 v = GETNUM(lp->d_trkseek, tp, 0, &errstr);
1510 if (errstr) {
1511 warnx("line %d: bad %s: %s", lineno, cp, tp);
1512 errors++;
1513 } else
1514 lp->d_trkseek = v;
1515 continue;
1516 }
1517 if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') {
1518 unsigned part = *cp - 'a';
1519
1520 if (part >= lp->d_npartitions) {
1521 if (part >= MAXPARTITIONS) {
1522 warnx("line %d: bad partition name: %s",
1523 lineno, cp);
1524 errors++;
1525 continue;
1526 } else {
1527 lp->d_npartitions = part + 1;
1528 }
1529 }
1530 pp = &lp->d_partitions[part];
1531 #define NXTNUM(n, field, errstr) { \
1532 if (tp == NULL) { \
1533 warnx("line %d: too few fields", lineno); \
1534 errors++; \
1535 break; \
1536 } else \
1537 cp = tp, tp = word(cp), (n) = GETNUM(field, cp, 0, errstr); \
1538 }
1539 NXTNUM(v, pp->p_size, &errstr);
1540 if (errstr) {
1541 warnx("line %d: bad partition size: %s",
1542 lineno, cp);
1543 errors++;
1544 } else
1545 pp->p_size = v;
1546 NXTNUM(v, pp->p_offset, &errstr);
1547 if (errstr) {
1548 warnx("line %d: bad partition offset: %s",
1549 lineno, cp);
1550 errors++;
1551 } else
1552 pp->p_offset = v;
1553 if (tp == NULL) {
1554 pp->p_fstype = FS_UNUSED;
1555 goto gottype;
1556 }
1557 cp = tp, tp = word(cp);
1558 cpp = fstypenames;
1559 for (; cpp < &fstypenames[FSMAXTYPES]; cpp++)
1560 if ((s = *cpp) && !strcasecmp(s, cp)) {
1561 pp->p_fstype = cpp - fstypenames;
1562 goto gottype;
1563 }
1564 if (isdigit(*cp))
1565 v = GETNUM(pp->p_fstype, cp, 0, &errstr);
1566 else
1567 v = FSMAXTYPES;
1568 if (errstr || v >= FSMAXTYPES) {
1569 warnx("line %d: warning, unknown filesystem type: %s",
1570 lineno, cp);
1571 v = FS_UNUSED;
1572 }
1573 pp->p_fstype = v;
1574 gottype:
1575 switch (pp->p_fstype) {
1576
1577 case FS_UNUSED: /* XXX */
1578 if (tp == NULL) /* ok to skip fsize/bsize */
1579 break;
1580 NXTNUM(pp->p_fsize, pp->p_fsize, &errstr);
1581 if (pp->p_fsize == 0)
1582 break;
1583 NXTNUM(v, v, &errstr);
1584 pp->p_frag = v / pp->p_fsize;
1585 break;
1586
1587 case FS_BSDFFS:
1588 NXTNUM(pp->p_fsize, pp->p_fsize, &errstr);
1589 if (pp->p_fsize == 0)
1590 break;
1591 NXTNUM(v, v, &errstr);
1592 pp->p_frag = v / pp->p_fsize;
1593 NXTNUM(pp->p_cpg, pp->p_cpg, &errstr);
1594 break;
1595
1596 default:
1597 break;
1598 }
1599 continue;
1600 }
1601 warnx("line %d: unknown field: %s", lineno, cp);
1602 errors++;
1603 next:
1604 ;
1605 }
1606 errors += checklabel(lp);
1607 return (errors == 0);
1608 }
1609
1610 /*
1611 * Check disklabel for errors and fill in
1612 * derived fields according to supplied values.
1613 */
1614 int
checklabel(struct disklabel * lp)1615 checklabel(struct disklabel *lp)
1616 {
1617 struct partition *pp;
1618 int i, errors = 0;
1619 char part;
1620
1621 if (lp->d_secsize == 0) {
1622 warnx("sector size %d", lp->d_secsize);
1623 return (1);
1624 }
1625 if (lp->d_nsectors == 0) {
1626 warnx("sectors/track %d", lp->d_nsectors);
1627 return (1);
1628 }
1629 if (lp->d_ntracks == 0) {
1630 warnx("tracks/cylinder %d", lp->d_ntracks);
1631 return (1);
1632 }
1633 if (lp->d_ncylinders == 0) {
1634 warnx("cylinders/unit %d", lp->d_ncylinders);
1635 errors++;
1636 }
1637 if (lp->d_rpm == 0)
1638 warnx("warning, revolutions/minute %d", lp->d_rpm);
1639 if (lp->d_secpercyl == 0)
1640 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1641 if (lp->d_secperunit == 0)
1642 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
1643 if (lp->d_bbsize == 0) {
1644 warnx("boot block size %d", lp->d_bbsize);
1645 errors++;
1646 } else if (lp->d_bbsize % lp->d_secsize)
1647 warnx("warning, boot block size %% sector-size != 0");
1648 if (lp->d_sbsize == 0) {
1649 warnx("super block size %d", lp->d_sbsize);
1650 errors++;
1651 } else if (lp->d_sbsize % lp->d_secsize)
1652 warnx("warning, super block size %% sector-size != 0");
1653 if (lp->d_npartitions > MAXPARTITIONS)
1654 warnx("warning, number of partitions (%d) > MAXPARTITIONS (%d)",
1655 lp->d_npartitions, MAXPARTITIONS);
1656 for (i = 0; i < lp->d_npartitions; i++) {
1657 part = 'a' + i;
1658 pp = &lp->d_partitions[i];
1659 if (pp->p_size == 0 && pp->p_offset != 0)
1660 warnx("warning, partition %c: size 0, but offset %d",
1661 part, pp->p_offset);
1662 #ifdef CYLCHECK
1663 if (pp->p_size % lp->d_secpercyl)
1664 warnx("warning, partition %c: size %% cylinder-size != 0",
1665 part);
1666 if (pp->p_offset % lp->d_secpercyl)
1667 warnx("warning, partition %c: offset %% cylinder-size != 0",
1668 part);
1669 #endif
1670 #ifdef AAT0
1671 if (i == 0 && pp->p_size != 0 && pp->p_offset != 0) {
1672 warnx("this architecture requires partition 'a' to "
1673 "start at sector 0");
1674 errors++;
1675 }
1676 #endif
1677 if (pp->p_offset > lp->d_secperunit) {
1678 warnx("partition %c: offset past end of unit", part);
1679 errors++;
1680 }
1681 if (pp->p_offset + pp->p_size > lp->d_secperunit) {
1682 warnx("partition %c: partition extends past end of unit",
1683 part);
1684 errors++;
1685 }
1686 if (pp->p_frag == 0 && pp->p_fsize != 0) {
1687 warnx("partition %c: block size < fragment size", part);
1688 errors++;
1689 }
1690 }
1691 for (; i < MAXPARTITIONS; i++) {
1692 part = 'a' + i;
1693 pp = &lp->d_partitions[i];
1694 if (pp->p_size || pp->p_offset)
1695 warnx("warning, unused partition %c: size %d offset %d",
1696 'a' + i, pp->p_size, pp->p_offset);
1697 }
1698 return (errors);
1699 }
1700
1701 #if NUMBOOT > 0
1702 /*
1703 * If we are installing a boot program that doesn't fit in d_bbsize
1704 * we need to mark those partitions that the boot overflows into.
1705 * This allows newfs to prevent creation of a filesystem where it might
1706 * clobber bootstrap code.
1707 */
1708 void
setbootflag(struct disklabel * lp)1709 setbootflag(struct disklabel *lp)
1710 {
1711 struct partition *pp;
1712 int i, errors = 0;
1713 u_long boffset;
1714 char part;
1715
1716 if (bootbuf == 0)
1717 return;
1718 boffset = bootsize / lp->d_secsize;
1719 for (i = 0; i < lp->d_npartitions; i++) {
1720 part = 'a' + i;
1721 pp = &lp->d_partitions[i];
1722 if (pp->p_size == 0)
1723 continue;
1724 if (boffset <= pp->p_offset) {
1725 if (pp->p_fstype == FS_BOOT)
1726 pp->p_fstype = FS_UNUSED;
1727 } else if (pp->p_fstype != FS_BOOT) {
1728 if (pp->p_fstype != FS_UNUSED) {
1729 warnx("boot overlaps used partition %c", part);
1730 errors++;
1731 } else {
1732 pp->p_fstype = FS_BOOT;
1733 warnx("warning, boot overlaps partition %c, %s",
1734 part, "marked as FS_BOOT");
1735 }
1736 }
1737 }
1738 if (errors)
1739 errx(4, "cannot install boot program");
1740 }
1741 #endif
1742
1743 int
cmplabel(struct disklabel * lp1,struct disklabel * lp2)1744 cmplabel(struct disklabel *lp1, struct disklabel *lp2)
1745 {
1746 struct disklabel lab1 = *lp1;
1747 struct disklabel lab2 = *lp2;
1748
1749 /* We don't compare these fields */
1750 lab1.d_magic = lab2.d_magic;
1751 lab1.d_magic2 = lab2.d_magic2;
1752 lab1.d_checksum = lab2.d_checksum;
1753 lab1.d_bbsize = lab2.d_bbsize;
1754 lab1.d_sbsize = lab2.d_sbsize;
1755
1756 return (memcmp(&lab1, &lab2, sizeof(struct disklabel)));
1757 }
1758
1759 void
usage(void)1760 usage(void)
1761 {
1762 char *boot = "";
1763 char blank[] = " ";
1764
1765 #if NUMBOOT == 1
1766 boot = " [-b boot1]";
1767 #elif NUMBOOT == 2
1768 boot = " [-b boot1] [-s boot2]";
1769 #endif
1770 blank[strlen(boot)] = '\0';
1771
1772 fprintf(stderr, "usage:\n");
1773 fprintf(stderr,
1774 " disklabel [-c | -d | -r | -t] [-v] [-p unit] disk\t\t(read)\n");
1775 fprintf(stderr,
1776 " disklabel -w [-c | -d | -r] [-nv] disk disktype [packid]\t(write)\n");
1777 fprintf(stderr,
1778 " disklabel -e [-c | -d | -r] [-nv] disk\t\t\t(edit)\n");
1779 fprintf(stderr,
1780 " disklabel -E [-c | -d | -r] [-nv] [-f tempfile] disk\t\t(simple editor)\n");
1781 fprintf(stderr,
1782 " disklabel -R [-nrv] disk protofile\t\t\t\t(restore)\n");
1783 fprintf(stderr,
1784 " disklabel -N | -W [-nv] disk\t\t\t\t\t(protect)\n\n");
1785 fprintf(stderr,
1786 " disklabel -B [-nv]%s disk [disktype]\t (boot)\n",
1787 boot);
1788 fprintf(stderr,
1789 " disklabel -Bw [-nv]%s disk disktype [packid] (write)\n",
1790 boot);
1791 fprintf(stderr,
1792 " disklabel -BR [-nv]%s disk protofile [disktype] (restore)\n\n",
1793 boot);
1794 fprintf(stderr,
1795 "'disk' may be of the form: sd0 or /dev/rsd0%c.\n", 'a'+RAW_PART);
1796 fprintf(stderr,
1797 "'disktype' is an entry from %s, see disktab(5) for more info.\n",
1798 DISKTAB);
1799 fprintf(stderr,
1800 "'packid' is an identification string for the device.\n");
1801 fprintf(stderr,
1802 "'protofile' is the output from the read cmd form; -R is powerful.\n");
1803 #ifdef SEEALSO
1804 fprintf(stderr,
1805 "For procedures specific to this architecture see: %s\n", SEEALSO);
1806 #endif
1807 exit(1);
1808 }
1809