1/*
2 * Copyright 1990 Network Computing Devices;
3 * Portions Copyright 1987 by Digital Equipment Corporation
4 *
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without fee,
7 * provided that the above copyright notice appear in all copies and
8 * that both that copyright notice and this permission notice appear
9 * in supporting documentation, and that the names of Network Computing
10 * Devices or Digital not be used in advertising or publicity pertaining
11 * to distribution of the software without specific, written prior
12 * permission. Network Computing Devices or Digital make no representations
13 * about the suitability of this software for any purpose.  It is provided
14 * "as is" without express or implied warranty.
15 *
16 * NETWORK COMPUTING DEVICES AND  DIGITAL DISCLAIM ALL WARRANTIES WITH
17 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES
19 * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES
20 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
21 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23 * SOFTWARE.
24 */
25
26/*
27
28Copyright 1987, 1994, 1998  The Open Group
29
30Permission to use, copy, modify, distribute, and sell this software and its
31documentation for any purpose is hereby granted without fee, provided that
32the above copyright notice appear in all copies and that both that
33copyright notice and this permission notice appear in supporting
34documentation.
35
36The above copyright notice and this permission notice shall be included in
37all copies or substantial portions of the Software.
38
39THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
42OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
43AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
44CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
45
46Except as contained in this notice, the name of The Open Group shall not be
47used in advertising or otherwise to promote the sale, use or other dealings
48in this Software without prior written authorization from The Open Group.
49
50*/
51
52/*
53 *	FSlibInt.c - Internal support routines for the C subroutine
54 *	interface library (FSlib).
55 */
56#ifdef HAVE_CONFIG_H
57#include <config.h>
58#endif
59#include <stdio.h>
60#include "FSlibint.h"
61#include <X11/Xtrans/Xtransint.h>
62#include <X11/Xos.h>
63
64static void _EatData32 ( FSServer *svr, unsigned long n );
65static const char * _SysErrorMsg ( int n );
66
67/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
68 * systems are broken and return EWOULDBLOCK when they should return EAGAIN
69 *
70 * Solaris defines EWOULDBLOCK to be EAGAIN, so don't need to check twice
71 * for it.
72 */
73#ifdef WIN32
74#define ETEST() (WSAGetLastError() == WSAEWOULDBLOCK)
75#else
76#if defined(EAGAIN) && defined(EWOULDBLOCK) && (EAGAIN != EWOULDBLOCK)
77#define ETEST() (errno == EAGAIN || errno == EWOULDBLOCK)
78#else
79#ifdef EAGAIN
80#define ETEST() (errno == EAGAIN)
81#else
82#define ETEST() (errno == EWOULDBLOCK)
83#endif
84#endif
85#endif
86#ifdef WIN32
87#define ECHECK(err) (WSAGetLastError() == err)
88#define ESET(val) WSASetLastError(val)
89#else
90#define ECHECK(err) (errno == err)
91#define ESET(val) errno = val
92#endif
93
94/*
95 * The following routines are internal routines used by FSlib for protocol
96 * packet transmission and reception.
97 *
98 * FSIOError(FSServer *) will be called if any sort of system call error occurs.
99 * This is assumed to be a fatal condition, i.e., FSIOError should not return.
100 *
101 * FSError(FSServer *, FSErrorEvent *) will be called whenever an FS_Error event is
102 * received.  This is not assumed to be a fatal condition, i.e., it is
103 * acceptable for this procedure to return.  However, FSError should NOT
104 * perform any operations (directly or indirectly) on the DISPLAY.
105 *
106 * Routines declared with a return type of 'Status' return 0 on failure,
107 * and non 0 on success.  Routines with no declared return type don't
108 * return anything.  Whenever possible routines that create objects return
109 * the object they have created.
110 */
111
112_FSQEvent  *_FSqfree = NULL;	/* NULL _FSQEvent. */
113
114static int  padlength[4] = {0, 3, 2, 1};
115
116 /*
117  * lookup table for adding padding bytes to data that is read from or written
118  * to the FS socket.
119  */
120
121static fsReq _dummy_request = {
122    0, 0, 0
123};
124
125/*
126 * _FSFlush - Flush the FS request buffer.  If the buffer is empty, no
127 * action is taken.  This routine correctly handles incremental writes.
128 * This routine may have to be reworked if int < long.
129 */
130void
131_FSFlush(register FSServer *svr)
132{
133    register long size,
134                todo;
135    register int write_stat;
136    register char *bufindex;
137
138    size = todo = svr->bufptr - svr->buffer;
139    bufindex = svr->bufptr = svr->buffer;
140    /*
141     * While write has not written the entire buffer, keep looping until the
142     * entire buffer is written.  bufindex will be incremented and size
143     * decremented as buffer is written out.
144     */
145    while (size) {
146	ESET(0);
147	write_stat = _FSTransWrite(svr->trans_conn, bufindex, (int) todo);
148	if (write_stat >= 0) {
149	    size -= write_stat;
150	    todo = size;
151	    bufindex += write_stat;
152	} else if (ETEST()) {
153	    _FSWaitForWritable(svr);
154#ifdef EMSGSIZE
155	} else if (ECHECK(EMSGSIZE)) {
156	    if (todo > 1)
157		todo >>= 1;
158	    else
159		_FSWaitForWritable(svr);
160#endif
161	} else {
162	    /* Write failed! */
163	    /* errno set by write system call. */
164	    (*_FSIOErrorFunction) (svr);
165	}
166    }
167    svr->last_req = (char *) &_dummy_request;
168}
169
170/* _FSReadEvents - Flush the output queue,
171 * then read as many events as possible (but at least 1) and enqueue them
172 */
173void
174_FSReadEvents(register FSServer *svr)
175{
176    char        buf[BUFSIZE];
177    BytesReadable_t pend_not_register;	/* because can't "&" a register
178					 * variable */
179    register BytesReadable_t pend;
180    register fsEvent *ev;
181    Bool        not_yet_flushed = True;
182
183    do {
184	/* find out how much data can be read */
185	if (_FSTransBytesReadable(svr->trans_conn, &pend_not_register) < 0)
186	    (*_FSIOErrorFunction) (svr);
187	pend = pend_not_register;
188
189	/*
190	 * must read at least one fsEvent; if none is pending, then we'll just
191	 * flush and block waiting for it
192	 */
193	if (pend < SIZEOF(fsEvent)) {
194	    pend = SIZEOF(fsEvent);
195	    /* don't flush until we block the first time */
196	    if (not_yet_flushed) {
197		int         qlen = svr->qlen;
198
199		_FSFlush(svr);
200		if (qlen != svr->qlen)
201		    return;
202		not_yet_flushed = False;
203	    }
204	}
205	/* but we won't read more than the max buffer size */
206	if (pend > BUFSIZE)
207	    pend = BUFSIZE;
208
209	/* round down to an integral number of XReps */
210	pend = (pend / SIZEOF(fsEvent)) * SIZEOF(fsEvent);
211
212	_FSRead(svr, buf, (long)pend);
213
214	/* no space between comma and type or else macro will die */
215	STARTITERATE(ev, fsEvent, buf, (pend > 0),
216		     pend -= SIZEOF(fsEvent)) {
217	    if (ev->type == FS_Error)
218		_FSError(svr, (fsError *) ev);
219	    else		/* it's an event packet; enqueue it */
220		_FSEnq(svr, ev);
221	}
222	ENDITERATE
223    } while (svr->head == NULL);
224}
225
226/*
227 * _FSRead - Read bytes from the socket taking into account incomplete
228 * reads.  This routine may have to be reworked if int < long.
229 */
230void
231_FSRead(
232    register FSServer	*svr,
233    register char	*data,
234    register long	 size)
235{
236    register long bytes_read;
237
238    if (size == 0)
239	return;
240    ESET(0);
241    /*
242     * For SVR4 with a unix-domain connection, ETEST() after selecting
243     * readable means the server has died.  To do this here, we look for
244     * two consecutive reads returning ETEST().
245     */
246    while ((bytes_read = _FSTransRead(svr->trans_conn, data, (int) size))
247	    != size) {
248
249	if (bytes_read > 0) {
250	    size -= bytes_read;
251	    data += bytes_read;
252	}
253	else if (ETEST()) {
254	    _FSWaitForReadable(svr);
255	    ESET(0);
256	}
257	else if (bytes_read == 0) {
258	    /* Read failed because of end of file! */
259	    ESET(EPIPE);
260	    (*_FSIOErrorFunction) (svr);
261	} else {		/* bytes_read is less than 0; presumably -1 */
262	    /* If it's a system call interrupt, it's not an error. */
263	    if (!ECHECK(EINTR))
264		(*_FSIOErrorFunction) (svr);
265	}
266    }
267}
268
269
270/*
271 * _FSReadPad - Read bytes from the socket taking into account incomplete
272 * reads.  If the number of bytes is not 0 mod 32, read additional pad
273 * bytes. This routine may have to be reworked if int < long.
274 */
275void
276_FSReadPad(
277    register FSServer	*svr,
278    register char	*data,
279    register long	 size)
280{
281    register long bytes_read;
282    struct iovec iov[2];
283    char        pad[3];
284
285    if (size == 0)
286	return;
287    iov[0].iov_len = size;
288    iov[0].iov_base = data;
289    /*
290     * The following hack is used to provide 32 bit long-word aligned padding.
291     * The [1] vector is of length 0, 1, 2, or 3, whatever is needed.
292     */
293
294    iov[1].iov_len = padlength[size & 3];
295    iov[1].iov_base = pad;
296    size += iov[1].iov_len;
297
298    ESET(0);
299    while ((bytes_read = readv(svr->trans_conn->fd, iov, 2)) != size) {
300
301	if (bytes_read > 0) {
302	    size -= bytes_read;
303	    if (iov[0].iov_len < bytes_read) {
304		int pad_bytes_read = bytes_read - iov[0].iov_len;
305		iov[1].iov_len -=  pad_bytes_read;
306		iov[1].iov_base =
307		    (char *)iov[1].iov_base + pad_bytes_read;
308		iov[0].iov_len = 0;
309	    } else {
310		iov[0].iov_len -= bytes_read;
311		iov[0].iov_base = (char *)iov[0].iov_base + bytes_read;
312	    }
313	}
314	else if (ETEST()) {
315	    _FSWaitForReadable(svr);
316	    ESET(0);
317	}
318	else if (bytes_read == 0) {
319	    /* Read failed because of end of file! */
320	    ESET(EPIPE);
321	    (*_FSIOErrorFunction) (svr);
322	} else {		/* bytes_read is less than 0; presumably -1 */
323	    /* If it's a system call interrupt, it's not an error. */
324	    if (!ECHECK(EINTR))
325		(*_FSIOErrorFunction) (svr);
326	}
327    }
328}
329
330/*
331 * _FSSend - Flush the buffer and send the client data. 32 bit word aligned
332 * transmission is used, if size is not 0 mod 4, extra bytes are transmitted.
333 * This routine may have to be reworked if int < long;
334 */
335void
336_FSSend(
337    register FSServer	*svr,
338    const char		*data,
339    register long	 size)
340{
341    struct iovec iov[3];
342    static char pad[3] = {0, 0, 0};
343
344    long        skip = 0;
345    long        svrbufsize = (svr->bufptr - svr->buffer);
346    long        padsize = padlength[size & 3];
347    long        total = svrbufsize + size + padsize;
348    long        todo = total;
349
350    /*
351     * There are 3 pieces that may need to be written out:
352     *
353     * o  whatever is in the display buffer o  the data passed in by the user o
354     * any padding needed to 32bit align the whole mess
355     *
356     * This loop looks at all 3 pieces each time through.  It uses skip to figure
357     * out whether or not a given piece is needed.
358     */
359    while (total) {
360	long        before = skip;	/* amount of whole thing written */
361	long        remain = todo;	/* amount to try this time, <= total */
362	int         i = 0;
363	long        len;
364
365	/*
366	 * You could be very general here and have "in" and "out" iovecs and
367	 * write a loop without using a macro, but what the heck.  This
368	 * translates to:
369	 *
370	 * how much of this piece is new? if more new then we are trying this
371	 * time, clamp if nothing new then bump down amount already written,
372	 * for next piece else put new stuff in iovec, will need all of next
373	 * piece
374	 *
375	 * Note that todo had better be at least 1 or else we'll end up writing 0
376	 * iovecs.
377	 */
378#define InsertIOV(pointer, length) \
379	    len = (length) - before; \
380	    if (len > remain) \
381		len = remain; \
382	    if (len <= 0) { \
383		before = (-len); \
384	    } else { \
385		iov[i].iov_len = len; \
386		iov[i].iov_base = (pointer) + before; \
387		i++; \
388		remain -= len; \
389		before = 0; \
390	    }
391
392	InsertIOV(svr->buffer, svrbufsize)
393	InsertIOV((char *)data, size)
394	InsertIOV(pad, padsize)
395
396	ESET(0);
397	if ((len = _FSTransWritev(svr->trans_conn, iov, i)) >= 0) {
398	    skip += len;
399	    total -= len;
400	    todo = total;
401	} else if (ETEST()) {
402		_FSWaitForWritable(svr);
403#ifdef EMSGSIZE
404	} else if (ECHECK(EMSGSIZE)) {
405	    if (todo > 1)
406		todo >>= 1;
407	    else
408		_FSWaitForWritable(svr);
409#endif
410	} else {
411	    (*_FSIOErrorFunction) (svr);
412	}
413    }
414
415    svr->bufptr = svr->buffer;
416    svr->last_req = (char *) &_dummy_request;
417}
418
419#ifdef undef
420/*
421 * _FSAllocID - normal resource ID allocation routine.  A client
422 * can roll their own and instantiate it if they want, but must
423 * follow the rules.
424 */
425FSID
426_FSAllocID(register FSServer *svr)
427{
428    return (svr->resource_base + (svr->resource_id++ << svr->resource_shift));
429}
430
431#endif
432
433/*
434 * The hard part about this is that we only get 16 bits from a reply.  Well,
435 * then, we have three values that will march along, with the following
436 * invariant:
437 *	svr->last_request_read <= rep->sequenceNumber <= svr->request
438 * The right choice for rep->sequenceNumber is the largest that
439 * still meets these constraints.
440 */
441
442unsigned long
443_FSSetLastRequestRead(
444    register FSServer		*svr,
445    register fsGenericReply	*rep)
446{
447    register unsigned long newseq,
448                lastseq;
449
450    newseq = (svr->last_request_read & ~((unsigned long) 0xffff)) |
451	rep->sequenceNumber;
452    lastseq = svr->last_request_read;
453    while (newseq < lastseq) {
454	newseq += 0x10000;
455	if (newseq > svr->request) {
456	    (void) fprintf(stderr,
457	       "FSlib:  sequence lost (0x%lx > 0x%lx) in reply type 0x%x!\n",
458			   newseq, svr->request,
459			   (unsigned int) rep->type);
460	    newseq -= 0x10000;
461	    break;
462	}
463    }
464
465    svr->last_request_read = newseq;
466    return (newseq);
467}
468
469/*
470 * _FSReply - Wait for a reply packet and copy its contents into the
471 * specified rep.  Mean while we must handle error and event packets that
472 * we may encounter.
473 */
474Status
475_FSReply(
476    register FSServer	*svr,
477    register fsReply	*rep,
478    int			 extra,	 /* number of 32-bit words expected after the
479				  * reply */
480    Bool		 discard)/* should I discard data following "extra"
481				  * words? */
482{
483    /*
484     * Pull out the serial number now, so that (currently illegal) requests
485     * generated by an error handler don't confuse us.
486     */
487    unsigned long cur_request = svr->request;
488    long rem_length;
489
490    _FSFlush(svr);
491    while (1) {
492	_FSRead(svr, (char *) rep, (long) SIZEOF(fsReply));
493	switch ((int) rep->generic.type) {
494
495	case FS_Reply:
496	    /*
497	     * Reply received.  Fast update for synchronous replies, but deal
498	     * with multiple outstanding replies.
499	     */
500	    if (rep->generic.sequenceNumber == (cur_request & 0xffff))
501		svr->last_request_read = cur_request;
502	    else
503		(void) _FSSetLastRequestRead(svr, &rep->generic);
504	    rem_length = rep->generic.length - (SIZEOF(fsReply) >> 2);
505	    if (rem_length < 0) rem_length = 0;
506	    if (extra == 0) {
507		if (discard && rem_length)
508		    /* unexpectedly long reply! */
509		    _EatData32(svr, rem_length);
510		return (1);
511	    }
512	    if (extra == rem_length) {
513		/*
514		 * Read the extra data into storage immediately following the
515		 * GenericReply structure.
516		 */
517		_FSRead(svr, (char *) NEXTPTR(rep, fsReply), ((long) extra) << 2);
518		return (1);
519	    }
520	    if (extra < rem_length) {
521		/* Actual reply is longer than "extra" */
522		_FSRead(svr, (char *) NEXTPTR(rep, fsReply), ((long) extra) << 2);
523		if (discard)
524		    _EatData32(svr, rem_length - extra);
525		return (1);
526	    }
527	    /*
528	     * if we get here, then extra > rem_length -- meaning we
529	     * read a reply that's shorter than we expected.  This is an
530	     * error,  but we still need to figure out how to handle it...
531	     */
532	    _FSRead(svr, (char *) NEXTPTR(rep, fsReply), rem_length << 2);
533	    (*_FSIOErrorFunction) (svr);
534	    return (0);
535
536	case FS_Error:
537	    {
538		register _FSExtension *ext;
539		register Bool ret = False;
540		int         ret_code;
541		fsError     err;
542		unsigned long serial;
543		long        err_data;
544
545		/* copy in the part we already read off the wire */
546		memcpy(&err, rep, SIZEOF(fsReply));
547		/* read the rest of the error */
548		_FSRead(svr, (char *) &err + SIZEOF(fsReply),
549			(long) (SIZEOF(fsError) - SIZEOF(fsReply)));
550		serial = _FSSetLastRequestRead(svr, (fsGenericReply *) rep);
551		if (serial == cur_request)
552		    /* do not die on certain failures */
553		    switch ((int) err.request) {
554			/* suck in any extra error info */
555		    case FSBadResolution:
556		    case FSBadLength:
557		    case FSBadIDChoice:
558		    case FSBadRange:
559		    case FSBadFont:
560		    case FSBadFormat:
561			_FSRead(svr, (char *) &err_data, 4);
562			break;
563		    case FSBadAccessContext:
564			_FSRead(svr, (char *) &err_data, 4);
565			return 0;
566		    case FSBadAlloc:
567			return (0);
568			/*
569			 * we better see if there is an extension who may want
570			 * to suppress the error.
571			 */
572		    default:
573			ext = svr->ext_procs;
574			while (ext) {
575			    if (ext->error != NULL)
576				ret = (*ext->error)
577				    (svr, &err, &ext->codes, &ret_code);
578			    ext = ext->next;
579			}
580			if (ret)
581			    return (ret_code);
582			break;
583		    }
584		_FSError(svr, &err);
585		if (serial == cur_request)
586		    return (0);
587	    }
588	    break;
589	default:
590	    _FSEnq(svr, (fsEvent *) rep);
591	    break;
592	}
593    }
594}
595
596
597/* Read and discard "n" 8-bit bytes of data */
598
599void
600_FSEatData(
601    FSServer			*svr,
602    register unsigned long	 n)
603{
604#define SCRATCHSIZE 2048
605    char        buf[SCRATCHSIZE];
606
607    while (n > 0) {
608	register long bytes_read = (n > SCRATCHSIZE) ? SCRATCHSIZE : n;
609
610	_FSRead(svr, buf, bytes_read);
611	n -= bytes_read;
612    }
613#undef SCRATCHSIZE
614}
615
616
617/* Read and discard "n" 32-bit words. */
618
619static void
620_EatData32(
621    FSServer		*svr,
622    unsigned long	 n)
623{
624    _FSEatData(svr, n << 2);
625}
626
627
628/*
629 * _FSEnq - Place event packets on the display's queue.
630 * note that no squishing of move events in V11, since there
631 * is pointer motion hints....
632 */
633void
634_FSEnq(
635    register FSServer	*svr,
636    register fsEvent	*event)
637{
638    register _FSQEvent *qelt;
639
640/*NOSTRICT*/
641    if ((qelt = _FSqfree) != NULL) {
642	/* If _FSqfree is non-NULL do this, else malloc a new one. */
643	_FSqfree = qelt->next;
644    } else if ((qelt = FSmalloc(sizeof(_FSQEvent))) == NULL) {
645	/* Malloc call failed! */
646	ESET(ENOMEM);
647	(*_FSIOErrorFunction) (svr);
648    }
649    qelt->next = NULL;
650    /* go call through display to find proper event reformatter */
651    if ((*svr->event_vec[event->type & 0177]) (svr, &qelt->event, event)) {
652	if (svr->tail)
653	    svr->tail->next = qelt;
654	else
655	    svr->head = qelt;
656
657	svr->tail = qelt;
658	svr->qlen++;
659    } else {
660	/* ignored, or stashed away for many-to-one compression */
661	qelt->next = _FSqfree;
662	_FSqfree = qelt;
663    }
664}
665
666/*
667 * EventToWire in separate file that is often not needed.
668 */
669
670/*ARGSUSED*/
671Bool
672_FSUnknownWireEvent(
673    register FSServer	*svr,	/* pointer to display structure */
674    register FSEvent	*re,	/* pointer to where event should be
675				 * reformatted */
676    register fsEvent	*event)	/* wire protocol event */
677{
678
679#ifdef notdef
680    (void) fprintf(stderr,
681	   "FSlib: unhandled wire event! event number = %d, display = %x\n.",
682		   event->type, svr);
683#endif
684
685    return (False);
686}
687
688/*ARGSUSED*/
689Status
690_FSUnknownNativeEvent(
691    register FSServer	*svr,	/* pointer to display structure */
692    register FSEvent	*re,	/* pointer to where event should be
693				 * reformatted */
694    register fsEvent	*event)	/* wire protocol event */
695{
696
697#ifdef notdef
698    (void) fprintf(stderr,
699	 "FSlib: unhandled native event! event number = %d, display = %x\n.",
700		   re->type, svr);
701#endif
702
703    return (0);
704}
705
706static const char *
707_SysErrorMsg(int n)
708{
709    char       *s = strerror(n);
710
711    return (s ? s : "no such error");
712}
713
714#ifdef __SUNPRO_C
715/* prevent "Function has no return statement" error for _FSDefaultIOError */
716#pragma does_not_return(exit)
717#endif
718
719/*
720 * _FSDefaultIOError - Default fatal system error reporting routine.  Called
721 * when an X internal system error is encountered.
722 */
723int
724_FSDefaultIOError(FSServer *svr)
725{
726    (void) fprintf(stderr,
727		   "FSIO:  fatal IO error %d (%s) on font server \"%s\"\r\n",
728#ifdef WIN32
729			WSAGetLastError(), strerror(WSAGetLastError()),
730#else
731
732		   errno, _SysErrorMsg(errno),
733#endif
734		   FSServerString(svr) ? FSServerString(svr) : "");
735    (void) fprintf(stderr,
736		   "      after %lu requests (%lu known processed) with %d events remaining.\r\n",
737		   FSNextRequest(svr) - 1, FSLastKnownRequestProcessed(svr),
738		   FSQLength(svr));
739
740    if (ECHECK(EPIPE)) {
741	(void) fprintf(stderr,
742	"      The connection was probably broken by a server shutdown.\r\n");
743    }
744    exit(1);
745    /* NOTREACHED */
746}
747
748/*
749 * _FSError - Default non-fatal error reporting routine.  Called when an
750 * FS_Error packet is encountered in the input stream.
751 */
752int
753_FSError(
754    FSServer	*svr,
755    fsError	*rep)
756{
757    FSErrorEvent event;
758
759    /*
760     * FS_Error packet encountered!  We need to unpack the error before giving
761     * it to the user.
762     */
763
764    event.server = svr;
765    event.type = FS_Error;
766    event.serial = _FSSetLastRequestRead(svr, (fsGenericReply *) rep);
767    event.error_code = rep->request;
768    event.request_code = rep->major_opcode;
769    event.minor_code = rep->minor_opcode;
770    if (_FSErrorFunction != NULL) {
771	return ((*_FSErrorFunction) (svr, &event));
772    }
773    exit(1);
774    /* NOTREACHED */
775}
776
777#ifdef __clang__
778#pragma clang diagnostic push
779#pragma clang diagnostic ignored "-Wformat-nonliteral" // We know better
780#endif
781
782int
783_FSPrintDefaultError(
784    FSServer		*svr,
785    FSErrorEvent	*event,
786    FILE		*fp)
787{
788    char        buffer[BUFSIZ];
789    char        mesg[BUFSIZ];
790    char        number[32];
791    const char *mtype = "FSlibMessage";
792    register _FSExtension *ext = (_FSExtension *) NULL;
793
794    (void) FSGetErrorText(svr, event->error_code, buffer, BUFSIZ);
795    (void) FSGetErrorDatabaseText(svr, mtype, "FSError", "FS Error", mesg,
796				  BUFSIZ);
797    (void) fprintf(fp, "%s:  %s\n  ", mesg, buffer);
798    (void) FSGetErrorDatabaseText(svr, mtype, "MajorCode",
799				  "Request Major code %d", mesg, BUFSIZ);
800    (void) fprintf(fp, mesg, event->request_code);
801    if (event->request_code < 128) {
802	snprintf(number, sizeof(number), "%d", event->request_code);
803	(void) FSGetErrorDatabaseText(svr, "FSRequest", number, "", buffer,
804				      BUFSIZ);
805    } else {
806	for (ext = svr->ext_procs;
807		ext && (ext->codes.major_opcode != event->request_code);
808		ext = ext->next);
809	if (ext)
810#ifdef HAVE_STRLCPY
811	    strlcpy(buffer, ext->name, sizeof(buffer));
812#else
813	    strcpy(buffer, ext->name);
814#endif
815	else
816	    buffer[0] = '\0';
817    }
818    (void) fprintf(fp, " (%s)\n  ", buffer);
819    (void) FSGetErrorDatabaseText(svr, mtype, "MinorCode",
820				  "Request Minor code %d", mesg, BUFSIZ);
821    (void) fprintf(fp, mesg, event->minor_code);
822    if (ext) {
823	snprintf(mesg, sizeof(mesg), "%s.%d", ext->name, event->minor_code);
824	(void) FSGetErrorDatabaseText(svr, "FSRequest", mesg, "", buffer,
825				      BUFSIZ);
826	(void) fprintf(fp, " (%s)", buffer);
827    }
828    fputs("\n  ", fp);
829    (void) FSGetErrorDatabaseText(svr, mtype, "ResourceID", "ResourceID 0x%x",
830				  mesg, BUFSIZ);
831    (void) fprintf(fp, mesg, event->resourceid);
832    fputs("\n  ", fp);
833    (void) FSGetErrorDatabaseText(svr, mtype, "ErrorSerial", "Error Serial #%d",
834				  mesg, BUFSIZ);
835    (void) fprintf(fp, mesg, event->serial);
836    fputs("\n  ", fp);
837    (void) FSGetErrorDatabaseText(svr, mtype, "CurrentSerial",
838				  "Current Serial #%d", mesg, BUFSIZ);
839    (void) fprintf(fp, mesg, svr->request);
840    fputs("\n", fp);
841    return 1;
842}
843
844#ifdef __clang__
845#pragma clang diagnostic pop
846#endif
847
848int
849_FSDefaultError(
850    FSServer		*svr,
851    FSErrorEvent	*event)
852{
853    if (_FSPrintDefaultError(svr, event, stderr) == 0)
854	return 0;
855    exit(1);
856    /* NOTREACHED */
857}
858
859
860FSIOErrorHandler _FSIOErrorFunction = _FSDefaultIOError;
861FSErrorHandler _FSErrorFunction = _FSDefaultError;
862
863int
864FSFree(char *data)
865{
866    FSfree(data);
867    return 1;
868}
869
870unsigned char *
871FSMalloc(unsigned size)
872{
873    return (unsigned char *) FSmalloc(size);
874}
875
876#ifdef DataRoutineIsProcedure
877void
878Data(
879    FSServer	*svr,
880    char	*data,
881    long	 len)
882{
883    if (svr->bufptr + (len) <= svr->bufmax) {
884	memmove(svr->bufptr, data, len);
885	svr->bufptr += ((len) + 3) & ~3;
886    } else {
887	_FSSend(svr, data, len);
888    }
889}
890
891#endif				/* DataRoutineIsProcedure */
892
893
894/*
895 * _FSFreeQ - free the queue of events, called by XCloseServer when there are
896 * no more displays left on the display list
897 */
898
899void
900_FSFreeQ(void)
901{
902    register _FSQEvent *qelt = _FSqfree;
903
904    while (qelt) {
905	register _FSQEvent *qnext = qelt->next;
906
907	FSfree(qelt);
908	qelt = qnext;
909    }
910    _FSqfree = NULL;
911    return;
912}
913
914#ifndef _FSANYSET
915/*
916 * This is not always a macro.
917 */
918_FSANYSET(long *src)
919{
920    int i;
921
922    for (i=0; i<MSKCNT; i++)
923	if (src[ i ])
924	    return (1);
925    return (0);
926}
927#endif
928