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

355 lines
8.2 KiB
C

#include "CompatServer.H"
#include <assert.h>
#include <bstring.h>
#include <errno.h>
#include <mntent.h>
#include <mediad.h>
#include <unistd.h>
#include <syslog.h>
#include "Device.H"
#include "DeviceAddress.H"
#include "DeviceMonitor.H"
#include "Log.H"
#include "Partition.H"
#include "PartitionAddress.H"
#include "Scheduler.H"
#include "Volume.H"
#include "VolumeAddress.H"
#include "strplus.H"
CompatServer::CompatServer(int fd)
: _client_handler(client_read_proc, this),
_exclusive_filename(NULL),
_exclusive_progname(NULL)
{
_client_handler.fd(fd);
_client_handler.activate();
}
CompatServer::~CompatServer()
{
(void) close(_client_handler.fd());
// If client holds exclusive use on a device, release it.
if (_exclusive_filename != NULL)
{ DeviceMonitor *mon = path_to_monitor(_exclusive_filename);
if (mon != NULL)
{
Log::info("client \"%s\" died. Releasing exclusive use of \"%s\".",
_exclusive_progname, mon->device()->name());
mon->resume();
}
delete [] _exclusive_filename;
delete [] _exclusive_progname;
}
}
void
CompatServer::client_read_proc(int sock, void *closure)
{
CompatServer *client = (CompatServer *) closure;
assert(sock == client->_client_handler.fd());
client->read_message(sock);
}
void
CompatServer::read_message(int sock)
{
_sock = sock;
emsg msg;
rmsg rmsg;
bool do_reply = true;
bool expecting_more = false;
bzero(&rmsg, sizeof rmsg);
rmsg.mtype = MSG_RETURN;
int readlen = read(sock, &msg, sizeof msg);
if (readlen != sizeof msg)
{ if (readlen < 0)
Log::perror("read from compat client %d", sock);
else if (readlen > 0)
Log::error("short read from compat client %d: %d bytes",
sock, readlen);
do_reply = false;
}
else
{
switch (msg.mtype)
{
case MSG_EJECT:
do_reply = handle_eject_msg(msg, rmsg);
break;
case MSG_TEST:
do_reply = handle_test_msg(msg, rmsg);
break;
case MSG_TERM:
do_reply = handle_terminate_msg(msg, rmsg);
break;
case MSG_SHOWMOUNT:
do_reply = handle_showmount_msg(msg, rmsg);
break;
case MSG_SUSPENDON:
do_reply = handle_suspend_msg(msg, rmsg);
expecting_more = true;
break;
case MSG_SUSPENDOFF:
do_reply = handle_resume_msg(msg, rmsg);
break;
case MSG_SETLOGLEVEL:
do_reply = handle_setloglevel_msg(msg, rmsg);
break;
case MSG_STARTENTRY:
case MSG_STOPENTRY:
break;
default:
Log::error("unknown compat message %d", msg.mtype);
do_reply = false;
break;
}
}
if (do_reply && write(sock, &rmsg, sizeof rmsg) < 0)
{ if (errno != EPIPE)
Log::perror("write to compat client %d", sock);
}
if (!expecting_more)
delete this;
}
bool
CompatServer::handle_eject_msg(const emsg& emsg, rmsg& rmsg)
{
DeviceMonitor *devmon = NULL;
if (emsg.ctrl >= 0)
{ Log::info("Got Eject msg for ctlr %d id %d lun %d",
emsg.ctrl, emsg.scsi, emsg.lun);
DeviceAddress da(emsg.ctrl, emsg.scsi, emsg.lun);
Device *d = Device::at(da);
if (d)
devmon = DeviceMonitor::at(d);
}
else
{
if (emsg.filename[0] == '\0')
{ Log::info("Got Eject msg for first find");
devmon = DeviceMonitor::first();
}
else
{ Log::info("Got Eject msg for device \"%s\"", emsg.filename);
// Navigate the twisty maze of little data structures.
// filename -> volume address -> partition address ->
// device address -> device ->device monitor
VolumeAddress va(emsg.filename);
const PartitionAddress *pa = va.partition(0);
if (pa)
{ const DeviceAddress& da = pa->device();
Device *d = Device::at(da);
if (d)
devmon = DeviceMonitor::at(d);
}
else
{
// Didn't find a device. Try a mounted filesystem.
for (const Volume *v = Volume::first(); v; v = v->next())
{ const char *dir = v->base_dir();
if (dir && !strcmp(emsg.filename, dir))
{ const Partition *p = v->partition(0);
if (p)
{ const Device *d = p->device();
if (d)
devmon = DeviceMonitor::at(d);
}
}
}
}
}
}
if (devmon)
rmsg.error = devmon->eject();
else
rmsg.error = RMED_ENODEVICE;
return true;
}
bool
CompatServer::handle_test_msg(const emsg&, rmsg& rmsg)
{
rmsg.mtype = MSG_TESTOK;
rmsg.error = RMED_NOERROR;
if (write(_sock, &rmsg, sizeof rmsg) < 0)
{ Log::info("compat reply: %m, exiting.");
Scheduler::exit();
}
return false;
}
bool
CompatServer::handle_terminate_msg(const emsg&, rmsg&)
{
Log::info("Got Terminate message. Exiting.");
Scheduler::exit();
return false;
}
bool
CompatServer::handle_showmount_msg(const emsg& emsg, rmsg& rmsg)
{
Log::info("Got Show Mount message for \"%s\"", emsg.filename);
// On a showmount message, we search the device list for a volume
// mounted on emsg.filename, and return that volume's mount point.
for (Volume *vol = Volume::first(); vol; vol = vol->next())
for (unsigned i = 0; i < vol->npartitions(); i++)
if (!strcmp(vol->fsname(), emsg.filename))
{ strncpy(rmsg.mpoint, vol->dir(), sizeof rmsg.mpoint);
return true;
}
// Didn't find it. Find a corresponding Device and return that
// Device's default mount point.
const VolumeAddress va(emsg.filename);
const PartitionAddress *pap;
for (unsigned i = 0; pap = va.partition(i); i++)
{ const DeviceAddress& da = pap->device();
Device *dev = Device::at(da);
if (dev)
{ rmsg.mpoint[0] = '/';
strncpy(rmsg.mpoint + 1, dev->name(), sizeof rmsg.mpoint - 1);
return true;
}
}
// We struck out. Return a reply message with an empty filename field.
return true;
}
bool
CompatServer::handle_suspend_msg(const emsg& emsg, rmsg& rmsg)
{
DeviceMonitor *mon = path_to_monitor(emsg.filename);
if (!mon)
rmsg.error = RMED_ENODEVICE;
else if (mon->is_suspended())
rmsg.error = RMED_EACCESS; // Somebody else already holds it
else
{
Log::info("client \"%s\" takes exclusive use of device \"%s\".",
emsg.progname, mon->device()->name());
rmsg.error = mon->suspend();
_exclusive_filename = strdupplus(emsg.filename);
_exclusive_progname = strdupplus(emsg.progname);
}
return true;
}
bool
CompatServer::handle_resume_msg(const emsg& /* emsg */, rmsg& rmsg)
{
if (!_exclusive_filename)
{ rmsg.error = RMED_EUSAGE;
return true;
}
DeviceMonitor *mon = path_to_monitor(_exclusive_filename);
if (mon)
{
Log::info("client \"%s\" releases exclusive use of device \"%s\".",
_exclusive_progname, mon->device()->name());
mon->resume();
delete [] _exclusive_filename; _exclusive_filename = NULL;
delete [] _exclusive_progname; _exclusive_progname = NULL;
}
else
rmsg.error = RMED_ENODEVICE;
return true;
}
bool
CompatServer::handle_setloglevel_msg(const emsg& emsg, rmsg& rmsg)
{
int level = emsg.scsi;
char *levelname;
if (level >= LOG_DEBUG)
{ Log::debug();
levelname = "high";
}
else if (level >= LOG_INFO)
{ Log::info();
levelname = "medium";
}
else
{ Log::error();
levelname = "normal (low)";
}
Log::error("Got setloglevel message. Log verbosity is %s", levelname);
rmsg.mtype = MSG_RETURN;
rmsg.error = 0;
return true;
}
DeviceMonitor *
CompatServer::path_to_monitor(const char *path)
{
// Navigate the twisty maze of little data structures.
//
// Either:
//
// filename ->
// volume address ->
// partition address ->
// device address ->
// device ->
// device monitor
//
// or:
//
// dir -> volume -> partiton -> device -> device monitor
VolumeAddress va(path);
const PartitionAddress *pa = va.partition(0);
if (pa)
{ const DeviceAddress& da = pa->device();
Device *d = Device::at(da);
if (d)
return DeviceMonitor::at(d);
}
// Didn't find a device. Try a mounted filesystem.
for (const Volume *v = Volume::first(); v; v = v->next())
{ const char *dir = v->dir();
if (dir && !strcmp(dir, path))
{ const Partition *p = v->partition(0);
if (p)
{ const Device *d = p->device();
if (d)
return DeviceMonitor::at(d);
}
}
}
return NULL; // admit defeat.
}