Subject: that disk labeling program
To: None <port-sparc@NetBSD.ORG, port-sun3@NetBSD.ORG>
From: der Mouse <mouse@Collatz.McRCIM.McGill.EDU>
List: port-sun3
Date: 01/16/1996 17:27:02
Back in October I wrote....

> I've had bad luck trying to repartition with disklabel.  I have a
> program that knows how to read, modify, and write Sun labels, which
> may be of use to people wishing to repartition disks for NetBSD/sparc
> and NetBSD/sun3.  [...]

I received at least three messages expressing interest; I then
experienced one of my typical mailbox overruns and they got buried.
Finally, though, here the program is, along with a rudimentary doc
file.  Note in particular that you need -DDISTRIB to build it on a
stock system.

					der Mouse

			    mouse@collatz.mcrcim.mcgill.edu

#! /bin/sh
#
# Shar: Shell Archiver
#
# This archive created Tue Jan 16 17:24:40 1996
# Run this through sh to create:
#	sunlabel.doc
#	sunlabel.c
echo x - sunlabel.doc \(2312 characters\)
sed 's/^X//' > sunlabel.doc << \EOF
Xsunlabel.c is the source; with -DDISTRIB, it builds on stock
XNetBSD/sun3.  It should build equally well on a SPARC, or probably just
Xabout anything else - though I don't expect it to work correctly on
Xlittle-endian machines.
X
XUsage: pass a single argument, which is the disk device you wish to
Xread/write the label to/from, or a file.  sunlabel reads/writes only
Xthe first 512 bytes of its argument.  There are also three flags
Xsupported: -disk, which takes an argument specifying the disk device
X(in case you want to give something beginning with a -); -fixsum, which
Xsays to ignore checksum errors when reading the label; and -new, which
Xsays to synthesize a new label rather than reading what's there.
X
Xsunlabel prints a prompt "sunlabel>" and expects commands.  You can
Xtype ? for help; as of this writing, the help is
X
X	? - print this help
X	l - print label, except for partition table
X	p - print partition table
X	[abcdefgh] <cylno> <size> - change partition
X	v <name> <value> - change a non-partition label value
X	w - write (possibly modified) label out
X	q - quit program (error if no write since last change)
X	Q - quit program (unconditionally)
X
XThe a through h commands will accept, for the <size> parameter, the
Xnnn/nnn/nnn syntax used by SunOS 4.x format(8).  (For those not
Xfamiliar with this syntax, a/b/c means a cylinders + b tracks + c
Xsectors.  For example, if the disk has 16 tracks of 32 sectors, 3/4/5
Xmeans (3*512)+(4*32)+5=1669.  This calculation always uses the nsect
Xand ntrack values as printed by the l command; in particular, if they
Xare zero (which they will initially be if -new is used), this syntax is
Xnot very useful.
X
XThe v command changes fields printed by the l command.  For example, if
Xthe l command prints
X
X	ascii: ST15230N cyl 5657 alt 2 hd 19 sec 78
X	rpm: 0          pcyl: 0         apc: 0          obs1: 0
X	obs2: 0         intrlv: 1       ncyl: 5657      acyl: 0
X	nhead: 19       nsect: 78       obs3: 0         obs4: 0
X
Xthen you could type "v ncyl 6204" to set the ncyl value to 6204, or
X"v ascii ST15230N cyl 5657 hd 19 sec varying" to set the ascii-label
Xstring to that string.  sunlabel performs no consistency checks; it's a
XYAFIYGI program.
X
XI will be glad to correspond with anyone about this program.  I'm...
X
X					der Mouse
X
X			    mouse@collatz.mcrcim.mcgill.edu
EOF
if test 2312 -ne "`wc -c sunlabel.doc`"
then
echo shar: error transmitting sunlabel.doc \(should have been 2312 characters\)
fi
echo x - sunlabel.c \(12171 characters\)
sed 's/^X//' > sunlabel.c << \EOF
X#ifdef DISTRIB
X
X#include <stdio.h>
X#include <errno.h>
X#include <ctype.h>
X#include <stdlib.h>
X#include <strings.h>
X#include <sys/file.h>
Xchar **argvec;
Xvoid main(int, char **);
Xvoid main_(int, char **);
Xvoid main(int ac, char **av) { argvec = av; main_(ac,av); }
X#define main main_
X
X#else
X
X#include <stdio.h>
X#include <errno.h>
X#include <ctype.h>
X#include <stdlib.h>
X#include <strings.h>
X#include <syscalls.h>
X#include <sys/file.h>
X
X#endif
X
Xextern char **argvec;
X
Xtypedef struct field FIELD;
Xtypedef struct label LABEL;
Xtypedef struct part PART;
X
Xstruct part {
X  unsigned int startcyl;
X  unsigned int nblk;
X  } ;
X
Xstruct label {
X  /* BEGIN fields taken directly from struct dk_label */
X  char asciilabel[128];
X  unsigned int rpm;
X  unsigned int pcyl;
X  unsigned int apc;
X  unsigned int obs1;
X  unsigned int obs2;
X  unsigned int intrlv;
X  unsigned int ncyl;
X  unsigned int acyl;
X  unsigned int nhead;
X  unsigned int nsect;
X  unsigned int obs3;
X  unsigned int obs4;
X  /* END fields taken directly from struct dk_label */
X  unsigned int spc;
X  unsigned int dirty : 1;
X  PART partitions[8];
X  } ;
X
Xstruct field {
X  const char *tag;
X  void *loc;
X  int (*print)(FIELD *, int);
X  void (*chval)(const char *, FIELD *);
X  int taglen;
X  } ;
X
X#define LABEL_MAGIC 0xdabe
X
Xstatic int diskfd;
Xstatic const char *diskname;
Xstatic int readonly;
Xstatic unsigned char labelbuf[512];
Xstatic LABEL label;
Xstatic int fixcksum;
Xstatic int newlabel;
X
Xstatic int print_ascii(FIELD *, int);
Xstatic void chval_ascii(const char *, FIELD *);
Xstatic int print_int(FIELD *, int);
Xstatic void chval_int(const char *, FIELD *);
Xstatic FIELD fields[]
X = { { "ascii",  &label.asciilabel[0], print_ascii, chval_ascii },
X     { "rpm",    &label.rpm,           print_int,   chval_int   },
X     { "pcyl",   &label.pcyl,          print_int,   chval_int   },
X     { "apc",    &label.apc,           print_int,   chval_int   },
X     { "obs1",   &label.obs1,          print_int,   chval_int   },
X     { "obs2",   &label.obs2,          print_int,   chval_int   },
X     { "intrlv", &label.intrlv,        print_int,   chval_int   },
X     { "ncyl",   &label.ncyl,          print_int,   chval_int   },
X     { "acyl",   &label.acyl,          print_int,   chval_int   },
X     { "nhead",  &label.nhead,         print_int,   chval_int   },
X     { "nsect",  &label.nsect,         print_int,   chval_int   },
X     { "obs3",   &label.obs3,          print_int,   chval_int   },
X     { "obs4",   &label.obs4,          print_int,   chval_int   },
X     { 0 } };
X
Xstatic int trydisk(const char *s, int mustsucceed)
X{
X diskname = s;
X diskfd = open(s,O_RDWR,0);
X if (diskfd < 0)
X  { diskfd = open(s,O_RDONLY,0);
X    if (diskfd < 0)
X     { if (mustsucceed)
X	{ fprintf(stderr,"%s: can't open %s: %s\n",argvec[0],s,strerror(errno));
X	  exit(1);
X	}
X       return(0);
X     }
X    readonly = 1;
X  }
X else
X  { readonly = 0;
X  }
X return(1);
X}
X
Xstatic void setdisk(const char *s)
X{
X char *tmp;
X
X if (index(s,'/'))
X  { trydisk(s,1);
X    return;
X  }
X if (trydisk(s,0)) return;
X tmp = malloc(strlen(s)+7);
X sprintf(tmp,"/dev/%s",s);
X if (trydisk(s,0)) return;
X sprintf(tmp,"/dev/%sc",s);
X if (trydisk(s,0)) return;
X fprintf(stderr,"%s: can't find device for disk %s\n",argvec[0],s);
X exit(1);
X}
X
Xstatic void handleargs(int ac, char **av)
X{
X int skip;
X int errs;
X int argno;
X
X skip = 0;
X errs = 0;
X argno = 0;
X for (ac--,av++;ac;ac--,av++)
X  { if (skip > 0)
X     { skip --;
X       continue;
X     }
X    if (**av != '-')
X     { switch (argno++)
X	{ case 0:
X	     setdisk(*av);
X	     break;
X	  default:
X	     fprintf(stderr,"%s: unrecognized argument `%s'\n",argvec[0],*av);
X	     errs ++;
X	     break;
X	}
X       continue;
X     }
X    if (0)
X     {
Xneedarg:;
X       fprintf(stderr,"%s: %s needs a following argument\n",argvec[0],*av);
X       errs ++;
X       continue;
X     }
X#define WANTARG() do { if (++skip >= ac) goto needarg; } while (0)
X    if (!strcmp(*av,"-disk"))
X     { WANTARG();
X       setdisk(av[skip]);
X       continue;
X     }
X    if (!strcmp(*av,"-fixsum"))
X     { fixcksum = 1;
X       continue;
X     }
X    if (!strcmp(*av,"-new"))
X     { newlabel = 1;
X       continue;
X     }
X#undef WANTARG
X    fprintf(stderr,"%s: unrecognized option `%s'\n",argvec[0],*av);
X    errs ++;
X  }
X if (errs)
X  { exit(1);
X  }
X}
X
Xstatic const char *unpack_label(void)
X{
X unsigned short int l_s[256];
X unsigned long int l_l[128];
X int i;
X unsigned short int sum;
X
X if (newlabel)
X  { bzero(&label.asciilabel[0],128);
X    label.rpm = 0;
X    label.pcyl = 0;
X    label.apc = 0;
X    label.obs1 = 0;
X    label.obs2 = 0;
X    label.intrlv = 0;
X    label.ncyl = 0;
X    label.acyl = 0;
X    label.nhead = 0;
X    label.nsect = 0;
X    label.obs3 = 0;
X    label.obs4 = 0;
X    for (i=0;i<8;i++)
X     { label.partitions[i].startcyl = 0;
X       label.partitions[i].nblk = 0;
X     }
X    label.spc = 0;
X    label.dirty = 1;
X    return(0);
X  }
X for (i=0;i<256;i++) l_s[i] = (labelbuf[i+i] << 8) | labelbuf[i+i+1];
X for (i=0;i<128;i++) l_l[i] = (l_s[i+i] << 16) | l_s[i+i+1];
X if (l_s[254] != LABEL_MAGIC) return("bad magic number");
X sum = 0;
X for (i=0;i<256;i++) sum ^= l_s[i];
X label.dirty = 0;
X if (sum != 0)
X  { if (fixcksum)
X     { label.dirty = 1;
X     }
X    else
X     { return("checksum wrong");
X     }
X  }
X bcopy(&labelbuf[0],&label.asciilabel[0],128);
X label.rpm = l_s[210];
X label.pcyl = l_s[211];
X label.apc = l_s[212];
X label.obs1 = l_s[213];
X label.obs2 = l_s[214];
X label.intrlv = l_s[215];
X label.ncyl = l_s[216];
X label.acyl = l_s[217];
X label.nhead = l_s[218];
X label.nsect = l_s[219];
X label.obs3 = l_s[220];
X label.obs4 = l_s[221];
X label.spc = label.nhead * label.nsect;
X for (i=0;i<8;i++)
X  { label.partitions[i].startcyl = l_l[i+i+111];
X    label.partitions[i].nblk = l_l[i+i+112];
X  }
X return(0);
X}
X
Xstatic void pack_label(void)
X{
X unsigned short int l_s[256];
X int i;
X unsigned short int sum;
X
X bzero(&l_s[0],512);
X bcopy(&label.asciilabel[0],&l_s[0],128);
X l_s[210] = label.rpm;
X l_s[211] = label.pcyl;
X l_s[212] = label.apc;
X l_s[213] = label.obs1;
X l_s[214] = label.obs2;
X l_s[215] = label.intrlv;
X l_s[216] = label.ncyl;
X l_s[217] = label.acyl;
X l_s[218] = label.nhead;
X l_s[219] = label.nsect;
X l_s[220] = label.obs3;
X l_s[221] = label.obs4;
X for (i=0;i<8;i++)
X  { l_s[(i*4)+222] = label.partitions[i].startcyl >> 16;
X    l_s[(i*4)+223] = label.partitions[i].startcyl & 0xffff;
X    l_s[(i*4)+224] = label.partitions[i].nblk >> 16;
X    l_s[(i*4)+225] = label.partitions[i].nblk & 0xffff;
X  }
X l_s[254] = LABEL_MAGIC;
X sum = 0;
X for (i=0;i<255;i++) sum ^= l_s[i];
X l_s[255] = sum;
X bcopy(&l_s[0],&labelbuf[0],512);
X}
X
Xstatic void getlabel(void)
X{
X int rv;
X const char *lerr;
X
X if (lseek(diskfd,0,L_SET) < 0)
X  { fprintf(stderr,"%s: lseek to 0 on %s: %s\n",argvec[0],diskname,strerror(errno));
X    exit(1);
X  }
X rv = read(diskfd,&labelbuf[0],512);
X if (rv < 0)
X  { fprintf(stderr,"%s: read label from %s: %s\n",argvec[0],diskname,strerror(errno));
X    exit(1);
X  }
X if (rv != 512)
X  { fprintf(stderr,"%s: short read from %s: wanted %d, got %d\n",argvec[0],diskname,512,rv);
X    exit(1);
X  }
X lerr = unpack_label();
X if (lerr)
X  { fprintf(stderr,"%s: bogus label on %s: %s\n",argvec[0],diskname,lerr);
X    exit(1);
X  }
X}
X
Xstatic void putlabel(void)
X{
X int rv;
X
X if (lseek(diskfd,0,L_SET) < 0)
X  { fprintf(stderr,"%s: lseek to 0 on %s: %s\n",argvec[0],diskname,strerror(errno));
X    exit(1);
X  }
X pack_label();
X rv = write(diskfd,&labelbuf[0],512);
X if (rv < 0)
X  { fprintf(stderr,"%s: write label to %s: %s\n",argvec[0],diskname,strerror(errno));
X    exit(1);
X  }
X if (rv != 512)
X  { fprintf(stderr,"%s: short write to %s: wanted %d, got %d\n",argvec[0],diskname,512,rv);
X    exit(1);
X  }
X label.dirty = 0;
X}
X
Xstatic void skipspaces(const char **cpp)
X#define cp (*cpp)
X{
X while (*cp && isspace(*cp)) cp ++;
X}
X#undef cp
X
Xstatic int scannum(const char **cpp, unsigned int *np, const char *tag)
X#define cp (*cpp)
X{
X unsigned int v;
X int nd;
X
X skipspaces(cpp);
X v = 0;
X nd = 0;
X while (*cp && isdigit(*cp))
X  { v = (10 * v) + (*cp++ - '0');
X    nd ++;
X  }
X if (nd == 0)
X  { printf("Missing/invalid %s: %s\n",tag,cp);
X    return(0);
X  }
X *np = v;
X return(1);
X}
X#undef cp
X
Xstatic void chpart(int pno, const char *numbers)
X{
X unsigned int cyl0;
X unsigned int size;
X unsigned int sizec;
X unsigned int sizet;
X unsigned int sizes;
X
X if (! scannum(&numbers,&cyl0,"starting cylinder")) return;
X if (! scannum(&numbers,&size,"partition size")) return;
X skipspaces(&numbers);
X if (*numbers == '/')
X  { sizec = size;
X    numbers ++;
X    if (! scannum(&numbers,&size,"partition size track value")) return;
X    skipspaces(&numbers);
X    if (*numbers != '/')
X    if (! scannum(&numbers,&size,"partition size sector value")) return;
X    size = sizes + (label.nsect * (sizet + (label.nhead * sizec)));
X  }
X if (label.spc && (size % label.spc))
X  { printf("Warning: size is not a multiple of cylinder size (is %u/%u/%u)\n",size/label.spc,(size%label.spc)/label.nhead,size%label.nsect);
X  }
X label.partitions[pno].startcyl = cyl0;
X label.partitions[pno].nblk = size;
X label.dirty = 1;
X}
X
Xstatic void chval_ascii(const char *cp, FIELD *f)
X{
X const char *nl;
X
X skipspaces(&cp);
X nl = index(cp,'\n');
X if (nl == 0) nl = cp + strlen(cp);
X if (nl-cp > 128)
X  { printf("ascii label string too long - max 128 characters\n");
X  }
X else
X  { bzero(f->loc,128);
X    bcopy(cp,f->loc,nl-cp);
X    label.dirty = 1;
X  }
X}
X
Xstatic void chval_int(const char *cp, FIELD *f)
X{
X int v;
X
X if (! scannum(&cp,&v,"value")) return;
X *(unsigned int *)f->loc = v;
X label.dirty = 1;
X}
X
Xstatic void chvalue(const char *str)
X{
X const char *cp;
X int n;
X int i;
X
X if (fields[0].taglen < 1)
X  { for (i=0;fields[i].tag;i++) fields[i].taglen = strlen(fields[i].tag);
X  }
X skipspaces(&str);
X cp = str;
X while (*cp && !isspace(*cp)) cp ++;
X n = cp - str;
X for (i=0;fields[i].tag;i++)
X  { if ((n == fields[i].taglen) && !bcmp(str,fields[i].tag,n))
X     { (*fields[i].chval)(cp,&fields[i]);
X       break;
X     }
X  }
X if (! fields[i].tag)
X  { printf("bad name %.*s - see l output for names\n",n,str);
X  }
X label.spc = label.nhead * label.nsect;
X}
X
Xstatic int print_ascii(FIELD *f, int sofar)
X{
X printf("%s: %.128s\n",f->tag,(char *)f->loc);
X return(0);
X}
X
Xstatic int print_int(FIELD *f, int sofar)
X{
X if (sofar >= 60)
X  { printf("\n");
X    sofar = 0;
X  }
X printf("%s: %-*u",f->tag,14-(int)strlen(f->tag),*(unsigned int *)f->loc);
X return(sofar+16);
X}
X
Xstatic void print_label(void)
X{
X int i;
X int c;
X
X c = 0;
X for (i=0;fields[i].tag;i++) c = (*fields[i].print)(&fields[i],c);
X if (c > 0) printf("\n");
X}
X
Xstatic void docmd(void)
X{
X char cmdline[512];
X
X printf("sunlabel> ");
X if (fgets(&cmdline[0],sizeof(cmdline),stdin) != &cmdline[0]) exit(0);
X switch (cmdline[0])
X  { case '?':
X       printf("? - print this help\n");
X       printf("l - print label, except for partition table\n");
X       printf("p - print partition table\n");
X       printf("[abcdefgh] <cylno> <size> - change partition\n");
X       printf("v <name> <value> - change a non-partition label value\n");
X       printf("w - write (possibly modified) label out\n");
X       printf("q - quit program (error if no write since last change)\n");
X       printf("Q - quit program (unconditionally)\n");
X       break;
X    case 'l':
X       print_label();
X       break;
X    case 'p':
X	{ int i;
X	  for (i=0;i<8;i++)
X	   { printf("%c: start cyl = %6u, size = %8u (",
X		"abcdefgh"[i],
X		label.partitions[i].startcyl, label.partitions[i].nblk );
X	     if (label.spc)
X	      { printf("%u/%u/%u - ",
X		label.partitions[i].nblk/label.spc,
X		(label.partitions[i].nblk%label.spc)/label.nhead,
X		label.partitions[i].nblk%label.nsect );
X	      }
X	     printf("%gMb)\n",label.partitions[i].nblk/2048.0);
X	   }
X	}
X       break;
X    case 'w':
X       putlabel();
X       break;
X    case 'q':
X       if (! label.dirty) exit(0);
X       printf("Label is dirty - use w to write it, or Q to quit anyway.\n");
X       break;
X    case 'Q':
X       exit(0);
X       break;
X    case 'a': case 'b': case 'c': case 'd':
X    case 'e': case 'f': case 'g': case 'h':
X       chpart(cmdline[0]-'a',&cmdline[1]);
X       break;
X    case 'v':
X       chvalue(&cmdline[1]);
X       break;
X  }
X}
X
Xvoid main(int, char **);
Xvoid main(int ac, char **av)
X{
X handleargs(ac,av);
X getlabel();
X while (1) docmd();
X}
EOF
if test 12171 -ne "`wc -c sunlabel.c`"
then
echo shar: error transmitting sunlabel.c \(should have been 12171 characters\)
fi
exit 0
# end of shell archive