1
0
Files
irix-657m-src/eoe/cmd/fx/lb.c
2022-09-29 17:59:04 +03:00

802 lines
17 KiB
C

#include <sys/types.h>
#include "dklabel.h" /* needs to be before fx.h for prototypes */
#include "fx.h"
char *bootfile = "/unix";
static struct device_parameters otherparams;
extern MENU *cmenu;
extern int verbose_sgiinfo;
extern MENU drive_menu;
extern int nomenus; /* see fx.c, -c option */
void
sync_func(void)
{
#ifdef SMFD_NUMBER
if(drivernum == SMFD_NUMBER) {
printf("no labels on floppy disks\n");
return;
}
#endif /* SMFD_NUMBER */
printf("writing label info to %s\n", dksub());
if (update() != 0)
scerrwarn("label write failed!\n");
}
void
show_all_func(void)
{
if(drivernum == SCSI_NUMBER) {
scsi_showparam_func();
scsi_showgeom_func();
}
#ifdef SMFD_NUMBER
else if(drivernum == SMFD_NUMBER) {
/* check so people won't see error messages when they choose
* 'all' and they are dealing with the floppy */
scsi_showparam_func();
scsi_showgeom_func();
return;
}
#endif /* SMFD_NUMBER */
show_pt_func();
show_bi_func();
show_dt_func();
show_sgiinfo_func();
}
void
create_all_func(void)
{
#ifdef SMFD_NUMBER
if(drivernum == SMFD_NUMBER)
/* nothing to do at all, so just return */
return;
#endif
/* do bootinfo before pt_func, because if bootinfo sets the swap
and root partition #'s, and if we are creating everything, we
want to use the sgi defaults, not something left over */
create_bi_func();
create_pt_func();
create_sgiinfo_func();
create_dt_func();
}
void
show_bi_func(void)
{
char *f;
#ifdef SMFD_NUMBER
if(drivernum == SMFD_NUMBER) {
printf("no bootinfo on floppy disks\n");
return;
}
#endif /* SMFD_NUMBER */
f = "%15s = %d ";
setoff("bootinfo");
printf(f, "root partition", VP(&vh)->vh_rootpt);
printf(f, "swap partition", VP(&vh)->vh_swappt);
printf("%s = %.16s", "bootfile", VP(&vh)->vh_bootfile);
newline();
}
void
set_bi_func(void)
{
uint rootpt, swappt;
STRBUF s;
#ifdef SMFD_NUMBER
if(drivernum == SMFD_NUMBER) {
printf("no bootinfo on floppy disks\n");
return;
}
#endif /* SMFD_NUMBER */
argslice(&rootpt, PTNUM_FSROOT, PTNUM_VOLHDR, "root partition");
argslice(&swappt, PTNUM_FSSWAP, PTNUM_VOLHDR, "swap partition");
strncpy(s.c, VP(&vh)->vh_bootfile, BFNAMESIZE);
s.c[BFNAMESIZE] = '\0';
argstring(s.c, s.c, "bootfile");
argcheck();
VP(&vh)->vh_rootpt = rootpt;
VP(&vh)->vh_swappt = swappt;
strncpy(VP(&vh)->vh_bootfile, s.c, BFNAMESIZE);
(void)checkparts();
changed = 1;
show_bi_func();
}
void
create_bi_func(void)
{
#ifdef SMFD_NUMBER
if(drivernum == SMFD_NUMBER) {
printf("no bootinfo on floppy disks\n");
return;
}
#endif /* SMFD_NUMBER */
printf("...creating default bootinfo\n");
VP(&vh)->vh_rootpt = PTNUM_FSROOT;
VP(&vh)->vh_swappt = PTNUM_FSSWAP;
strncpy(VP(&vh)->vh_bootfile, bootfile, BFNAMESIZE);
changed = 1;
}
void
readin_bi_func(void)
{
CBLOCK b;
printf("...reading in bootinfo\n");
if( readdvh(VP(&b)) < 0 )
return;
bcopy((char *)VP(&b)->vh_bootfile, (char *)VP(&vh)->vh_bootfile,
sizeof VP(&b)->vh_bootfile);
VP(&vh)->vh_rootpt = VP(&b)->vh_rootpt;
VP(&vh)->vh_swappt = VP(&b)->vh_swappt;
}
void
create_dt_func(void)
{
#ifdef SMFD_NUMBER
if(drivernum == SMFD_NUMBER) {
printf("no volume header on floppy disks\n");
return;
}
#endif /* SMFD_NUMBER */
bzero((char *)DT(&vh), sizeof DT(&vh));
printf("...creating default volume directory\n");
changed = 1;
}
void
readin_dt_func(void)
{
CBLOCK b;
printf("...reading in volume directory\n");
if( readdvh(VP(&b)) < 0 )
return;
bcopy((char *)DT(&b), (char *)DT(&vh), sizeof DT(&vh));
}
/* ix not used, but colprint passes it */
/*ARGSUSED*/
static void
desub(int ix, int *t, char *tgt)
{
register struct volume_directory *dirp;
dirp = DT(&vh)+*t;
sprintf(tgt, "%2d: %-10.8s block %4d size %7d",
*t, dirp->vd_name, dirp->vd_lbn, dirp->vd_nbytes);
}
void
show_dt_func(void)
{
int dirnums[NVDIR];
register uint i, j;
#ifdef SMFD_NUMBER
if(drivernum == SMFD_NUMBER) {
printf("no volume header on floppy disks\n");
return;
}
#endif /* SMFD_NUMBER */
j = 0;
for( i = 0; i < NVDIR; i++ )
if( *DT(&vh)[i].vd_name != '\0' )
dirnums[j++] = i;
setoff("directory entries");
colprint(dirnums, j, sizeof *dirnums, 38, desub);
}
/*
* update the named directory entry with the given data.
*/
void
update_dt(char *name, void *data, int len)
{
register struct volume_directory *vd;
char ls_map[4096]; /* this is pretty ugly; the size
sets how much of the vh is even looked at... */
int ls_max = sizeof(ls_map);
int slen; /* len in sectors */
int lbn;
#ifdef SMFD_NUMBER
if(drivernum == SMFD_NUMBER) {
printf("no volume header on floppy disks\n");
return;
}
#endif /* SMFD_NUMBER */
if (!len)
{
printf("Request for 0 len directory entry!?\n"); /* DHXX*/
return;
}
if( (vd = findent(name, 1)) == 0 )
{
errwarn("can't alloc entry for %s", name);
return;
}
ls_init(ls_map, &ls_max);
slen = btos(len);
len = stob(slen); /* round it up to a sector size */
if(vd->vd_lbn)
map_unbusy(ls_map, ls_max, vd->vd_lbn, slen);
if((lbn = map_alloc(ls_map, ls_max, slen)) < 0 )
{
map_busy(ls_map, ls_max, lbn, slen);
errwarn("can't alloc label space for %s", name);
return;
}
if( gwrite((daddr_t)lbn, data, slen) < 0 )
{
/* print this even if EROFS */
errwarn("can't write %s", name);
return;
}
vd->vd_lbn = lbn; /* Success */
vd->vd_nbytes = len;
}
void
ls_init(char *lmap, int *lmax)
{
register int i;
if(*lmax > PT(&vh)[PTNUM_VOLHDR].pt_nblks)
*lmax = PT(&vh)[PTNUM_VOLHDR].pt_nblks;
map_unbusy(lmap, *lmax, (daddr_t)0, *lmax);
/* Busy the first 2 blocks. 2 because we had limited
* FAT support that we ended up never using. May find a
* use for it in the future... This number must agree with
* the code in dvhtool that creates files in the volhdr.
*
* NOTE: originally the volume_header struct was supposed to be
* written in sector 0 of each track in cyl 0 for redundancy.
* Due to a bug in dvhtool and fx, this wasn't enforced until
* 3.2. The redundant copies have never been used by anything,
* and few people knew about them, and NOW (2/92) we find that
* we need to put much larger files in the volhdr. That meant
* that as of 3.2, we simply busied out the entire first
* cylinder (because even though we only wrote 2 single sector
* files, if we didn't do this, the copies of the volhdr could
* have gotten written out on top of files we put in volhdr
* after we wrote the files, thus trashing them. We can't go
* out and retroactively increase the size of the volhdr
* partition on thousands of machines, so now we are
* deliberately going back to NOT making the redundant copies,
* and allowing use of the whole volhdr partition (except sector
* 0, of course) for files. This big comment is so that no
* one will come back in the future and 'fix' this again...
* Dave Olson, 2/92 */
map_busy(lmap, *lmax, 0, 2);
/* now mark all the blocks used by existing files as in use */
for( i = 0; i < NVDIR; i++ )
map_busy(lmap, *lmax, DT(&vh)[i].vd_lbn,
btos(DT(&vh)[i].vd_nbytes));
}
/*
* find the named entry. optionally create it if nonexistent.
*/
struct volume_directory *
findent(char *name, int flag)
{
register struct volume_directory *vd, *slot;
register int i;
slot = 0;
for( vd = DT(&vh) , i = NVDIR; --i >= 0; vd++ )
{
if( strncmp(name, vd->vd_name, VDNAMESIZE) == 0 )
return vd;
if( slot == 0 )
if( *vd->vd_name == '\0' && vd->vd_nbytes == 0 )
slot = vd;
}
if(flag && slot) {
strncpy(slot->vd_name, name, VDNAMESIZE);
slot->vd_lbn = 0;
changed = 1;
return slot;
}
return 0;
}
/*
* Clear the named entry, if it exists, from the volume directory.
* Needed when zapping the badblock list.
*/
void
clearent(char *name)
{
register struct volume_directory *vd;
register int i;
int zapping = 0;
for( vd = DT(&vh) , i = NVDIR; --i >= 0; vd++ )
{
if (!zapping && strncmp(name, vd->vd_name, VDNAMESIZE) == 0 )
zapping = 1;
if (zapping)
{
if (i > 1) bcopy((caddr_t)(vd + 1), (caddr_t)vd,
sizeof (struct volume_directory));
else bzero((caddr_t)vd, sizeof (struct volume_directory));
}
}
}
/*
* read in the label information.
* first we must get the volume header. if that is invalid,
* get the drive type and set up defaults.
*/
void
init_label(char *dname)
{
int mustrewrite = 0;
int partsok;
#ifdef SMFD_NUMBER
if(drivernum == SMFD_NUMBER) {
check_dp(dname, 0);
return;
}
#endif /* SMFD_NUMBER */
if( readdvh(&vh) < 0 ) { /* no volhdr of either type */
mustrewrite = 1;
check_dp(dname, 0);
create_label();
}
else {
check_dp(dname, 1);
if(expert && (partsok=checkparts())) {
printf("NOTE: %s existing partitions are"
" inconsistent with drive geometry\n", dname);
if(partsok < 0) {
/* some were out of range default to no, since
* this will make it difficult if not impossible
* to get their old partitions (and thus their data)
* back. */
if(!no("create default partitions (answering yes may"
"make it difficult\n\tto retrieve existing"
"data from the drive)")) {
create_pt_func();
mustrewrite = 1;
}
/* default to no here also */
if(!no("edit partitions") ){
callfunc(set_pt_func, "partitions");
mustrewrite = 1;
}
}
}
}
if(mustrewrite)
set_vh(VP(&vh));
}
/*
* initialize drive parameters; if vhvalid, use the volume header.
* in the end, we should have 3 consistent pieces of info:
* the disk name
* the sgi disk type
* drive parameters
*
* the argument is the name of a disk drive. it may be
* '' null; ask for drive type
* 'other' the literal other; prompt for all info
* xxx the full name of a disk drive; get info from tables
*
* Returns: 0 if existing volume header is OK,
* 1 if the volume header must be rewritten to the driver.
*/
void
check_dp(char *dname, int vhvalid)
{
CBLOCK sgijunk;
int goodsgilab = 0;
int cantread = 0;
switch (drivernum) {
#ifdef SMFD_NUMBER
case SMFD_NUMBER: /* done just to get name printed */
#endif /* SMFD_NUMBER */
case SCSI_NUMBER:
otherparams.dp_flags = DP(&vh)->dp_flags;
otherparams.dp_ctq_depth = DP(&vh)->dp_ctq_depth;
otherparams.dp_drivecap = DP(&vh)->dp_drivecap;
scsiset_dp(&otherparams);
scsiset_label(&sgijunk, 1);
break;
default:
printf("Don't know how to set parameters for driver type %d\n",
drivernum);
return;
}
if(expert)
changed = !vhvalid;
if(vhvalid && expert && dpcmp(DP(&vh), &otherparams)) {
printf("\
warning: %s disagrees with existing volume header parameters\n",
dname);
if( yes("show differences") )
showdiff_dp();
/* default to using existing vh; otherwise user can wind
up with partitition layout that dosn't match their
filesystems. */
if(!yes("use existing volume header") )
changed = 1;
}
/* always do this; was if mustrewrite || expert; but vh still needs
to be valid for exercising, even if not expert. Turns out
the equivalent of this must be buried down in the code
for hard disks, because it worked for them, but wouldn't
work for floppies. Can't see what this would ever hurt,
and hopefully we can remove the redundant code in other
portions of fx sometime... Olson, 4/83 */
bcopy((char *)&otherparams, (char *)DP(&vh), sizeof otherparams);
if (vhvalid && expert)
{
bzero(&sg, sizeof (struct disk_label));
cantread = readsgilabel (&sg, !expert);
/* hardly worth it for scsi, but... */
if(cantread==0 && ((struct disk_label *)&sg)->d_magic == D_MAGIC)
goodsgilab = 1;
}
if (!goodsgilab
#ifdef SMFD_NUMBER
&& drivernum != SMFD_NUMBER
#endif /* SMFD_NUMBER */
)
/* don't complain, and don't mark anything as changed. If they
* do happen to write the volhdr for some other reason, then
* we'll create the sgilabel; see comments at readsgilabel()
* for why we don't complain, 4/97. */
bcopy((char *)&sgijunk, (char *)&sg, sizeof(struct disk_label));
}
int
dpcmp(struct device_parameters *v, struct device_parameters *a)
{
if(v->dp_secbytes == a->dp_secbytes &&
(!a->dp_drivecap || v->dp_drivecap == a->dp_drivecap))
return 0;
return 1;
}
void
showdiff_dp(void)
{
register struct device_parameters *v, *a;
register char *f;
v = DP(&vh);
a = &otherparams;
# define DD(s, e) if(v->e!=a->e)printf(f,s,v->e,a->e)
f = "%15s = volume header %-5d; should be %-5d to match drive\n";
DD("bytes/sec", dp_secbytes);
if(v->dp_drivecap) DD("drive capacity", dp_drivecap);
# undef DD
}
/*
* make a default volume header based on the current drive parameters.
*/
void
create_label(void)
{
DP(&vh)->dp_flags = 0; /* make ctq default disabled */
create_bi_func();
create_pt_func();
create_dt_func();
}
/* Update mbr from vh */
int
update_vh(void)
{
int error;
char b[MAX_BSIZE]; /* gwrite will use the 'actual' secsize */
/* DHXX: must set volume header in driver as well as on disk!!
set_vh now has the side-effect of setting the magic # and
checksum in vh for us. */
VP(&vh)->vh_magic = 0;
error = set_vh(VP(&vh));
if ( ! error) {
bzero(b, sizeof b);
bcopy((char *)VP(&vh), b, sizeof *VP(&vh));
if (gwrite(0, b, 1) < 0 )
errwarn("can't write volume header on disk");
}
return error;
}
int
checkvh(struct volume_header *vhp)
{
if ((vhp->vh_magic == VHMAGIC
&& vhchksum((int *)vhp, sizeof *vhp) == 0 ))
return 0;
bzero(vhp, sizeof *vhp);
return -1;
}
int
readdvh(struct volume_header *vhp)
{
get_vh(vhp);
if (checkvh(vhp) < 0 )
return errwarn("invalid label from disk driver, ignored");
return 0;
}
int
readinvh(struct volume_header *vhp)
{
if(gread(0, vhp, 1) == 0 && checkvh(vhp) == 0 ) {
extern unsigned scsi_cap;
if(!DP(vhp)->dp_drivecap) {
if(!scsi_cap) scsi_readcapacity(&scsi_cap); /* shouldn't happen */
DP(vhp)->dp_drivecap = scsi_cap;
}
return 0;
}
return -1;
}
void
lastchance(void)
{
STRBUF s;
sprintf(s.c, "about to destroy data on disk %s! ok", dksub());
if(nomenus)
printf("%s\n", s.c);
else {
banner("WARNING");
if( !yesno(-1, s.c) )
mpop();
}
changed = 1;
}
void
optupdate(void)
{
STRBUF s;
CBLOCK b;
#ifdef SMFD_NUMBER
if(drivernum == SMFD_NUMBER) /* not on floppies */
return;
#endif /* SMFD_NUMBER */
/* fetch real label from disk, make sure it's valid */
if( readinvh(VP(&b)) < 0 )
changed = 1;
if( changed )
{
sprintf(s.c, "\
label info has changed for disk %s. write out changes", dksub());
if( yes(s.c) ) {
if (update() != 0)
scerrwarn("label write failed!\n");
}
}
}
int
update(void)
{
int error;
switch (drivernum) {
case SCSI_NUMBER:
break; /* nothing to do for badblocks on scsi */
default:
printf("Don't know how to update for driver type %d\n",
drivernum);
return EINVAL;
}
error = update_vh();
if ( ! error ) {
/* Don't allow messing with
* sgilabel if nonexpert
*/
if (expert)
update_sgi();
changed = 0;
}
return error;
}
void
getattribs(int *_n, ITEM *items)
{
register ITEM *t;
register int n, b;
STRBUF s;
n = *_n;
for( t = items; t->name != 0; t++ )
{
b = n & t->value;
n &= ~t->value;
sprintf(s.c, "enable %s", t->name);
if( yesno(b, s.c) )
n |= t->value;
}
*_n = n;
}
/* bytes to sectors */
uint
btos(uint n)
{
return (n + DP(&vh)->dp_secbytes - 1) / DP(&vh)->dp_secbytes;
}
void
readin_dp(void)
{
CBLOCK b;
if( readdvh(VP(&b)) < 0 )
return;
bcopy((char *)DP(&b), (char *)DP(&vh), sizeof *DP(&vh));
}
char *
dksub(void)
{
static STRBUF s;
if (device_name_specified)
sprintf(s.c, "%s", device_name);
else
{
sprintf(s.c, "%s(%d,%d,%d)", driver, ctlrno, driveno, scsilun);
#ifdef SMFD_NUMBER
if(drivernum == SMFD_NUMBER) {
char *type;
if(type=(char *)smfd_partname(partnum))
strcat(s.c, type);
}
#endif /* SMFD_NUMBER */
}
return s.c;
}
/* ----- map routines ----- */
void
map_busy(char *map, uint len, uint a, int n)
{
while(n) {
if(a < len )
map[a++] = 1;
n--;
}
}
void
map_unbusy(char *map, uint len, uint a, int n)
{
while(n) {
if(a < len )
map[a++] = 0;
n--;
}
}
map_alloc(char *map, uint len, uint n)
{
register uint r, f;
f = 0;
for( r = 0; r < len; r++ )
if( map[r] )
{
f = 0;
}
else
{
if( ++f >= n )
{
r++;
while(n) {
map[--r] = 1;
n--;
}
return (int)r;
}
}
return -1;
}
/* ----- geometry routines ----- */
uint
stob(uint n)
{
return n * DP(&vh)->dp_secbytes;
}
/* round # of blocks to to number of megabytes; since we are getting
* close to 4 Gb disks, do in such a way that we don't overflow an
* unsigned 32bit value.
*/
uint
mbytes(uint blocks)
{
blocks += ((1<<19)-1) / DP(&vh)->dp_secbytes;
return blocks / ((1<<20) / DP(&vh)->dp_secbytes);
}
/* return block number corresponding to value in megabytes */
uint
mbytetoblk(uint mbyte)
{
return mbyte * ((1<<20) / DP(&vh)->dp_secbytes);
}