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