1 /*-
2 * SPDX-License-Identifier: BSD-4-Clause
3 *
4 * Copyright (c) 1994, 1995 Gordon W. Ross
5 * Copyright (c) 1994 Theo de Raadt
6 * All rights reserved.
7 * Copyright (c) 1987, 1993
8 * The Regents of the University of California. All rights reserved.
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. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * This product includes software developed by Theo de Raadt.
26 * 4. Neither the name of the University nor the names of its contributors
27 * may be used to endorse or promote products derived from this software
28 * without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 *
42 * from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $
43 */
44
45 #include <sys/param.h>
46 #include <stdint.h>
47 #include <sys/file.h>
48 #include <sys/stat.h>
49 #include <sys/wait.h>
50 #include <sys/disk.h>
51 #define DKTYPENAMES
52 #define FSTYPENAMES
53 #define MAXPARTITIONS 8 /* XXX should be 20, but see PR276517 */
54 #include <sys/disklabel.h>
55
56 #include <unistd.h>
57 #include <string.h>
58 #include <stdio.h>
59 #include <libgeom.h>
60 #include <stdlib.h>
61 #include <signal.h>
62 #include <stdarg.h>
63 #include <ctype.h>
64 #include <err.h>
65 #include <errno.h>
66
67 #include "pathnames.h"
68
69 static void makelabel(const char *, struct disklabel *);
70 static int geom_class_available(const char *);
71 static int writelabel(void);
72 static int readlabel(int flag);
73 static void display(FILE *, const struct disklabel *);
74 static int edit(void);
75 static int editit(void);
76 static void fixlabel(struct disklabel *);
77 static char *skip(char *);
78 static char *word(char *);
79 static int getasciilabel(FILE *, struct disklabel *);
80 static int getasciipartspec(char *, struct disklabel *, int, int);
81 static int checklabel(struct disklabel *);
82 static void usage(void);
83 static struct disklabel *getvirginlabel(void);
84
85 #define DEFEDITOR _PATH_VI
86 #define DEFPARTITIONS 8
87
88 static char *specname;
89 static char *pname;
90 static char tmpfil[] = PATH_TMPFILE;
91
92 static struct disklabel lab;
93 static u_char bootarea[BBSIZE];
94 static off_t mediasize;
95 static ssize_t secsize;
96 static char blank[] = "";
97 static char unknown[] = "unknown";
98
99 #define MAX_PART ('z')
100 #define MAX_NUM_PARTS (1 + MAX_PART - 'a')
101 static char part_size_type[MAX_NUM_PARTS];
102 static char part_offset_type[MAX_NUM_PARTS];
103 static int part_set[MAX_NUM_PARTS];
104
105 static int installboot; /* non-zero if we should install a boot program */
106 static int allfields; /* present all fields in edit */
107 static char const *xxboot; /* primary boot */
108
109 static uint32_t lba_offset;
110 #ifndef LABELSECTOR
111 #define LABELSECTOR -1
112 #endif
113 #ifndef LABELOFFSET
114 #define LABELOFFSET -1
115 #endif
116 static int labelsoffset = LABELSECTOR;
117 static int labeloffset = LABELOFFSET;
118 static int bbsize = BBSIZE;
119
120 static enum {
121 UNSPEC, EDIT, READ, RESTORE, WRITE, WRITEBOOT
122 } op = UNSPEC;
123
124
125 static int disable_write; /* set to disable writing to disk label */
126 static int is_file; /* work on a file (abs. pathname), "-f" opt. */
127
128 int
main(int argc,char * argv[])129 main(int argc, char *argv[])
130 {
131 FILE *t;
132 int ch, error, fd;
133 const char *name;
134
135 error = 0;
136 name = NULL;
137
138 fprintf(stderr,
139 "WARNING: bsdlabel is deprecated and is not available in FreeBSD 15 or later.\n"
140 "Please use gpart instead.\n\n");
141
142 while ((ch = getopt(argc, argv, "ABb:efm:nRrw")) != -1)
143 switch (ch) {
144 case 'A':
145 allfields = 1;
146 break;
147 case 'B':
148 ++installboot;
149 break;
150 case 'b':
151 xxboot = optarg;
152 break;
153 case 'f':
154 is_file=1;
155 break;
156 case 'm':
157 if (!strcmp(optarg, "i386") ||
158 !strcmp(optarg, "amd64")) {
159 labelsoffset = 1;
160 labeloffset = 0;
161 bbsize = 8192;
162 } else {
163 errx(1, "Unsupported architecture");
164 }
165 break;
166 case 'n':
167 disable_write = 1;
168 break;
169 case 'R':
170 if (op != UNSPEC)
171 usage();
172 op = RESTORE;
173 break;
174 case 'e':
175 if (op != UNSPEC)
176 usage();
177 op = EDIT;
178 break;
179 case 'r':
180 /*
181 * We accept and ignore -r for compatibility with
182 * historical disklabel usage.
183 */
184 break;
185 case 'w':
186 if (op != UNSPEC)
187 usage();
188 op = WRITE;
189 break;
190 case '?':
191 default:
192 usage();
193 }
194 argc -= optind;
195 argv += optind;
196
197 if (argc < 1)
198 usage();
199 if (labelsoffset < 0 || labeloffset < 0)
200 errx(1, "a -m <architecture> option must be specified");
201
202 /* Figure out the names of the thing we're working on */
203 if (is_file) {
204 specname = argv[0];
205 } else {
206 specname = g_device_path(argv[0]);
207 if (specname == NULL) {
208 warn("unable to get correct path for %s", argv[0]);
209 return(1);
210 }
211 fd = open(specname, O_RDONLY);
212 if (fd < 0) {
213 warn("error opening %s", specname);
214 return(1);
215 }
216 pname = g_providername(fd);
217 if (pname == NULL) {
218 warn("error getting providername for %s", specname);
219 close(fd);
220 return(1);
221 }
222 close(fd);
223 }
224
225 if (installboot && op == UNSPEC)
226 op = WRITEBOOT;
227 else if (op == UNSPEC)
228 op = READ;
229
230 switch(op) {
231
232 case UNSPEC:
233 break;
234
235 case EDIT:
236 if (argc != 1)
237 usage();
238 readlabel(1);
239 fixlabel(&lab);
240 error = edit();
241 break;
242
243 case READ:
244 if (argc != 1)
245 usage();
246 readlabel(1);
247 display(stdout, NULL);
248 error = checklabel(NULL);
249 break;
250
251 case RESTORE:
252 if (argc != 2)
253 usage();
254 if (!(t = fopen(argv[1], "r")))
255 err(4, "fopen %s", argv[1]);
256 readlabel(0);
257 if (!getasciilabel(t, &lab))
258 exit(1);
259 error = writelabel();
260 break;
261
262 case WRITE:
263 if (argc == 2)
264 name = argv[1];
265 else if (argc == 1)
266 name = "auto";
267 else
268 usage();
269 readlabel(0);
270 makelabel(name, &lab);
271 fixlabel(&lab);
272 if (checklabel(NULL) == 0)
273 error = writelabel();
274 break;
275
276 case WRITEBOOT:
277
278 readlabel(1);
279 fixlabel(&lab);
280 if (argc == 2)
281 makelabel(argv[1], &lab);
282 if (checklabel(NULL) == 0)
283 error = writelabel();
284 break;
285 }
286 exit(error);
287 }
288
289 static void
fixlabel(struct disklabel * lp)290 fixlabel(struct disklabel *lp)
291 {
292 struct partition *dp;
293 int i;
294
295 for (i = 0; i < lp->d_npartitions; i++) {
296 if (i == RAW_PART)
297 continue;
298 if (lp->d_partitions[i].p_size)
299 return;
300 }
301
302 dp = &lp->d_partitions[0];
303 dp->p_offset = BBSIZE / secsize;
304 dp->p_size = lp->d_secperunit - dp->p_offset;
305 }
306
307 /*
308 * Construct a prototype disklabel from /etc/disktab.
309 */
310 static void
makelabel(const char * type,struct disklabel * lp)311 makelabel(const char *type, struct disklabel *lp)
312 {
313 struct disklabel *dp;
314
315 if (strcmp(type, "auto") == 0)
316 dp = getvirginlabel();
317 else
318 dp = getdiskbyname(type);
319 if (dp == NULL)
320 errx(1, "%s: unknown disk type", type);
321 *lp = *dp;
322 bzero(lp->d_packname, sizeof(lp->d_packname));
323 }
324
325 static void
readboot(void)326 readboot(void)
327 {
328 int fd;
329 struct stat st;
330
331 if (xxboot == NULL)
332 xxboot = "/boot/boot";
333 fd = open(xxboot, O_RDONLY);
334 if (fd < 0)
335 err(1, "cannot open %s", xxboot);
336 fstat(fd, &st);
337 if (st.st_size <= BBSIZE) {
338 if (read(fd, bootarea, st.st_size) != st.st_size)
339 err(1, "read error %s", xxboot);
340 close(fd);
341 return;
342 }
343 errx(1, "boot code %s is wrong size", xxboot);
344 }
345
346 static int
geom_class_available(const char * name)347 geom_class_available(const char *name)
348 {
349 struct gclass *class;
350 struct gmesh mesh;
351 int error;
352
353 error = geom_gettree(&mesh);
354 if (error != 0)
355 errc(1, error, "Cannot get GEOM tree");
356
357 LIST_FOREACH(class, &mesh.lg_class, lg_class) {
358 if (strcmp(class->lg_name, name) == 0) {
359 geom_deletetree(&mesh);
360 return (1);
361 }
362 }
363
364 geom_deletetree(&mesh);
365
366 return (0);
367 }
368
369 static int
writelabel(void)370 writelabel(void)
371 {
372 int i, fd, serrno;
373 struct disklabel *lp = &lab;
374
375 if (disable_write) {
376 warnx("write to disk label suppressed - label was as follows:");
377 display(stdout, NULL);
378 return (0);
379 }
380
381 lp->d_magic = DISKMAGIC;
382 lp->d_magic2 = DISKMAGIC;
383 lp->d_checksum = 0;
384 lp->d_checksum = dkcksum(lp);
385 if (installboot)
386 readboot();
387 for (i = 0; i < lab.d_npartitions; i++)
388 if (lab.d_partitions[i].p_size)
389 lab.d_partitions[i].p_offset += lba_offset;
390 bsd_disklabel_le_enc(bootarea + labeloffset + labelsoffset * lab.d_secsize,
391 lp);
392
393 fd = open(specname, O_RDWR);
394 if (fd < 0) {
395 if (is_file) {
396 warn("cannot open file %s for writing label", specname);
397 return(1);
398 } else
399 serrno = errno;
400
401 if (geom_class_available("PART") != 0) {
402 /*
403 * Since we weren't able open provider for
404 * writing, then recommend user to use gpart(8).
405 */
406 warnc(serrno,
407 "cannot open provider %s for writing label",
408 specname);
409 warnx("Try to use gpart(8).");
410 return (1);
411 }
412
413 warnc(serrno, "%s", specname);
414 return (1);
415 } else {
416 if (write(fd, bootarea, bbsize) != bbsize) {
417 warn("write %s", specname);
418 close (fd);
419 return (1);
420 }
421 close (fd);
422 }
423 return (0);
424 }
425
426 static void
get_file_parms(int f)427 get_file_parms(int f)
428 {
429 int i;
430 struct stat sb;
431
432 if (fstat(f, &sb) != 0)
433 err(4, "fstat failed");
434 i = sb.st_mode & S_IFMT;
435 if (i != S_IFREG && i != S_IFLNK)
436 errx(4, "%s is not a valid file or link", specname);
437 secsize = DEV_BSIZE;
438 mediasize = sb.st_size;
439 }
440
441 /*
442 * Fetch disklabel for disk.
443 */
444 static int
readlabel(int flag)445 readlabel(int flag)
446 {
447 ssize_t nbytes;
448 uint32_t lba;
449 int f, i;
450 int error;
451
452 f = open(specname, O_RDONLY);
453 if (f < 0)
454 err(1, "%s", specname);
455 if (is_file)
456 get_file_parms(f);
457 else {
458 mediasize = g_mediasize(f);
459 secsize = g_sectorsize(f);
460 if (secsize < 0 || mediasize < 0)
461 err(4, "cannot get disk geometry");
462 }
463 if (mediasize > (off_t)0xffffffff * secsize)
464 errx(1,
465 "disks with more than 2^32-1 sectors are not supported");
466 (void)lseek(f, (off_t)0, SEEK_SET);
467 nbytes = read(f, bootarea, BBSIZE);
468 if (nbytes == -1)
469 err(4, "%s read", specname);
470 if (nbytes != BBSIZE)
471 errx(4, "couldn't read %d bytes from %s", BBSIZE, specname);
472 close (f);
473 error = bsd_disklabel_le_dec(
474 bootarea + (labeloffset + labelsoffset * secsize),
475 &lab, MAXPARTITIONS);
476 if (flag && error)
477 errx(1, "%s: no valid label found", specname);
478
479 if (is_file)
480 return(0);
481
482 /*
483 * Compensate for absolute block addressing by finding the
484 * smallest partition offset and if the offset of the 'c'
485 * partition is equal to that, subtract it from all offsets.
486 */
487 lba = ~0;
488 for (i = 0; i < lab.d_npartitions; i++) {
489 if (lab.d_partitions[i].p_size)
490 lba = MIN(lba, lab.d_partitions[i].p_offset);
491 }
492 if (lba != 0 && lab.d_partitions[RAW_PART].p_offset == lba) {
493 for (i = 0; i < lab.d_npartitions; i++) {
494 if (lab.d_partitions[i].p_size)
495 lab.d_partitions[i].p_offset -= lba;
496 }
497 /*
498 * Save the offset so that we can write the label
499 * back with absolute block addresses.
500 */
501 lba_offset = lba;
502 }
503 return (error);
504 }
505
506
507 static void
display(FILE * f,const struct disklabel * lp)508 display(FILE *f, const struct disklabel *lp)
509 {
510 int i, j;
511 const struct partition *pp;
512
513 if (lp == NULL)
514 lp = &lab;
515
516 fprintf(f, "# %s:\n", specname);
517 if (allfields) {
518 if (lp->d_type < DKMAXTYPES)
519 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
520 else
521 fprintf(f, "type: %u\n", lp->d_type);
522 fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
523 lp->d_typename);
524 fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
525 lp->d_packname);
526 fprintf(f, "flags:");
527 if (lp->d_flags & D_REMOVABLE)
528 fprintf(f, " removeable");
529 if (lp->d_flags & D_ECC)
530 fprintf(f, " ecc");
531 if (lp->d_flags & D_BADSECT)
532 fprintf(f, " badsect");
533 fprintf(f, "\n");
534 fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
535 fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
536 fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
537 fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
538 fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
539 fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
540 fprintf(f, "rpm: %u\n", lp->d_rpm);
541 fprintf(f, "interleave: %u\n", lp->d_interleave);
542 fprintf(f, "trackskew: %u\n", lp->d_trackskew);
543 fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
544 fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
545 (u_long)lp->d_headswitch);
546 fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
547 (u_long)lp->d_trkseek);
548 fprintf(f, "drivedata: ");
549 for (i = NDDATA - 1; i >= 0; i--)
550 if (lp->d_drivedata[i])
551 break;
552 if (i < 0)
553 i = 0;
554 for (j = 0; j <= i; j++)
555 fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
556 fprintf(f, "\n\n");
557 }
558 fprintf(f, "%u partitions:\n", lp->d_npartitions);
559 fprintf(f,
560 "# size offset fstype [fsize bsize bps/cpg]\n");
561 pp = lp->d_partitions;
562 for (i = 0; i < lp->d_npartitions; i++, pp++) {
563 if (pp->p_size) {
564 fprintf(f, " %c: %10lu %10lu ", 'a' + i,
565 (u_long)pp->p_size, (u_long)pp->p_offset);
566 if (pp->p_fstype < FSMAXTYPES)
567 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
568 else
569 fprintf(f, "%8d", pp->p_fstype);
570 switch (pp->p_fstype) {
571
572 case FS_UNUSED: /* XXX */
573 fprintf(f, " %5lu %5lu %2s",
574 (u_long)pp->p_fsize,
575 (u_long)(pp->p_fsize * pp->p_frag), "");
576 break;
577
578 case FS_BSDFFS:
579 fprintf(f, " %5lu %5lu %5u",
580 (u_long)pp->p_fsize,
581 (u_long)(pp->p_fsize * pp->p_frag),
582 pp->p_cpg);
583 break;
584
585 case FS_BSDLFS:
586 fprintf(f, " %5lu %5lu %5d",
587 (u_long)pp->p_fsize,
588 (u_long)(pp->p_fsize * pp->p_frag),
589 pp->p_cpg);
590 break;
591
592 default:
593 fprintf(f, "%20.20s", "");
594 break;
595 }
596 if (i == RAW_PART) {
597 fprintf(f, " # \"raw\" part, don't edit");
598 }
599 fprintf(f, "\n");
600 }
601 }
602 fflush(f);
603 }
604
605 static int
edit(void)606 edit(void)
607 {
608 int c, fd;
609 struct disklabel label;
610 FILE *fp;
611
612 if ((fd = mkstemp(tmpfil)) == -1 ||
613 (fp = fdopen(fd, "w")) == NULL) {
614 warnx("can't create %s", tmpfil);
615 return (1);
616 }
617 display(fp, NULL);
618 fclose(fp);
619 for (;;) {
620 if (!editit())
621 break;
622 fp = fopen(tmpfil, "r");
623 if (fp == NULL) {
624 warnx("can't reopen %s for reading", tmpfil);
625 break;
626 }
627 bzero((char *)&label, sizeof(label));
628 c = getasciilabel(fp, &label);
629 fclose(fp);
630 if (c) {
631 lab = label;
632 if (writelabel() == 0) {
633 (void) unlink(tmpfil);
634 return (0);
635 }
636 }
637 printf("re-edit the label? [y]: ");
638 fflush(stdout);
639 c = getchar();
640 if (c != EOF && c != (int)'\n')
641 while (getchar() != (int)'\n')
642 ;
643 if (c == (int)'n')
644 break;
645 }
646 (void) unlink(tmpfil);
647 return (1);
648 }
649
650 static int
editit(void)651 editit(void)
652 {
653 int pid, xpid;
654 int locstat, omask;
655 const char *ed;
656 uid_t uid;
657 gid_t gid;
658
659 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
660 while ((pid = fork()) < 0) {
661 if (errno == EPROCLIM) {
662 warnx("you have too many processes");
663 return(0);
664 }
665 if (errno != EAGAIN) {
666 warn("fork");
667 return(0);
668 }
669 sleep(1);
670 }
671 if (pid == 0) {
672 sigsetmask(omask);
673 gid = getgid();
674 if (setresgid(gid, gid, gid) == -1)
675 err(1, "setresgid");
676 uid = getuid();
677 if (setresuid(uid, uid, uid) == -1)
678 err(1, "setresuid");
679 if ((ed = getenv("EDITOR")) == (char *)0)
680 ed = DEFEDITOR;
681 execlp(ed, ed, tmpfil, (char *)0);
682 err(1, "%s", ed);
683 }
684 while ((xpid = wait(&locstat)) >= 0)
685 if (xpid == pid)
686 break;
687 sigsetmask(omask);
688 return(!locstat);
689 }
690
691 static char *
skip(char * cp)692 skip(char *cp)
693 {
694
695 while (*cp != '\0' && isspace(*cp))
696 cp++;
697 if (*cp == '\0' || *cp == '#')
698 return (NULL);
699 return (cp);
700 }
701
702 static char *
word(char * cp)703 word(char *cp)
704 {
705 char c;
706
707 while (*cp != '\0' && !isspace(*cp) && *cp != '#')
708 cp++;
709 if ((c = *cp) != '\0') {
710 *cp++ = '\0';
711 if (c != '#')
712 return (skip(cp));
713 }
714 return (NULL);
715 }
716
717 /*
718 * Read an ascii label in from fd f,
719 * in the same format as that put out by display(),
720 * and fill in lp.
721 */
722 static int
getasciilabel(FILE * f,struct disklabel * lp)723 getasciilabel(FILE *f, struct disklabel *lp)
724 {
725 char *cp, *endp;
726 const char **cpp;
727 u_int part;
728 char *tp, line[BUFSIZ];
729 u_long v;
730 int lineno = 0, errors = 0;
731 int i;
732
733 makelabel("auto", lp);
734 bzero(&part_set, sizeof(part_set));
735 bzero(&part_size_type, sizeof(part_size_type));
736 bzero(&part_offset_type, sizeof(part_offset_type));
737 lp->d_bbsize = BBSIZE; /* XXX */
738 lp->d_sbsize = 0; /* XXX */
739 while (fgets(line, sizeof(line) - 1, f)) {
740 lineno++;
741 if ((cp = strchr(line,'\n')) != NULL)
742 *cp = '\0';
743 cp = skip(line);
744 if (cp == NULL)
745 continue;
746 tp = strchr(cp, ':');
747 if (tp == NULL) {
748 fprintf(stderr, "line %d: syntax error\n", lineno);
749 errors++;
750 continue;
751 }
752 *tp++ = '\0', tp = skip(tp);
753 if (!strcmp(cp, "type")) {
754 if (tp == NULL)
755 tp = unknown;
756 cpp = dktypenames;
757 for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
758 if (*cpp && !strcmp(*cpp, tp)) {
759 lp->d_type = cpp - dktypenames;
760 break;
761 }
762 if (cpp < &dktypenames[DKMAXTYPES])
763 continue;
764 errno = 0;
765 v = strtoul(tp, &endp, 10);
766 if (errno != 0 || *endp != '\0')
767 v = DKMAXTYPES;
768 if (v >= DKMAXTYPES)
769 fprintf(stderr, "line %d:%s %lu\n", lineno,
770 "Warning, unknown disk type", v);
771 else
772 lp->d_type = v;
773 continue;
774 }
775 if (!strcmp(cp, "flags")) {
776 for (v = 0; (cp = tp) && *cp != '\0';) {
777 tp = word(cp);
778 if (!strcmp(cp, "removeable"))
779 v |= D_REMOVABLE;
780 else if (!strcmp(cp, "ecc"))
781 v |= D_ECC;
782 else if (!strcmp(cp, "badsect"))
783 v |= D_BADSECT;
784 else {
785 fprintf(stderr,
786 "line %d: %s: bad flag\n",
787 lineno, cp);
788 errors++;
789 }
790 }
791 lp->d_flags = v;
792 continue;
793 }
794 if (!strcmp(cp, "drivedata")) {
795 for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
796 lp->d_drivedata[i++] = strtoul(cp, NULL, 10);
797 tp = word(cp);
798 }
799 continue;
800 }
801 if (sscanf(cp, "%lu partitions", &v) == 1) {
802 if (v > MAXPARTITIONS) {
803 fprintf(stderr,
804 "line %d: bad # of partitions\n", lineno);
805 lp->d_npartitions = MAXPARTITIONS;
806 errors++;
807 } else if (v < DEFPARTITIONS) {
808 fprintf(stderr,
809 "line %d: bad # of partitions\n", lineno);
810 lp->d_npartitions = DEFPARTITIONS;
811 errors++;
812 } else
813 lp->d_npartitions = v;
814 continue;
815 }
816 if (tp == NULL)
817 tp = blank;
818 if (!strcmp(cp, "disk")) {
819 strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
820 continue;
821 }
822 if (!strcmp(cp, "label")) {
823 strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
824 continue;
825 }
826 if (!strcmp(cp, "bytes/sector")) {
827 v = strtoul(tp, NULL, 10);
828 if (v == 0 || (v % DEV_BSIZE) != 0) {
829 fprintf(stderr,
830 "line %d: %s: bad sector size\n",
831 lineno, tp);
832 errors++;
833 } else
834 lp->d_secsize = v;
835 continue;
836 }
837 if (!strcmp(cp, "sectors/track")) {
838 v = strtoul(tp, NULL, 10);
839 #if (ULONG_MAX != 0xffffffffUL)
840 if (v == 0 || v > 0xffffffff)
841 #else
842 if (v == 0)
843 #endif
844 {
845 fprintf(stderr, "line %d: %s: bad %s\n",
846 lineno, tp, cp);
847 errors++;
848 } else
849 lp->d_nsectors = v;
850 continue;
851 }
852 if (!strcmp(cp, "sectors/cylinder")) {
853 v = strtoul(tp, NULL, 10);
854 if (v == 0) {
855 fprintf(stderr, "line %d: %s: bad %s\n",
856 lineno, tp, cp);
857 errors++;
858 } else
859 lp->d_secpercyl = v;
860 continue;
861 }
862 if (!strcmp(cp, "tracks/cylinder")) {
863 v = strtoul(tp, NULL, 10);
864 if (v == 0) {
865 fprintf(stderr, "line %d: %s: bad %s\n",
866 lineno, tp, cp);
867 errors++;
868 } else
869 lp->d_ntracks = v;
870 continue;
871 }
872 if (!strcmp(cp, "cylinders")) {
873 v = strtoul(tp, NULL, 10);
874 if (v == 0) {
875 fprintf(stderr, "line %d: %s: bad %s\n",
876 lineno, tp, cp);
877 errors++;
878 } else
879 lp->d_ncylinders = v;
880 continue;
881 }
882 if (!strcmp(cp, "sectors/unit")) {
883 v = strtoul(tp, NULL, 10);
884 if (v == 0) {
885 fprintf(stderr, "line %d: %s: bad %s\n",
886 lineno, tp, cp);
887 errors++;
888 } else
889 lp->d_secperunit = v;
890 continue;
891 }
892 if (!strcmp(cp, "rpm")) {
893 v = strtoul(tp, NULL, 10);
894 if (v == 0 || v > USHRT_MAX) {
895 fprintf(stderr, "line %d: %s: bad %s\n",
896 lineno, tp, cp);
897 errors++;
898 } else
899 lp->d_rpm = v;
900 continue;
901 }
902 if (!strcmp(cp, "interleave")) {
903 v = strtoul(tp, NULL, 10);
904 if (v == 0 || v > USHRT_MAX) {
905 fprintf(stderr, "line %d: %s: bad %s\n",
906 lineno, tp, cp);
907 errors++;
908 } else
909 lp->d_interleave = v;
910 continue;
911 }
912 if (!strcmp(cp, "trackskew")) {
913 v = strtoul(tp, NULL, 10);
914 if (v > USHRT_MAX) {
915 fprintf(stderr, "line %d: %s: bad %s\n",
916 lineno, tp, cp);
917 errors++;
918 } else
919 lp->d_trackskew = v;
920 continue;
921 }
922 if (!strcmp(cp, "cylinderskew")) {
923 v = strtoul(tp, NULL, 10);
924 if (v > USHRT_MAX) {
925 fprintf(stderr, "line %d: %s: bad %s\n",
926 lineno, tp, cp);
927 errors++;
928 } else
929 lp->d_cylskew = v;
930 continue;
931 }
932 if (!strcmp(cp, "headswitch")) {
933 v = strtoul(tp, NULL, 10);
934 lp->d_headswitch = v;
935 continue;
936 }
937 if (!strcmp(cp, "track-to-track seek")) {
938 v = strtoul(tp, NULL, 10);
939 lp->d_trkseek = v;
940 continue;
941 }
942 /* the ':' was removed above */
943 if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') {
944 fprintf(stderr,
945 "line %d: %s: Unknown disklabel field\n", lineno,
946 cp);
947 errors++;
948 continue;
949 }
950
951 /* Process a partition specification line. */
952 part = *cp - 'a';
953 if (part >= lp->d_npartitions) {
954 fprintf(stderr,
955 "line %d: partition name out of range a-%c: %s\n",
956 lineno, 'a' + lp->d_npartitions - 1, cp);
957 errors++;
958 continue;
959 }
960 part_set[part] = 1;
961
962 if (getasciipartspec(tp, lp, part, lineno) != 0) {
963 errors++;
964 break;
965 }
966 }
967 errors += checklabel(lp);
968 return (errors == 0);
969 }
970
971 #define NXTNUM(n) do { \
972 if (tp == NULL) { \
973 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
974 return (1); \
975 } else { \
976 cp = tp, tp = word(cp); \
977 (n) = strtoul(cp, NULL, 10); \
978 } \
979 } while (0)
980
981 /* retain 1 character following number */
982 #define NXTWORD(w,n) do { \
983 if (tp == NULL) { \
984 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
985 return (1); \
986 } else { \
987 char *tmp; \
988 cp = tp, tp = word(cp); \
989 (n) = strtoul(cp, &tmp, 10); \
990 if (tmp) (w) = *tmp; \
991 } \
992 } while (0)
993
994 /*
995 * Read a partition line into partition `part' in the specified disklabel.
996 * Return 0 on success, 1 on failure.
997 */
998 static int
getasciipartspec(char * tp,struct disklabel * lp,int part,int lineno)999 getasciipartspec(char *tp, struct disklabel *lp, int part, int lineno)
1000 {
1001 struct partition *pp;
1002 char *cp, *endp;
1003 const char **cpp;
1004 u_long v;
1005
1006 pp = &lp->d_partitions[part];
1007 cp = NULL;
1008
1009 v = 0;
1010 NXTWORD(part_size_type[part],v);
1011 if (v == 0 && part_size_type[part] != '*') {
1012 fprintf(stderr,
1013 "line %d: %s: bad partition size\n", lineno, cp);
1014 return (1);
1015 }
1016 pp->p_size = v;
1017
1018 v = 0;
1019 NXTWORD(part_offset_type[part],v);
1020 if (v == 0 && part_offset_type[part] != '*' &&
1021 part_offset_type[part] != '\0') {
1022 fprintf(stderr,
1023 "line %d: %s: bad partition offset\n", lineno, cp);
1024 return (1);
1025 }
1026 pp->p_offset = v;
1027 if (tp == NULL) {
1028 fprintf(stderr, "line %d: missing file system type\n", lineno);
1029 return (1);
1030 }
1031 cp = tp, tp = word(cp);
1032 for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++)
1033 if (*cpp && !strcmp(*cpp, cp))
1034 break;
1035 if (*cpp != NULL) {
1036 pp->p_fstype = cpp - fstypenames;
1037 } else {
1038 if (isdigit(*cp)) {
1039 errno = 0;
1040 v = strtoul(cp, &endp, 10);
1041 if (errno != 0 || *endp != '\0')
1042 v = FSMAXTYPES;
1043 } else
1044 v = FSMAXTYPES;
1045 if (v >= FSMAXTYPES) {
1046 fprintf(stderr,
1047 "line %d: Warning, unknown file system type %s\n",
1048 lineno, cp);
1049 v = FS_UNUSED;
1050 }
1051 pp->p_fstype = v;
1052 }
1053
1054 switch (pp->p_fstype) {
1055 case FS_UNUSED:
1056 case FS_BSDFFS:
1057 case FS_BSDLFS:
1058 /* accept defaults for fsize/frag/cpg */
1059 if (tp) {
1060 NXTNUM(pp->p_fsize);
1061 if (pp->p_fsize == 0)
1062 break;
1063 NXTNUM(v);
1064 pp->p_frag = v / pp->p_fsize;
1065 if (tp != NULL)
1066 NXTNUM(pp->p_cpg);
1067 }
1068 /* else default to 0's */
1069 break;
1070 default:
1071 break;
1072 }
1073 return (0);
1074 }
1075
1076 /*
1077 * Check disklabel for errors and fill in
1078 * derived fields according to supplied values.
1079 */
1080 static int
checklabel(struct disklabel * lp)1081 checklabel(struct disklabel *lp)
1082 {
1083 struct partition *pp;
1084 int i, errors = 0;
1085 char part;
1086 u_long base_offset, needed, total_percent, current_offset;
1087 long free_space;
1088 int seen_default_offset;
1089 int hog_part;
1090 int j;
1091 struct partition *pp2;
1092
1093 if (lp == NULL)
1094 lp = &lab;
1095
1096 if (allfields) {
1097
1098 if (lp->d_secsize == 0) {
1099 fprintf(stderr, "sector size 0\n");
1100 return (1);
1101 }
1102 if (lp->d_nsectors == 0) {
1103 fprintf(stderr, "sectors/track 0\n");
1104 return (1);
1105 }
1106 if (lp->d_ntracks == 0) {
1107 fprintf(stderr, "tracks/cylinder 0\n");
1108 return (1);
1109 }
1110 if (lp->d_ncylinders == 0) {
1111 fprintf(stderr, "cylinders/unit 0\n");
1112 errors++;
1113 }
1114 if (lp->d_rpm == 0)
1115 warnx("revolutions/minute 0");
1116 if (lp->d_secpercyl == 0)
1117 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1118 if (lp->d_secperunit == 0)
1119 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
1120 if (lp->d_bbsize == 0) {
1121 fprintf(stderr, "boot block size 0\n");
1122 errors++;
1123 } else if (lp->d_bbsize % lp->d_secsize)
1124 warnx("boot block size %% sector-size != 0");
1125 if (lp->d_npartitions > MAXPARTITIONS) {
1126 warnx("number of partitions (%lu) > MAXPARTITIONS (%d)",
1127 (u_long)lp->d_npartitions, MAXPARTITIONS);
1128 errors++;
1129 }
1130 if (lp->d_npartitions < DEFPARTITIONS) {
1131 warnx("number of partitions (%lu) < DEFPARTITIONS (%d)",
1132 (u_long)lp->d_npartitions, DEFPARTITIONS);
1133 errors++;
1134 }
1135 } else {
1136 struct disklabel *vl;
1137
1138 vl = getvirginlabel();
1139 if (lp->d_secsize == 0)
1140 lp->d_secsize = vl->d_secsize;
1141 if (lp->d_nsectors == 0)
1142 lp->d_nsectors = vl->d_nsectors;
1143 if (lp->d_ntracks == 0)
1144 lp->d_ntracks = vl->d_ntracks;
1145 if (lp->d_ncylinders == 0)
1146 lp->d_ncylinders = vl->d_ncylinders;
1147 if (lp->d_rpm == 0)
1148 lp->d_rpm = vl->d_rpm;
1149 if (lp->d_interleave == 0)
1150 lp->d_interleave = vl->d_interleave;
1151 if (lp->d_secpercyl == 0)
1152 lp->d_secpercyl = vl->d_secpercyl;
1153 if (lp->d_secperunit == 0 ||
1154 lp->d_secperunit > vl->d_secperunit)
1155 lp->d_secperunit = vl->d_secperunit;
1156 if (lp->d_bbsize == 0)
1157 lp->d_bbsize = vl->d_bbsize;
1158 if (lp->d_npartitions < DEFPARTITIONS ||
1159 lp->d_npartitions > MAXPARTITIONS)
1160 lp->d_npartitions = vl->d_npartitions;
1161 }
1162
1163
1164 /* first allocate space to the partitions, then offsets */
1165 total_percent = 0; /* in percent */
1166 hog_part = -1;
1167 /* find all fixed partitions */
1168 for (i = 0; i < lp->d_npartitions; i++) {
1169 pp = &lp->d_partitions[i];
1170 if (part_set[i]) {
1171 if (part_size_type[i] == '*') {
1172 if (i == RAW_PART) {
1173 pp->p_size = lp->d_secperunit;
1174 } else {
1175 if (hog_part != -1)
1176 warnx("Too many '*' partitions (%c and %c)",
1177 hog_part + 'a',i + 'a');
1178 else
1179 hog_part = i;
1180 }
1181 } else {
1182 off_t size;
1183
1184 size = pp->p_size;
1185 switch (part_size_type[i]) {
1186 case '%':
1187 total_percent += size;
1188 break;
1189 case 't':
1190 case 'T':
1191 size *= 1024ULL;
1192 /* FALLTHROUGH */
1193 case 'g':
1194 case 'G':
1195 size *= 1024ULL;
1196 /* FALLTHROUGH */
1197 case 'm':
1198 case 'M':
1199 size *= 1024ULL;
1200 /* FALLTHROUGH */
1201 case 'k':
1202 case 'K':
1203 size *= 1024ULL;
1204 break;
1205 case '\0':
1206 break;
1207 default:
1208 warnx("unknown multiplier suffix '%c' for partition %c (should be K, M, G or T)",
1209 part_size_type[i], i + 'a');
1210 break;
1211 }
1212 /* don't count %'s yet */
1213 if (part_size_type[i] != '%') {
1214 /*
1215 * for all not in sectors, convert to
1216 * sectors
1217 */
1218 if (part_size_type[i] != '\0') {
1219 if (size % lp->d_secsize != 0)
1220 warnx("partition %c not an integer number of sectors",
1221 i + 'a');
1222 size /= lp->d_secsize;
1223 pp->p_size = size;
1224 }
1225 }
1226 }
1227 }
1228 }
1229
1230 /* Find out the total free space, excluding the boot block area. */
1231 base_offset = BBSIZE / secsize;
1232 free_space = 0;
1233 for (i = 0; i < lp->d_npartitions; i++) {
1234 pp = &lp->d_partitions[i];
1235 if (!part_set[i] || i == RAW_PART ||
1236 part_size_type[i] == '%' || part_size_type[i] == '*')
1237 continue;
1238 if (pp->p_offset > base_offset)
1239 free_space += pp->p_offset - base_offset;
1240 if (pp->p_offset + pp->p_size > base_offset)
1241 base_offset = pp->p_offset + pp->p_size;
1242 }
1243 if (base_offset < lp->d_secperunit)
1244 free_space += lp->d_secperunit - base_offset;
1245
1246 /* handle % partitions - note %'s don't need to add up to 100! */
1247 if (total_percent != 0) {
1248 if (total_percent > 100) {
1249 fprintf(stderr,"total percentage %lu is greater than 100\n",
1250 total_percent);
1251 errors++;
1252 }
1253
1254 if (free_space > 0) {
1255 for (i = 0; i < lp->d_npartitions; i++) {
1256 pp = &lp->d_partitions[i];
1257 if (part_set[i] && part_size_type[i] == '%') {
1258 /* careful of overflows! and integer roundoff */
1259 pp->p_size = ((double)pp->p_size/100) * free_space;
1260
1261 /* FIX we can lose a sector or so due to roundoff per
1262 partition. A more complex algorithm could avoid that */
1263 }
1264 }
1265 } else {
1266 fprintf(stderr,
1267 "%ld sectors available to give to '*' and '%%' partitions\n",
1268 free_space);
1269 errors++;
1270 /* fix? set all % partitions to size 0? */
1271 }
1272 }
1273 /* give anything remaining to the hog partition */
1274 if (hog_part != -1) {
1275 /*
1276 * Find the range of offsets usable by '*' partitions around
1277 * the hog partition and how much space they need.
1278 */
1279 needed = 0;
1280 base_offset = BBSIZE / secsize;
1281 for (i = hog_part - 1; i >= 0; i--) {
1282 pp = &lp->d_partitions[i];
1283 if (!part_set[i] || i == RAW_PART)
1284 continue;
1285 if (part_offset_type[i] == '*') {
1286 needed += pp->p_size;
1287 continue;
1288 }
1289 base_offset = pp->p_offset + pp->p_size;
1290 break;
1291 }
1292 current_offset = lp->d_secperunit;
1293 for (i = lp->d_npartitions - 1; i > hog_part; i--) {
1294 pp = &lp->d_partitions[i];
1295 if (!part_set[i] || i == RAW_PART)
1296 continue;
1297 if (part_offset_type[i] == '*') {
1298 needed += pp->p_size;
1299 continue;
1300 }
1301 current_offset = pp->p_offset;
1302 }
1303
1304 if (current_offset - base_offset <= needed) {
1305 fprintf(stderr, "Cannot find space for partition %c\n",
1306 hog_part + 'a');
1307 fprintf(stderr,
1308 "Need more than %lu sectors between %lu and %lu\n",
1309 needed, base_offset, current_offset);
1310 errors++;
1311 lp->d_partitions[hog_part].p_size = 0;
1312 } else {
1313 lp->d_partitions[hog_part].p_size = current_offset -
1314 base_offset - needed;
1315 }
1316 }
1317
1318 /* Now set the offsets for each partition */
1319 current_offset = BBSIZE / secsize; /* in sectors */
1320 seen_default_offset = 0;
1321 for (i = 0; i < lp->d_npartitions; i++) {
1322 part = 'a' + i;
1323 pp = &lp->d_partitions[i];
1324 if (part_set[i]) {
1325 if (part_offset_type[i] == '*') {
1326 if (i == RAW_PART) {
1327 pp->p_offset = 0;
1328 } else {
1329 pp->p_offset = current_offset;
1330 seen_default_offset = 1;
1331 }
1332 } else {
1333 /* allow them to be out of order for old-style tables */
1334 if (pp->p_offset < current_offset &&
1335 seen_default_offset && i != RAW_PART &&
1336 pp->p_fstype != FS_VINUM) {
1337 fprintf(stderr,
1338 "Offset %ld for partition %c overlaps previous partition which ends at %lu\n",
1339 (long)pp->p_offset,i+'a',current_offset);
1340 fprintf(stderr,
1341 "Labels with any *'s for offset must be in ascending order by sector\n");
1342 errors++;
1343 } else if (pp->p_offset != current_offset &&
1344 i != RAW_PART && seen_default_offset) {
1345 /*
1346 * this may give unneeded warnings if
1347 * partitions are out-of-order
1348 */
1349 warnx(
1350 "Offset %ld for partition %c doesn't match expected value %ld",
1351 (long)pp->p_offset, i + 'a', current_offset);
1352 }
1353 }
1354 if (i != RAW_PART)
1355 current_offset = pp->p_offset + pp->p_size;
1356 }
1357 }
1358
1359 for (i = 0; i < lp->d_npartitions; i++) {
1360 part = 'a' + i;
1361 pp = &lp->d_partitions[i];
1362 if (pp->p_size == 0 && pp->p_offset != 0)
1363 warnx("partition %c: size 0, but offset %lu",
1364 part, (u_long)pp->p_offset);
1365 #ifdef notdef
1366 if (pp->p_size % lp->d_secpercyl)
1367 warnx("partition %c: size %% cylinder-size != 0",
1368 part);
1369 if (pp->p_offset % lp->d_secpercyl)
1370 warnx("partition %c: offset %% cylinder-size != 0",
1371 part);
1372 #endif
1373 if (pp->p_offset > lp->d_secperunit) {
1374 fprintf(stderr,
1375 "partition %c: offset past end of unit\n", part);
1376 errors++;
1377 }
1378 if (pp->p_offset + pp->p_size > lp->d_secperunit) {
1379 fprintf(stderr,
1380 "partition %c: partition extends past end of unit\n",
1381 part);
1382 errors++;
1383 }
1384 if (i == RAW_PART) {
1385 if (pp->p_fstype != FS_UNUSED)
1386 warnx("partition %c is not marked as unused!",part);
1387 if (pp->p_offset != 0)
1388 warnx("partition %c doesn't start at 0!",part);
1389 if (pp->p_size != lp->d_secperunit)
1390 warnx("partition %c doesn't cover the whole unit!",part);
1391
1392 if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) ||
1393 (pp->p_size != lp->d_secperunit)) {
1394 warnx("An incorrect partition %c may cause problems for "
1395 "standard system utilities",part);
1396 }
1397 }
1398
1399 /* check for overlaps */
1400 /* this will check for all possible overlaps once and only once */
1401 for (j = 0; j < i; j++) {
1402 pp2 = &lp->d_partitions[j];
1403 if (j != RAW_PART && i != RAW_PART &&
1404 pp->p_fstype != FS_VINUM &&
1405 pp2->p_fstype != FS_VINUM &&
1406 part_set[i] && part_set[j]) {
1407 if (pp2->p_offset < pp->p_offset + pp->p_size &&
1408 (pp2->p_offset + pp2->p_size > pp->p_offset ||
1409 pp2->p_offset >= pp->p_offset)) {
1410 fprintf(stderr,"partitions %c and %c overlap!\n",
1411 j + 'a', i + 'a');
1412 errors++;
1413 }
1414 }
1415 }
1416 }
1417 for (; i < lp->d_npartitions; i++) {
1418 part = 'a' + i;
1419 pp = &lp->d_partitions[i];
1420 if (pp->p_size || pp->p_offset)
1421 warnx("unused partition %c: size %d offset %lu",
1422 'a' + i, pp->p_size, (u_long)pp->p_offset);
1423 }
1424 return (errors);
1425 }
1426
1427 /*
1428 * When operating on a "virgin" disk, try getting an initial label
1429 * from the associated device driver. This might work for all device
1430 * drivers that are able to fetch some initial device parameters
1431 * without even having access to a (BSD) disklabel, like SCSI disks,
1432 * most IDE drives, or vn devices.
1433 *
1434 * The device name must be given in its "canonical" form.
1435 */
1436 static struct disklabel *
getvirginlabel(void)1437 getvirginlabel(void)
1438 {
1439 static struct disklabel loclab;
1440 struct partition *dp;
1441 int f;
1442 u_int u;
1443
1444 if ((f = open(specname, O_RDONLY)) == -1) {
1445 warn("cannot open %s", specname);
1446 return (NULL);
1447 }
1448
1449 if (is_file)
1450 get_file_parms(f);
1451 else {
1452 mediasize = g_mediasize(f);
1453 secsize = g_sectorsize(f);
1454 if (secsize < 0 || mediasize < 0) {
1455 close (f);
1456 return (NULL);
1457 }
1458 }
1459 memset(&loclab, 0, sizeof loclab);
1460 loclab.d_magic = DISKMAGIC;
1461 loclab.d_magic2 = DISKMAGIC;
1462 loclab.d_secsize = secsize;
1463 loclab.d_secperunit = mediasize / secsize;
1464
1465 /*
1466 * Nobody in these enlightened days uses the CHS geometry for
1467 * anything, but nonetheless try to get it right. If we fail
1468 * to get any good ideas from the device, construct something
1469 * which is IBM-PC friendly.
1470 */
1471 if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1472 loclab.d_nsectors = u;
1473 else
1474 loclab.d_nsectors = 63;
1475 if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1476 loclab.d_ntracks = u;
1477 else if (loclab.d_secperunit <= 63*1*1024)
1478 loclab.d_ntracks = 1;
1479 else if (loclab.d_secperunit <= 63*16*1024)
1480 loclab.d_ntracks = 16;
1481 else
1482 loclab.d_ntracks = 255;
1483 loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1484 loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1485 loclab.d_npartitions = DEFPARTITIONS;
1486
1487 /* Various (unneeded) compat stuff */
1488 loclab.d_rpm = 3600;
1489 loclab.d_bbsize = BBSIZE;
1490 loclab.d_interleave = 1;
1491 strncpy(loclab.d_typename, "amnesiac",
1492 sizeof(loclab.d_typename));
1493
1494 dp = &loclab.d_partitions[RAW_PART];
1495 dp->p_size = loclab.d_secperunit;
1496 loclab.d_checksum = dkcksum(&loclab);
1497 close (f);
1498 return (&loclab);
1499 }
1500
1501 static void
usage(void)1502 usage(void)
1503 {
1504
1505 fprintf(stderr,
1506 "%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",
1507 "usage: bsdlabel disk",
1508 "\t\t(to read label)",
1509 " bsdlabel -w [-n] [-m machine] disk [type]",
1510 "\t\t(to write label with existing boot program)",
1511 " bsdlabel -e [-n] [-m machine] disk",
1512 "\t\t(to edit label)",
1513 " bsdlabel -R [-n] [-m machine] disk protofile",
1514 "\t\t(to restore label with existing boot program)",
1515 " bsdlabel -B [-b boot] [-m machine] disk",
1516 "\t\t(to install boot program with existing on-disk label)",
1517 " bsdlabel -w -B [-n] [-b boot] [-m machine] disk [type]",
1518 "\t\t(to write label and install boot program)",
1519 " bsdlabel -R -B [-n] [-b boot] [-m machine] disk protofile",
1520 "\t\t(to restore label and install boot program)"
1521 );
1522 exit(1);
1523 }
1524