1
0
Files
irix-657m-src/eoe/cmd/mediad/VolumeAddress.C
2022-09-29 17:59:04 +03:00

222 lines
4.6 KiB
C

#include "VolumeAddress.H"
#include <assert.h>
#include <devconvert.h>
#include <diskinvent.h>
#include <stdio.h>
#include <sys/conf.h>
#include <sys/dir.h>
#include "DeviceAddress.H"
#include "PartitionAddress.H"
#include "operators.H"
VolumeAddress::VolumeAddress(const VolumeAddress& that)
: _refcount(0)
{
if (that._refcount == 0)
{
// That is a VolumeAddress, not a derived class.
// Share its rep.
_rep = that._rep;
if (_rep)
_rep->_refcount++;
}
else
{
// That is a derived class. Clone it.
_rep = that.clone();
}
}
VolumeAddress&
VolumeAddress::operator = (const VolumeAddress& that)
{
if (this != &that)
{ if (_rep && !--_rep->_refcount)
delete _rep;
_rep = that._rep;
if (_rep)
_rep->_refcount++;
}
return *this;
}
VolumeAddress::~VolumeAddress()
{
assert(!_rep || _rep->_refcount > 0);
if (_rep && !--_rep->_refcount)
delete _rep;
}
VolumeAddress *
VolumeAddress::clone() const
{
return new VolumeAddress(*this);
}
const PartitionAddress *
VolumeAddress::partition(unsigned index) const
{
if (_rep)
return _rep->partition(index);
else
return NULL;
}
bool
VolumeAddress::operator == (const VolumeAddress& that) const
{
if (this == &that)
return true;
if (_rep)
return *_rep == that;
if (that._rep)
return *this == *that._rep;
for (int i = 0; ; i++)
{ const PartitionAddress *a = partition(i);
const PartitionAddress *b = that.partition(i);
if (!a || !b)
return !a && !b;
if (a->partition() != b->partition())
return false;
if (a->device() != b->device())
return false;
}
}
bool
VolumeAddress::overlaps(const VolumeAddress& that) const
{
if (_rep == that._rep)
return true;
if (!_rep || !that._rep)
return false;
const PartitionAddress *p;
for (int i = 0; p = partition(i); i++)
if (p->overlaps(that))
return true;
return false;
}
const PartitionAddress *
VolumeAddress::as_PartitionAddress() const
{
return _rep ? _rep->as_PartitionAddress() : NULL;
}
PartitionAddress *
VolumeAddress::as_PartitionAddress()
{
return _rep ? _rep->as_PartitionAddress() : NULL;
}
static bool match_scsi_dev(dev_t dev, int *ctlrp, int *unitp, int *lunp)
{
static struct SCSI_Dev {
dev_t dev;
int ctlr, unit, lun;
} *devs;
static int ndevs;
if (!devs)
{
// devs is not initialized. Read /dev/scsi, count all entries,
// and store them away.
DIR *D = opendir("/dev/scsi");
direct *dp;
int ctlr, unit, lun;
if (!D)
return false;
ndevs = 0;
while (dp = readdir(D))
if (sscanf(dp->d_name, "sc%dd%dl%d", &ctlr, &unit, &lun) == 3)
ndevs++;
closedir(D);
D = opendir("/dev/scsi");
if (!D)
return false;
devs = new SCSI_Dev[ndevs];
for (int i = 0; i < ndevs; )
{ if (!(dp = readdir(D)))
break;
if (sscanf(dp->d_name, "sc%dd%dl%d", &ctlr, &unit, &lun) != 3)
continue;
struct stat status;
char fullpath[100];
sprintf(fullpath, "/dev/scsi/%s", dp->d_name);
if (stat(fullpath, &status) != 0)
continue;
devs[i].dev = status.st_rdev;
devs[i].ctlr = ctlr;
devs[i].unit = unit;
devs[i].lun = lun;
i++;
}
closedir(D);
}
// Look at all SCSI devices, find the match.
for (SCSI_Dev *p = devs; p < devs + ndevs; p++)
if (p->dev == dev)
{ *ctlrp = p->ctlr;
*unitp = p->unit;
*lunp = p->lun;
return true;
}
return false;
}
VolumeAddress::VolumeAddress(const char *path, FormatIndex fmt, int partno)
: _refcount(0), _rep(NULL)
{
// Map the device to a /dev/scsi device.
char scsipath[MAXDEVNAME];
int len = sizeof scsipath;
if (filename_to_scsiname(path, scsipath, &len) != NULL)
{
// This is a scsi device.
// Find out which /dev/scsi device we found.
struct stat status;
if (stat(scsipath, &status) != 0)
return;
int ctlr, unit, lun;
if (!match_scsi_dev(status.st_rdev, &ctlr, &unit, &lun))
return;
// If this is a disk, we need to figure out which partition it
// hits.
int partition = partno;
if (partition == UnknownPartition)
{ partition = path_to_partnum((char *) path);
if (partition == -1)
partition = WholeDisk;
}
// Build the DeviceAddress and the PartitionAddress
_rep = new PartitionAddress(DeviceAddress(ctlr, unit, lun),
fmt, partition);
}
else if (!strcmp(path, "/dev/pfd/pfd.2dd") ||
!strcmp(path, "/dev/pfd/pfd.2hd"))
{
// This is a parallel device.
int partition = partno;
if (partition == UnknownPartition)
partition = WholeDisk;
_rep = new PartitionAddress(DeviceAddress(DeviceAddress::Parallel()),
fmt, partition);
}
// else (_rep == NULL) => invalid VolumeAddress
}