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