char	*skip __P((char *)); char	*word __P((char *)); int	getasciilabel __P((FILE *, struct disklabel *)); int	checklabel __P((struct disklabel *)); int	cmplabel __P((struct disklabel *, struct disklabel *)); void	setbootflag __P((struct disklabel *)); void	usage __P((void)); u_short	dkcksum __P((struct disklabel *));  int main(argc, argv) int argc; char *argv[]; { int ch, f, writeable, error = 0; struct disklabel *lp; FILE *t;  while ((ch = getopt(argc, argv, "BENRWb:denrs:tvw")) != -1) switch (ch) { #if NUMBOOT > 0 case 'B': ++installboot; break; case 'b': xxboot = optarg; break; #if NUMBOOT > 1 case 's': bootxx = optarg; break; #endif #endif case 'N': if (op != UNSPEC) usage(); writeable = 0; op = SETWRITEABLE; break; case 'R': if (op != UNSPEC) usage(); op = RESTORE; break; case 'W': if (op != UNSPEC) usage(); writeable = 1; op = SETWRITEABLE; break; case 'd': ++dflag; break; case 'e': if (op != UNSPEC) usage(); op = EDIT; break; case 'E': if (op != UNSPEC) usage(); op = EDITOR; break; case 'r': ++rflag; break; case 't': ++tflag; break; case 'w': if (op != UNSPEC) usage(); op = WRITE; break; case 'n': donothing++; break; case 'v': verbose++; break; case '?': default: usage(); } argc -= optind; argv += optind;  #if NUMBOOT > 0 if (installboot) { rflag++; if (op == UNSPEC) op = WRITEBOOT; } else { if (op == UNSPEC) op = READ; } #else if (op == UNSPEC) op = READ; #endif  if (argc < 1 || (rflag && dflag)) usage();  dkname = argv[0]; f = opendev(dkname, (op == READ ? O_RDONLY : O_RDWR), OPENDEV_PART, &specname); if (f < 0) err(4, "%s", specname);  #ifdef DOSLABEL  dosdp = readmbr(f); #endif  switch (op) { case EDIT: if (argc != 1) usage(); if ((lp = readlabel(f)) == NULL) exit(1); error = edit(lp, f); break; case EDITOR: if (argc != 1) usage(); if ((lp = readlabel(f)) == NULL) exit(1); error = editor(lp, f, specname); break; case READ: if (argc != 1) usage(); if ((lp = readlabel(f)) == NULL) exit(1); if (tflag) makedisktab(stdout, lp); else display(stdout, lp); error = checklabel(lp); break; case RESTORE: if (argc < 2 || argc > 3) usage(); #if NUMBOOT > 0 if (installboot && argc == 3) makelabel(argv[2], NULL, &lab); #endif lp = makebootarea(bootarea, &lab, f); if (!(t = fopen(argv[1], "r"))) err(4, "%s", argv[1]); if (getasciilabel(t, lp)) error = writelabel(f, bootarea, lp); break; case SETWRITEABLE: if (!donothing) { if (ioctl(f, DIOCWLABEL, (char *)&writeable) < 0) err(4, "ioctl DIOCWLABEL"); } break; case WRITE: if (argc < 2 || argc > 3) usage(); makelabel(argv[1], argc == 3 ? argv[2] : NULL, &lab); lp = makebootarea(bootarea, &lab, f); *lp = lab; if (checklabel(lp) == 0) error = writelabel(f, bootarea, lp); break; #if NUMBOOT > 0 case WRITEBOOT: { struct disklabel tlab;  if ((lp = readlabel(f)) == NULL) exit(1); tlab = *lp; if (argc == 2) makelabel(argv[1], NULL, &lab); lp = makebootarea(bootarea, &lab, f); *lp = tlab; if (checklabel(lp) == 0) error = writelabel(f, bootarea, lp); break; } #endif } exit(error); }   void makelabel(type, name, lp) char *type, *name; struct disklabel *lp; { struct disklabel *dp;  dp = getdiskbyname(type); if (dp == NULL) errx(1, "unknown disk type: %s", type); *lp = *dp; #if NUMBOOT > 0  if (!xxboot && lp->d_boot0) { if (*lp->d_boot0 != '/') (void)sprintf(boot0, "%s%s", _PATH_BOOTDIR, lp->d_boot0); else (void)strcpy(boot0, lp->d_boot0); xxboot = boot0; } #if NUMBOOT > 1 if (!bootxx && lp->d_boot1) { if (*lp->d_boot1 != '/') (void)sprintf(boot1, "%s%s", _PATH_BOOTDIR, lp->d_boot1); else (void)strcpy(boot1, lp->d_boot1); bootxx = boot1; } #endif #endif  memset(lp->d_packname, 0, sizeof(lp->d_packname)); if (name) (void)strncpy(lp->d_packname, name, sizeof(lp->d_packname)); }  int writelabel(f, boot, lp) int f; char *boot; struct disklabel *lp; { int writeable; off_t sectoffset = 0;  if (nwflag) { warnx("DANGER! The disklabel was not found at the correct location!"); warnx("To repair this situation, use `disklabel %s > file' to", dkname); warnx("save it, then use `disklabel -R %s file' to replace it.", dkname); warnx("A new disklabel is not being installed now."); return(0);  } #if NUMBOOT > 0 setbootflag(lp); #endif lp->d_magic = DISKMAGIC; lp->d_magic2 = DISKMAGIC; lp->d_checksum = 0; lp->d_checksum = dkcksum(lp); if (rflag) { #ifdef DOSLABEL struct partition *pp = &lp->d_partitions[2];   if (dosdp && pp->p_size && (dosdp->dp_typ == DOSPTYP_OPENBSD || dosdp->dp_typ == DOSPTYP_FREEBSD || dosdp->dp_typ == DOSPTYP_NETBSD)) { sectoffset = (off_t)get_le(&dosdp->dp_start) * lp->d_secsize; } else { if (dosdp) { int first, ch;  printf("Erase the previous contents of the disk? [n]: "); fflush(stdout); first = ch = getchar(); while (ch != '\n' && ch != EOF) ch = getchar(); if (first != 'y' && first != 'Y') exit(0); } sectoffset = 0; }  #if NUMBOOT > 0  if (!installboot) { struct disklabel tlab;  if (lseek(f, sectoffset, SEEK_SET) < 0) { perror("lseek"); return (1); } tlab = *lp; if (read(f, boot, tlab.d_bbsize) != tlab.d_bbsize) { perror("read"); return (1); } *lp =tlab; } #endif #endif   if (!donothing) { if (ioctl(f, DIOCSDINFO, lp) < 0 && errno != ENODEV && errno != ENOTTY) { l_perror("ioctl DIOCSDINFO"); return (1); } } if (verbose) printf("writing label to block %qd (0x%qx)\n", sectoffset/DEV_BSIZE, sectoffset/DEV_BSIZE); if (!donothing) { if (lseek(f, sectoffset, SEEK_SET) < 0) { perror("lseek"); return (1); }  writeable = 1;  if (ioctl(f, DIOCWLABEL, &writeable) < 0) perror("ioctl DIOCWLABEL"); #ifdef __alpha__  { int i; u_int64_t *dp, sum;  dp = (u_int64_t *)boot; sum = 0; for (i = 0; i < 63; i++) sum += dp[i]; dp[63] = sum; } #endif if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) { perror("write"); return (1); } } #if NUMBOOT > 0  if (!donothing && bootbuf && write(f, bootbuf, bootsize) != bootsize) { perror("write"); return(1); } #endif writeable = 0; if (!donothing) if (ioctl(f, DIOCWLABEL, &writeable) < 0) perror("ioctl DIOCWLABEL"); } else { if (!donothing) { if (ioctl(f, DIOCWDINFO, lp) < 0) { l_perror("ioctl DIOCWDINFO"); return (1); } } } #ifdef vax if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { daddr_t alt; int i;  alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { (void)lseek(f, (off_t)((alt + i) * lp->d_secsize), SEEK_SET); if (!donothing) if (write(f, boot, lp->d_secsize) < lp->d_secsize) warn("alternate label %d write", i/2); } } #endif return (0); }  void l_perror(s) char *s; {  switch (errno) { case ESRCH: warnx("%s: No disk label on disk;\n" "use \"disklabel -r\" to install initial label", s); break; case EINVAL: warnx("%s: Label magic number or checksum is wrong!\n" "(disklabel or kernel is out of date?)", s); break; case EBUSY: warnx("%s: Open partition would move or shrink", s); break; case EXDEV: warnx("%s: Labeled partition or 'a' partition must start " "at beginning of disk", s); break; default: warn("%s", s); break; } }  #ifdef DOSLABEL  struct dos_partition * readmbr(f) int f; { static int mbr[DEV_BSIZE / sizeof(int)]; struct dos_partition *dp; int part;   dp = (struct dos_partition *)mbr; if (lseek(f, (off_t)DOSBBSECTOR * DEV_BSIZE, SEEK_SET) < 0 || read(f, mbr, sizeof(mbr)) < sizeof(mbr)) err(4, "can't read master boot record");  bcopy((char *)mbr+DOSPARTOFF, (char *)mbr, sizeof(*dp) * NDOSPART);    for (part = 0; part < NDOSPART; part++) { if ((dp[part].dp_flag & ~0x80) != 0) return (0); }  for (part = 0; part < NDOSPART; part++) { if (get_le(&dp[part].dp_size) && dp[part].dp_typ == DOSPTYP_OPENBSD) { fprintf(stderr, "# using MBR partition %d: " "type %02X off %d (0x%x) size %d (0x%x)\n", part, dp[part].dp_typ, get_le(&dp[part].dp_start), get_le(&dp[part].dp_start), get_le(&dp[part].dp_size), get_le(&dp[part].dp_size)); return (&dp[part]); } } for (part = 0; part < NDOSPART; part++) { if (get_le(&dp[part].dp_size) && dp[part].dp_typ == DOSPTYP_FREEBSD) { fprintf(stderr, "# using MBR partition %d: " "type %02X off %d (0x%x) size %d (0x%x)\n", part, dp[part].dp_typ, get_le(&dp[part].dp_start), get_le(&dp[part].dp_start), get_le(&dp[part].dp_size), get_le(&dp[part].dp_size)); return (&dp[part]); } } for (part = 0; part < NDOSPART; part++) { if (get_le(&dp[part].dp_size) && dp[part].dp_typ == DOSPTYP_NETBSD) { fprintf(stderr, "# using MBR partition %d: " "type %02X off %d (0x%x) size %d (0x%x)\n", part, dp[part].dp_typ, get_le(&dp[part].dp_start), get_le(&dp[part].dp_start), get_le(&dp[part].dp_size), get_le(&dp[part].dp_size)); return (&dp[part]); } }   for (part = 0; part < NDOSPART; part++) { if (get_le(&dp[part].dp_size)) { warnx("warning, DOS partition table with no valid OpenBSD partition"); return (&dp[part]); } }  return (0); } #endif   struct disklabel * readlabel(f) int f; { struct disklabel *lp = NULL;  if (rflag) { char *msg; off_t sectoffset = 0;  #ifdef DOSLABEL if (dosdp && get_le(&dosdp->dp_size) && (dosdp->dp_typ == DOSPTYP_OPENBSD || dosdp->dp_typ == DOSPTYP_FREEBSD || dosdp->dp_typ == DOSPTYP_NETBSD)) sectoffset = (off_t)get_le(&dosdp->dp_start) * DEV_BSIZE; #endif if (verbose) printf("reading label from block %qd, offset %qd\n", sectoffset/DEV_BSIZE, sectoffset/DEV_BSIZE + (LABELSECTOR * DEV_BSIZE) + LABELOFFSET); if (lseek(f, sectoffset, SEEK_SET) < 0 || read(f, bootarea, BBSIZE) < BBSIZE) err(4, "%s", specname);  lp = (struct disklabel *)(bootarea + (LABELSECTOR * DEV_BSIZE) + LABELOFFSET); if (lp->d_magic == DISKMAGIC && lp->d_magic2 == DISKMAGIC) { if (lp->d_npartitions <= MAXPARTITIONS && dkcksum(lp) == 0) return (lp);  msg = "disk label corrupted"; } else { warnx("no disklabel found. scanning."); } nwflag++;  msg = "no disk label"; for (lp = (struct disklabel *)bootarea; lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp)); lp = (struct disklabel *)((char *)lp + sizeof(long))) { if (lp->d_magic == DISKMAGIC && lp->d_magic2 == DISKMAGIC) { if (lp->d_npartitions <= MAXPARTITIONS && dkcksum(lp) == 0) { warnx("found at 0x%x", (char *)lp - bootarea); return (lp); } msg = "disk label corrupted"; } } warnx(msg); return(NULL); } else if (dflag) { lp = &lab; if (ioctl(f, DIOCGPDINFO, lp) < 0) err(4, "ioctl DIOCGPDINFO"); } else { lp = &lab; if (ioctl(f, DIOCGDINFO, lp) < 0) err(4, "ioctl DIOCGDINFO"); } return (lp); }   struct disklabel * makebootarea(boot, dp, f) char *boot; struct disklabel *dp; int f; { struct disklabel *lp; char *p; int b; #if NUMBOOT > 0 char *dkbasename; #if NUMBOOT == 1 struct stat sb; #endif #endif   if (dp->d_secsize == 0) { dp->d_secsize = DEV_BSIZE; dp->d_bbsize = BBSIZE; } lp = (struct disklabel *) (boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET); memset(lp, 0, sizeof *lp); #if NUMBOOT > 0  if (!installboot) { #ifndef i386 if (rflag) { if (read(f, boot, BBSIZE) < BBSIZE) err(4, "%s", specname); memset(lp, 0, sizeof *lp); } #endif return (lp); }  if (!xxboot || !bootxx) { dkbasename = np; if ((p = strrchr(dkname, '/')) == NULL) p = dkname; else p++; while (*p && !isdigit(*p)) *np++ = *p++; *np++ = '\0';  if (!xxboot) { (void)sprintf(np, "%s%sboot", _PATH_BOOTDIR, dkbasename); if (access(np, F_OK) < 0 && dkbasename[0] == 'r') dkbasename++; xxboot = np; (void)sprintf(xxboot, "%s%sboot", _PATH_BOOTDIR, dkbasename); np += strlen(xxboot) + 1; } #if NUMBOOT > 1 if (!bootxx) { (void)sprintf(np, "%sboot%s", _PATH_BOOTDIR, dkbasename); if (access(np, F_OK) < 0 && dkbasename[0] == 'r') dkbasename++; bootxx = np; (void)sprintf(bootxx, "%sboot%s", _PATH_BOOTDIR, dkbasename); np += strlen(bootxx) + 1; } #endif } if (verbose) warnx("bootstraps: xxboot = %s, bootxx = %s", xxboot, bootxx ? bootxx : "NONE");   b = open(xxboot, O_RDONLY); if (b < 0) err(4, "%s", xxboot); #if NUMBOOT > 1 if (read(b, boot, (int)dp->d_secsize) < 0) err(4, "%s", xxboot); (void)close(b); b = open(bootxx, O_RDONLY); if (b < 0) err(4, "%s", bootxx); if (read(b, &boot[dp->d_secsize], (int)(dp->d_bbsize-dp->d_secsize)) < 0) err(4, "%s", bootxx); #else if (read(b, boot, (int)dp->d_bbsize) < 0) err(4, "%s", xxboot); (void)fstat(b, &sb); bootsize = (int)sb.st_size - dp->d_bbsize; if (bootsize > 0) {  bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1); bootbuf = (char *)malloc((size_t)bootsize); if (bootbuf == 0) err(4, "%s", xxboot); if (read(b, bootbuf, bootsize) < 0) { free(bootbuf); err(4, "%s", xxboot); } } #endif (void)close(b); #endif  for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++) if (*p) errx(2, "Bootstrap doesn't leave room for disk label"); return (lp); }  void makedisktab(f, lp) FILE *f; struct disklabel *lp; { int i, j; char *did = "\\\n\t:"; struct partition *pp;  if (lp->d_packname[0]) (void)fprintf(f, "%.*s|", sizeof(lp->d_packname), lp->d_packname); if (lp->d_typename[0]) (void)fprintf(f, "%.*s|", sizeof(lp->d_typename), lp->d_typename); (void)fputs("Automatically generated label:\\\n\t:dt=", f); if ((unsigned) lp->d_type < DKMAXTYPES) (void)fprintf(f, "%s:", dktypenames[lp->d_type]); else (void)fprintf(f, "unknown%d:", lp->d_type);  (void)fprintf(f, "se#%d:", lp->d_secsize); (void)fprintf(f, "ns#%d:", lp->d_nsectors); (void)fprintf(f, "nt#%d:", lp->d_ntracks); (void)fprintf(f, "sc#%d:", lp->d_secpercyl); (void)fprintf(f, "nc#%d:", lp->d_ncylinders);  if (lp->d_rpm != 3600) { (void)fprintf(f, "%srm#%d:", did, lp->d_rpm); did = ""; } if (lp->d_interleave != 1) { (void)fprintf(f, "%sil#%d:", did, lp->d_interleave); did = ""; } if (lp->d_trackskew != 0) { (void)fprintf(f, "%ssk#%d:", did, lp->d_trackskew); did = ""; } if (lp->d_cylskew != 0) { (void)fprintf(f, "%scs#%d:", did, lp->d_cylskew); did = ""; } if (lp->d_headswitch != 0) { (void)fprintf(f, "%shs#%d:", did, lp->d_headswitch); did = ""; } if (lp->d_trkseek != 0) { (void)fprintf(f, "%sts#%d:", did, lp->d_trkseek); did = ""; } for (i = 0; i < NDDATA; i++) if (lp->d_drivedata[i]) (void)fprintf(f, "d%d#%d", lp->d_drivedata[i]); pp = lp->d_partitions; for (i = 0; i < lp->d_npartitions; i++, pp++) { if (pp->p_size) { char c = 'a' + i;  (void)fprintf(f, "\\\n\t:"); (void)fprintf(f, "p%c#%d:", c, pp->p_size); (void)fprintf(f, "o%c#%d:", c, pp->p_offset); if (pp->p_fstype != FS_UNUSED) { if ((unsigned) pp->p_fstype < FSMAXTYPES) (void)fprintf(f, "t%c=%s:", c, fstypenames[pp->p_fstype]); else (void)fprintf(f, "t%c=unknown%d:", c, pp->p_fstype); } switch (pp->p_fstype) {  case FS_UNUSED: break;  case FS_BSDFFS: (void)fprintf(f, "b%c#%d:", c, pp->p_fsize * pp->p_frag); (void)fprintf(f, "f%c#%d:", c, pp->p_fsize); break;  default: break; } } } (void)fputc('\n', f); (void)fflush(f); }  int width_partition(lp, unit) struct disklabel *lp; { unit = toupper(unit); switch (unit) { case 'K': return 10; } return 8; }   void display_partition(f, lp, i, unit, width) FILE *f; struct disklabel *lp; int i; char unit; int width; { struct partition *pp = &lp->d_partitions[i]; double p_size, p_offset;  if (width == 0) width = 8; unit = toupper(unit); switch (unit) { case 'B': p_size = (double)pp->p_size * lp->d_secsize; p_offset = (double)pp->p_offset * lp->d_secsize; break;  case 'C': p_size = (double)pp->p_size / lp->d_secpercyl; p_offset = (double)pp->p_offset / lp->d_secpercyl; break;  case 'K': p_size = (double)pp->p_size / (1024 / lp->d_secsize); p_offset = (double)pp->p_offset / (1024 / lp->d_secsize); break;  case 'M': p_size = (double)pp->p_size / ((1024*1024) / lp->d_secsize); p_offset = (double)pp->p_offset / ((1024*1024) / lp->d_secsize); break;  case 'G': p_size = (double)pp->p_size / ((1024*1024*1024) / lp->d_secsize); p_offset = (double)pp->p_offset / ((1024*1024*1024) / lp->d_secsize); break;  default: p_size = -1;			 break; }  if (pp->p_size) { if (p_size < 0) fprintf(f, "  %c: %*u %*u  ", 'a' + i, width, pp->p_size, width, pp->p_offset); else fprintf(f, "  %c: %*.1f%c %*.1f%c  ", 'a' + i, width-1, p_size, unit, width-1, p_offset, unit); if ((unsigned) pp->p_fstype < FSMAXTYPES) fprintf(f, "%8.8s", fstypenames[pp->p_fstype]); else fprintf(f, "%8d", pp->p_fstype); switch (pp->p_fstype) {  case FS_UNUSED:				 fprintf(f, "    %5d %5d %5.5s ", pp->p_fsize, pp->p_fsize * pp->p_frag, ""); break;  case FS_BSDFFS: fprintf(f, "    %5d %5d %5d ", pp->p_fsize, pp->p_fsize * pp->p_frag, pp->p_cpg); break;  default: fprintf(f, "%20.20s", ""); break; } if (lp->d_secpercyl) { fprintf(f, "\t# (Cyl. %4d", pp->p_offset / lp->d_secpercyl); if (pp->p_offset % lp->d_secpercyl) putc('*', f); else putc(' ', f); fprintf(f, "- %d", (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl - 1); if ((pp->p_offset + pp->p_size) % lp->d_secpercyl) putc('*', f); putc(')', f); } putc('\n', f); } }  void display(f, lp) FILE *f; struct disklabel *lp; { int i, j; int width;  fprintf(f, "# %s:\n", specname); if ((unsigned) lp->d_type < DKMAXTYPES) fprintf(f, "type: %s\n", dktypenames[lp->d_type]); else fprintf(f, "type: %d\n", lp->d_type); fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename); fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname); fprintf(f, "flags:"); if (lp->d_flags & D_REMOVABLE) fprintf(f, " removable"); if (lp->d_flags & D_ECC) fprintf(f, " ecc"); if (lp->d_flags & D_BADSECT) fprintf(f, " badsect"); putc('\n', f); fprintf(f, "bytes/sector: %ld\n", (long)lp->d_secsize); fprintf(f, "sectors/track: %ld\n", (long)lp->d_nsectors); fprintf(f, "tracks/cylinder: %ld\n", (long)lp->d_ntracks); fprintf(f, "sectors/cylinder: %ld\n", (long)lp->d_secpercyl); fprintf(f, "cylinders: %ld\n", (long)lp->d_ncylinders); fprintf(f, "total sectors: %ld\n", (long)lp->d_secperunit); fprintf(f, "rpm: %ld\n", (long)lp->d_rpm); fprintf(f, "interleave: %ld\n", (long)lp->d_interleave); fprintf(f, "trackskew: %ld\n", (long)lp->d_trackskew); fprintf(f, "cylinderskew: %ld\n", (long)lp->d_cylskew); fprintf(f, "headswitch: %ld\t\t# milliseconds\n", (long)lp->d_headswitch); fprintf(f, "track-to-track seek: %ld\t# milliseconds\n", (long)lp->d_trkseek); fprintf(f, "drivedata: "); for (i = NDDATA - 1; i >= 0; i--) if (lp->d_drivedata[i]) break; if (i < 0) i = 0; for (j = 0; j <= i; j++) fprintf(f, "%d ", lp->d_drivedata[j]); fprintf(f, "\n\n%d partitions:\n", lp->d_npartitions); width = width_partition(lp, 0); fprintf(f, "#    %*.*s %*.*s    fstype   [fsize bsize   cpg]\n", width, width, "size", width, width, "offset"); for (i = 0; i < lp->d_npartitions; i++) display_partition(f, lp, i, 0, width); fflush(f); }  int edit(lp, f) struct disklabel *lp; int f; { int first, ch, fd; struct disklabel label; FILE *fp;  if ((fd = mkstemp(tmpfil)) == -1 || (fp = fdopen(fd, "w")) == NULL) { if (fd != -1) close(fd); warn("%s", tmpfil); return (1); } display(fp, lp); fprintf(fp, "\n# Notes:\n"); fprintf(fp, "# Up to 16 partitions are valid, named from 'a' to 'p'.  Partition 'a' is\n" "# your root filesystem, 'b' is your swap, and 'c' should cover your whole\n" "# disk. Any other partition is free for any use.  'size' and 'offset' are\n" "# in 512-byte blocks. fstype should be '4.2BSD', 'swap', or 'none' or some\n" "# other values.  fsize/bsize/cpg should typically be '1024 8192 16' for a\n" "# 4.2BSD filesystem (or '512 4096 16' except on alpha, sun4, amiga, sun3...)\n"); fclose(fp); for (;;) { if (!editit()) break; fp = fopen(tmpfil, "r"); if (fp == NULL) { warn("%s", tmpfil); break; } memset(&label, 0, sizeof(label)); if (getasciilabel(fp, &label)) { if (cmplabel(lp, &label) == 0) { puts("No changes."); fclose(fp); (void) unlink(tmpfil); return (0); } *lp = label; if (writelabel(f, bootarea, lp) == 0) { fclose(fp); (void) unlink(tmpfil); return (0); } } fclose(fp); printf("re-edit the label? [y]: "); fflush(stdout); first = ch = getchar(); while (ch != '\n' && ch != EOF) ch = getchar(); if (first == 'n' || first == 'N') break; } (void)unlink(tmpfil); return (1); }  int editit() { pid_t pid, xpid; int stat; extern char *getenv(); char *argp[] = {"sh", "-c", NULL, NULL}; char *ed, *p;  if ((ed = getenv("EDITOR")) == NULL) ed = _PATH_VI; p = (char *)malloc(strlen(ed) + 1 + strlen(tmpfil) + 1); if (!p) { warn("failed to start editor"); return (0); } sprintf(p, "%s %s", ed, tmpfil); argp[2] = p;   (void)signal(SIGHUP, SIG_IGN); (void)signal(SIGINT, SIG_IGN); (void)signal(SIGQUIT, SIG_IGN); while ((pid = fork()) < 0) { if (errno != EAGAIN) { warn("fork"); free(p); stat = 1; goto bail; } sleep(1); } if (pid == 0) { execv(_PATH_BSHELL, argp); _exit(127); } free(p); for (;;) { xpid = waitpid(pid, (int *)&stat, WUNTRACED); if (WIFSTOPPED(stat)) raise(WSTOPSIG(stat)); else if (WIFEXITED(stat)) break; } bail: (void)signal(SIGHUP, SIG_DFL); (void)signal(SIGINT, SIG_DFL); (void)signal(SIGQUIT, SIG_DFL); return (!stat); }  char *
skip(cp)	char *cp;{	cp += strspn(cp, " \t");	if (*cp == '\0')		return (NULL);	return (cp);}