1 /* Copyright 1999 Peter Schlaile.
2 * Copyright 1999-2002,2005-2007,2009 Alain Knaff.
3 * This file is part of mtools.
5 * Mtools is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * Mtools is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
18 * IO to the floppyd daemon running on the local X-Server Host
24 * udbz@rz.uni-karlsruhe.de
28 #include "sysincludes.h"
33 #include "partition.h"
34 #include "floppyd_io.h"
38 /* ######################################################################## */
41 typedef unsigned char Byte;
42 typedef unsigned long Dword;
43 typedef mt_off_t Qword;
45 const char* AuthErrors[] = {
47 "Auth failed: Packet oversized",
48 "Auth failed: X-Cookie doesn't match",
49 "Auth failed: Wrong transmission protocol version",
50 "Auth failed: Device locked"
51 "Auth failed: Bad packet",
52 "Auth failed: I/O Error"
56 typedef struct RemoteFile_t {
71 #include "byte_dword.h"
72 #include "read_dword.h"
75 /* ######################################################################## */
77 static int authenticate_to_floppyd(RemoteFile_t *floppyd, int sock, char *display)
81 const char *command[] = { "xauth", "xauth", "extract", "-", 0, 0 };
88 filelen=strlen(display);
91 xcookie = (char *) safe_malloc(filelen+4);
92 filelen = safePopenOut(command, xcookie+4, filelen);
94 return AUTH_AUTHFAILED;
96 /* Version negotiation */
98 dword2byte(floppyd->version,buf+4);
99 if(write(sock, buf, 8) < 8)
100 return AUTH_IO_ERROR;
102 if ( (l = read_dword(sock)) < 4) {
103 return AUTH_WRONGVERSION;
106 errcode = read_dword(sock);
108 if (errcode != AUTH_SUCCESS) {
113 floppyd->version = read_dword(sock);
115 floppyd->capabilities = read_dword(sock);
117 dword2byte(filelen, (Byte *)xcookie);
118 if(write(sock, xcookie, filelen+4) < filelen + 4)
119 return AUTH_IO_ERROR;
121 if (read_dword(sock) != 4) {
122 return AUTH_PACKETOVERSIZE;
125 errcode = read_dword(sock);
131 static int floppyd_reader(int fd, char* buffer, int len)
141 dword2byte(4, buf+5);
142 dword2byte(len, buf+9);
143 if(write(fd, buf, 13) < 13)
144 return AUTH_IO_ERROR;
146 if (read_dword(fd) != 8) {
151 gotlen = read_dword(fd);
152 errcode = read_dword(fd);
155 if (read_dword(fd) != gotlen) {
159 for (start = 0, l = 0; start < gotlen; start += l) {
160 l = read(fd, buffer+start, gotlen-start);
172 static int floppyd_writer(int fd, char* buffer, int len)
180 dword2byte(len, buf+5);
182 if(write(fd, buf, 9) < 9)
183 return AUTH_IO_ERROR;
184 if(write(fd, buffer, len) < len)
185 return AUTH_IO_ERROR;
187 if (read_dword(fd) != 8) {
192 gotlen = read_dword(fd);
193 errcode = read_dword(fd);
196 if(errno != 0 && gotlen == 0) {
205 static int floppyd_lseek(int fd, mt_off_t offset, int whence)
214 dword2byte(8, buf+5);
215 dword2byte(truncBytes32(offset), buf+9);
216 dword2byte(whence, buf+13);
218 if(write(fd, buf, 17) < 17)
219 return AUTH_IO_ERROR;
221 if (read_dword(fd) != 8) {
226 gotlen = read_dword(fd);
227 errcode = read_dword(fd);
234 static mt_off_t floppyd_lseek64(int fd, mt_off_t offset, int whence)
243 dword2byte(12, buf+5);
244 qword2byte(offset, buf+9);
245 dword2byte(whence, buf+17);
247 if(write(fd, buf, 21) < 21)
248 return AUTH_IO_ERROR;
250 if (read_dword(fd) != 12) {
255 gotlen = read_qword(fd);
256 errcode = read_dword(fd);
263 static int floppyd_open(RemoteFile_t *This, int mode)
269 if(! (This->capabilities & FLOPPYD_CAP_EXPLICIT_OPEN) ) {
270 /* floppyd has no "explicit seek" capabilities */
275 if((mode & O_ACCMODE) == O_RDONLY)
279 dword2byte(4, buf+5);
280 dword2byte(This->drive, buf+9);
282 if(write(This->fd, buf, 13) < 13)
283 return AUTH_IO_ERROR;
285 if (read_dword(This->fd) != 8) {
290 gotlen = read_dword(This->fd);
291 errcode = read_dword(This->fd);
299 /* ######################################################################## */
301 typedef int (*iofn) (int, char *, int);
303 static int floppyd_io(Stream_t *Stream, char *buf, mt_off_t where, int len,
306 DeclareThis(RemoteFile_t);
309 where += This->offset;
311 if (where != This->lastwhere ){
312 if(This->capabilities & FLOPPYD_CAP_LARGE_SEEK) {
313 if(floppyd_lseek64( This->fd, where, SEEK_SET) < 0 ){
314 perror("floppyd_lseek64");
315 This->lastwhere = (mt_off_t) -1;
319 if(floppyd_lseek( This->fd, where, SEEK_SET) < 0 ){
320 perror("floppyd_lseek");
321 This->lastwhere = (mt_off_t) -1;
326 ret = io(This->fd, buf, len);
328 perror("floppyd_io");
329 This->lastwhere = (mt_off_t) -1;
332 This->lastwhere = where + ret;
336 static int floppyd_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
338 return floppyd_io(Stream, buf, where, len, (iofn) floppyd_reader);
341 static int floppyd_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
343 return floppyd_io(Stream, buf, where, len, (iofn) floppyd_writer);
346 static int floppyd_flush(Stream_t *Stream)
350 DeclareThis(RemoteFile_t);
354 dword2byte(1, buf+5);
357 if(write(This->fd, buf, 10) < 10)
358 return AUTH_IO_ERROR;
360 if (read_dword(This->fd) != 8) {
365 read_dword(This->fd);
366 read_dword(This->fd);
370 static int floppyd_free(Stream_t *Stream)
375 DeclareThis(RemoteFile_t);
380 if(write(This->fd, buf, 5) < 5)
381 return AUTH_IO_ERROR;
382 shutdown(This->fd, 1);
383 if (read_dword(This->fd) != 8) {
388 gotlen = read_dword(This->fd);
389 errcode = read_dword(This->fd);
400 static int floppyd_geom(Stream_t *Stream, struct device *dev,
401 struct device *orig_dev,
402 int media, union bootsector *boot)
406 DeclareThis(RemoteFile_t);
408 dev->ssize = 2; /* allow for init_geom to change it */
409 dev->use_2m = 0x80; /* disable 2m mode to begin */
411 if(media == 0xf0 || media >= 0x100){
412 dev->heads = WORD(nheads);
413 dev->sectors = WORD(nsect);
414 tot_sectors = DWORD(bigsect);
415 SET_INT(tot_sectors, WORD(psect));
416 sect_per_track = dev->heads * dev->sectors;
417 tot_sectors += sect_per_track - 1; /* round size up */
418 dev->tracks = tot_sectors / sect_per_track;
420 } else if (media >= 0xf8){
422 dev->heads = old_dos[media].heads;
423 dev->tracks = old_dos[media].tracks;
424 dev->sectors = old_dos[media].sectors;
428 fprintf(stderr,"Unknown media type\n");
432 This->size = (mt_off_t) 512 * dev->sectors * dev->tracks * dev->heads;
438 static int floppyd_data(Stream_t *Stream, time_t *date, mt_size_t *size,
439 int *type, int *address)
441 DeclareThis(RemoteFile_t);
444 /* unknown, and irrelevant anyways */
447 /* the size derived from the geometry */
448 *size = (mt_size_t) This->size;
450 *type = 0; /* not a directory */
456 /* ######################################################################## */
458 static Class_t FloppydFileClass = {
467 /* ######################################################################## */
469 static int get_host_and_port_and_drive(const char* name, char** hostname,
470 char **display, short* port, int *drive)
472 char* newname = strdup(name);
477 while (*p != '/' && *p) p++;
482 *port = FLOPPYD_DEFAULT_PORT;
483 if(*p >= '0' && *p <= '9')
484 *port = strtoul(p, &p, 0);
488 if(*p >= '0' && *p <= '9')
489 *drive = strtoul(p, &p, 0);
491 *display = strdup(newname);
494 while (*p != ':' && *p) p++;
499 *port += atoi(p); /* add display number to the port */
501 if (!*newname || strcmp(newname, "unix") == 0) {
503 newname = strdup("localhost");
511 * * Return the IP address of the specified host.
513 static IPaddr_t getipaddress(char *ipaddr)
516 struct hostent *host;
519 if (((ip = inet_addr(ipaddr)) == INADDR_NONE) &&
520 (strcmp(ipaddr, "255.255.255.255") != 0)) {
522 if ((host = gethostbyname(ipaddr)) != NULL) {
523 memcpy(&ip, host->h_addr, sizeof(ip));
530 fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip);
537 * * Connect to the floppyd server.
539 static int connect_to_server(IPaddr_t ip, short port)
542 struct sockaddr_in addr;
548 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
553 * Set the address to connect to.
556 addr.sin_family = AF_INET;
557 addr.sin_port = htons(port);
558 addr.sin_addr.s_addr = ip;
561 * Connect our socket to the above address.
563 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
568 * Set the keepalive socket option to on.
572 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
573 (char *)&on, sizeof(on));
579 static int ConnectToFloppyd(RemoteFile_t *floppyd, const char* name,
582 Stream_t *FloppydOpen(struct device *dev, struct device *dev2,
583 char *name, int mode, char *errmsg,
584 int mode2, int locked, mt_size_t *maxSize)
588 if (!dev || !(dev->misc_flags & FLOPPYD_FLAG))
591 This = New(RemoteFile_t);
596 This->Class = &FloppydFileClass;
603 This->fd = ConnectToFloppyd(This, name, errmsg);
604 if (This->fd == -1) {
609 if(floppyd_open(This, mode) < 0) {
611 "Can't open remote drive: %s", strerror(errno));
619 (This->capabilities & FLOPPYD_CAP_LARGE_SEEK) ?
620 max_off_t_seek : max_off_t_31;
622 return (Stream_t *) This;
625 static int ConnectToFloppyd(RemoteFile_t *floppyd, const char* name,
631 int rval = get_host_and_port_and_drive(name, &hostname, &display,
632 &port, &floppyd->drive);
636 if (!rval) return -1;
638 floppyd->version = FLOPPYD_PROTOCOL_VERSION;
639 floppyd->capabilities = 0;
641 sock = connect_to_server(getipaddress(hostname), port);
645 snprintf(errmsg, 200,
646 "Can't connect to floppyd server on %s, port %i (%s)!",
647 hostname, port, strerror(errno));
650 "Can't connect to floppyd server on %s, port %i!",
656 reply = authenticate_to_floppyd(floppyd, sock, display);
657 if(floppyd->version == FLOPPYD_PROTOCOL_VERSION_OLD)
659 if(reply == AUTH_WRONGVERSION) {
660 /* fall back on old version */
661 floppyd->version = FLOPPYD_PROTOCOL_VERSION_OLD;
669 "Permission denied, authentication failed!\n"
670 "%s\n", AuthErrors[reply]);