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