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-sparc
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