minix/commands/i386/mtools-3.9.7/floppyd_io.c
2005-04-21 14:53:53 +00:00

560 lines
9.9 KiB
C
Executable file

/*
* IO to the floppyd daemon running on the local X-Server Host
*
* written by:
*
* Peter Schlaile
*
* udbz@rz.uni-karlsruhe.de
*
*/
#include "sysincludes.h"
#include "stream.h"
#include "mtools.h"
#include "msdos.h"
#include "scsi.h"
#include "partition.h"
#include "floppyd_io.h"
#ifdef USE_FLOPPYD
/* ######################################################################## */
typedef unsigned char Byte;
typedef unsigned long Dword;
char* AuthErrors[] = {
"Auth success!",
"Auth failed: Packet oversized!",
"Auth failed: X-Cookie doesn't match!",
"Auth failed: Wrong transmission protocol version!",
"Auth failed: Device locked!"
};
typedef struct RemoteFile_t {
Class_t *Class;
int refs;
Stream_t *Next;
Stream_t *Buffer;
int fd;
mt_off_t offset;
mt_off_t lastwhere;
mt_off_t size;
} RemoteFile_t;
#ifndef HAVE_HTONS
unsigned short myhtons(unsigned short parm)
{
Byte val[2];
val[0] = (parm >> 8) & 0xff;
val[1] = parm & 0xff;
return *((unsigned short*) (val));
}
#endif
Dword byte2dword(Byte* val)
{
Dword l;
l = (val[0] << 24) + (val[1] << 16) + (val[2] << 8) + val[3];
return l;
}
void dword2byte(Dword parm, Byte* rval)
{
rval[0] = (parm >> 24) & 0xff;
rval[1] = (parm >> 16) & 0xff;
rval[2] = (parm >> 8) & 0xff;
rval[3] = parm & 0xff;
}
Dword read_dword(int handle)
{
Byte val[4];
read(handle, val, 4);
return byte2dword(val);
}
void write_dword(int handle, Dword parm)
{
Byte val[4];
dword2byte(parm, val);
write(handle, val, 4);
}
/* ######################################################################## */
int authenticate_to_floppyd(int sock, char *display)
{
off_t filelen;
Byte buf[16];
char *command[] = { "xauth", "xauth", "extract", "-", 0, 0 };
char *xcookie;
Dword errcode;
command[4] = display;
filelen=strlen(display);
filelen += 100;
xcookie = (char *) safe_malloc(filelen+4);
filelen = safePopenOut(command, xcookie+4, filelen);
if(filelen < 1)
return AUTH_AUTHFAILED;
dword2byte(4,buf);
dword2byte(FLOPPYD_PROTOCOL_VERSION,buf+4);
write(sock, buf, 8);
if (read_dword(sock) != 4) {
return AUTH_WRONGVERSION;
}
errcode = read_dword(sock);
if (errcode != AUTH_SUCCESS) {
return errcode;
}
dword2byte(filelen, xcookie);
write(sock, xcookie, filelen+4);
if (read_dword(sock) != 4) {
return AUTH_PACKETOVERSIZE;
}
errcode = read_dword(sock);
return errcode;
}
static int floppyd_reader(int fd, char* buffer, int len)
{
Dword errcode;
Dword gotlen;
int l;
int start;
Byte buf[16];
dword2byte(1, buf);
buf[4] = OP_READ;
dword2byte(4, buf+5);
dword2byte(len, buf+9);
write(fd, buf, 13);
if (read_dword(fd) != 8) {
errno = EIO;
return -1;
}
gotlen = read_dword(fd);
errcode = read_dword(fd);
if (gotlen != -1) {
if (read_dword(fd) != gotlen) {
errno = EIO;
return -1;
}
for (start = 0, l = 0; start < gotlen; start += l) {
l = read(fd, buffer+start, gotlen-start);
if (l == 0) {
errno = EIO;
return -1;
}
}
} else {
errno = errcode;
}
return gotlen;
}
static int floppyd_writer(int fd, char* buffer, int len)
{
Dword errcode;
Dword gotlen;
Byte buf[16];
dword2byte(1, buf);
buf[4] = OP_WRITE;
dword2byte(len, buf+5);
write(fd, buf, 9);
write(fd, buffer, len);
if (read_dword(fd) != 8) {
errno = EIO;
return -1;
}
gotlen = read_dword(fd);
errcode = read_dword(fd);
errno = errcode;
return gotlen;
}
static int floppyd_lseek(int fd, mt_off_t offset, int whence)
{
Dword errcode;
Dword gotlen;
Byte buf[32];
dword2byte(1, buf);
buf[4] = OP_SEEK;
dword2byte(8, buf+5);
dword2byte(truncBytes32(offset), buf+9);
dword2byte(whence, buf+13);
write(fd, buf, 17);
if (read_dword(fd) != 8) {
errno = EIO;
return -1;
}
gotlen = read_dword(fd);
errcode = read_dword(fd);
errno = errcode;
return gotlen;
}
/* ######################################################################## */
typedef int (*iofn) (int, char *, int);
static int floppyd_io(Stream_t *Stream, char *buf, mt_off_t where, int len,
iofn io)
{
DeclareThis(RemoteFile_t);
int ret;
where += This->offset;
if (where != This->lastwhere ){
if(floppyd_lseek( This->fd, where, SEEK_SET) < 0 ){
perror("floppyd_lseek");
This->lastwhere = (mt_off_t) -1;
return -1;
}
}
ret = io(This->fd, buf, len);
if ( ret == -1 ){
perror("floppyd_io");
This->lastwhere = (mt_off_t) -1;
return -1;
}
This->lastwhere = where + ret;
return ret;
}
static int floppyd_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
{
return floppyd_io(Stream, buf, where, len, (iofn) floppyd_reader);
}
static int floppyd_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
{
return floppyd_io(Stream, buf, where, len, (iofn) floppyd_writer);
}
static int floppyd_flush(Stream_t *Stream)
{
#if 0
Byte buf[16];
DeclareThis(RemoteFile_t);
dword2byte(1, buf);
buf[4] = OP_FLUSH;
write(This->fd, buf, 5);
if (read_dword(This->fd) != 8) {
errno = EIO;
return -1;
}
read_dword(This->fd);
read_dword(This->fd);
#endif
return 0;
}
static int floppyd_free(Stream_t *Stream)
{
Byte buf[16];
DeclareThis(RemoteFile_t);
if (This->fd > 2) {
dword2byte(1, buf);
buf[4] = OP_CLOSE;
write(This->fd, buf, 5);
return close(This->fd);
} else {
return 0;
}
}
static int floppyd_geom(Stream_t *Stream, struct device *dev,
struct device *orig_dev,
int media, struct bootsector *boot)
{
size_t tot_sectors;
int sect_per_track;
DeclareThis(RemoteFile_t);
dev->ssize = 2; /* allow for init_geom to change it */
dev->use_2m = 0x80; /* disable 2m mode to begin */
if(media == 0xf0 || media >= 0x100){
dev->heads = WORD(nheads);
dev->sectors = WORD(nsect);
tot_sectors = DWORD(bigsect);
SET_INT(tot_sectors, WORD(psect));
sect_per_track = dev->heads * dev->sectors;
tot_sectors += sect_per_track - 1; /* round size up */
dev->tracks = tot_sectors / sect_per_track;
} else if (media >= 0xf8){
media &= 3;
dev->heads = old_dos[media].heads;
dev->tracks = old_dos[media].tracks;
dev->sectors = old_dos[media].sectors;
dev->ssize = 0x80;
dev->use_2m = ~1;
} else {
fprintf(stderr,"Unknown media type\n");
exit(1);
}
This->size = (mt_off_t) 512 * dev->sectors * dev->tracks * dev->heads;
return 0;
}
static int floppyd_data(Stream_t *Stream, time_t *date, mt_size_t *size,
int *type, int *address)
{
DeclareThis(RemoteFile_t);
if(date)
/* unknown, and irrelevant anyways */
*date = 0;
if(size)
/* the size derived from the geometry */
*size = (mt_size_t) This->size;
if(type)
*type = 0; /* not a directory */
if(address)
*address = 0;
return 0;
}
/* ######################################################################## */
static Class_t FloppydFileClass = {
floppyd_read,
floppyd_write,
floppyd_flush,
floppyd_free,
floppyd_geom,
floppyd_data
};
/* ######################################################################## */
int get_host_and_port(const char* name, char** hostname, char **display,
short* port)
{
char* newname = strdup(name);
char* p;
char* p2;
p = newname;
while (*p != '/' && *p) p++;
p2 = p;
if (*p) p++;
*p2 = 0;
*port = atoi(p);
if (*port == 0) {
*port = FLOPPYD_DEFAULT_PORT;
}
*display = strdup(newname);
p = newname;
while (*p != ':' && *p) p++;
p2 = p;
if (*p) p++;
*p2 = 0;
*port += atoi(p); /* add display number to the port */
if (!*newname || strcmp(newname, "unix") == 0) {
free(newname);
newname = strdup("localhost");
}
*hostname = newname;
return 1;
}
/*
* * Return the IP address of the specified host.
* */
static IPaddr_t getipaddress(char *ipaddr)
{
struct hostent *host;
IPaddr_t ip;
if (((ip = inet_addr(ipaddr)) == INADDR_NONE) &&
(strcmp(ipaddr, "255.255.255.255") != 0)) {
if ((host = gethostbyname(ipaddr)) != NULL) {
memcpy(&ip, host->h_addr, sizeof(ip));
}
endhostent();
}
#ifdef DEBUG
fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip);
#endif
return (ip);
}
/*
* * Connect to the floppyd server.
* */
static int connect_to_server(IPaddr_t ip, short port)
{
struct sockaddr_in addr;
int sock;
/*
* Allocate a socket.
*/
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return (-1);
}
/*
* Set the address to connect to.
*/
addr.sin_family = AF_INET;
#ifndef HAVE_HTONS
addr.sin_port = myhtons(port);
#else
addr.sin_port = htons(port);
#endif
addr.sin_addr.s_addr = ip;
/*
* Connect our socket to the above address.
*/
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
return (-1);
}
/*
* Set the keepalive socket option to on.
*/
{
int on = 1;
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
(char *)&on, sizeof(on));
}
return (sock);
}
static int ConnectToFloppyd(const char* name);
Stream_t *FloppydOpen(struct device *dev, struct device *dev2,
char *name, int mode, char *errmsg,
int mode2, int locked)
{
RemoteFile_t *This;
if (!dev || !(dev->misc_flags & FLOPPYD_FLAG))
return NULL;
This = New(RemoteFile_t);
if (!This){
printOom();
return NULL;
}
This->Class = &FloppydFileClass;
This->Next = 0;
This->offset = 0;
This->lastwhere = 0;
This->refs = 1;
This->Buffer = 0;
This->fd = ConnectToFloppyd(name);
if (This->fd == -1) {
Free(This);
return NULL;
}
return (Stream_t *) This;
}
static int ConnectToFloppyd(const char* name)
{
char* hostname;
char* display;
short port;
int rval = get_host_and_port(name, &hostname, &display, &port);
int sock;
int reply;
if (!rval) return -1;
sock = connect_to_server(getipaddress(hostname), port);
if (sock == -1) {
fprintf(stderr,
"Can't connect to floppyd server on %s, port %i!\n",
hostname, port);
return -1;
}
reply = authenticate_to_floppyd(sock, display);
if (reply != 0) {
fprintf(stderr,
"Permission denied, authentication failed!\n"
"%s\n", AuthErrors[reply]);
return -1;
}
free(hostname);
free(display);
return sock;
}
#endif