1*d5c9a868SElliott Hughes /* Copyright 1999 Peter Schlaile.
2*d5c9a868SElliott Hughes * Copyright 1999-2005,2007-2009 Alain Knaff.
3*d5c9a868SElliott Hughes * This file is part of mtools.
4*d5c9a868SElliott Hughes *
5*d5c9a868SElliott Hughes * Mtools is free software: you can redistribute it and/or modify
6*d5c9a868SElliott Hughes * it under the terms of the GNU General Public License as published by
7*d5c9a868SElliott Hughes * the Free Software Foundation, either version 3 of the License, or
8*d5c9a868SElliott Hughes * (at your option) any later version.
9*d5c9a868SElliott Hughes *
10*d5c9a868SElliott Hughes * Mtools is distributed in the hope that it will be useful,
11*d5c9a868SElliott Hughes * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*d5c9a868SElliott Hughes * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*d5c9a868SElliott Hughes * GNU General Public License for more details.
14*d5c9a868SElliott Hughes *
15*d5c9a868SElliott Hughes * You should have received a copy of the GNU General Public License
16*d5c9a868SElliott Hughes * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
17*d5c9a868SElliott Hughes *
18*d5c9a868SElliott Hughes * the floppyd daemon running on the local X-Server
19*d5c9a868SElliott Hughes *
20*d5c9a868SElliott Hughes * written by:
21*d5c9a868SElliott Hughes *
22*d5c9a868SElliott Hughes * Peter Schlaile
23*d5c9a868SElliott Hughes *
24*d5c9a868SElliott Hughes * [email protected]
25*d5c9a868SElliott Hughes *
26*d5c9a868SElliott Hughes * Large parts of the network code shamelessly stolen from
27*d5c9a868SElliott Hughes * transproxy by John Saunders <[email protected]>
28*d5c9a868SElliott Hughes *
29*d5c9a868SElliott Hughes * Rewritten in C by Alain Knaff. Apparently C++ is still not as
30*d5c9a868SElliott Hughes * portable as C. */
31*d5c9a868SElliott Hughes
32*d5c9a868SElliott Hughes #define DEBUG 0
33*d5c9a868SElliott Hughes
34*d5c9a868SElliott Hughes #include "sysincludes.h"
35*d5c9a868SElliott Hughes #include "llong.h"
36*d5c9a868SElliott Hughes
37*d5c9a868SElliott Hughes #ifdef USE_FLOPPYD
38*d5c9a868SElliott Hughes
39*d5c9a868SElliott Hughes #define USE_FLOPPYD_BUFFERED_IO 1
40*d5c9a868SElliott Hughes
41*d5c9a868SElliott Hughes #include "sysincludes.h"
42*d5c9a868SElliott Hughes #include "grp.h"
43*d5c9a868SElliott Hughes #include <X11/Xlib.h>
44*d5c9a868SElliott Hughes #include <X11/Xauth.h>
45*d5c9a868SElliott Hughes
46*d5c9a868SElliott Hughes #include "floppyd_io.h"
47*d5c9a868SElliott Hughes
48*d5c9a868SElliott Hughes #ifndef SIGCLD
49*d5c9a868SElliott Hughes #define SIGCLD SIGCHLD
50*d5c9a868SElliott Hughes #endif
51*d5c9a868SElliott Hughes
52*d5c9a868SElliott Hughes /* For Linux 1.2.13 */
53*d5c9a868SElliott Hughes #ifndef SOMAXCONN
54*d5c9a868SElliott Hughes #define SOMAXCONN 5
55*d5c9a868SElliott Hughes #endif
56*d5c9a868SElliott Hughes
57*d5c9a868SElliott Hughes /*
58*d5c9a868SElliott Hughes To compile:
59*d5c9a868SElliott Hughes
60*d5c9a868SElliott Hughes gcc -Wall floppyd.cpp -o floppyd -lX11
61*d5c9a868SElliott Hughes
62*d5c9a868SElliott Hughes floppyd
63*d5c9a868SElliott Hughes
64*d5c9a868SElliott Hughes Communication to the clients works the following way:
65*d5c9a868SElliott Hughes
66*d5c9a868SElliott Hughes Client sends his protocol-version. If the version between server and client
67*d5c9a868SElliott Hughes differ: bail out.
68*d5c9a868SElliott Hughes
69*d5c9a868SElliott Hughes After that,we send our .Xauthority-file (a maximum of MAX_XAUTHORITY_LENGTH
70*d5c9a868SElliott Hughes Bytes long) to the server.
71*d5c9a868SElliott Hughes
72*d5c9a868SElliott Hughes The server then checks, if it already has a .Xauthority file. If so
73*d5c9a868SElliott Hughes it is interpreted as LOCK-File for the floppy-device and the communication
74*d5c9a868SElliott Hughes gets terminated.
75*d5c9a868SElliott Hughes
76*d5c9a868SElliott Hughes (What if we have 2 floppy devices? Well. Two floppy users with different
77*d5c9a868SElliott Hughes home-directories should work nicely...)
78*d5c9a868SElliott Hughes
79*d5c9a868SElliott Hughes Now, the data is written to the .Xauthority file. Then we try to open
80*d5c9a868SElliott Hughes a connection to the local X-Server. If this fails -> bail out.
81*d5c9a868SElliott Hughes
82*d5c9a868SElliott Hughes ***
83*d5c9a868SElliott Hughes
84*d5c9a868SElliott Hughes The data packets are built as follows:
85*d5c9a868SElliott Hughes
86*d5c9a868SElliott Hughes Base-packets: 1 Dword length, then data.
87*d5c9a868SElliott Hughes length is in Network-Byte order. (4 Bytes)
88*d5c9a868SElliott Hughes
89*d5c9a868SElliott Hughes Commands are: 1. Packet Opcode (length 1), 1. Data packet as parameter.
90*d5c9a868SElliott Hughes
91*d5c9a868SElliott Hughes Return: 1.Packet: 1. Dword: Bytes processed, 2. Dword: Error-Code
92*d5c9a868SElliott Hughes
93*d5c9a868SElliott Hughes ***
94*d5c9a868SElliott Hughes
95*d5c9a868SElliott Hughes TODO:
96*d5c9a868SElliott Hughes * Implement some IOCTL calls to format floppy disks or so...
97*d5c9a868SElliott Hughes * Read is somewhat dirty implemented. Tries multiple times to
98*d5c9a868SElliott Hughes read the expected bytes from the socket stream. Don't know
99*d5c9a868SElliott Hughes why this is necessary. Maybe the socket stream is nonblocking
100*d5c9a868SElliott Hughes or something IT SHOULD NOT BE!
101*d5c9a868SElliott Hughes
102*d5c9a868SElliott Hughes */
103*d5c9a868SElliott Hughes
104*d5c9a868SElliott Hughes
105*d5c9a868SElliott Hughes #define MAX_XAUTHORITY_LENGTH 3000
106*d5c9a868SElliott Hughes #define MAX_DATA_REQUEST 3000000
107*d5c9a868SElliott Hughes #define BUFFERED_IO_SIZE 16348
108*d5c9a868SElliott Hughes
109*d5c9a868SElliott Hughes unsigned int mtools_lock_timeout=30;
110*d5c9a868SElliott Hughes
111*d5c9a868SElliott Hughes void serve_client(int sock, const char *const*device_name, unsigned int n_dev,
112*d5c9a868SElliott Hughes int close_stderr);
113*d5c9a868SElliott Hughes
114*d5c9a868SElliott Hughes
115*d5c9a868SElliott Hughes #ifdef USE_FLOPPYD_BUFFERED_IO
116*d5c9a868SElliott Hughes typedef struct io_buffer {
117*d5c9a868SElliott Hughes Byte out_buffer[BUFFERED_IO_SIZE];
118*d5c9a868SElliott Hughes Byte in_buffer[BUFFERED_IO_SIZE];
119*d5c9a868SElliott Hughes
120*d5c9a868SElliott Hughes size_t in_valid;
121*d5c9a868SElliott Hughes size_t in_start;
122*d5c9a868SElliott Hughes size_t out_valid;
123*d5c9a868SElliott Hughes
124*d5c9a868SElliott Hughes int handle;
125*d5c9a868SElliott Hughes } *io_buffer;
126*d5c9a868SElliott Hughes
new_io_buffer(int _handle)127*d5c9a868SElliott Hughes static io_buffer new_io_buffer (int _handle) {
128*d5c9a868SElliott Hughes io_buffer buffer;
129*d5c9a868SElliott Hughes
130*d5c9a868SElliott Hughes buffer = New(struct io_buffer);
131*d5c9a868SElliott Hughes
132*d5c9a868SElliott Hughes buffer->handle = _handle;
133*d5c9a868SElliott Hughes buffer->in_valid = buffer->in_start = 0;
134*d5c9a868SElliott Hughes buffer->out_valid = 0;
135*d5c9a868SElliott Hughes return buffer;
136*d5c9a868SElliott Hughes }
137*d5c9a868SElliott Hughes
138*d5c9a868SElliott Hughes
flush(io_buffer buffer)139*d5c9a868SElliott Hughes static void flush(io_buffer buffer) {
140*d5c9a868SElliott Hughes if (buffer->out_valid) {
141*d5c9a868SElliott Hughes if(write(buffer->handle, buffer->out_buffer, buffer->out_valid) < 0) {
142*d5c9a868SElliott Hughes perror("floppyd flush");
143*d5c9a868SElliott Hughes }
144*d5c9a868SElliott Hughes buffer->out_valid = 0;
145*d5c9a868SElliott Hughes }
146*d5c9a868SElliott Hughes }
147*d5c9a868SElliott Hughes
free_io_buffer(io_buffer buffer)148*d5c9a868SElliott Hughes static void free_io_buffer(io_buffer buffer) {
149*d5c9a868SElliott Hughes flush(buffer);
150*d5c9a868SElliott Hughes free(buffer);
151*d5c9a868SElliott Hughes }
152*d5c9a868SElliott Hughes
153*d5c9a868SElliott Hughes
buf_read(io_buffer buf,Byte * buffer,size_t nbytes)154*d5c9a868SElliott Hughes static size_t buf_read (io_buffer buf, Byte* buffer, size_t nbytes) {
155*d5c9a868SElliott Hughes size_t ret;
156*d5c9a868SElliott Hughes
157*d5c9a868SElliott Hughes if (nbytes <= buf->in_valid) {
158*d5c9a868SElliott Hughes memcpy(buffer, buf->in_buffer+buf->in_start, nbytes);
159*d5c9a868SElliott Hughes buf->in_valid -= nbytes;
160*d5c9a868SElliott Hughes buf->in_start += nbytes;
161*d5c9a868SElliott Hughes ret = nbytes;
162*d5c9a868SElliott Hughes } else {
163*d5c9a868SElliott Hughes if (buf->in_valid)
164*d5c9a868SElliott Hughes memcpy(buffer, buf->in_buffer+buf->in_start,
165*d5c9a868SElliott Hughes buf->in_valid);
166*d5c9a868SElliott Hughes nbytes -= buf->in_valid;
167*d5c9a868SElliott Hughes buffer += buf->in_valid;
168*d5c9a868SElliott Hughes if (nbytes > BUFFERED_IO_SIZE) {
169*d5c9a868SElliott Hughes ssize_t rval = read(buf->handle, buffer, nbytes);
170*d5c9a868SElliott Hughes if (rval >= 0) {
171*d5c9a868SElliott Hughes ret = (size_t) rval + buf->in_valid;
172*d5c9a868SElliott Hughes } else {
173*d5c9a868SElliott Hughes perror("read error");
174*d5c9a868SElliott Hughes exit(1);
175*d5c9a868SElliott Hughes }
176*d5c9a868SElliott Hughes buf->in_valid = buf->in_start = 0;
177*d5c9a868SElliott Hughes } else {
178*d5c9a868SElliott Hughes ssize_t rval = read(buf->handle, buf->in_buffer,
179*d5c9a868SElliott Hughes BUFFERED_IO_SIZE);
180*d5c9a868SElliott Hughes if (rval >= 0) {
181*d5c9a868SElliott Hughes if (rval < (ssize_t) nbytes) {
182*d5c9a868SElliott Hughes memcpy(buffer, buf->in_buffer,
183*d5c9a868SElliott Hughes (size_t) rval);
184*d5c9a868SElliott Hughes ret = (size_t) rval + buf->in_valid;
185*d5c9a868SElliott Hughes buf->in_valid = buf->in_start = 0;
186*d5c9a868SElliott Hughes } else {
187*d5c9a868SElliott Hughes size_t a;
188*d5c9a868SElliott Hughes memcpy(buffer, buf->in_buffer, nbytes);
189*d5c9a868SElliott Hughes buf->in_start = nbytes;
190*d5c9a868SElliott Hughes a = buf->in_valid;
191*d5c9a868SElliott Hughes buf->in_valid = (size_t) rval-nbytes;
192*d5c9a868SElliott Hughes ret = a + nbytes;
193*d5c9a868SElliott Hughes }
194*d5c9a868SElliott Hughes } else {
195*d5c9a868SElliott Hughes perror("read error");
196*d5c9a868SElliott Hughes exit(1);
197*d5c9a868SElliott Hughes }
198*d5c9a868SElliott Hughes }
199*d5c9a868SElliott Hughes }
200*d5c9a868SElliott Hughes return ret;
201*d5c9a868SElliott Hughes }
202*d5c9a868SElliott Hughes
buf_write(io_buffer buf,void * buffer,size_t nbytes)203*d5c9a868SElliott Hughes static ssize_t buf_write(io_buffer buf, void* buffer, size_t nbytes) {
204*d5c9a868SElliott Hughes if (buf->out_valid + nbytes > BUFFERED_IO_SIZE) {
205*d5c9a868SElliott Hughes flush(buf);
206*d5c9a868SElliott Hughes return write(buf->handle, buffer, nbytes);
207*d5c9a868SElliott Hughes }
208*d5c9a868SElliott Hughes memcpy(buf->out_buffer+buf->out_valid, buffer, nbytes);
209*d5c9a868SElliott Hughes buf->out_valid += nbytes;
210*d5c9a868SElliott Hughes return (ssize_t) nbytes;
211*d5c9a868SElliott Hughes }
212*d5c9a868SElliott Hughes
213*d5c9a868SElliott Hughes
214*d5c9a868SElliott Hughes
215*d5c9a868SElliott Hughes #else
216*d5c9a868SElliott Hughes
217*d5c9a868SElliott Hughes typedef int io_buffer;
218*d5c9a868SElliott Hughes
new_io_buffer(int handle)219*d5c9a868SElliott Hughes io_buffer new_io_buffer (int handle) {
220*d5c9a868SElliott Hughes return handle;
221*d5c9a868SElliott Hughes }
222*d5c9a868SElliott Hughes
223*d5c9a868SElliott Hughes
buf_read(io_buffer handle,Byte * buffer,size_t nbytes)224*d5c9a868SElliott Hughes size_t buf_read (io_buffer handle, Byte* buffer, size_t nbytes) {
225*d5c9a868SElliott Hughes return (read(handle, buffer, nbytes));
226*d5c9a868SElliott Hughes }
227*d5c9a868SElliott Hughes
buf_write(io_buffer handle,void * buffer,size_t nbytes)228*d5c9a868SElliott Hughes ssize_t buf_write(io_buffer handle, void* buffer, size_t nbytes) {
229*d5c9a868SElliott Hughes return (write(handle, buffer, nbytes));
230*d5c9a868SElliott Hughes }
231*d5c9a868SElliott Hughes
232*d5c9a868SElliott Hughes
free_io_buffer(io_buffer buffer)233*d5c9a868SElliott Hughes void free_io_buffer(io_buffer buffer) { }
234*d5c9a868SElliott Hughes
235*d5c9a868SElliott Hughes
flush(io_buffer buffer)236*d5c9a868SElliott Hughes void flush(io_buffer buffer) { }
237*d5c9a868SElliott Hughes
238*d5c9a868SElliott Hughes #endif
239*d5c9a868SElliott Hughes
240*d5c9a868SElliott Hughes typedef struct Packet {
241*d5c9a868SElliott Hughes Byte* data;
242*d5c9a868SElliott Hughes Dword len;
243*d5c9a868SElliott Hughes Dword alloc_size;
244*d5c9a868SElliott Hughes } *Packet;
245*d5c9a868SElliott Hughes
246*d5c9a868SElliott Hughes #include "byte_dword.h"
247*d5c9a868SElliott Hughes
read_dword(io_buffer fp)248*d5c9a868SElliott Hughes static Dword read_dword(io_buffer fp)
249*d5c9a868SElliott Hughes {
250*d5c9a868SElliott Hughes Byte val[4];
251*d5c9a868SElliott Hughes if (buf_read(fp, val, 4) < 4) {
252*d5c9a868SElliott Hughes return 0xffffffff;
253*d5c9a868SElliott Hughes }
254*d5c9a868SElliott Hughes
255*d5c9a868SElliott Hughes return byte2dword(val);
256*d5c9a868SElliott Hughes }
257*d5c9a868SElliott Hughes
write_dword(io_buffer fp,Dword parm)258*d5c9a868SElliott Hughes static void write_dword(io_buffer fp, Dword parm)
259*d5c9a868SElliott Hughes {
260*d5c9a868SElliott Hughes Byte val[4];
261*d5c9a868SElliott Hughes
262*d5c9a868SElliott Hughes dword2byte(parm, val);
263*d5c9a868SElliott Hughes
264*d5c9a868SElliott Hughes buf_write(fp, val,4);
265*d5c9a868SElliott Hughes }
266*d5c9a868SElliott Hughes
267*d5c9a868SElliott Hughes
newPacket(void)268*d5c9a868SElliott Hughes static Packet newPacket(void)
269*d5c9a868SElliott Hughes {
270*d5c9a868SElliott Hughes Packet packet;
271*d5c9a868SElliott Hughes
272*d5c9a868SElliott Hughes packet = New(struct Packet);
273*d5c9a868SElliott Hughes packet->data = NULL;
274*d5c9a868SElliott Hughes packet->len = packet->alloc_size = 0;
275*d5c9a868SElliott Hughes return packet;
276*d5c9a868SElliott Hughes }
277*d5c9a868SElliott Hughes
278*d5c9a868SElliott Hughes
destroyPacket(Packet packet)279*d5c9a868SElliott Hughes static void destroyPacket(Packet packet)
280*d5c9a868SElliott Hughes {
281*d5c9a868SElliott Hughes if(packet->data)
282*d5c9a868SElliott Hughes free(packet->data);
283*d5c9a868SElliott Hughes free(packet);
284*d5c9a868SElliott Hughes }
285*d5c9a868SElliott Hughes
kill_packet(Packet packet)286*d5c9a868SElliott Hughes static void kill_packet(Packet packet)
287*d5c9a868SElliott Hughes {
288*d5c9a868SElliott Hughes if(packet->data)
289*d5c9a868SElliott Hughes free(packet->data);
290*d5c9a868SElliott Hughes packet->data = NULL;
291*d5c9a868SElliott Hughes packet->len = 0;
292*d5c9a868SElliott Hughes packet->alloc_size = 0;
293*d5c9a868SElliott Hughes }
294*d5c9a868SElliott Hughes
make_new(Packet packet,Dword l)295*d5c9a868SElliott Hughes static void make_new(Packet packet, Dword l)
296*d5c9a868SElliott Hughes {
297*d5c9a868SElliott Hughes if (l < packet->alloc_size) {
298*d5c9a868SElliott Hughes packet->len = l;
299*d5c9a868SElliott Hughes return;
300*d5c9a868SElliott Hughes }
301*d5c9a868SElliott Hughes kill_packet(packet);
302*d5c9a868SElliott Hughes packet->len = packet->alloc_size = l;
303*d5c9a868SElliott Hughes packet->data = malloc(l);
304*d5c9a868SElliott Hughes memset(packet->data, 0, l);
305*d5c9a868SElliott Hughes }
306*d5c9a868SElliott Hughes
send_packet(Packet packet,io_buffer fp)307*d5c9a868SElliott Hughes static char send_packet(Packet packet, io_buffer fp)
308*d5c9a868SElliott Hughes {
309*d5c9a868SElliott Hughes if (packet->data) {
310*d5c9a868SElliott Hughes write_dword(fp, packet->len);
311*d5c9a868SElliott Hughes buf_write(fp, packet->data, packet->len);
312*d5c9a868SElliott Hughes flush(fp);
313*d5c9a868SElliott Hughes #if DEBUG
314*d5c9a868SElliott Hughes fprintf(stderr, "send_packet(): Size: %li\n", packet->len);
315*d5c9a868SElliott Hughes #endif
316*d5c9a868SElliott Hughes
317*d5c9a868SElliott Hughes #if DEBUG
318*d5c9a868SElliott Hughes fprintf(stderr, "send_packet(): ");
319*d5c9a868SElliott Hughes for (int i = 0; i < packet->len; i++) {
320*d5c9a868SElliott Hughes fprintf(stderr, "%d ", packet->data[i]);
321*d5c9a868SElliott Hughes }
322*d5c9a868SElliott Hughes fprintf(stderr, "\n");
323*d5c9a868SElliott Hughes #endif
324*d5c9a868SElliott Hughes
325*d5c9a868SElliott Hughes }
326*d5c9a868SElliott Hughes return (packet->data != NULL);
327*d5c9a868SElliott Hughes }
328*d5c9a868SElliott Hughes
recv_packet(Packet packet,io_buffer fp,Dword maxlength)329*d5c9a868SElliott Hughes static char recv_packet(Packet packet, io_buffer fp, Dword maxlength)
330*d5c9a868SElliott Hughes {
331*d5c9a868SElliott Hughes Dword start;
332*d5c9a868SElliott Hughes size_t l;
333*d5c9a868SElliott Hughes Dword length = read_dword(fp);
334*d5c9a868SElliott Hughes #if DEBUG
335*d5c9a868SElliott Hughes fprintf(stderr, "recv_packet(): Size: %li\n", length);
336*d5c9a868SElliott Hughes #endif
337*d5c9a868SElliott Hughes if (length > maxlength || length == 0xffffffff ) {
338*d5c9a868SElliott Hughes return 0;
339*d5c9a868SElliott Hughes }
340*d5c9a868SElliott Hughes make_new(packet, length);
341*d5c9a868SElliott Hughes l = 0;
342*d5c9a868SElliott Hughes for (start = 0; start < length; start += l) {
343*d5c9a868SElliott Hughes l = buf_read(fp, packet->data+start, length-start);
344*d5c9a868SElliott Hughes if (l == 0) {
345*d5c9a868SElliott Hughes return 0;
346*d5c9a868SElliott Hughes }
347*d5c9a868SElliott Hughes }
348*d5c9a868SElliott Hughes if (packet->len == 0) {
349*d5c9a868SElliott Hughes return 0;
350*d5c9a868SElliott Hughes }
351*d5c9a868SElliott Hughes #if DEBUG
352*d5c9a868SElliott Hughes fprintf(stderr, "*** read: %li\n", packet->len);
353*d5c9a868SElliott Hughes #endif
354*d5c9a868SElliott Hughes
355*d5c9a868SElliott Hughes #if DEBUG
356*d5c9a868SElliott Hughes fprintf(stderr, "recv_packet(): ");
357*d5c9a868SElliott Hughes for (i = 0; i < packet->len; i++) {
358*d5c9a868SElliott Hughes fprintf(stderr, "%d ", packet->data[i]);
359*d5c9a868SElliott Hughes }
360*d5c9a868SElliott Hughes fprintf(stderr, "\n");
361*d5c9a868SElliott Hughes #endif
362*d5c9a868SElliott Hughes return 1;
363*d5c9a868SElliott Hughes }
364*d5c9a868SElliott Hughes
read_packet(Packet packet,int fd,Dword length)365*d5c9a868SElliott Hughes static ssize_t read_packet(Packet packet, int fd, Dword length) {
366*d5c9a868SElliott Hughes ssize_t ret;
367*d5c9a868SElliott Hughes make_new(packet, length);
368*d5c9a868SElliott Hughes ret = read(fd, packet->data, packet->len);
369*d5c9a868SElliott Hughes if(ret < 0)
370*d5c9a868SElliott Hughes return ret;
371*d5c9a868SElliott Hughes packet->len = (Dword) ret;
372*d5c9a868SElliott Hughes return 0;
373*d5c9a868SElliott Hughes }
374*d5c9a868SElliott Hughes
write_packet(Packet packet,int fd)375*d5c9a868SElliott Hughes static int write_packet(Packet packet, int fd) {
376*d5c9a868SElliott Hughes return (int)write(fd, packet->data, packet->len);
377*d5c9a868SElliott Hughes }
378*d5c9a868SElliott Hughes
put_dword(Packet packet,int my_index,Dword val)379*d5c9a868SElliott Hughes static void put_dword(Packet packet, int my_index, Dword val) {
380*d5c9a868SElliott Hughes dword2byte(val, packet->data+my_index);
381*d5c9a868SElliott Hughes }
382*d5c9a868SElliott Hughes
put_qword(Packet packet,int my_index,Qword val)383*d5c9a868SElliott Hughes static void put_qword(Packet packet, int my_index, Qword val) {
384*d5c9a868SElliott Hughes qword2byte(val, packet->data+my_index);
385*d5c9a868SElliott Hughes }
386*d5c9a868SElliott Hughes
get_dword(Packet packet,int my_index)387*d5c9a868SElliott Hughes static Dword get_dword(Packet packet, int my_index) {
388*d5c9a868SElliott Hughes return byte2dword(packet->data+my_index);
389*d5c9a868SElliott Hughes }
390*d5c9a868SElliott Hughes
get_qword(Packet packet,int my_index)391*d5c9a868SElliott Hughes static Qword get_qword(Packet packet, int my_index) {
392*d5c9a868SElliott Hughes return byte2qword(packet->data+my_index);
393*d5c9a868SElliott Hughes }
394*d5c9a868SElliott Hughes
get_length(Packet packet)395*d5c9a868SElliott Hughes static Dword get_length(Packet packet) {
396*d5c9a868SElliott Hughes return packet->len;
397*d5c9a868SElliott Hughes }
398*d5c9a868SElliott Hughes
eat(unsigned char ** ptr,size_t * len,unsigned char c)399*d5c9a868SElliott Hughes static int eat(unsigned char **ptr, size_t *len, unsigned char c) {
400*d5c9a868SElliott Hughes /* remove length + size code + terminating 0 */
401*d5c9a868SElliott Hughes if (*len < c + 3u)
402*d5c9a868SElliott Hughes return -1;
403*d5c9a868SElliott Hughes (*ptr) += c + 2;
404*d5c9a868SElliott Hughes (*len) -= c + 2;
405*d5c9a868SElliott Hughes return 0;
406*d5c9a868SElliott Hughes }
407*d5c9a868SElliott Hughes
408*d5c9a868SElliott Hughes static const char *dispName;
409*d5c9a868SElliott Hughes
410*d5c9a868SElliott Hughes static char XAUTHORITY[]="XAUTHORITY";
411*d5c9a868SElliott Hughes
do_auth(io_buffer sock,unsigned int * version)412*d5c9a868SElliott Hughes static char do_auth(io_buffer sock, unsigned int *version)
413*d5c9a868SElliott Hughes {
414*d5c9a868SElliott Hughes int fd;
415*d5c9a868SElliott Hughes Display* displ;
416*d5c9a868SElliott Hughes Packet proto_version = newPacket();
417*d5c9a868SElliott Hughes Packet mit_cookie;
418*d5c9a868SElliott Hughes unsigned char *ptr;
419*d5c9a868SElliott Hughes size_t len;
420*d5c9a868SElliott Hughes
421*d5c9a868SElliott Hughes char authFile[41]="/tmp/floppyd.XXXXXX";
422*d5c9a868SElliott Hughes unsigned char template[4096];
423*d5c9a868SElliott Hughes
424*d5c9a868SElliott Hughes Packet reply = newPacket();
425*d5c9a868SElliott Hughes
426*d5c9a868SElliott Hughes make_new(reply, 4);
427*d5c9a868SElliott Hughes
428*d5c9a868SElliott Hughes if (!recv_packet(proto_version, sock, 4)) {
429*d5c9a868SElliott Hughes put_dword(reply, 0, AUTH_PACKETOVERSIZE);
430*d5c9a868SElliott Hughes send_packet(reply, sock);
431*d5c9a868SElliott Hughes destroyPacket(reply);
432*d5c9a868SElliott Hughes destroyPacket(proto_version);
433*d5c9a868SElliott Hughes return 0;
434*d5c9a868SElliott Hughes }
435*d5c9a868SElliott Hughes
436*d5c9a868SElliott Hughes *version = get_dword(proto_version, 0);
437*d5c9a868SElliott Hughes if (*version > FLOPPYD_PROTOCOL_VERSION ||
438*d5c9a868SElliott Hughes *version < FLOPPYD_PROTOCOL_VERSION_OLD) {
439*d5c9a868SElliott Hughes /* fail if client requests a newer version than us */
440*d5c9a868SElliott Hughes put_dword(reply, 0, AUTH_WRONGVERSION);
441*d5c9a868SElliott Hughes send_packet(reply, sock);
442*d5c9a868SElliott Hughes destroyPacket(reply);
443*d5c9a868SElliott Hughes destroyPacket(proto_version);
444*d5c9a868SElliott Hughes return 0;
445*d5c9a868SElliott Hughes }
446*d5c9a868SElliott Hughes
447*d5c9a868SElliott Hughes if(*version == FLOPPYD_PROTOCOL_VERSION_OLD) {
448*d5c9a868SElliott Hughes put_dword(reply, 0, AUTH_SUCCESS);
449*d5c9a868SElliott Hughes } else {
450*d5c9a868SElliott Hughes Dword cap = FLOPPYD_CAP_EXPLICIT_OPEN;
451*d5c9a868SElliott Hughes if(sizeof(mt_off_t) >= 8) {
452*d5c9a868SElliott Hughes cap |= FLOPPYD_CAP_LARGE_SEEK;
453*d5c9a868SElliott Hughes }
454*d5c9a868SElliott Hughes make_new(reply, 12);
455*d5c9a868SElliott Hughes put_dword(reply, 0, AUTH_SUCCESS);
456*d5c9a868SElliott Hughes put_dword(reply, 4, FLOPPYD_PROTOCOL_VERSION);
457*d5c9a868SElliott Hughes put_dword(reply, 8, cap);
458*d5c9a868SElliott Hughes }
459*d5c9a868SElliott Hughes send_packet(reply, sock);
460*d5c9a868SElliott Hughes destroyPacket(proto_version);
461*d5c9a868SElliott Hughes
462*d5c9a868SElliott Hughes make_new(reply, 4);
463*d5c9a868SElliott Hughes mit_cookie = newPacket();
464*d5c9a868SElliott Hughes if (!recv_packet(mit_cookie, sock, MAX_XAUTHORITY_LENGTH)) {
465*d5c9a868SElliott Hughes put_dword(reply, 0, AUTH_PACKETOVERSIZE);
466*d5c9a868SElliott Hughes send_packet(reply, sock);
467*d5c9a868SElliott Hughes destroyPacket(reply);
468*d5c9a868SElliott Hughes destroyPacket(mit_cookie);
469*d5c9a868SElliott Hughes return 0;
470*d5c9a868SElliott Hughes }
471*d5c9a868SElliott Hughes
472*d5c9a868SElliott Hughes umask(077);
473*d5c9a868SElliott Hughes fd = mkstemp(authFile);
474*d5c9a868SElliott Hughes if(fd == -1) {
475*d5c9a868SElliott Hughes /* Different error than file exists */
476*d5c9a868SElliott Hughes put_dword(reply, 0, AUTH_DEVLOCKED);
477*d5c9a868SElliott Hughes send_packet(reply, sock);
478*d5c9a868SElliott Hughes close(fd);
479*d5c9a868SElliott Hughes destroyPacket(reply);
480*d5c9a868SElliott Hughes destroyPacket(mit_cookie);
481*d5c9a868SElliott Hughes return 0;
482*d5c9a868SElliott Hughes }
483*d5c9a868SElliott Hughes #ifdef HAVE_SETENV
484*d5c9a868SElliott Hughes setenv(XAUTHORITY, authFile, 1);
485*d5c9a868SElliott Hughes #else
486*d5c9a868SElliott Hughes {
487*d5c9a868SElliott Hughes char *buffer=malloc(strlen(XAUTHORITY)+strlen(authFile)+2);
488*d5c9a868SElliott Hughes strcpy(buffer, XAUTHORITY);
489*d5c9a868SElliott Hughes strcat(buffer, "=");
490*d5c9a868SElliott Hughes strcat(buffer, authFile);
491*d5c9a868SElliott Hughes putenv(buffer);
492*d5c9a868SElliott Hughes }
493*d5c9a868SElliott Hughes #endif
494*d5c9a868SElliott Hughes
495*d5c9a868SElliott Hughes ptr = template;
496*d5c9a868SElliott Hughes ptr[4095] = 0;
497*d5c9a868SElliott Hughes *ptr++ = 1;
498*d5c9a868SElliott Hughes *ptr++ = 0;
499*d5c9a868SElliott Hughes *ptr++ = 0;
500*d5c9a868SElliott Hughes gethostname((char*)ptr+1, 4088);
501*d5c9a868SElliott Hughes len = strlen((char*)ptr+1);
502*d5c9a868SElliott Hughes *ptr++ = (unsigned char) len;
503*d5c9a868SElliott Hughes ptr += len;
504*d5c9a868SElliott Hughes *ptr++ = 0;
505*d5c9a868SElliott Hughes *ptr++ = 1;
506*d5c9a868SElliott Hughes *ptr++ = '0'; /* Display number */
507*d5c9a868SElliott Hughes *ptr++ = '\0';
508*d5c9a868SElliott Hughes
509*d5c9a868SElliott Hughes if(write(fd, template, len+8) < (ssize_t) (len + 8)) {
510*d5c9a868SElliott Hughes close(fd);
511*d5c9a868SElliott Hughes return 0;
512*d5c9a868SElliott Hughes }
513*d5c9a868SElliott Hughes ptr = mit_cookie->data;
514*d5c9a868SElliott Hughes len = mit_cookie->len;
515*d5c9a868SElliott Hughes
516*d5c9a868SElliott Hughes if (eat(&ptr,&len,1) || /* the "type" */
517*d5c9a868SElliott Hughes eat(&ptr,&len,*ptr) || /* the hostname */
518*d5c9a868SElliott Hughes eat(&ptr,&len,*ptr)) { /* the display number */
519*d5c9a868SElliott Hughes destroyPacket(mit_cookie);
520*d5c9a868SElliott Hughes unlink(XauFileName());
521*d5c9a868SElliott Hughes put_dword(reply, 0, AUTH_BADPACKET);
522*d5c9a868SElliott Hughes send_packet(reply, sock);
523*d5c9a868SElliott Hughes destroyPacket(reply);
524*d5c9a868SElliott Hughes return 0;
525*d5c9a868SElliott Hughes }
526*d5c9a868SElliott Hughes
527*d5c9a868SElliott Hughes if(write(fd, ptr, len) < (ssize_t) len) {
528*d5c9a868SElliott Hughes close(fd);
529*d5c9a868SElliott Hughes return 0;
530*d5c9a868SElliott Hughes }
531*d5c9a868SElliott Hughes close(fd);
532*d5c9a868SElliott Hughes
533*d5c9a868SElliott Hughes destroyPacket(mit_cookie);
534*d5c9a868SElliott Hughes
535*d5c9a868SElliott Hughes displ = XOpenDisplay(dispName);
536*d5c9a868SElliott Hughes if (!displ) {
537*d5c9a868SElliott Hughes unlink(XauFileName());
538*d5c9a868SElliott Hughes put_dword(reply, 0, AUTH_AUTHFAILED);
539*d5c9a868SElliott Hughes send_packet(reply, sock);
540*d5c9a868SElliott Hughes destroyPacket(reply);
541*d5c9a868SElliott Hughes return 0;
542*d5c9a868SElliott Hughes }
543*d5c9a868SElliott Hughes XCloseDisplay(displ);
544*d5c9a868SElliott Hughes
545*d5c9a868SElliott Hughes put_dword(reply, 0, AUTH_SUCCESS);
546*d5c9a868SElliott Hughes send_packet(reply, sock);
547*d5c9a868SElliott Hughes destroyPacket(reply);
548*d5c9a868SElliott Hughes unlink(XauFileName());
549*d5c9a868SElliott Hughes return 1;
550*d5c9a868SElliott Hughes }
551*d5c9a868SElliott Hughes
552*d5c9a868SElliott Hughes /*
553*d5c9a868SElliott Hughes * Return the port number, in network order, of the specified service.
554*d5c9a868SElliott Hughes */
getportnum(char * portnum)555*d5c9a868SElliott Hughes static uint16_t getportnum(char *portnum)
556*d5c9a868SElliott Hughes {
557*d5c9a868SElliott Hughes char *digits = portnum;
558*d5c9a868SElliott Hughes struct servent *serv;
559*d5c9a868SElliott Hughes uint16_t port;
560*d5c9a868SElliott Hughes
561*d5c9a868SElliott Hughes for (port = 0; isdigit(*digits); ++digits)
562*d5c9a868SElliott Hughes {
563*d5c9a868SElliott Hughes port = (port * 10) + (uint8_t)(*digits - '0');
564*d5c9a868SElliott Hughes }
565*d5c9a868SElliott Hughes
566*d5c9a868SElliott Hughes if ((*digits != '\0') || (port <= 0))
567*d5c9a868SElliott Hughes {
568*d5c9a868SElliott Hughes if ((serv = getservbyname(portnum, "tcp")) != NULL)
569*d5c9a868SElliott Hughes {
570*d5c9a868SElliott Hughes port = ntohs((uint16_t)serv->s_port);
571*d5c9a868SElliott Hughes }
572*d5c9a868SElliott Hughes else
573*d5c9a868SElliott Hughes {
574*d5c9a868SElliott Hughes port = 0;
575*d5c9a868SElliott Hughes }
576*d5c9a868SElliott Hughes endservent();
577*d5c9a868SElliott Hughes }
578*d5c9a868SElliott Hughes
579*d5c9a868SElliott Hughes #if DEBUG
580*d5c9a868SElliott Hughes fprintf(stderr, "Port lookup %s -> %hd\n", portnum, port);
581*d5c9a868SElliott Hughes #endif
582*d5c9a868SElliott Hughes
583*d5c9a868SElliott Hughes return (port);
584*d5c9a868SElliott Hughes }
585*d5c9a868SElliott Hughes
586*d5c9a868SElliott Hughes /*
587*d5c9a868SElliott Hughes * Return the IP address of the specified host.
588*d5c9a868SElliott Hughes */
getipaddress(char * ipaddr)589*d5c9a868SElliott Hughes static in_addr_t getipaddress(char *ipaddr)
590*d5c9a868SElliott Hughes {
591*d5c9a868SElliott Hughes struct hostent *host;
592*d5c9a868SElliott Hughes in_addr_t ip;
593*d5c9a868SElliott Hughes
594*d5c9a868SElliott Hughes if (((ip = inet_addr(ipaddr)) == INADDR_NONE)
595*d5c9a868SElliott Hughes &&
596*d5c9a868SElliott Hughes (strcmp(ipaddr, "255.255.255.255") != 0))
597*d5c9a868SElliott Hughes {
598*d5c9a868SElliott Hughes if ((host = gethostbyname(ipaddr)) != NULL)
599*d5c9a868SElliott Hughes {
600*d5c9a868SElliott Hughes memcpy(&ip, host->h_addr, sizeof(ip));
601*d5c9a868SElliott Hughes }
602*d5c9a868SElliott Hughes endhostent();
603*d5c9a868SElliott Hughes }
604*d5c9a868SElliott Hughes
605*d5c9a868SElliott Hughes #if DEBUG
606*d5c9a868SElliott Hughes fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip);
607*d5c9a868SElliott Hughes #endif
608*d5c9a868SElliott Hughes
609*d5c9a868SElliott Hughes return (ip);
610*d5c9a868SElliott Hughes }
611*d5c9a868SElliott Hughes
612*d5c9a868SElliott Hughes /*
613*d5c9a868SElliott Hughes * Find the userid of the specified user.
614*d5c9a868SElliott Hughes */
getuserid(char * user)615*d5c9a868SElliott Hughes static uid_t getuserid(char *user)
616*d5c9a868SElliott Hughes {
617*d5c9a868SElliott Hughes struct passwd *pw;
618*d5c9a868SElliott Hughes uid_t uid;
619*d5c9a868SElliott Hughes
620*d5c9a868SElliott Hughes if ((pw = getpwnam(user)) != NULL)
621*d5c9a868SElliott Hughes {
622*d5c9a868SElliott Hughes uid = pw->pw_uid;
623*d5c9a868SElliott Hughes }
624*d5c9a868SElliott Hughes else if (*user == '#')
625*d5c9a868SElliott Hughes {
626*d5c9a868SElliott Hughes uid = (uid_t)atoi(&user[1]);
627*d5c9a868SElliott Hughes }
628*d5c9a868SElliott Hughes else
629*d5c9a868SElliott Hughes {
630*d5c9a868SElliott Hughes #ifdef HAVE_GETUSERID
631*d5c9a868SElliott Hughes id = getuserid("nobody");
632*d5c9a868SElliott Hughes #else
633*d5c9a868SElliott Hughes uid = 65535;
634*d5c9a868SElliott Hughes #endif
635*d5c9a868SElliott Hughes }
636*d5c9a868SElliott Hughes
637*d5c9a868SElliott Hughes #if DEBUG
638*d5c9a868SElliott Hughes fprintf(stderr, "User lookup %s -> %d\n", user, uid);
639*d5c9a868SElliott Hughes #endif
640*d5c9a868SElliott Hughes
641*d5c9a868SElliott Hughes endpwent();
642*d5c9a868SElliott Hughes
643*d5c9a868SElliott Hughes return (uid);
644*d5c9a868SElliott Hughes }
645*d5c9a868SElliott Hughes
646*d5c9a868SElliott Hughes /*
647*d5c9a868SElliott Hughes * Find the groupid of the specified user.
648*d5c9a868SElliott Hughes */
getgroupid(uid_t uid)649*d5c9a868SElliott Hughes static uid_t getgroupid(uid_t uid)
650*d5c9a868SElliott Hughes {
651*d5c9a868SElliott Hughes struct passwd *pw;
652*d5c9a868SElliott Hughes gid_t gid;
653*d5c9a868SElliott Hughes
654*d5c9a868SElliott Hughes if ((pw = getpwuid(uid)) != NULL)
655*d5c9a868SElliott Hughes {
656*d5c9a868SElliott Hughes gid = pw->pw_gid;
657*d5c9a868SElliott Hughes }
658*d5c9a868SElliott Hughes else
659*d5c9a868SElliott Hughes {
660*d5c9a868SElliott Hughes #ifdef HAVE_GETGROUPID
661*d5c9a868SElliott Hughes id = getgroupid(uid);
662*d5c9a868SElliott Hughes #else
663*d5c9a868SElliott Hughes gid = 65535;
664*d5c9a868SElliott Hughes #endif
665*d5c9a868SElliott Hughes }
666*d5c9a868SElliott Hughes
667*d5c9a868SElliott Hughes #if DEBUG
668*d5c9a868SElliott Hughes fprintf(stderr, "Group lookup %d -> %d\n", uid, gid);
669*d5c9a868SElliott Hughes #endif
670*d5c9a868SElliott Hughes
671*d5c9a868SElliott Hughes endpwent();
672*d5c9a868SElliott Hughes
673*d5c9a868SElliott Hughes return (gid);
674*d5c9a868SElliott Hughes }
675*d5c9a868SElliott Hughes
676*d5c9a868SElliott Hughes /*
677*d5c9a868SElliott Hughes * Bind to the specified ip and port.
678*d5c9a868SElliott Hughes */
bind_to_port(in_addr_t bind_ip,uint16_t bind_port)679*d5c9a868SElliott Hughes static int bind_to_port(in_addr_t bind_ip, uint16_t bind_port)
680*d5c9a868SElliott Hughes {
681*d5c9a868SElliott Hughes struct sockaddr_in addr;
682*d5c9a868SElliott Hughes int sock;
683*d5c9a868SElliott Hughes
684*d5c9a868SElliott Hughes /*
685*d5c9a868SElliott Hughes * Allocate a socket.
686*d5c9a868SElliott Hughes */
687*d5c9a868SElliott Hughes if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
688*d5c9a868SElliott Hughes {
689*d5c9a868SElliott Hughes perror("socket()");
690*d5c9a868SElliott Hughes exit(1);
691*d5c9a868SElliott Hughes }
692*d5c9a868SElliott Hughes
693*d5c9a868SElliott Hughes /*
694*d5c9a868SElliott Hughes * Set the SO_REUSEADDR option for debugging.
695*d5c9a868SElliott Hughes */
696*d5c9a868SElliott Hughes {
697*d5c9a868SElliott Hughes int on = 1;
698*d5c9a868SElliott Hughes if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
699*d5c9a868SElliott Hughes (char *)&on, sizeof(on)) < 0) {
700*d5c9a868SElliott Hughes perror("setsockopt");
701*d5c9a868SElliott Hughes exit(1);
702*d5c9a868SElliott Hughes }
703*d5c9a868SElliott Hughes }
704*d5c9a868SElliott Hughes
705*d5c9a868SElliott Hughes /*
706*d5c9a868SElliott Hughes * Set the address to listen to.
707*d5c9a868SElliott Hughes */
708*d5c9a868SElliott Hughes addr.sin_family = AF_INET;
709*d5c9a868SElliott Hughes addr.sin_port = htons(bind_port);
710*d5c9a868SElliott Hughes addr.sin_addr.s_addr = bind_ip;
711*d5c9a868SElliott Hughes
712*d5c9a868SElliott Hughes /*
713*d5c9a868SElliott Hughes * Bind our socket to the above address.
714*d5c9a868SElliott Hughes */
715*d5c9a868SElliott Hughes if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
716*d5c9a868SElliott Hughes {
717*d5c9a868SElliott Hughes perror("bind()");
718*d5c9a868SElliott Hughes exit(1);
719*d5c9a868SElliott Hughes }
720*d5c9a868SElliott Hughes
721*d5c9a868SElliott Hughes /*
722*d5c9a868SElliott Hughes * Establish a large listen backlog.
723*d5c9a868SElliott Hughes */
724*d5c9a868SElliott Hughes if (listen(sock, SOMAXCONN) < 0)
725*d5c9a868SElliott Hughes {
726*d5c9a868SElliott Hughes perror("listen()");
727*d5c9a868SElliott Hughes exit(1);
728*d5c9a868SElliott Hughes }
729*d5c9a868SElliott Hughes
730*d5c9a868SElliott Hughes return (sock);
731*d5c9a868SElliott Hughes }
732*d5c9a868SElliott Hughes
733*d5c9a868SElliott Hughes static int sockethandle_now = -1;
734*d5c9a868SElliott Hughes
735*d5c9a868SElliott Hughes /*
736*d5c9a868SElliott Hughes * Catch alarm signals and exit.
737*d5c9a868SElliott Hughes */
738*d5c9a868SElliott Hughes static void alarm_signal(int a UNUSEDP) NORETURN;
alarm_signal(int a UNUSEDP)739*d5c9a868SElliott Hughes static void alarm_signal(int a UNUSEDP)
740*d5c9a868SElliott Hughes {
741*d5c9a868SElliott Hughes if (sockethandle_now != -1) {
742*d5c9a868SElliott Hughes close(sockethandle_now);
743*d5c9a868SElliott Hughes sockethandle_now = -1;
744*d5c9a868SElliott Hughes unlink(XauFileName());
745*d5c9a868SElliott Hughes }
746*d5c9a868SElliott Hughes exit(1);
747*d5c9a868SElliott Hughes }
748*d5c9a868SElliott Hughes
749*d5c9a868SElliott Hughes
750*d5c9a868SElliott Hughes /*
751*d5c9a868SElliott Hughes * This is the main loop when running as a server.
752*d5c9a868SElliott Hughes */
753*d5c9a868SElliott Hughes static void server_main_loop(int sock, const char *const*device_name,
754*d5c9a868SElliott Hughes unsigned int n_dev) NORETURN;
server_main_loop(int sock,const char * const * device_name,unsigned int n_dev)755*d5c9a868SElliott Hughes static void server_main_loop(int sock, const char *const*device_name,
756*d5c9a868SElliott Hughes unsigned int n_dev)
757*d5c9a868SElliott Hughes {
758*d5c9a868SElliott Hughes struct sockaddr_in addr;
759*d5c9a868SElliott Hughes unsigned int len;
760*d5c9a868SElliott Hughes
761*d5c9a868SElliott Hughes /*
762*d5c9a868SElliott Hughes * Ignore dead servers so no zombies should be left hanging.
763*d5c9a868SElliott Hughes */
764*d5c9a868SElliott Hughes signal(SIGCLD, SIG_IGN);
765*d5c9a868SElliott Hughes
766*d5c9a868SElliott Hughes for (;;) {
767*d5c9a868SElliott Hughes int new_sock;
768*d5c9a868SElliott Hughes /*
769*d5c9a868SElliott Hughes * Accept an incoming connection.
770*d5c9a868SElliott Hughes */
771*d5c9a868SElliott Hughes len = sizeof(addr);
772*d5c9a868SElliott Hughes while ((new_sock = accept(sock, (struct sockaddr *)&addr, &len)) < 0){}
773*d5c9a868SElliott Hughes
774*d5c9a868SElliott Hughes /*
775*d5c9a868SElliott Hughes * Create a new process to handle the connection.
776*d5c9a868SElliott Hughes */
777*d5c9a868SElliott Hughes #if DEBUG == 0
778*d5c9a868SElliott Hughes switch (fork()) {
779*d5c9a868SElliott Hughes case -1:
780*d5c9a868SElliott Hughes /*
781*d5c9a868SElliott Hughes * Under load conditions just ignore new connections.
782*d5c9a868SElliott Hughes */
783*d5c9a868SElliott Hughes break;
784*d5c9a868SElliott Hughes
785*d5c9a868SElliott Hughes case 0:
786*d5c9a868SElliott Hughes /*
787*d5c9a868SElliott Hughes * Start the proxy work in the new socket.
788*d5c9a868SElliott Hughes */
789*d5c9a868SElliott Hughes #endif
790*d5c9a868SElliott Hughes serve_client(new_sock, device_name, n_dev, 0);
791*d5c9a868SElliott Hughes exit(0);
792*d5c9a868SElliott Hughes #if DEBUG == 0
793*d5c9a868SElliott Hughes }
794*d5c9a868SElliott Hughes #endif
795*d5c9a868SElliott Hughes /*
796*d5c9a868SElliott Hughes * Close the socket as the child does the handling.
797*d5c9a868SElliott Hughes */
798*d5c9a868SElliott Hughes close(new_sock);
799*d5c9a868SElliott Hughes new_sock = -1;
800*d5c9a868SElliott Hughes }
801*d5c9a868SElliott Hughes }
802*d5c9a868SElliott Hughes
803*d5c9a868SElliott Hughes /*
804*d5c9a868SElliott Hughes * Print some basic help information.
805*d5c9a868SElliott Hughes */
806*d5c9a868SElliott Hughes static void usage(char *prog, const char *opt, int ret) NORETURN;
usage(char * prog,const char * opt,int ret)807*d5c9a868SElliott Hughes static void usage(char *prog, const char *opt, int ret)
808*d5c9a868SElliott Hughes {
809*d5c9a868SElliott Hughes if (opt)
810*d5c9a868SElliott Hughes {
811*d5c9a868SElliott Hughes fprintf(stderr, "%s: %s\n", prog, opt);
812*d5c9a868SElliott Hughes }
813*d5c9a868SElliott Hughes fprintf(stderr, "usage: %s [-s port [-r user] [-b ipaddr]] devicename [Names of local host]\n",
814*d5c9a868SElliott Hughes prog);
815*d5c9a868SElliott Hughes fprintf(stderr, " -d Run as a server (default port 5703 + DISPLAY)\n");
816*d5c9a868SElliott Hughes fprintf(stderr, " -s port Run as a server bound to the specified port.\n");
817*d5c9a868SElliott Hughes fprintf(stderr, " -r user Run as the specified user in server mode.\n");
818*d5c9a868SElliott Hughes fprintf(stderr, " -b ipaddr Bind to the specified ipaddr in server mode.\n");
819*d5c9a868SElliott Hughes fprintf(stderr, " -l Do not attempt to connect to localhost:0 to validate connection\n");
820*d5c9a868SElliott Hughes exit(ret);
821*d5c9a868SElliott Hughes }
822*d5c9a868SElliott Hughes
823*d5c9a868SElliott Hughes
makeDisplayName(int dispNr)824*d5c9a868SElliott Hughes static char *makeDisplayName(int dispNr)
825*d5c9a868SElliott Hughes {
826*d5c9a868SElliott Hughes char result[80];
827*d5c9a868SElliott Hughes sprintf(result, ":%d.0", dispNr);
828*d5c9a868SElliott Hughes return strdup(result);
829*d5c9a868SElliott Hughes }
830*d5c9a868SElliott Hughes
main(int argc,char ** argv)831*d5c9a868SElliott Hughes int main (int argc, char** argv)
832*d5c9a868SElliott Hughes {
833*d5c9a868SElliott Hughes int sockfd = 0;
834*d5c9a868SElliott Hughes int arg;
835*d5c9a868SElliott Hughes int run_as_server = 0;
836*d5c9a868SElliott Hughes in_addr_t bind_ip = INADDR_ANY;
837*d5c9a868SElliott Hughes uint16_t bind_port = 0;
838*d5c9a868SElliott Hughes uid_t run_uid = 65535;
839*d5c9a868SElliott Hughes gid_t run_gid = 65535;
840*d5c9a868SElliott Hughes char* username = strdup("nobody");
841*d5c9a868SElliott Hughes int sock;
842*d5c9a868SElliott Hughes
843*d5c9a868SElliott Hughes const char *const* device_name = NULL;
844*d5c9a868SElliott Hughes const char *floppy0 = "/dev/fd0";
845*d5c9a868SElliott Hughes unsigned int n_dev;
846*d5c9a868SElliott Hughes
847*d5c9a868SElliott Hughes
848*d5c9a868SElliott Hughes /*
849*d5c9a868SElliott Hughes * Parse the command line arguments.
850*d5c9a868SElliott Hughes */
851*d5c9a868SElliott Hughes if(argc > 1 && !strcmp(argv[0], "--help"))
852*d5c9a868SElliott Hughes usage(argv[0], NULL, 0);
853*d5c9a868SElliott Hughes while ((arg = getopt(argc, argv, "ds:r:b:x:h")) != EOF)
854*d5c9a868SElliott Hughes {
855*d5c9a868SElliott Hughes switch (arg)
856*d5c9a868SElliott Hughes {
857*d5c9a868SElliott Hughes case 'd':
858*d5c9a868SElliott Hughes run_as_server = 1;
859*d5c9a868SElliott Hughes break;
860*d5c9a868SElliott Hughes case 's':
861*d5c9a868SElliott Hughes run_as_server = 1;
862*d5c9a868SElliott Hughes bind_port = getportnum(optarg);
863*d5c9a868SElliott Hughes break;
864*d5c9a868SElliott Hughes
865*d5c9a868SElliott Hughes case 'r':
866*d5c9a868SElliott Hughes free(username); username = strdup(optarg);
867*d5c9a868SElliott Hughes run_uid = getuserid(optarg);
868*d5c9a868SElliott Hughes run_gid = getgroupid(run_uid);
869*d5c9a868SElliott Hughes break;
870*d5c9a868SElliott Hughes
871*d5c9a868SElliott Hughes case 'b':
872*d5c9a868SElliott Hughes run_as_server = 1;
873*d5c9a868SElliott Hughes bind_ip = getipaddress(optarg);
874*d5c9a868SElliott Hughes break;
875*d5c9a868SElliott Hughes case 'x':
876*d5c9a868SElliott Hughes dispName = strdup(optarg);
877*d5c9a868SElliott Hughes break;
878*d5c9a868SElliott Hughes
879*d5c9a868SElliott Hughes case 'h':
880*d5c9a868SElliott Hughes usage(argv[0], NULL, 0);
881*d5c9a868SElliott Hughes case '?':
882*d5c9a868SElliott Hughes usage(argv[0], NULL, 1);
883*d5c9a868SElliott Hughes }
884*d5c9a868SElliott Hughes }
885*d5c9a868SElliott Hughes
886*d5c9a868SElliott Hughes if(optind < argc) {
887*d5c9a868SElliott Hughes device_name = (const char * const *) argv + optind;
888*d5c9a868SElliott Hughes n_dev = (unsigned int) (argc - optind);
889*d5c9a868SElliott Hughes } else {
890*d5c9a868SElliott Hughes device_name = &floppy0;
891*d5c9a868SElliott Hughes n_dev = 1;
892*d5c9a868SElliott Hughes }
893*d5c9a868SElliott Hughes
894*d5c9a868SElliott Hughes if(dispName == NULL)
895*d5c9a868SElliott Hughes dispName = getenv("DISPLAY");
896*d5c9a868SElliott Hughes if(dispName==NULL && bind_port != 0)
897*d5c9a868SElliott Hughes dispName=makeDisplayName((unsigned short)(bind_port - 5703));
898*d5c9a868SElliott Hughes if(dispName==NULL)
899*d5c9a868SElliott Hughes dispName=":0";
900*d5c9a868SElliott Hughes
901*d5c9a868SElliott Hughes if(bind_port == 0) {
902*d5c9a868SElliott Hughes char *p = strchr(dispName,':');
903*d5c9a868SElliott Hughes bind_port = FLOPPYD_DEFAULT_PORT;
904*d5c9a868SElliott Hughes if(p != NULL)
905*d5c9a868SElliott Hughes bind_port += atoi(p+1);
906*d5c9a868SElliott Hughes }
907*d5c9a868SElliott Hughes
908*d5c9a868SElliott Hughes if(!run_as_server) {
909*d5c9a868SElliott Hughes struct sockaddr_in addr;
910*d5c9a868SElliott Hughes unsigned int len = sizeof(addr);
911*d5c9a868SElliott Hughes
912*d5c9a868SElliott Hughes /* try to find out port that we are connected to */
913*d5c9a868SElliott Hughes if(getsockname(0, (struct sockaddr*) &addr, &len) >= 0 &&
914*d5c9a868SElliott Hughes len == sizeof(addr)) {
915*d5c9a868SElliott Hughes bind_port = ntohs(addr.sin_port);
916*d5c9a868SElliott Hughes }
917*d5c9a868SElliott Hughes }
918*d5c9a868SElliott Hughes
919*d5c9a868SElliott Hughes umask(0077);
920*d5c9a868SElliott Hughes
921*d5c9a868SElliott Hughes /*
922*d5c9a868SElliott Hughes * Test to make sure required args were provided and are valid.
923*d5c9a868SElliott Hughes */
924*d5c9a868SElliott Hughes if (run_as_server && (bind_ip == INADDR_NONE)) {
925*d5c9a868SElliott Hughes usage(argv[0], "The server ipaddr is invalid.", 1);
926*d5c9a868SElliott Hughes }
927*d5c9a868SElliott Hughes if (run_as_server && (bind_port == 0)) {
928*d5c9a868SElliott Hughes usage(argv[0], "No server port was specified (or it was invalid).", 1);
929*d5c9a868SElliott Hughes }
930*d5c9a868SElliott Hughes
931*d5c9a868SElliott Hughes
932*d5c9a868SElliott Hughes /*
933*d5c9a868SElliott Hughes * See if we should run as a server.
934*d5c9a868SElliott Hughes */
935*d5c9a868SElliott Hughes if (run_as_server) {
936*d5c9a868SElliott Hughes /*
937*d5c9a868SElliott Hughes * Start by binding to the port, the child inherits this socket.
938*d5c9a868SElliott Hughes */
939*d5c9a868SElliott Hughes sock = bind_to_port(bind_ip, bind_port);
940*d5c9a868SElliott Hughes
941*d5c9a868SElliott Hughes /*
942*d5c9a868SElliott Hughes * Start a server process. When DEBUG is defined, just run
943*d5c9a868SElliott Hughes * in the foreground.
944*d5c9a868SElliott Hughes */
945*d5c9a868SElliott Hughes #if DEBUG
946*d5c9a868SElliott Hughes switch (0)
947*d5c9a868SElliott Hughes #else
948*d5c9a868SElliott Hughes switch (fork())
949*d5c9a868SElliott Hughes #endif
950*d5c9a868SElliott Hughes {
951*d5c9a868SElliott Hughes case -1:
952*d5c9a868SElliott Hughes perror("fork()");
953*d5c9a868SElliott Hughes exit(1);
954*d5c9a868SElliott Hughes
955*d5c9a868SElliott Hughes case 0:
956*d5c9a868SElliott Hughes /*
957*d5c9a868SElliott Hughes * Ignore some signals.
958*d5c9a868SElliott Hughes */
959*d5c9a868SElliott Hughes signal(SIGHUP, SIG_IGN);
960*d5c9a868SElliott Hughes #if DEBUG
961*d5c9a868SElliott Hughes signal(SIGINT, SIG_IGN);
962*d5c9a868SElliott Hughes #endif
963*d5c9a868SElliott Hughes signal(SIGQUIT, SIG_IGN);
964*d5c9a868SElliott Hughes signal(SIGTSTP, SIG_IGN);
965*d5c9a868SElliott Hughes signal(SIGCONT, SIG_IGN);
966*d5c9a868SElliott Hughes signal(SIGPIPE, alarm_signal);
967*d5c9a868SElliott Hughes /*signal(SIGALRM, alarm_signal);*/
968*d5c9a868SElliott Hughes
969*d5c9a868SElliott Hughes /*
970*d5c9a868SElliott Hughes * Drop back to an untrusted user.
971*d5c9a868SElliott Hughes */
972*d5c9a868SElliott Hughes setgid(run_gid);
973*d5c9a868SElliott Hughes initgroups(username, run_gid);
974*d5c9a868SElliott Hughes setuid(run_uid);
975*d5c9a868SElliott Hughes
976*d5c9a868SElliott Hughes /*
977*d5c9a868SElliott Hughes * Start a new session and group.
978*d5c9a868SElliott Hughes */
979*d5c9a868SElliott Hughes setsid();
980*d5c9a868SElliott Hughes #ifdef HAVE_SETPGRP
981*d5c9a868SElliott Hughes #ifdef SETPGRP_VOID
982*d5c9a868SElliott Hughes setpgrp();
983*d5c9a868SElliott Hughes #else
984*d5c9a868SElliott Hughes setpgrp(0,0);
985*d5c9a868SElliott Hughes #endif
986*d5c9a868SElliott Hughes #endif
987*d5c9a868SElliott Hughes #if DEBUG
988*d5c9a868SElliott Hughes close(2);
989*d5c9a868SElliott Hughes open("/dev/null", O_WRONLY);
990*d5c9a868SElliott Hughes #endif
991*d5c9a868SElliott Hughes /*
992*d5c9a868SElliott Hughes * Handle the server main loop.
993*d5c9a868SElliott Hughes */
994*d5c9a868SElliott Hughes server_main_loop(sock, device_name,
995*d5c9a868SElliott Hughes n_dev);
996*d5c9a868SElliott Hughes }
997*d5c9a868SElliott Hughes
998*d5c9a868SElliott Hughes /*
999*d5c9a868SElliott Hughes * Parent exits at this stage.
1000*d5c9a868SElliott Hughes */
1001*d5c9a868SElliott Hughes exit(0);
1002*d5c9a868SElliott Hughes }
1003*d5c9a868SElliott Hughes
1004*d5c9a868SElliott Hughes signal(SIGHUP, alarm_signal);
1005*d5c9a868SElliott Hughes #if DEBUG == 0
1006*d5c9a868SElliott Hughes signal(SIGINT, alarm_signal);
1007*d5c9a868SElliott Hughes #endif
1008*d5c9a868SElliott Hughes signal(SIGQUIT, alarm_signal);
1009*d5c9a868SElliott Hughes signal(SIGTERM, alarm_signal);
1010*d5c9a868SElliott Hughes signal(SIGTSTP, SIG_IGN);
1011*d5c9a868SElliott Hughes signal(SIGCONT, SIG_IGN);
1012*d5c9a868SElliott Hughes signal(SIGPIPE, alarm_signal);
1013*d5c9a868SElliott Hughes /*signal(SIGALRM, alarm_signal);*/
1014*d5c9a868SElliott Hughes
1015*d5c9a868SElliott Hughes /* Starting from inetd */
1016*d5c9a868SElliott Hughes
1017*d5c9a868SElliott Hughes serve_client(sockfd, device_name, n_dev, 1);
1018*d5c9a868SElliott Hughes return 0;
1019*d5c9a868SElliott Hughes }
1020*d5c9a868SElliott Hughes
send_reply(int rval,io_buffer sock,Dword len)1021*d5c9a868SElliott Hughes static void send_reply(int rval, io_buffer sock, Dword len) {
1022*d5c9a868SElliott Hughes Packet reply = newPacket();
1023*d5c9a868SElliott Hughes
1024*d5c9a868SElliott Hughes make_new(reply, 8);
1025*d5c9a868SElliott Hughes put_dword(reply, 0, len);
1026*d5c9a868SElliott Hughes if (rval == -1) {
1027*d5c9a868SElliott Hughes put_dword(reply, 4, 0);
1028*d5c9a868SElliott Hughes } else {
1029*d5c9a868SElliott Hughes put_dword(reply, 4, (Dword) errno);
1030*d5c9a868SElliott Hughes }
1031*d5c9a868SElliott Hughes send_packet(reply, sock);
1032*d5c9a868SElliott Hughes destroyPacket(reply);
1033*d5c9a868SElliott Hughes }
1034*d5c9a868SElliott Hughes
send_reply64(int rval,io_buffer sock,mt_off_t len)1035*d5c9a868SElliott Hughes static void send_reply64(int rval, io_buffer sock, mt_off_t len) {
1036*d5c9a868SElliott Hughes Packet reply = newPacket();
1037*d5c9a868SElliott Hughes
1038*d5c9a868SElliott Hughes make_new(reply, 12);
1039*d5c9a868SElliott Hughes put_qword(reply, 0, (Qword) len);
1040*d5c9a868SElliott Hughes if (rval == -1) {
1041*d5c9a868SElliott Hughes put_dword(reply, 8, 0);
1042*d5c9a868SElliott Hughes } else {
1043*d5c9a868SElliott Hughes put_dword(reply, 8, (Dword) errno);
1044*d5c9a868SElliott Hughes }
1045*d5c9a868SElliott Hughes send_packet(reply, sock);
1046*d5c9a868SElliott Hughes destroyPacket(reply);
1047*d5c9a868SElliott Hughes }
1048*d5c9a868SElliott Hughes
1049*d5c9a868SElliott Hughes static void cleanup(int x UNUSEDP) NORETURN;
cleanup(int x UNUSEDP)1050*d5c9a868SElliott Hughes static void cleanup(int x UNUSEDP) {
1051*d5c9a868SElliott Hughes unlink(XauFileName());
1052*d5c9a868SElliott Hughes exit(-1);
1053*d5c9a868SElliott Hughes }
1054*d5c9a868SElliott Hughes
1055*d5c9a868SElliott Hughes #include "lockdev.h"
1056*d5c9a868SElliott Hughes
serve_client(int sockhandle,const char * const * device_name,unsigned int n_dev,int close_stderr)1057*d5c9a868SElliott Hughes void serve_client(int sockhandle, const char *const*device_name,
1058*d5c9a868SElliott Hughes unsigned int n_dev, int close_stderr) {
1059*d5c9a868SElliott Hughes Packet opcode;
1060*d5c9a868SElliott Hughes Packet parm;
1061*d5c9a868SElliott Hughes
1062*d5c9a868SElliott Hughes int readOnly;
1063*d5c9a868SElliott Hughes int devFd;
1064*d5c9a868SElliott Hughes io_buffer sock;
1065*d5c9a868SElliott Hughes int stopLoop;
1066*d5c9a868SElliott Hughes unsigned int version;
1067*d5c9a868SElliott Hughes int needSendReply=0;
1068*d5c9a868SElliott Hughes int rval=0;
1069*d5c9a868SElliott Hughes
1070*d5c9a868SElliott Hughes /*
1071*d5c9a868SElliott Hughes * Set the keepalive socket option to on.
1072*d5c9a868SElliott Hughes */
1073*d5c9a868SElliott Hughes {
1074*d5c9a868SElliott Hughes int on = 1;
1075*d5c9a868SElliott Hughes if(setsockopt(sockhandle, SOL_SOCKET,
1076*d5c9a868SElliott Hughes SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) {
1077*d5c9a868SElliott Hughes perror("setsockopt");
1078*d5c9a868SElliott Hughes exit(1);
1079*d5c9a868SElliott Hughes }
1080*d5c9a868SElliott Hughes
1081*d5c9a868SElliott Hughes }
1082*d5c9a868SElliott Hughes
1083*d5c9a868SElliott Hughes
1084*d5c9a868SElliott Hughes #if DEBUG == 0
1085*d5c9a868SElliott Hughes if(close_stderr) {
1086*d5c9a868SElliott Hughes close(2);
1087*d5c9a868SElliott Hughes open("/dev/null", O_WRONLY);
1088*d5c9a868SElliott Hughes }
1089*d5c9a868SElliott Hughes #endif
1090*d5c9a868SElliott Hughes
1091*d5c9a868SElliott Hughes sock = new_io_buffer(sockhandle);
1092*d5c9a868SElliott Hughes
1093*d5c9a868SElliott Hughes /*
1094*d5c9a868SElliott Hughes * Allow 60 seconds for any activity.
1095*d5c9a868SElliott Hughes */
1096*d5c9a868SElliott Hughes alarm(60);
1097*d5c9a868SElliott Hughes
1098*d5c9a868SElliott Hughes version = 0;
1099*d5c9a868SElliott Hughes if (!do_auth(sock, &version)) {
1100*d5c9a868SElliott Hughes free_io_buffer(sock);
1101*d5c9a868SElliott Hughes return;
1102*d5c9a868SElliott Hughes }
1103*d5c9a868SElliott Hughes alarm(0);
1104*d5c9a868SElliott Hughes
1105*d5c9a868SElliott Hughes
1106*d5c9a868SElliott Hughes signal(SIGTERM, cleanup);
1107*d5c9a868SElliott Hughes signal(SIGALRM, cleanup);
1108*d5c9a868SElliott Hughes
1109*d5c9a868SElliott Hughes
1110*d5c9a868SElliott Hughes
1111*d5c9a868SElliott Hughes sockethandle_now = sockhandle;
1112*d5c9a868SElliott Hughes
1113*d5c9a868SElliott Hughes
1114*d5c9a868SElliott Hughes opcode = newPacket();
1115*d5c9a868SElliott Hughes parm = newPacket();
1116*d5c9a868SElliott Hughes
1117*d5c9a868SElliott Hughes devFd = -1;
1118*d5c9a868SElliott Hughes readOnly = 1;
1119*d5c9a868SElliott Hughes
1120*d5c9a868SElliott Hughes stopLoop = 0;
1121*d5c9a868SElliott Hughes if(version == FLOPPYD_PROTOCOL_VERSION_OLD) {
1122*d5c9a868SElliott Hughes /* old protocol */
1123*d5c9a868SElliott Hughes readOnly = 0;
1124*d5c9a868SElliott Hughes devFd = open(device_name[0], O_RDWR|O_LARGEFILE);
1125*d5c9a868SElliott Hughes
1126*d5c9a868SElliott Hughes if (devFd < 0) {
1127*d5c9a868SElliott Hughes readOnly = 1;
1128*d5c9a868SElliott Hughes devFd = open(device_name[0],
1129*d5c9a868SElliott Hughes O_RDONLY|O_LARGEFILE);
1130*d5c9a868SElliott Hughes }
1131*d5c9a868SElliott Hughes if(devFd < 0) {
1132*d5c9a868SElliott Hughes send_reply(0, sock, devFd >= 0 ? 0 : DWORD_ERR);
1133*d5c9a868SElliott Hughes stopLoop = 1;
1134*d5c9a868SElliott Hughes }
1135*d5c9a868SElliott Hughes lock_dev(devFd, !readOnly, NULL);
1136*d5c9a868SElliott Hughes }
1137*d5c9a868SElliott Hughes
1138*d5c9a868SElliott Hughes
1139*d5c9a868SElliott Hughes while(!stopLoop) {
1140*d5c9a868SElliott Hughes uint32_t dev_nr = 0;
1141*d5c9a868SElliott Hughes /*
1142*d5c9a868SElliott Hughes * Allow 60 seconds for any activity.
1143*d5c9a868SElliott Hughes */
1144*d5c9a868SElliott Hughes /*alarm(60);*/
1145*d5c9a868SElliott Hughes
1146*d5c9a868SElliott Hughes if (!recv_packet(opcode, sock, 1)) {
1147*d5c9a868SElliott Hughes break;
1148*d5c9a868SElliott Hughes }
1149*d5c9a868SElliott Hughes /* if(opcode->data[0] != OP_CLOSE)*/
1150*d5c9a868SElliott Hughes recv_packet(parm, sock, MAX_DATA_REQUEST);
1151*d5c9a868SElliott Hughes
1152*d5c9a868SElliott Hughes /* on its own, floppyd does several small writes,
1153*d5c9a868SElliott Hughes * running into the performance issue described in
1154*d5c9a868SElliott Hughes * https://eklitzke.org/the-caveats-of-tcp-nodelay
1155*d5c9a868SElliott Hughes * Cork fixes this by stalling the small writes until
1156*d5c9a868SElliott Hughes * floppyd has assembled its entire message, thus
1157*d5c9a868SElliott Hughes * preventing the bad interaction between Nagle's
1158*d5c9a868SElliott Hughes * algorithm and Linux' delayed ACKs. Another fix
1159*d5c9a868SElliott Hughes * would be to not send the small batches immediately,
1160*d5c9a868SElliott Hughes * but instead keep them around and submit them to the
1161*d5c9a868SElliott Hughes * kernel in one go using writev. However, writev is
1162*d5c9a868SElliott Hughes * not available everywhere
1163*d5c9a868SElliott Hughes */
1164*d5c9a868SElliott Hughes cork(sock->handle, 1);
1165*d5c9a868SElliott Hughes
1166*d5c9a868SElliott Hughes switch(opcode->data[0]) {
1167*d5c9a868SElliott Hughes case OP_OPRO:
1168*d5c9a868SElliott Hughes if(get_length(parm) >= 4)
1169*d5c9a868SElliott Hughes dev_nr = get_dword(parm,0);
1170*d5c9a868SElliott Hughes else
1171*d5c9a868SElliott Hughes dev_nr = 0;
1172*d5c9a868SElliott Hughes if(dev_nr >= n_dev) {
1173*d5c9a868SElliott Hughes send_reply(0, sock, DWORD_ERR);
1174*d5c9a868SElliott Hughes break;
1175*d5c9a868SElliott Hughes }
1176*d5c9a868SElliott Hughes
1177*d5c9a868SElliott Hughes devFd = open(device_name[dev_nr],
1178*d5c9a868SElliott Hughes O_RDONLY | O_LARGEFILE);
1179*d5c9a868SElliott Hughes #if DEBUG
1180*d5c9a868SElliott Hughes fprintf(stderr, "Device opened\n");
1181*d5c9a868SElliott Hughes #endif
1182*d5c9a868SElliott Hughes if(devFd >= 0 && lock_dev(devFd, 0, NULL)) {
1183*d5c9a868SElliott Hughes send_reply(0, sock, DWORD_ERR);
1184*d5c9a868SElliott Hughes break;
1185*d5c9a868SElliott Hughes }
1186*d5c9a868SElliott Hughes send_reply(0, sock,
1187*d5c9a868SElliott Hughes devFd >= 0 ? 0 : DWORD_ERR);
1188*d5c9a868SElliott Hughes readOnly = 1;
1189*d5c9a868SElliott Hughes break;
1190*d5c9a868SElliott Hughes case OP_OPRW:
1191*d5c9a868SElliott Hughes if(get_length(parm) >= 4)
1192*d5c9a868SElliott Hughes dev_nr = get_dword(parm,0);
1193*d5c9a868SElliott Hughes else
1194*d5c9a868SElliott Hughes dev_nr = 0;
1195*d5c9a868SElliott Hughes if(dev_nr >= n_dev) {
1196*d5c9a868SElliott Hughes send_reply(0, sock, DWORD_ERR);
1197*d5c9a868SElliott Hughes break;
1198*d5c9a868SElliott Hughes }
1199*d5c9a868SElliott Hughes devFd = open(device_name[dev_nr], O_RDWR);
1200*d5c9a868SElliott Hughes if(devFd >= 0 && lock_dev(devFd, 1, NULL)) {
1201*d5c9a868SElliott Hughes send_reply(0, sock, DWORD_ERR);
1202*d5c9a868SElliott Hughes break;
1203*d5c9a868SElliott Hughes }
1204*d5c9a868SElliott Hughes send_reply(0, sock,
1205*d5c9a868SElliott Hughes devFd >= 0 ? 0 : DWORD_ERR);
1206*d5c9a868SElliott Hughes readOnly = 0;
1207*d5c9a868SElliott Hughes break;
1208*d5c9a868SElliott Hughes case OP_READ:
1209*d5c9a868SElliott Hughes #if DEBUG
1210*d5c9a868SElliott Hughes fprintf(stderr, "READ:\n");
1211*d5c9a868SElliott Hughes #endif
1212*d5c9a868SElliott Hughes if(read_packet(parm, devFd,
1213*d5c9a868SElliott Hughes get_dword(parm, 0)) < 0)
1214*d5c9a868SElliott Hughes send_reply(devFd, sock, DWORD_ERR);
1215*d5c9a868SElliott Hughes else {
1216*d5c9a868SElliott Hughes send_reply(devFd, sock,
1217*d5c9a868SElliott Hughes get_length(parm));
1218*d5c9a868SElliott Hughes send_packet(parm, sock);
1219*d5c9a868SElliott Hughes }
1220*d5c9a868SElliott Hughes break;
1221*d5c9a868SElliott Hughes case OP_WRITE:
1222*d5c9a868SElliott Hughes #if DEBUG
1223*d5c9a868SElliott Hughes fprintf(stderr, "WRITE:\n");
1224*d5c9a868SElliott Hughes #endif
1225*d5c9a868SElliott Hughes if(readOnly) {
1226*d5c9a868SElliott Hughes errno = -EROFS;
1227*d5c9a868SElliott Hughes rval = -1;
1228*d5c9a868SElliott Hughes } else {
1229*d5c9a868SElliott Hughes rval = write_packet(parm, devFd);
1230*d5c9a868SElliott Hughes }
1231*d5c9a868SElliott Hughes send_reply(devFd, sock, (Dword) rval);
1232*d5c9a868SElliott Hughes break;
1233*d5c9a868SElliott Hughes case OP_SEEK:
1234*d5c9a868SElliott Hughes #if DEBUG
1235*d5c9a868SElliott Hughes fprintf(stderr, "SEEK:\n");
1236*d5c9a868SElliott Hughes #endif
1237*d5c9a868SElliott Hughes
1238*d5c9a868SElliott Hughes lseek(devFd,
1239*d5c9a868SElliott Hughes (off_t) get_dword(parm, 0),
1240*d5c9a868SElliott Hughes (int) get_dword(parm, 4));
1241*d5c9a868SElliott Hughes send_reply(devFd,
1242*d5c9a868SElliott Hughes sock,
1243*d5c9a868SElliott Hughes (Dword) lseek(devFd, 0, SEEK_CUR));
1244*d5c9a868SElliott Hughes break;
1245*d5c9a868SElliott Hughes case OP_SEEK64:
1246*d5c9a868SElliott Hughes if(sizeof(mt_off_t) < 8) {
1247*d5c9a868SElliott Hughes #if DEBUG
1248*d5c9a868SElliott Hughes fprintf(stderr, "64 bit requested where not available!\n");
1249*d5c9a868SElliott Hughes #endif
1250*d5c9a868SElliott Hughes errno = EINVAL;
1251*d5c9a868SElliott Hughes send_reply(devFd, sock, DWORD_ERR);
1252*d5c9a868SElliott Hughes break;
1253*d5c9a868SElliott Hughes }
1254*d5c9a868SElliott Hughes #if DEBUG
1255*d5c9a868SElliott Hughes fprintf(stderr, "SEEK64:\n");
1256*d5c9a868SElliott Hughes #endif
1257*d5c9a868SElliott Hughes mt_lseek(devFd,
1258*d5c9a868SElliott Hughes (mt_off_t) get_qword(parm,0),
1259*d5c9a868SElliott Hughes (int) get_dword(parm,8));
1260*d5c9a868SElliott Hughes send_reply64(devFd,
1261*d5c9a868SElliott Hughes sock,
1262*d5c9a868SElliott Hughes mt_lseek(devFd, 0, SEEK_CUR));
1263*d5c9a868SElliott Hughes break;
1264*d5c9a868SElliott Hughes case OP_FLUSH:
1265*d5c9a868SElliott Hughes #if DEBUG
1266*d5c9a868SElliott Hughes fprintf(stderr, "FLUSH:\n");
1267*d5c9a868SElliott Hughes #endif
1268*d5c9a868SElliott Hughes fsync(devFd);
1269*d5c9a868SElliott Hughes send_reply(devFd, sock, 0);
1270*d5c9a868SElliott Hughes break;
1271*d5c9a868SElliott Hughes case OP_CLOSE:
1272*d5c9a868SElliott Hughes #if DEBUG
1273*d5c9a868SElliott Hughes fprintf(stderr, "CLOSE:\n");
1274*d5c9a868SElliott Hughes #endif
1275*d5c9a868SElliott Hughes
1276*d5c9a868SElliott Hughes close(devFd);
1277*d5c9a868SElliott Hughes needSendReply = 1;
1278*d5c9a868SElliott Hughes rval = devFd;
1279*d5c9a868SElliott Hughes devFd = -1;
1280*d5c9a868SElliott Hughes stopLoop = 1;
1281*d5c9a868SElliott Hughes break;
1282*d5c9a868SElliott Hughes case OP_IOCTL:
1283*d5c9a868SElliott Hughes /* Unimplemented for now... */
1284*d5c9a868SElliott Hughes break;
1285*d5c9a868SElliott Hughes default:
1286*d5c9a868SElliott Hughes #if DEBUG
1287*d5c9a868SElliott Hughes fprintf(stderr, "Invalid Opcode!\n");
1288*d5c9a868SElliott Hughes #endif
1289*d5c9a868SElliott Hughes errno = EINVAL;
1290*d5c9a868SElliott Hughes send_reply(devFd, sock, DWORD_ERR);
1291*d5c9a868SElliott Hughes break;
1292*d5c9a868SElliott Hughes }
1293*d5c9a868SElliott Hughes cork(sock->handle, 0);
1294*d5c9a868SElliott Hughes kill_packet(parm);
1295*d5c9a868SElliott Hughes alarm(0);
1296*d5c9a868SElliott Hughes }
1297*d5c9a868SElliott Hughes
1298*d5c9a868SElliott Hughes
1299*d5c9a868SElliott Hughes
1300*d5c9a868SElliott Hughes #if DEBUG
1301*d5c9a868SElliott Hughes fprintf(stderr, "Closing down...\n");
1302*d5c9a868SElliott Hughes #endif
1303*d5c9a868SElliott Hughes
1304*d5c9a868SElliott Hughes if (devFd >= 0) {
1305*d5c9a868SElliott Hughes close(devFd);
1306*d5c9a868SElliott Hughes devFd = -1;
1307*d5c9a868SElliott Hughes }
1308*d5c9a868SElliott Hughes
1309*d5c9a868SElliott Hughes free_io_buffer(sock);
1310*d5c9a868SElliott Hughes
1311*d5c9a868SElliott Hughes /* remove "Lock"-File */
1312*d5c9a868SElliott Hughes unlink(XauFileName());
1313*d5c9a868SElliott Hughes
1314*d5c9a868SElliott Hughes if(needSendReply)
1315*d5c9a868SElliott Hughes send_reply(rval, sock, 0);
1316*d5c9a868SElliott Hughes destroyPacket(opcode);
1317*d5c9a868SElliott Hughes destroyPacket(parm);
1318*d5c9a868SElliott Hughes }
1319*d5c9a868SElliott Hughes
1320*d5c9a868SElliott Hughes #else
1321*d5c9a868SElliott Hughes #include <stdio.h>
1322*d5c9a868SElliott Hughes
main(int argc,char ** argv)1323*d5c9a868SElliott Hughes int main(int argc, char **argv)
1324*d5c9a868SElliott Hughes {
1325*d5c9a868SElliott Hughes puts("Floppyd support not included!");
1326*d5c9a868SElliott Hughes return -1;
1327*d5c9a868SElliott Hughes }
1328*d5c9a868SElliott Hughes
1329*d5c9a868SElliott Hughes #endif
1330