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