Home | History | Annotate | Line # | Download | only in src
      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 
     28 Copyright 1987, 1994, 1998  The Open Group
     29 
     30 Permission to use, copy, modify, distribute, and sell this software and its
     31 documentation for any purpose is hereby granted without fee, provided that
     32 the above copyright notice appear in all copies and that both that
     33 copyright notice and this permission notice appear in supporting
     34 documentation.
     35 
     36 The above copyright notice and this permission notice shall be included in
     37 all copies or substantial portions of the Software.
     38 
     39 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     40 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     41 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     42 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     43 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     44 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     45 
     46 Except as contained in this notice, the name of The Open Group shall not be
     47 used in advertising or otherwise to promote the sale, use or other dealings
     48 in 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 
     64 static void _EatData32 ( FSServer *svr, unsigned long n );
     65 static 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 
    114 static 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 
    121 static 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  */
    130 void
    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  */
    173 void
    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  */
    230 void
    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  */
    275 void
    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  */
    335 void
    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  */
    425 FSID
    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 
    442 unsigned 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  */
    474 Status
    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 
    599 void
    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 
    619 static 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  */
    633 void
    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*/
    671 Bool
    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*/
    689 Status
    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 
    706 static 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  */
    723 int
    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  */
    752 int
    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 
    782 int
    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 
    848 int
    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 
    860 FSIOErrorHandler _FSIOErrorFunction = _FSDefaultIOError;
    861 FSErrorHandler _FSErrorFunction = _FSDefaultError;
    862 
    863 int
    864 FSFree(char *data)
    865 {
    866     FSfree(data);
    867     return 1;
    868 }
    869 
    870 unsigned char *
    871 FSMalloc(unsigned size)
    872 {
    873     return (unsigned char *) FSmalloc(size);
    874 }
    875 
    876 #ifdef DataRoutineIsProcedure
    877 void
    878 Data(
    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 
    899 void
    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