disklabel32/64: Add support for 'T' size specifier.
[dragonfly.git] / sbin / disklabel32 / disklabel.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1987, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Symmetric Computer Systems.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
1de703da
MD
35 *
36 * @(#) Copyright (c) 1987, 1993 The Regents of the University of California. All rights reserved.
37 * @(#)disklabel.c 1.2 (Symmetric) 11/28/85
38 * @(#)disklabel.c 8.2 (Berkeley) 1/7/94
39 * $FreeBSD: src/sbin/disklabel/disklabel.c,v 1.28.2.15 2003/01/24 16:18:16 des Exp $
984263bc
MD
40 */
41
984263bc
MD
42#include <sys/param.h>
43#include <sys/file.h>
44#include <sys/stat.h>
45#include <sys/wait.h>
46#define DKTYPENAMES
2b961883
MD
47#include <sys/disklabel32.h>
48#include <sys/disklabel64.h>
595e3440 49#include <sys/diskslice.h>
6af3b87d 50#include <sys/diskmbr.h>
ba0cc1ab 51#include <sys/dtype.h>
2b961883 52#include <sys/sysctl.h>
e5d03018 53#include <disktab.h>
d736a600 54#include <fstab.h>
67ad9090
MD
55
56#include <vfs/ufs/dinode.h>
38a690d7 57#include <vfs/ufs/fs.h>
67ad9090 58
984263bc
MD
59#include <unistd.h>
60#include <string.h>
61#include <stdio.h>
62#include <stdlib.h>
63#include <signal.h>
64#include <stdarg.h>
65#include <ctype.h>
66#include <err.h>
67#include <errno.h>
68#include "pathnames.h"
69
70/*
c61a095d 71 * Disklabel32: read and write 32 bit disklabels.
984263bc
MD
72 * The label is usually placed on one of the first sectors of the disk.
73 * Many machines also place a bootstrap in the same area,
74 * in which case the label is embedded in the bootstrap.
75 * The bootstrap source must leave space at the proper offset
76 * for the label on such machines.
77 */
78
79#ifndef BBSIZE
80#define BBSIZE 8192 /* size of boot area, with label */
81#endif
82
83/* FIX! These are too low, but are traditional */
84#define DEFAULT_NEWFS_BLOCK 8192U
85#define DEFAULT_NEWFS_FRAG 1024U
86#define DEFAULT_NEWFS_CPG 16U
87
88#define BIG_NEWFS_BLOCK 16384U
89#define BIG_NEWFS_FRAG 2048U
90#define BIG_NEWFS_CPG 64U
91
984263bc 92#define NUMBOOT 2
984263bc 93
2b961883
MD
94void makelabel(const char *, const char *, struct disklabel32 *);
95int writelabel(int, const char *, struct disklabel32 *);
984263bc 96void l_perror(const char *);
2b961883
MD
97struct disklabel32 *readlabel(int);
98struct disklabel32 *makebootarea(char *, struct disklabel32 *, int);
99void display(FILE *, const struct disklabel32 *);
100int edit(struct disklabel32 *, int);
984263bc
MD
101int editit(void);
102char *skip(char *);
103char *word(char *);
2b961883
MD
104int getasciilabel(FILE *, struct disklabel32 *);
105int getasciipartspec(char *, struct disklabel32 *, int, int);
106int checklabel(struct disklabel32 *);
107void setbootflag(struct disklabel32 *);
984263bc
MD
108void Warning(const char *, ...) __printflike(1, 2);
109void usage(void);
93217a19 110int checkoldboot(int, const char *);
2b961883
MD
111const char *fixlabel(int, struct disklabel32 *, int);
112struct disklabel32 *getvirginlabel(void);
113struct disklabel32 *getdisklabelfromdisktab(const char *name);
984263bc
MD
114
115#define DEFEDITOR _PATH_VI
116#define streq(a,b) (strcmp(a,b) == 0)
117
118char *dkname;
119char *specname;
120char tmpfil[] = PATH_TMPFILE;
121
d736a600 122char namebuf[BBSIZE];
2b961883 123struct disklabel32 lab;
984263bc
MD
124char bootarea[BBSIZE];
125
126#define MAX_PART ('z')
127#define MAX_NUM_PARTS (1 + MAX_PART - 'a')
128char part_size_type[MAX_NUM_PARTS];
129char part_offset_type[MAX_NUM_PARTS];
130int part_set[MAX_NUM_PARTS];
131
132#if NUMBOOT > 0
133int installboot; /* non-zero if we should install a boot program */
134char *bootbuf; /* pointer to buffer with remainder of boot prog */
135int bootsize; /* size of remaining boot program */
136char *xxboot; /* primary boot */
137char *bootxx; /* secondary boot */
138char boot0[MAXPATHLEN];
139char boot1[MAXPATHLEN];
140#endif
141
142enum {
143 UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT
144} op = UNSPEC;
145
146int rflag;
147int disable_write; /* set to disable writing to disk label */
2b961883
MD
148int forceflag;
149u_int32_t slice_start_lba;
984263bc
MD
150
151#ifdef DEBUG
152int debug;
2b961883 153#define OPTIONS "BNRWb:def:nrs:w"
984263bc 154#else
2b961883 155#define OPTIONS "BNRWb:ef:nrs:w"
984263bc
MD
156#endif
157
158int
159main(int argc, char *argv[])
160{
2b961883 161 struct disklabel32 *lp;
984263bc
MD
162 FILE *t;
163 int ch, f = 0, flag, error = 0;
678e8cc6 164 char *name = NULL;
984263bc
MD
165
166 while ((ch = getopt(argc, argv, OPTIONS)) != -1)
167 switch (ch) {
168#if NUMBOOT > 0
169 case 'B':
170 ++installboot;
171 break;
172 case 'b':
173 xxboot = optarg;
174 break;
2b961883
MD
175
176 case 'f':
177 forceflag = 1;
178 slice_start_lba = strtoul(optarg, NULL, 0);
179 break;
984263bc
MD
180#if NUMBOOT > 1
181 case 's':
182 bootxx = optarg;
183 break;
184#endif
185#endif
186 case 'N':
187 if (op != UNSPEC)
188 usage();
189 op = NOWRITE;
190 break;
191 case 'n':
192 disable_write = 1;
193 break;
194 case 'R':
195 if (op != UNSPEC)
196 usage();
197 op = RESTORE;
198 break;
199 case 'W':
200 if (op != UNSPEC)
201 usage();
202 op = WRITEABLE;
203 break;
204 case 'e':
205 if (op != UNSPEC)
206 usage();
207 op = EDIT;
208 break;
209 case 'r':
210 ++rflag;
211 break;
212 case 'w':
213 if (op != UNSPEC)
214 usage();
215 op = WRITE;
216 break;
217#ifdef DEBUG
218 case 'd':
219 debug++;
220 break;
221#endif
222 case '?':
223 default:
224 usage();
225 }
226 argc -= optind;
227 argv += optind;
228#if NUMBOOT > 0
229 if (installboot) {
230 rflag++;
231 if (op == UNSPEC)
232 op = WRITEBOOT;
233 } else {
234 if (op == UNSPEC)
235 op = READ;
678e8cc6 236 xxboot = bootxx = NULL;
984263bc
MD
237 }
238#else
239 if (op == UNSPEC)
240 op = READ;
241#endif
242 if (argc < 1)
243 usage();
244
d736a600
MD
245 dkname = getdevpath(argv[0], 0);
246 specname = dkname;
984263bc 247 f = open(specname, op == READ ? O_RDONLY : O_RDWR);
984263bc
MD
248 if (f < 0)
249 err(4, "%s", specname);
250
251 switch(op) {
252
253 case UNSPEC:
254 break;
255
256 case EDIT:
257 if (argc != 1)
258 usage();
259 lp = readlabel(f);
260 error = edit(lp, f);
261 break;
262
263 case NOWRITE:
264 flag = 0;
265 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
266 err(4, "ioctl DIOCWLABEL");
267 break;
268
269 case READ:
270 if (argc != 1)
271 usage();
272 lp = readlabel(f);
273 display(stdout, lp);
274 error = checklabel(lp);
9e792b7e
MD
275 if (checkoldboot(f, NULL))
276 warnx("Warning, old bootblocks detected, install new bootblocks & reinstall the disklabel");
984263bc
MD
277 break;
278
279 case RESTORE:
280#if NUMBOOT > 0
281 if (installboot && argc == 3) {
282 makelabel(argv[2], 0, &lab);
283 argc--;
284
285 /*
286 * We only called makelabel() for its side effect
287 * of setting the bootstrap file names. Discard
288 * all changes to `lab' so that all values in the
289 * final label come from the ASCII label.
290 */
291 bzero((char *)&lab, sizeof(lab));
292 }
293#endif
294 if (argc != 2)
295 usage();
296 if (!(t = fopen(argv[1], "r")))
297 err(4, "%s", argv[1]);
298 if (!getasciilabel(t, &lab))
299 exit(1);
300 lp = makebootarea(bootarea, &lab, f);
301 *lp = lab;
302 error = writelabel(f, bootarea, lp);
303 break;
304
305 case WRITE:
306 if (argc == 3) {
307 name = argv[2];
308 argc--;
309 }
310 if (argc != 2)
311 usage();
312 makelabel(argv[1], name, &lab);
313 lp = makebootarea(bootarea, &lab, f);
314 *lp = lab;
315 if (checklabel(lp) == 0)
316 error = writelabel(f, bootarea, lp);
317 break;
318
319 case WRITEABLE:
320 flag = 1;
321 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
322 err(4, "ioctl DIOCWLABEL");
323 break;
324
325#if NUMBOOT > 0
326 case WRITEBOOT:
327 {
2b961883 328 struct disklabel32 tlab;
984263bc
MD
329
330 lp = readlabel(f);
331 tlab = *lp;
332 if (argc == 2)
333 makelabel(argv[1], 0, &lab);
334 lp = makebootarea(bootarea, &lab, f);
335 *lp = tlab;
336 if (checklabel(lp) == 0)
337 error = writelabel(f, bootarea, lp);
338 break;
339 }
340#endif
341 }
342 exit(error);
343}
344
345/*
346 * Construct a prototype disklabel from /etc/disktab. As a side
347 * effect, set the names of the primary and secondary boot files
348 * if specified.
349 */
350void
2b961883 351makelabel(const char *type, const char *name, struct disklabel32 *lp)
984263bc 352{
2b961883 353 struct disklabel32 *dp;
984263bc
MD
354
355 if (strcmp(type, "auto") == 0)
356 dp = getvirginlabel();
357 else
e5d03018 358 dp = getdisklabelfromdisktab(type);
984263bc
MD
359 if (dp == NULL)
360 errx(1, "%s: unknown disk type", type);
361 *lp = *dp;
e5d03018 362
984263bc 363 /*
e5d03018 364 * NOTE: boot control files may no longer be specified in disktab.
984263bc 365 */
984263bc 366 if (name)
7cee7052 367 strncpy(lp->d_packname, name, sizeof(lp->d_packname));
984263bc
MD
368}
369
370int
2b961883 371writelabel(int f, const char *boot, struct disklabel32 *lp)
984263bc 372{
2b961883 373 const char *msg;
984263bc 374 int flag;
1c3c151b 375 int r;
984263bc
MD
376
377 if (disable_write) {
0ca0cd25 378 Warning("write to disk label suppressed - label was as follows:");
984263bc
MD
379 display(stdout, lp);
380 return (0);
381 } else {
9e792b7e
MD
382 /* make sure we are not overwriting our boot code */
383 if (checkoldboot(f, boot))
384 errx(4, "Will not overwrite old bootblocks w/ label, install new boot blocks first!");
984263bc 385 setbootflag(lp);
2b961883
MD
386 lp->d_magic = DISKMAGIC32;
387 lp->d_magic2 = DISKMAGIC32;
984263bc 388 lp->d_checksum = 0;
2b961883 389 lp->d_checksum = dkcksum32(lp);
984263bc
MD
390 if (rflag) {
391 /*
392 * First set the kernel disk label,
393 * then write a label to the raw disk.
394 * If the SDINFO ioctl fails because it is unimplemented,
395 * keep going; otherwise, the kernel consistency checks
396 * may prevent us from changing the current (in-core)
397 * label.
398 */
2b961883 399 if (ioctl(f, DIOCSDINFO32, lp) < 0 &&
984263bc 400 errno != ENODEV && errno != ENOTTY) {
0ffe40b3 401 l_perror("ioctl DIOCSDINFO32");
984263bc
MD
402 return (1);
403 }
7cee7052 404 lseek(f, (off_t)0, SEEK_SET);
ce19f97e 405
984263bc 406 /*
1c3c151b
MD
407 * write enable label sector before write
408 * (if necessary), disable after writing.
984263bc
MD
409 */
410 flag = 1;
411 if (ioctl(f, DIOCWLABEL, &flag) < 0)
412 warn("ioctl DIOCWLABEL");
2b961883
MD
413 msg = fixlabel(f, lp, 1);
414 if (msg) {
415 warn(msg);
416 return (1);
417 }
1c3c151b 418 r = write(f, boot, lp->d_bbsize);
2b961883 419 fixlabel(f, lp, 0);
1c3c151b 420 if (r != ((ssize_t)lp->d_bbsize)) {
984263bc
MD
421 warn("write");
422 return (1);
423 }
424#if NUMBOOT > 0
425 /*
426 * Output the remainder of the disklabel
427 */
1c3c151b 428 if (bootbuf) {
2b961883 429 fixlabel(f, lp, 1);
1c3c151b 430 r = write(f, bootbuf, bootsize);
2b961883 431 fixlabel(f, lp, 0);
1c3c151b
MD
432 if (r != bootsize) {
433 warn("write");
434 return(1);
435 }
984263bc
MD
436 }
437#endif
438 flag = 0;
7cee7052 439 ioctl(f, DIOCWLABEL, &flag);
2b961883 440 } else if (ioctl(f, DIOCWDINFO32, lp) < 0) {
0ffe40b3 441 l_perror("ioctl DIOCWDINFO32");
984263bc
MD
442 return (1);
443 }
984263bc
MD
444 }
445 return (0);
446}
447
448void
449l_perror(const char *s)
450{
451 switch (errno) {
452
453 case ESRCH:
454 warnx("%s: no disk label on disk;", s);
455 fprintf(stderr, "add \"-r\" to install initial label\n");
456 break;
457
458 case EINVAL:
459 warnx("%s: label magic number or checksum is wrong!", s);
460 fprintf(stderr, "(disklabel or kernel is out of date?)\n");
461 break;
462
463 case EBUSY:
464 warnx("%s: open partition would move or shrink", s);
465 break;
466
467 case EXDEV:
468 warnx("%s: '%c' partition must start at beginning of disk",
469 s, 'a' + RAW_PART);
470 break;
471
0ffe40b3
MD
472 case ENOATTR:
473 warnx("%s: the disk already has a label of a different type,\n"
474 "probably a 64 bit disklabel. It must be cleaned out "
475 "first.\n", s);
476 break;
477
984263bc 478 default:
2038fb68 479 warn(NULL);
984263bc
MD
480 break;
481 }
482}
483
484/*
485 * Fetch disklabel for disk.
486 * Use ioctl to get label unless -r flag is given.
487 */
2b961883 488struct disklabel32 *
984263bc
MD
489readlabel(int f)
490{
2b961883
MD
491 const char *msg;
492 struct disklabel32 *lp;
1c3c151b 493 int r;
984263bc
MD
494
495 if (rflag) {
1c3c151b 496 r = read(f, bootarea, BBSIZE);
1c3c151b 497 if (r < BBSIZE)
984263bc 498 err(4, "%s", specname);
2b961883
MD
499 for (lp = (struct disklabel32 *)bootarea;
500 lp <= (struct disklabel32 *)(bootarea + BBSIZE - sizeof(*lp));
501 lp = (struct disklabel32 *)((char *)lp + 16)) {
502 if (lp->d_magic == DISKMAGIC32 &&
503 lp->d_magic2 == DISKMAGIC32)
984263bc 504 break;
2b961883
MD
505 }
506 if (lp > (struct disklabel32 *)(bootarea+BBSIZE-sizeof(*lp)) ||
507 lp->d_magic != DISKMAGIC32 || lp->d_magic2 != DISKMAGIC32 ||
508 dkcksum32(lp) != 0) {
509 errx(1, "bad pack magic number (label is damaged, "
510 "or pack is unlabeled)");
511 }
512 if ((msg = fixlabel(f, lp, 0)) != NULL)
513 errx(1, msg);
984263bc
MD
514 } else {
515 lp = &lab;
0ffe40b3
MD
516 if (ioctl(f, DIOCGDINFO32, lp) < 0) {
517 l_perror("ioctl DIOCGDINFO32");
518 exit(4);
519 }
984263bc
MD
520 }
521 return (lp);
522}
523
524/*
525 * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot''
526 * Returns a pointer to the disklabel portion of the bootarea.
527 */
2b961883
MD
528struct disklabel32 *
529makebootarea(char *boot, struct disklabel32 *dp, int f)
984263bc 530{
2b961883 531 struct disklabel32 *lp;
984263bc
MD
532 char *p;
533 int b;
534#if NUMBOOT > 0
984263bc
MD
535 struct stat sb;
536#endif
984263bc
MD
537#ifdef __i386__
538 char *tmpbuf;
93217a19 539 unsigned int i, found;
984263bc
MD
540#endif
541
542 /* XXX */
543 if (dp->d_secsize == 0) {
544 dp->d_secsize = DEV_BSIZE;
545 dp->d_bbsize = BBSIZE;
546 }
2b961883
MD
547 lp = (struct disklabel32 *)
548 (boot + (LABELSECTOR32 * dp->d_secsize) + LABELOFFSET32);
984263bc
MD
549 bzero((char *)lp, sizeof *lp);
550#if NUMBOOT > 0
551 /*
552 * If we are not installing a boot program but we are installing a
553 * label on disk then we must read the current bootarea so we don't
554 * clobber the existing boot.
555 */
556 if (!installboot) {
557 if (rflag) {
558 if (read(f, boot, BBSIZE) < BBSIZE)
559 err(4, "%s", specname);
560 bzero((char *)lp, sizeof *lp);
561 }
562 return (lp);
563 }
564 /*
565 * We are installing a boot program. Determine the name(s) and
566 * read them into the appropriate places in the boot area.
567 */
568 if (!xxboot || !bootxx) {
984263bc 569 if (!xxboot) {
7cee7052 570 sprintf(boot0, "%s/boot1", _PATH_BOOTDIR);
984263bc
MD
571 xxboot = boot0;
572 }
573#if NUMBOOT > 1
574 if (!bootxx) {
7cee7052 575 sprintf(boot1, "%s/boot2", _PATH_BOOTDIR);
984263bc
MD
576 bootxx = boot1;
577 }
578#endif
579 }
580#ifdef DEBUG
581 if (debug)
582 fprintf(stderr, "bootstraps: xxboot = %s, bootxx = %s\n",
583 xxboot, bootxx ? bootxx : "NONE");
584#endif
585
586 /*
587 * Strange rules:
588 * 1. One-piece bootstrap (hp300/hp800)
589 * up to d_bbsize bytes of ``xxboot'' go in bootarea, the rest
590 * is remembered and written later following the bootarea.
591 * 2. Two-piece bootstraps (vax/i386?/mips?)
592 * up to d_secsize bytes of ``xxboot'' go in first d_secsize
593 * bytes of bootarea, remaining d_bbsize-d_secsize filled
594 * from ``bootxx''.
595 */
596 b = open(xxboot, O_RDONLY);
597 if (b < 0)
598 err(4, "%s", xxboot);
599#if NUMBOOT > 1
600#ifdef __i386__
601 /*
602 * XXX Botch alert.
603 * The i386 has the so-called fdisk table embedded into the
604 * primary bootstrap. We take care to not clobber it, but
605 * only if it does already contain some data. (Otherwise,
606 * the xxboot provides a template.)
607 */
678e8cc6 608 if ((tmpbuf = (char *)malloc((int)dp->d_secsize)) == NULL)
984263bc
MD
609 err(4, "%s", xxboot);
610 memcpy((void *)tmpbuf, (void *)boot, (int)dp->d_secsize);
611#endif /* i386 */
612 if (read(b, boot, (int)dp->d_secsize) < 0)
613 err(4, "%s", xxboot);
7cee7052 614 close(b);
984263bc
MD
615#ifdef __i386__
616 for (i = DOSPARTOFF, found = 0;
617 !found && i < DOSPARTOFF + NDOSPART*sizeof(struct dos_partition);
618 i++)
619 found = tmpbuf[i] != 0;
620 if (found)
621 memcpy((void *)&boot[DOSPARTOFF],
622 (void *)&tmpbuf[DOSPARTOFF],
623 NDOSPART * sizeof(struct dos_partition));
624 free(tmpbuf);
625#endif /* i386 */
626 b = open(bootxx, O_RDONLY);
627 if (b < 0)
628 err(4, "%s", bootxx);
629 if (fstat(b, &sb) != 0)
630 err(4, "%s", bootxx);
631 if (dp->d_secsize + sb.st_size > dp->d_bbsize)
632 errx(4, "%s too large", bootxx);
633 if (read(b, &boot[dp->d_secsize],
634 (int)(dp->d_bbsize-dp->d_secsize)) < 0)
635 err(4, "%s", bootxx);
636#else /* !(NUMBOOT > 1) */
984263bc
MD
637 if (read(b, boot, (int)dp->d_bbsize) < 0)
638 err(4, "%s", xxboot);
984263bc
MD
639 if (fstat(b, &sb) != 0)
640 err(4, "%s", xxboot);
641 bootsize = (int)sb.st_size - dp->d_bbsize;
642 if (bootsize > 0) {
643 /* XXX assume d_secsize is a power of two */
644 bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1);
645 bootbuf = (char *)malloc((size_t)bootsize);
678e8cc6 646 if (bootbuf == NULL)
984263bc
MD
647 err(4, "%s", xxboot);
648 if (read(b, bootbuf, bootsize) < 0) {
649 free(bootbuf);
650 err(4, "%s", xxboot);
651 }
652 }
653#endif /* NUMBOOT > 1 */
7cee7052 654 close(b);
984263bc
MD
655#endif /* NUMBOOT > 0 */
656 /*
657 * Make sure no part of the bootstrap is written in the area
658 * reserved for the label.
659 */
2b961883 660 for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel32); p++)
984263bc
MD
661 if (*p)
662 errx(2, "bootstrap doesn't leave room for disk label");
663 return (lp);
664}
665
666void
2b961883 667display(FILE *f, const struct disklabel32 *lp)
984263bc
MD
668{
669 int i, j;
2b961883 670 const struct partition32 *pp;
984263bc
MD
671
672 fprintf(f, "# %s:\n", specname);
673 if (lp->d_type < DKMAXTYPES)
674 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
675 else
676 fprintf(f, "type: %u\n", lp->d_type);
677 fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
678 lp->d_typename);
679 fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
680 lp->d_packname);
681 fprintf(f, "flags:");
984263bc
MD
682 fprintf(f, "\n");
683 fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
684 fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
685 fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
686 fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
687 fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
688 fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
689 fprintf(f, "rpm: %u\n", lp->d_rpm);
690 fprintf(f, "interleave: %u\n", lp->d_interleave);
691 fprintf(f, "trackskew: %u\n", lp->d_trackskew);
692 fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
693 fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
694 (u_long)lp->d_headswitch);
695 fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
696 (u_long)lp->d_trkseek);
697 fprintf(f, "drivedata: ");
2b961883 698 for (i = NDDATA32 - 1; i >= 0; i--) {
984263bc
MD
699 if (lp->d_drivedata[i])
700 break;
cc1ce052 701 }
984263bc
MD
702 if (i < 0)
703 i = 0;
704 for (j = 0; j <= i; j++)
705 fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
706 fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
707 fprintf(f,
cbefee19 708 "# size offset fstype\n");
984263bc
MD
709 pp = lp->d_partitions;
710 for (i = 0; i < lp->d_npartitions; i++, pp++) {
711 if (pp->p_size) {
cc1ce052
MD
712 u_long onemeg = 1024 * 1024 / lp->d_secsize;
713 fprintf(f, " %c: ", 'a' + i);
714
715 fprintf(f, "%10lu ", (u_long)pp->p_size);
716 fprintf(f, "%10lu ", (u_long)pp->p_offset);
984263bc
MD
717 if (pp->p_fstype < FSMAXTYPES)
718 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
719 else
720 fprintf(f, "%8d", pp->p_fstype);
984263bc 721
58635e07 722 fprintf(f, "\t# %11.3fMB", (double)pp->p_size / onemeg);
cc1ce052 723 fprintf(f, "\n");
984263bc
MD
724 }
725 }
726 fflush(f);
727}
728
729int
2b961883 730edit(struct disklabel32 *lp, int f)
984263bc
MD
731{
732 int c, fd;
2b961883 733 struct disklabel32 label;
984263bc
MD
734 FILE *fp;
735
736 if ((fd = mkstemp(tmpfil)) == -1 ||
737 (fp = fdopen(fd, "w")) == NULL) {
738 warnx("can't create %s", tmpfil);
739 return (1);
740 }
741 display(fp, lp);
742 fclose(fp);
743 for (;;) {
744 if (!editit())
745 break;
746 fp = fopen(tmpfil, "r");
747 if (fp == NULL) {
748 warnx("can't reopen %s for reading", tmpfil);
749 break;
750 }
751 bzero((char *)&label, sizeof(label));
752 if (getasciilabel(fp, &label)) {
753 *lp = label;
754 if (writelabel(f, bootarea, lp) == 0) {
755 fclose(fp);
7cee7052 756 unlink(tmpfil);
984263bc
MD
757 return (0);
758 }
759 }
760 fclose(fp);
761 printf("re-edit the label? [y]: "); fflush(stdout);
762 c = getchar();
763 if (c != EOF && c != (int)'\n')
764 while (getchar() != (int)'\n')
765 ;
766 if (c == (int)'n')
767 break;
768 }
7cee7052 769 unlink(tmpfil);
984263bc
MD
770 return (1);
771}
772
773int
774editit(void)
775{
776 int pid, xpid;
93217a19
PA
777 int status, omask;
778 const char *ed;
984263bc
MD
779
780 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
781 while ((pid = fork()) < 0) {
782 if (errno == EPROCLIM) {
783 warnx("you have too many processes");
784 return(0);
785 }
786 if (errno != EAGAIN) {
787 warn("fork");
788 return(0);
789 }
790 sleep(1);
791 }
792 if (pid == 0) {
793 sigsetmask(omask);
794 setgid(getgid());
795 setuid(getuid());
60233e58 796 if ((ed = getenv("EDITOR")) == NULL)
984263bc 797 ed = DEFEDITOR;
60233e58 798 execlp(ed, ed, tmpfil, NULL);
984263bc
MD
799 err(1, "%s", ed);
800 }
93217a19 801 while ((xpid = wait(&status)) >= 0)
984263bc
MD
802 if (xpid == pid)
803 break;
804 sigsetmask(omask);
93217a19 805 return(!status);
984263bc
MD
806}
807
808char *
809skip(char *cp)
810{
811
812 while (*cp != '\0' && isspace(*cp))
813 cp++;
814 if (*cp == '\0' || *cp == '#')
815 return (NULL);
816 return (cp);
817}
818
819char *
820word(char *cp)
821{
822 char c;
823
824 while (*cp != '\0' && !isspace(*cp) && *cp != '#')
825 cp++;
826 if ((c = *cp) != '\0') {
827 *cp++ = '\0';
828 if (c != '#')
829 return (skip(cp));
830 }
831 return (NULL);
832}
833
834/*
835 * Read an ascii label in from fd f,
836 * in the same format as that put out by display(),
837 * and fill in lp.
838 */
839int
2b961883 840getasciilabel(FILE *f, struct disklabel32 *lp)
984263bc
MD
841{
842 char *cp;
89671a80 843 const char **cpp;
984263bc
MD
844 u_int part;
845 char *tp, line[BUFSIZ];
846 u_long v;
847 int lineno = 0, errors = 0;
848 int i;
93217a19
PA
849 char empty[] = "";
850 char unknown[] = "unknown";
984263bc
MD
851
852 bzero(&part_set, sizeof(part_set));
853 bzero(&part_size_type, sizeof(part_size_type));
854 bzero(&part_offset_type, sizeof(part_offset_type));
855 lp->d_bbsize = BBSIZE; /* XXX */
856 lp->d_sbsize = SBSIZE; /* XXX */
857 while (fgets(line, sizeof(line) - 1, f)) {
858 lineno++;
678e8cc6 859 if ((cp = strchr(line,'\n')) != NULL)
984263bc
MD
860 *cp = '\0';
861 cp = skip(line);
862 if (cp == NULL)
863 continue;
17b61719 864 tp = strchr(cp, ':');
984263bc
MD
865 if (tp == NULL) {
866 fprintf(stderr, "line %d: syntax error\n", lineno);
867 errors++;
868 continue;
869 }
870 *tp++ = '\0', tp = skip(tp);
871 if (streq(cp, "type")) {
872 if (tp == NULL)
93217a19 873 tp = unknown;
984263bc 874 cpp = dktypenames;
cc1ce052 875 for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) {
a8de4644 876 if (*cpp && strcasecmp(*cpp, tp) == 0) {
984263bc
MD
877 lp->d_type = cpp - dktypenames;
878 break;
879 }
cc1ce052 880 }
984263bc
MD
881 if (cpp < &dktypenames[DKMAXTYPES])
882 continue;
883 v = strtoul(tp, NULL, 10);
cc1ce052 884 if (v >= DKMAXTYPES) {
984263bc
MD
885 fprintf(stderr, "line %d:%s %lu\n", lineno,
886 "Warning, unknown disk type", v);
cc1ce052 887 }
984263bc
MD
888 lp->d_type = v;
889 continue;
890 }
891 if (streq(cp, "flags")) {
892 for (v = 0; (cp = tp) && *cp != '\0';) {
893 tp = word(cp);
894 if (streq(cp, "removeable"))
656d6a69 895 v |= 0; /* obsolete */
984263bc 896 else if (streq(cp, "ecc"))
656d6a69 897 v |= 0; /* obsolete */
984263bc 898 else if (streq(cp, "badsect"))
656d6a69 899 v |= 0; /* obsolete */
984263bc
MD
900 else {
901 fprintf(stderr,
902 "line %d: %s: bad flag\n",
903 lineno, cp);
904 errors++;
905 }
906 }
907 lp->d_flags = v;
908 continue;
909 }
910 if (streq(cp, "drivedata")) {
2b961883 911 for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA32;) {
984263bc
MD
912 lp->d_drivedata[i++] = strtoul(cp, NULL, 10);
913 tp = word(cp);
914 }
915 continue;
916 }
917 if (sscanf(cp, "%lu partitions", &v) == 1) {
2b961883 918 if (v == 0 || v > MAXPARTITIONS32) {
984263bc
MD
919 fprintf(stderr,
920 "line %d: bad # of partitions\n", lineno);
2b961883 921 lp->d_npartitions = MAXPARTITIONS32;
984263bc
MD
922 errors++;
923 } else
924 lp->d_npartitions = v;
925 continue;
926 }
927 if (tp == NULL)
93217a19 928 tp = empty;
984263bc
MD
929 if (streq(cp, "disk")) {
930 strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
931 continue;
932 }
933 if (streq(cp, "label")) {
934 strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
935 continue;
936 }
937 if (streq(cp, "bytes/sector")) {
938 v = strtoul(tp, NULL, 10);
939 if (v == 0 || (v % DEV_BSIZE) != 0) {
940 fprintf(stderr,
941 "line %d: %s: bad sector size\n",
942 lineno, tp);
943 errors++;
944 } else
945 lp->d_secsize = v;
946 continue;
947 }
948 if (streq(cp, "sectors/track")) {
949 v = strtoul(tp, NULL, 10);
950#if (ULONG_MAX != 0xffffffffUL)
951 if (v == 0 || v > 0xffffffff) {
952#else
953 if (v == 0) {
954#endif
955 fprintf(stderr, "line %d: %s: bad %s\n",
956 lineno, tp, cp);
957 errors++;
958 } else
959 lp->d_nsectors = v;
960 continue;
961 }
962 if (streq(cp, "sectors/cylinder")) {
963 v = strtoul(tp, NULL, 10);
964 if (v == 0) {
965 fprintf(stderr, "line %d: %s: bad %s\n",
966 lineno, tp, cp);
967 errors++;
968 } else
969 lp->d_secpercyl = v;
970 continue;
971 }
972 if (streq(cp, "tracks/cylinder")) {
973 v = strtoul(tp, NULL, 10);
974 if (v == 0) {
975 fprintf(stderr, "line %d: %s: bad %s\n",
976 lineno, tp, cp);
977 errors++;
978 } else
979 lp->d_ntracks = v;
980 continue;
981 }
982 if (streq(cp, "cylinders")) {
983 v = strtoul(tp, NULL, 10);
984 if (v == 0) {
985 fprintf(stderr, "line %d: %s: bad %s\n",
986 lineno, tp, cp);
987 errors++;
988 } else
989 lp->d_ncylinders = v;
990 continue;
991 }
992 if (streq(cp, "sectors/unit")) {
993 v = strtoul(tp, NULL, 10);
994 if (v == 0) {
995 fprintf(stderr, "line %d: %s: bad %s\n",
996 lineno, tp, cp);
997 errors++;
998 } else
999 lp->d_secperunit = v;
1000 continue;
1001 }
1002 if (streq(cp, "rpm")) {
1003 v = strtoul(tp, NULL, 10);
1004 if (v == 0 || v > USHRT_MAX) {
1005 fprintf(stderr, "line %d: %s: bad %s\n",
1006 lineno, tp, cp);
1007 errors++;
1008 } else
1009 lp->d_rpm = v;
1010 continue;
1011 }
1012 if (streq(cp, "interleave")) {
1013 v = strtoul(tp, NULL, 10);
1014 if (v == 0 || v > USHRT_MAX) {
1015 fprintf(stderr, "line %d: %s: bad %s\n",
1016 lineno, tp, cp);
1017 errors++;
1018 } else
1019 lp->d_interleave = v;
1020 continue;
1021 }
1022 if (streq(cp, "trackskew")) {
1023 v = strtoul(tp, NULL, 10);
1024 if (v > USHRT_MAX) {
1025 fprintf(stderr, "line %d: %s: bad %s\n",
1026 lineno, tp, cp);
1027 errors++;
1028 } else
1029 lp->d_trackskew = v;
1030 continue;
1031 }
1032 if (streq(cp, "cylinderskew")) {
1033 v = strtoul(tp, NULL, 10);
1034 if (v > USHRT_MAX) {
1035 fprintf(stderr, "line %d: %s: bad %s\n",
1036 lineno, tp, cp);
1037 errors++;
1038 } else
1039 lp->d_cylskew = v;
1040 continue;
1041 }
1042 if (streq(cp, "headswitch")) {
1043 v = strtoul(tp, NULL, 10);
1044 lp->d_headswitch = v;
1045 continue;
1046 }
1047 if (streq(cp, "track-to-track seek")) {
1048 v = strtoul(tp, NULL, 10);
1049 lp->d_trkseek = v;
1050 continue;
1051 }
1052 /* the ':' was removed above */
1053 if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') {
1054 fprintf(stderr,
1055 "line %d: %s: Unknown disklabel field\n", lineno,
1056 cp);
1057 errors++;
1058 continue;
1059 }
1060
1061 /* Process a partition specification line. */
1062 part = *cp - 'a';
1063 if (part >= lp->d_npartitions) {
1064 fprintf(stderr,
1065 "line %d: partition name out of range a-%c: %s\n",
1066 lineno, 'a' + lp->d_npartitions - 1, cp);
1067 errors++;
1068 continue;
1069 }
1070 part_set[part] = 1;
1071
1072 if (getasciipartspec(tp, lp, part, lineno) != 0) {
1073 errors++;
1074 break;
1075 }
1076 }
1077 errors += checklabel(lp);
1078 return (errors == 0);
1079}
1080
1081#define NXTNUM(n) do { \
1082 if (tp == NULL) { \
1083 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
1084 return (1); \
1085 } else { \
1086 cp = tp, tp = word(cp); \
1087 (n) = strtoul(cp, NULL, 10); \
1088 } \
1089} while (0)
1090
1091/* retain 1 character following number */
1092#define NXTWORD(w,n) do { \
1093 if (tp == NULL) { \
1094 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
1095 return (1); \
1096 } else { \
1097 char *tmp; \
1098 cp = tp, tp = word(cp); \
1099 (n) = strtoul(cp, &tmp, 10); \
1100 if (tmp) (w) = *tmp; \
1101 } \
1102} while (0)
1103
1104/*
1105 * Read a partition line into partition `part' in the specified disklabel.
1106 * Return 0 on success, 1 on failure.
1107 */
1108int
2b961883 1109getasciipartspec(char *tp, struct disklabel32 *lp, int part, int lineno)
984263bc 1110{
2b961883 1111 struct partition32 *pp;
984263bc 1112 char *cp;
4e7535c7 1113 const char **cpp;
984263bc
MD
1114 u_long v;
1115
1116 pp = &lp->d_partitions[part];
1117 cp = NULL;
1118
cc1ce052
MD
1119 /*
1120 * size
1121 */
984263bc
MD
1122 v = 0;
1123 NXTWORD(part_size_type[part],v);
1124 if (v == 0 && part_size_type[part] != '*') {
1125 fprintf(stderr,
1126 "line %d: %s: bad partition size\n", lineno, cp);
1127 return (1);
1128 }
1129 pp->p_size = v;
1130
cc1ce052
MD
1131 /*
1132 * offset
1133 */
984263bc
MD
1134 v = 0;
1135 NXTWORD(part_offset_type[part],v);
1136 if (v == 0 && part_offset_type[part] != '*' &&
1137 part_offset_type[part] != '\0') {
1138 fprintf(stderr,
1139 "line %d: %s: bad partition offset\n", lineno, cp);
1140 return (1);
1141 }
1142 pp->p_offset = v;
cc1ce052
MD
1143
1144 /*
1145 * fstype
1146 */
37b93035
NT
1147 if (tp == NULL) {
1148 fprintf(stderr,
1149 "line %d: no filesystem type was specified\n", lineno);
1150 return(1);
1151 }
cc1ce052
MD
1152 cp = tp;
1153 tp = word(cp);
a8de4644
MD
1154 for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++) {
1155 if (*cpp && strcasecmp(*cpp, cp) == 0)
984263bc 1156 break;
a8de4644 1157 }
984263bc
MD
1158 if (*cpp != NULL) {
1159 pp->p_fstype = cpp - fstypenames;
1160 } else {
1161 if (isdigit(*cp))
1162 v = strtoul(cp, NULL, 10);
1163 else
1164 v = FSMAXTYPES;
1165 if (v >= FSMAXTYPES) {
1166 fprintf(stderr,
1167 "line %d: Warning, unknown filesystem type %s\n",
1168 lineno, cp);
1169 v = FS_UNUSED;
1170 }
1171 pp->p_fstype = v;
1172 }
1173
cc1ce052
MD
1174 pp->p_fsize = 0;
1175 pp->p_frag = 0;
1176 pp->p_cpg = 0;
1177
1178 cp = tp;
1179 if (tp) {
1180 fprintf(stderr, "line %d: Warning, fragment, block, "
1181 "and bps/cpg fields are no\n"
1182 "longer supported and must be specified "
1183 "via newfs options instead.\n",
1184 lineno);
984263bc 1185 }
cc1ce052 1186 return(0);
984263bc
MD
1187}
1188
1189/*
1190 * Check disklabel for errors and fill in
1191 * derived fields according to supplied values.
1192 */
1193int
2b961883 1194checklabel(struct disklabel32 *lp)
984263bc 1195{
2b961883 1196 struct partition32 *pp;
984263bc
MD
1197 int i, errors = 0;
1198 char part;
cd88939f
SW
1199 u_long base_offset, needed, total_size, total_percent, current_offset;
1200 long free_space;
984263bc
MD
1201 int seen_default_offset;
1202 int hog_part;
1203 int j;
2b961883 1204 struct partition32 *pp2;
984263bc
MD
1205
1206 if (lp->d_secsize == 0) {
1207 fprintf(stderr, "sector size 0\n");
1208 return (1);
1209 }
1210 if (lp->d_nsectors == 0) {
1211 fprintf(stderr, "sectors/track 0\n");
1212 return (1);
1213 }
1214 if (lp->d_ntracks == 0) {
1215 fprintf(stderr, "tracks/cylinder 0\n");
1216 return (1);
1217 }
1218 if (lp->d_ncylinders == 0) {
1219 fprintf(stderr, "cylinders/unit 0\n");
1220 errors++;
1221 }
1222 if (lp->d_rpm == 0)
1223 Warning("revolutions/minute 0");
1224 if (lp->d_secpercyl == 0)
1225 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1226 if (lp->d_secperunit == 0)
1227 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
1228 if (lp->d_bbsize == 0) {
1229 fprintf(stderr, "boot block size 0\n");
1230 errors++;
1231 } else if (lp->d_bbsize % lp->d_secsize)
1232 Warning("boot block size %% sector-size != 0");
1233 if (lp->d_sbsize == 0) {
1234 fprintf(stderr, "super block size 0\n");
1235 errors++;
1236 } else if (lp->d_sbsize % lp->d_secsize)
1237 Warning("super block size %% sector-size != 0");
2b961883 1238 if (lp->d_npartitions > MAXPARTITIONS32)
984263bc 1239 Warning("number of partitions (%lu) > MAXPARTITIONS (%d)",
2b961883 1240 (u_long)lp->d_npartitions, MAXPARTITIONS32);
984263bc
MD
1241
1242 /* first allocate space to the partitions, then offsets */
1243 total_size = 0; /* in sectors */
1244 total_percent = 0; /* in percent */
1245 hog_part = -1;
1246 /* find all fixed partitions */
1247 for (i = 0; i < lp->d_npartitions; i++) {
1248 pp = &lp->d_partitions[i];
1249 if (part_set[i]) {
b00e432b 1250
984263bc
MD
1251 if (part_size_type[i] == '*') {
1252 if (i == RAW_PART) {
1253 pp->p_size = lp->d_secperunit;
1254 } else {
b00e432b
MD
1255 if (part_offset_type[i] != '*') {
1256 if (total_size < pp->p_offset)
1257 total_size = pp->p_offset;
1258 }
984263bc
MD
1259 if (hog_part != -1)
1260 Warning("Too many '*' partitions (%c and %c)",
1261 hog_part + 'a',i + 'a');
1262 else
1263 hog_part = i;
1264 }
1265 } else {
1266 off_t size;
1267
1268 size = pp->p_size;
1269 switch (part_size_type[i]) {
1270 case '%':
1271 total_percent += size;
1272 break;
f61a91d2
SW
1273 case 't':
1274 case 'T':
984263bc 1275 size *= 1024ULL;
f61a91d2 1276 /* FALLTHROUGH */
984263bc
MD
1277 case 'g':
1278 case 'G':
f61a91d2
SW
1279 size *= 1024ULL;
1280 /* FALLTHROUGH */
1281 case 'm':
1282 case 'M':
1283 size *= 1024ULL;
1284 /* FALLTHROUGH */
1285 case 'k':
1286 case 'K':
1287 size *= 1024ULL;
984263bc
MD
1288 break;
1289 case '\0':
1290 break;
1291 default:
f61a91d2 1292 Warning("unknown size specifier '%c' (K/M/G/T are valid)",part_size_type[i]);
984263bc
MD
1293 break;
1294 }
1295 /* don't count %'s yet */
1296 if (part_size_type[i] != '%') {
1297 /*
1298 * for all not in sectors, convert to
1299 * sectors
1300 */
1301 if (part_size_type[i] != '\0') {
1302 if (size % lp->d_secsize != 0)
1303 Warning("partition %c not an integer number of sectors",
1304 i + 'a');
1305 size /= lp->d_secsize;
1306 pp->p_size = size;
1307 }
1308 /* else already in sectors */
1309 if (i != RAW_PART)
1310 total_size += size;
1311 }
1312 }
1313 }
1314 }
cd88939f
SW
1315
1316 /* Find out the total free space, excluding the boot block area. */
1317 base_offset = BBSIZE / lp->d_secsize;
1318 free_space = 0;
1319 for (i = 0; i < lp->d_npartitions; i++) {
1320 pp = &lp->d_partitions[i];
1321 if (!part_set[i] || i == RAW_PART ||
1322 part_size_type[i] == '%' || part_size_type[i] == '*')
1323 continue;
1324 if (pp->p_offset > base_offset)
1325 free_space += pp->p_offset - base_offset;
1326 if (pp->p_offset + pp->p_size > base_offset)
1327 base_offset = pp->p_offset + pp->p_size;
1328 }
1329 if (base_offset < lp->d_secperunit)
1330 free_space += lp->d_secperunit - base_offset;
1331
984263bc
MD
1332 /* handle % partitions - note %'s don't need to add up to 100! */
1333 if (total_percent != 0) {
984263bc
MD
1334 if (total_percent > 100) {
1335 fprintf(stderr,"total percentage %lu is greater than 100\n",
1336 total_percent);
1337 errors++;
1338 }
1339
1340 if (free_space > 0) {
1341 for (i = 0; i < lp->d_npartitions; i++) {
1342 pp = &lp->d_partitions[i];
1343 if (part_set[i] && part_size_type[i] == '%') {
1344 /* careful of overflows! and integer roundoff */
1345 pp->p_size = ((double)pp->p_size/100) * free_space;
1346 total_size += pp->p_size;
1347
1348 /* FIX we can lose a sector or so due to roundoff per
1349 partition. A more complex algorithm could avoid that */
1350 }
1351 }
1352 } else {
1353 fprintf(stderr,
1354 "%ld sectors available to give to '*' and '%%' partitions\n",
1355 free_space);
1356 errors++;
1357 /* fix? set all % partitions to size 0? */
1358 }
1359 }
1360 /* give anything remaining to the hog partition */
1361 if (hog_part != -1) {
cd88939f
SW
1362 /*
1363 * Find the range of offsets usable by '*' partitions around
1364 * the hog partition and how much space they need.
1365 */
1366 needed = 0;
1367 base_offset = BBSIZE / lp->d_secsize;
1368 for (i = hog_part - 1; i >= 0; i--) {
1369 pp = &lp->d_partitions[i];
1370 if (!part_set[i] || i == RAW_PART)
1371 continue;
1372 if (part_offset_type[i] == '*') {
1373 needed += pp->p_size;
1374 continue;
1375 }
1376 base_offset = pp->p_offset + pp->p_size;
1377 break;
1378 }
1379 current_offset = lp->d_secperunit;
1380 for (i = lp->d_npartitions - 1; i > hog_part; i--) {
1381 pp = &lp->d_partitions[i];
1382 if (!part_set[i] || i == RAW_PART)
1383 continue;
1384 if (part_offset_type[i] == '*') {
1385 needed += pp->p_size;
1386 continue;
1387 }
1388 current_offset = pp->p_offset;
1389 }
1390
1391 if (current_offset - base_offset <= needed) {
1392 fprintf(stderr, "Cannot find space for partition %c\n",
1393 hog_part + 'a');
1394 fprintf(stderr,
1395 "Need more than %lu sectors between %lu and %lu\n",
1396 needed, base_offset, current_offset);
1397 errors++;
1398 lp->d_partitions[hog_part].p_size = 0;
1399 } else {
1400 lp->d_partitions[hog_part].p_size = current_offset -
1401 base_offset - needed;
1402 total_size += lp->d_partitions[hog_part].p_size;
1403 }
984263bc
MD
1404 }
1405
1406 /* Now set the offsets for each partition */
cd88939f 1407 current_offset = BBSIZE / lp->d_secsize; /* in sectors */
984263bc
MD
1408 seen_default_offset = 0;
1409 for (i = 0; i < lp->d_npartitions; i++) {
1410 part = 'a' + i;
1411 pp = &lp->d_partitions[i];
1412 if (part_set[i]) {
1413 if (part_offset_type[i] == '*') {
1414 if (i == RAW_PART) {
1415 pp->p_offset = 0;
1416 } else {
1417 pp->p_offset = current_offset;
1418 seen_default_offset = 1;
1419 }
1420 } else {
1421 /* allow them to be out of order for old-style tables */
ce19f97e 1422 if (pp->p_offset < current_offset &&
984263bc
MD
1423 seen_default_offset && i != RAW_PART &&
1424 pp->p_fstype != FS_VINUM) {
1425 fprintf(stderr,
1426"Offset %ld for partition %c overlaps previous partition which ends at %lu\n",
1427 (long)pp->p_offset,i+'a',current_offset);
1428 fprintf(stderr,
1429"Labels with any *'s for offset must be in ascending order by sector\n");
1430 errors++;
1431 } else if (pp->p_offset != current_offset &&
1432 i != RAW_PART && seen_default_offset) {
ce19f97e
MD
1433 /*
1434 * this may give unneeded warnings if
984263bc
MD
1435 * partitions are out-of-order
1436 */
1437 Warning(
1438"Offset %ld for partition %c doesn't match expected value %ld",
1439 (long)pp->p_offset, i + 'a', current_offset);
1440 }
1441 }
1442 if (i != RAW_PART)
ce19f97e 1443 current_offset = pp->p_offset + pp->p_size;
984263bc
MD
1444 }
1445 }
1446
1447 for (i = 0; i < lp->d_npartitions; i++) {
1448 part = 'a' + i;
1449 pp = &lp->d_partitions[i];
1450 if (pp->p_size == 0 && pp->p_offset != 0)
1451 Warning("partition %c: size 0, but offset %lu",
1452 part, (u_long)pp->p_offset);
1453#ifdef notdef
1454 if (pp->p_size % lp->d_secpercyl)
1455 Warning("partition %c: size %% cylinder-size != 0",
1456 part);
1457 if (pp->p_offset % lp->d_secpercyl)
1458 Warning("partition %c: offset %% cylinder-size != 0",
1459 part);
1460#endif
1461 if (pp->p_offset > lp->d_secperunit) {
1462 fprintf(stderr,
1463 "partition %c: offset past end of unit\n", part);
1464 errors++;
1465 }
1466 if (pp->p_offset + pp->p_size > lp->d_secperunit) {
1467 fprintf(stderr,
1468 "partition %c: partition extends past end of unit\n",
1469 part);
1470 errors++;
1471 }
1472 if (i == RAW_PART)
1473 {
1474 if (pp->p_fstype != FS_UNUSED)
1475 Warning("partition %c is not marked as unused!",part);
1476 if (pp->p_offset != 0)
1477 Warning("partition %c doesn't start at 0!",part);
1478 if (pp->p_size != lp->d_secperunit)
1479 Warning("partition %c doesn't cover the whole unit!",part);
1480
1481 if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) ||
1482 (pp->p_size != lp->d_secperunit)) {
1483 Warning("An incorrect partition %c may cause problems for "
1484 "standard system utilities",part);
1485 }
1486 }
1487
1488 /* check for overlaps */
1489 /* this will check for all possible overlaps once and only once */
1490 for (j = 0; j < i; j++) {
1491 pp2 = &lp->d_partitions[j];
ce19f97e 1492 if (j != RAW_PART && i != RAW_PART &&
984263bc
MD
1493 pp->p_fstype != FS_VINUM &&
1494 pp2->p_fstype != FS_VINUM &&
1495 part_set[i] && part_set[j]) {
1496 if (pp2->p_offset < pp->p_offset + pp->p_size &&
1497 (pp2->p_offset + pp2->p_size > pp->p_offset ||
1498 pp2->p_offset >= pp->p_offset)) {
1499 fprintf(stderr,"partitions %c and %c overlap!\n",
1500 j + 'a', i + 'a');
1501 errors++;
1502 }
1503 }
1504 }
1505 }
9e792b7e 1506 for (; i < 8 || i < lp->d_npartitions; i++) {
984263bc
MD
1507 part = 'a' + i;
1508 pp = &lp->d_partitions[i];
1509 if (pp->p_size || pp->p_offset)
1510 Warning("unused partition %c: size %d offset %lu",
1511 'a' + i, pp->p_size, (u_long)pp->p_offset);
1512 }
1513 return (errors);
1514}
1515
1516/*
1517 * When operating on a "virgin" disk, try getting an initial label
1518 * from the associated device driver. This might work for all device
1519 * drivers that are able to fetch some initial device parameters
1520 * without even having access to a (BSD) disklabel, like SCSI disks,
1521 * most IDE drives, or vn devices.
984263bc 1522 */
2b961883 1523static struct disklabel32 dlab;
e5d03018 1524
2b961883 1525struct disklabel32 *
984263bc
MD
1526getvirginlabel(void)
1527{
5c5f4647 1528 struct partinfo info;
2b961883 1529 struct disklabel32 *dl = &dlab;
984263bc
MD
1530 int f;
1531
d736a600
MD
1532 if ((f = open(dkname, O_RDONLY)) == -1) {
1533 warn("cannot open %s", dkname);
984263bc
MD
1534 return (NULL);
1535 }
1536
1537 /*
5c5f4647
MD
1538 * Check to see if the media is too big for a 32 bit disklabel.
1539 */
1540 if (ioctl(f, DIOCGPART, &info) == 0) {
1541 if (info.media_size >= 0x100000000ULL * 512) {
cc298a13
MD
1542 warnx("The media is too large for a 32 bit disklabel,"
1543 " please use disklabel64.");
5c5f4647
MD
1544 return (NULL);
1545 }
1546 }
1547
1548 /*
1549 * Generate a virgin disklabel via ioctl
984263bc 1550 */
2b961883 1551 if (ioctl(f, DIOCGDVIRGIN32, dl) < 0) {
0ffe40b3
MD
1552 l_perror("ioctl DIOCGDVIRGIN32");
1553 close(f);
1554 return(NULL);
984263bc
MD
1555 }
1556 close(f);
e5d03018
MD
1557 return (dl);
1558}
1559
2b961883 1560struct disklabel32 *
e5d03018
MD
1561getdisklabelfromdisktab(const char *name)
1562{
1563 struct disktab *dt;
2b961883 1564 struct disklabel32 *dl = &dlab;
e5d03018
MD
1565 int i;
1566
1567 if ((dt = getdisktabbyname(name)) == NULL)
1568 return(NULL);
2b961883 1569 dl->d_magic = DISKMAGIC32;
e5d03018
MD
1570 dl->d_type = dt->d_typeid;
1571 dl->d_subtype = 0;
1572 dl->d_secsize = dt->d_media_blksize;
1573 dl->d_nsectors = dt->d_secpertrack;
1574 dl->d_ntracks = dt->d_nheads;
1575 dl->d_ncylinders = dt->d_ncylinders;
1576 dl->d_secpercyl = dt->d_secpercyl;
1577 dl->d_secperunit = dt->d_media_blocks;
1578 dl->d_rpm = dt->d_rpm;
1579 dl->d_interleave = dt->d_interleave;
1580 dl->d_trackskew = dt->d_trackskew;
1581 dl->d_cylskew = dt->d_cylskew;
1582 dl->d_headswitch = dt->d_headswitch;
1583 dl->d_trkseek = dt->d_trkseek;
2b961883 1584 dl->d_magic2 = DISKMAGIC32;
e5d03018
MD
1585 dl->d_npartitions = dt->d_npartitions;
1586 dl->d_bbsize = dt->d_bbsize;
1587 dl->d_sbsize = dt->d_sbsize;
1588 for (i = 0; i < dt->d_npartitions; ++i) {
2b961883 1589 struct partition32 *dlp = &dl->d_partitions[i];
e5d03018
MD
1590 struct dt_partition *dtp = &dt->d_partitions[i];
1591
1592 dlp->p_size = dtp->p_size;
1593 dlp->p_offset = dtp->p_offset;
1594 dlp->p_fsize = dtp->p_fsize;
1595 dlp->p_fstype = dtp->p_fstype;
1596 dlp->p_frag = dtp->p_fsize;
1597 }
1598 return(dl);
984263bc
MD
1599}
1600
1601/*
1602 * If we are installing a boot program that doesn't fit in d_bbsize
1603 * we need to mark those partitions that the boot overflows into.
1604 * This allows newfs to prevent creation of a filesystem where it might
1605 * clobber bootstrap code.
1606 */
1607void
2b961883 1608setbootflag(struct disklabel32 *lp)
984263bc 1609{
2b961883 1610 struct partition32 *pp;
984263bc
MD
1611 int i, errors = 0;
1612 char part;
1613 u_long boffset;
1614
678e8cc6 1615 if (bootbuf == NULL)
984263bc
MD
1616 return;
1617 boffset = bootsize / lp->d_secsize;
1618 for (i = 0; i < lp->d_npartitions; i++) {
1619 part = 'a' + i;
1620 pp = &lp->d_partitions[i];
1621 if (pp->p_size == 0)
1622 continue;
1623 if (boffset <= pp->p_offset) {
1624 if (pp->p_fstype == FS_BOOT)
1625 pp->p_fstype = FS_UNUSED;
1626 } else if (pp->p_fstype != FS_BOOT) {
1627 if (pp->p_fstype != FS_UNUSED) {
1628 fprintf(stderr,
1629 "boot overlaps used partition %c\n",
1630 part);
1631 errors++;
1632 } else {
1633 pp->p_fstype = FS_BOOT;
1634 Warning("boot overlaps partition %c, %s",
1635 part, "marked as FS_BOOT");
1636 }
1637 }
1638 }
1639 if (errors)
1640 errx(4, "cannot install boot program");
1641}
1642
1643/*VARARGS1*/
1644void
1645Warning(const char *fmt, ...)
1646{
1647 va_list ap;
1648
1649 fprintf(stderr, "Warning, ");
1650 va_start(ap, fmt);
1651 vfprintf(stderr, fmt, ap);
1652 fprintf(stderr, "\n");
1653 va_end(ap);
1654}
1655
9e792b7e
MD
1656/*
1657 * Check to see if the bootblocks are in the wrong place. FBsd5 bootblocks
1658 * and earlier DFly bb's are packed against the old disklabel and a new
1659 * disklabel would blow them up. This is a hack that should be removed
1660 * in 2006 sometime (if ever).
1661 */
1662
1663int
93217a19 1664checkoldboot(int f, const char *bootbuffer)
9e792b7e
MD
1665{
1666 char buf[BBSIZE];
1667
93217a19 1668 if (bootbuffer && strncmp(bootbuffer + 0x402, "BTX", 3) == 0)
9e792b7e
MD
1669 return(0);
1670 lseek(f, (off_t)0, SEEK_SET);
1671 if (read(f, buf, sizeof(buf)) != sizeof(buf))
1672 return(0);
1673 if (strncmp(buf + 0x402, "BTX", 3) == 0) /* new location */
1674 return(0);
1675 if (strncmp(buf + 0x316, "BTX", 3) == 0) /* old location */
1676 return(1);
1677 return(0);
1678}
1679
2b961883
MD
1680/*
1681 * Traditional 32 bit disklabels actually use absolute sector numbers on
1682 * disk, NOT slice relative sector numbres. The OS hides this from us
1683 * when we use DIOC ioctls to access the label, but newer versions of
1684 * Dragonfly no longer adjusts the disklabel when snooping reads or writes
1685 * so we have to figure it out ourselves.
1686 */
1687const char *
1688fixlabel(int f, struct disklabel32 *lp, int writeadj)
1689{
1690 const char *msg = NULL;
1691 struct partinfo info;
1692 struct partition32 *pp;
1693 u_int64_t start;
1694 u_int64_t end;
1695 u_int64_t offset;
1696 int part;
1697 int rev;
a67bacc9 1698 size_t rev_len = sizeof(rev);
2b961883
MD
1699
1700 if (sysctlbyname("kern.osrevision", &rev, &rev_len, NULL, 0) < 0) {
1701 errx(1, "Cannot use raw mode on non-DragonFly systems\n");
1702 }
1703 if (rev < 200701) {
1704 warnx("Warning running new disklabel on old DragonFly systems,\n"
1705 "assuming the disk layer will fixup the label.\n");
1706 sleep(3);
1707 return(NULL);
1708 }
1709
1710 pp = &lp->d_partitions[RAW_PART];
1711
1712 if (forceflag) {
1713 info.media_offset = slice_start_lba * lp->d_secsize;
1714 info.media_blocks = pp->p_size;
1715 info.media_blksize = lp->d_secsize;
1716 } else if (ioctl(f, DIOCGPART, &info) < 0) {
1717 msg = "Unable to extract the slice starting LBA, "
1718 "you must use the -f <slice_start_lba> option\n"
1719 "to specify it manually, or perhaps try without "
1720 "using -r and let the kernel deal with it\n";
1721 return(msg);
1722 }
1723
1724 if (lp->d_magic != DISKMAGIC32 || lp->d_magic2 != DISKMAGIC32)
1725 return ("fixlabel: invalid magic");
1726 if (dkcksum32(lp) != 0)
1727 return ("fixlabel: invalid checksum");
1728
1729 /*
1730 * What a mess. For ages old backwards compatibility the disklabel
1731 * on-disk stores absolute offsets instead of slice-relative offsets.
1732 * So fix it up when reading, writing, or snooping.
1733 *
1734 * The in-core label is always slice-relative.
1735 */
1736 if (writeadj) {
1737 /*
1738 * incore -> disk
1739 */
1740 start = 0;
1741 offset = info.media_offset / info.media_blksize;
1742 } else {
1743 /*
1744 * disk -> incore
1745 */
1746 start = info.media_offset / info.media_blksize;
1747 offset = -info.media_offset / info.media_blksize;
1748 }
1749 if (pp->p_offset != start)
1750 return ("fixlabel: raw partition offset != slice offset");
1751 if (pp->p_size != info.media_blocks) {
1752 if (pp->p_size > info.media_blocks)
1753 return ("fixlabel: raw partition size > slice size");
1754 }
1755 end = start + info.media_blocks;
1756 if (start > end)
1757 return ("fixlabel: slice wraps");
1758 if (lp->d_secpercyl <= 0)
1759 return ("fixlabel: d_secpercyl <= 0");
1760 pp -= RAW_PART;
1761 for (part = 0; part < lp->d_npartitions; part++, pp++) {
1762 if (pp->p_offset != 0 || pp->p_size != 0) {
1763 if (pp->p_offset < start
1764 || pp->p_offset + pp->p_size > end
1765 || pp->p_offset + pp->p_size < pp->p_offset) {
1766 /* XXX else silently discard junk. */
1767 bzero(pp, sizeof *pp);
1768 } else {
1769 pp->p_offset += offset;
1770 }
1771 }
1772 }
1773 lp->d_checksum = 0;
1774 lp->d_checksum = dkcksum32(lp);
1775 return (NULL);
1776}
1777
984263bc
MD
1778void
1779usage(void)
1780{
1781#if NUMBOOT > 0
1782 fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
c61a095d 1783 "usage: disklabel32 [-r] disk",
984263bc 1784 "\t\t(to read label)",
c61a095d 1785 " disklabel32 -w [-r] [-n] disk type [packid]",
984263bc 1786 "\t\t(to write label with existing boot program)",
c61a095d 1787 " disklabel32 -e [-r] [-n] disk",
984263bc 1788 "\t\t(to edit label)",
c61a095d 1789 " disklabel32 -R [-r] [-n] disk protofile",
984263bc
MD
1790 "\t\t(to restore label with existing boot program)",
1791#if NUMBOOT > 1
c61a095d 1792 " disklabel32 -B [-n] [-b boot1 -s boot2] disk [type]",
984263bc 1793 "\t\t(to install boot program with existing label)",
c61a095d 1794 " disklabel32 -w -B [-n] [-b boot1 -s boot2] disk type [packid]",
984263bc 1795 "\t\t(to write label and boot program)",
c61a095d 1796 " disklabel32 -R -B [-n] [-b boot1 -s boot2] disk protofile [type]",
984263bc
MD
1797 "\t\t(to restore label and boot program)",
1798#else
c61a095d 1799 " disklabel32 -B [-n] [-b bootprog] disk [type]",
984263bc 1800 "\t\t(to install boot program with existing on-disk label)",
c61a095d 1801 " disklabel32 -w -B [-n] [-b bootprog] disk type [packid]",
984263bc 1802 "\t\t(to write label and install boot program)",
c61a095d 1803 " disklabel32 -R -B [-n] [-b bootprog] disk protofile [type]",
984263bc
MD
1804 "\t\t(to restore label and install boot program)",
1805#endif
c61a095d 1806 " disklabel32 [-NW] disk",
984263bc
MD
1807 "\t\t(to write disable/enable label)");
1808#else
1809 fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
c61a095d
TN
1810 "usage: disklabel32 [-r] disk", "(to read label)",
1811 " disklabel32 -w [-r] [-n] disk type [packid]",
984263bc 1812 "\t\t(to write label)",
c61a095d 1813 " disklabel32 -e [-r] [-n] disk",
984263bc 1814 "\t\t(to edit label)",
c61a095d 1815 " disklabel32 -R [-r] [-n] disk protofile",
984263bc 1816 "\t\t(to restore label)",
c61a095d 1817 " disklabel32 [-NW] disk",
984263bc
MD
1818 "\t\t(to write disable/enable label)");
1819#endif
395137b5 1820 fprintf(stderr, "%s\n%s\n",
c61a095d 1821 " disklabel32 [-f slice_start_lba] [options]",
395137b5 1822 "\t\t(to force using manual offset)");
984263bc
MD
1823 exit(1);
1824}