560 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			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
 | 
