utils.c revision 6b007147
1/*
2
3Copyright 1987, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
28Copyright 1994 Quarterdeck Office Systems.
29
30                        All Rights Reserved
31
32Permission to use, copy, modify, and distribute this software and its
33documentation for any purpose and without fee is hereby granted,
34provided that the above copyright notice appear in all copies and that
35both that copyright notice and this permission notice appear in
36supporting documentation, and that the names of Digital and
37Quarterdeck not be used in advertising or publicity pertaining to
38distribution of the software without specific, written prior
39permission.
40
41DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
42SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
43FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
44OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
45OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
46OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
47OR PERFORMANCE OF THIS SOFTWARE.
48
49*/
50
51#ifdef HAVE_DIX_CONFIG_H
52#include <dix-config.h>
53#endif
54
55#ifdef __CYGWIN__
56#include <stdlib.h>
57#include <signal.h>
58/*
59   Sigh... We really need a prototype for this to know it is stdcall,
60   but #include-ing <windows.h> here is not a good idea...
61*/
62__stdcall unsigned long GetTickCount(void);
63#endif
64
65#if defined(WIN32) && !defined(__CYGWIN__)
66#include <X11/Xwinsock.h>
67#endif
68#include <X11/Xos.h>
69#include <stdio.h>
70#include <time.h>
71#if !defined(WIN32) || !defined(__MINGW32__)
72#include <sys/time.h>
73#include <sys/resource.h>
74#endif
75#include "misc.h"
76#include <X11/X.h>
77#define XSERV_t
78#define TRANS_SERVER
79#define TRANS_REOPEN
80#include <X11/Xtrans/Xtrans.h>
81#include "input.h"
82#include "dixfont.h"
83#include <X11/fonts/libxfont2.h>
84#include "osdep.h"
85#include "extension.h"
86#include <signal.h>
87#ifndef WIN32
88#include <sys/wait.h>
89#endif
90#if !defined(SYSV) && !defined(WIN32)
91#include <sys/resource.h>
92#endif
93#include <sys/stat.h>
94#include <ctype.h>              /* for isspace */
95#include <stdarg.h>
96
97#include <stdlib.h>             /* for malloc() */
98
99#if defined(TCPCONN)
100#ifndef WIN32
101#include <netdb.h>
102#endif
103#endif
104
105#include "opaque.h"
106
107#include "dixstruct.h"
108
109#include "xkbsrv.h"
110
111#include "picture.h"
112
113#include "miinitext.h"
114
115#include "present.h"
116
117Bool noTestExtensions;
118
119#ifdef COMPOSITE
120Bool noCompositeExtension = FALSE;
121#endif
122
123#ifdef DAMAGE
124Bool noDamageExtension = FALSE;
125#endif
126#ifdef DBE
127Bool noDbeExtension = FALSE;
128#endif
129#ifdef DPMSExtension
130#include "dpmsproc.h"
131Bool noDPMSExtension = FALSE;
132#endif
133#ifdef GLXEXT
134Bool noGlxExtension = FALSE;
135#endif
136#ifdef SCREENSAVER
137Bool noScreenSaverExtension = FALSE;
138#endif
139#ifdef MITSHM
140Bool noMITShmExtension = FALSE;
141#endif
142#ifdef RANDR
143Bool noRRExtension = FALSE;
144#endif
145Bool noRenderExtension = FALSE;
146
147#ifdef XCSECURITY
148Bool noSecurityExtension = FALSE;
149#endif
150#ifdef RES
151Bool noResExtension = FALSE;
152#endif
153#ifdef XF86BIGFONT
154Bool noXFree86BigfontExtension = FALSE;
155#endif
156#ifdef XFreeXDGA
157Bool noXFree86DGAExtension = FALSE;
158#endif
159#ifdef XF86DRI
160Bool noXFree86DRIExtension = FALSE;
161#endif
162#ifdef XF86VIDMODE
163Bool noXFree86VidModeExtension = FALSE;
164#endif
165Bool noXFixesExtension = FALSE;
166#ifdef PANORAMIX
167/* Xinerama is disabled by default unless enabled via +xinerama */
168Bool noPanoramiXExtension = TRUE;
169#endif
170#ifdef XSELINUX
171Bool noSELinuxExtension = FALSE;
172int selinuxEnforcingState = SELINUX_MODE_DEFAULT;
173#endif
174#ifdef XV
175Bool noXvExtension = FALSE;
176#endif
177#ifdef DRI2
178Bool noDRI2Extension = FALSE;
179#endif
180
181Bool noGEExtension = FALSE;
182
183#define X_INCLUDE_NETDB_H
184#include <X11/Xos_r.h>
185
186#include <errno.h>
187
188Bool CoreDump;
189
190Bool enableIndirectGLX = FALSE;
191
192#ifdef PANORAMIX
193Bool PanoramiXExtensionDisabledHack = FALSE;
194#endif
195
196int auditTrailLevel = 1;
197
198char *SeatId = NULL;
199
200sig_atomic_t inSignalContext = FALSE;
201
202#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
203#define HAS_SAVED_IDS_AND_SETEUID
204#endif
205
206#ifdef MONOTONIC_CLOCK
207static clockid_t clockid;
208#endif
209
210OsSigHandlerPtr
211OsSignal(int sig, OsSigHandlerPtr handler)
212{
213#if defined(WIN32) && !defined(__CYGWIN__)
214    return signal(sig, handler);
215#else
216    struct sigaction act, oact;
217
218    sigemptyset(&act.sa_mask);
219    if (handler != SIG_IGN)
220        sigaddset(&act.sa_mask, sig);
221    act.sa_flags = 0;
222    act.sa_handler = handler;
223    if (sigaction(sig, &act, &oact))
224        perror("sigaction");
225    return oact.sa_handler;
226#endif
227}
228
229/*
230 * Explicit support for a server lock file like the ones used for UUCP.
231 * For architectures with virtual terminals that can run more than one
232 * server at a time.  This keeps the servers from stomping on each other
233 * if the user forgets to give them different display numbers.
234 */
235#define LOCK_DIR "/tmp"
236#define LOCK_TMP_PREFIX "/.tX"
237#define LOCK_PREFIX "/.X"
238#define LOCK_SUFFIX "-lock"
239
240#if !defined(WIN32) || defined(__CYGWIN__)
241#define LOCK_SERVER
242#endif
243
244#ifndef LOCK_SERVER
245void
246LockServer(void)
247{}
248
249void
250UnlockServer(void)
251{}
252#else /* LOCK_SERVER */
253static Bool StillLocking = FALSE;
254static char LockFile[PATH_MAX];
255static Bool nolock = FALSE;
256
257/*
258 * LockServer --
259 *      Check if the server lock file exists.  If so, check if the PID
260 *      contained inside is valid.  If so, then die.  Otherwise, create
261 *      the lock file containing the PID.
262 */
263void
264LockServer(void)
265{
266    char tmp[PATH_MAX], pid_str[12];
267    int lfd, i, haslock, l_pid, t;
268    const char *tmppath = LOCK_DIR;
269    int len;
270    char port[20];
271
272    if (nolock || NoListenAll)
273        return;
274    /*
275     * Path names
276     */
277    snprintf(port, sizeof(port), "%d", atoi(display));
278    len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) :
279        strlen(LOCK_TMP_PREFIX);
280    len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1;
281    if (len > sizeof(LockFile))
282        FatalError("Display name `%s' is too long\n", port);
283    (void) sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
284    (void) sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
285
286    /*
287     * Create a temporary file containing our PID.  Attempt three times
288     * to create the file.
289     */
290    StillLocking = TRUE;
291    i = 0;
292    do {
293        i++;
294        lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
295        if (lfd < 0)
296            sleep(2);
297        else
298            break;
299    } while (i < 3);
300    if (lfd < 0) {
301        unlink(tmp);
302        i = 0;
303        do {
304            i++;
305            lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
306            if (lfd < 0)
307                sleep(2);
308            else
309                break;
310        } while (i < 3);
311    }
312    if (lfd < 0)
313        FatalError("Could not create lock file in %s\n", tmp);
314    snprintf(pid_str, sizeof(pid_str), "%10lu\n", (unsigned long) getpid());
315    if (write(lfd, pid_str, 11) != 11)
316        FatalError("Could not write pid to lock file in %s\n", tmp);
317    (void) fchmod(lfd, 0444);
318    (void) close(lfd);
319
320    /*
321     * OK.  Now the tmp file exists.  Try three times to move it in place
322     * for the lock.
323     */
324    i = 0;
325    haslock = 0;
326    while ((!haslock) && (i++ < 3)) {
327        haslock = (link(tmp, LockFile) == 0);
328        if (haslock) {
329            /*
330             * We're done.
331             */
332            break;
333        }
334        else if (errno == EEXIST) {
335            /*
336             * Read the pid from the existing file
337             */
338            lfd = open(LockFile, O_RDONLY | O_NOFOLLOW);
339            if (lfd < 0) {
340                unlink(tmp);
341                FatalError("Can't read lock file %s\n", LockFile);
342            }
343            pid_str[0] = '\0';
344            if (read(lfd, pid_str, 11) != 11) {
345                /*
346                 * Bogus lock file.
347                 */
348                unlink(LockFile);
349                close(lfd);
350                continue;
351            }
352            pid_str[11] = '\0';
353            sscanf(pid_str, "%d", &l_pid);
354            close(lfd);
355
356            /*
357             * Now try to kill the PID to see if it exists.
358             */
359            errno = 0;
360            t = kill(l_pid, 0);
361            if ((t < 0) && (errno == ESRCH)) {
362                /*
363                 * Stale lock file.
364                 */
365                unlink(LockFile);
366                continue;
367            }
368            else if (((t < 0) && (errno == EPERM)) || (t == 0)) {
369                /*
370                 * Process is still active.
371                 */
372                unlink(tmp);
373                FatalError
374                    ("Server is already active for display %s\n%s %s\n%s\n",
375                     port, "\tIf this server is no longer running, remove",
376                     LockFile, "\tand start again.");
377            }
378        }
379        else {
380            unlink(tmp);
381            FatalError
382                ("Linking lock file (%s) in place failed: %s\n",
383                 LockFile, strerror(errno));
384        }
385    }
386    unlink(tmp);
387    if (!haslock)
388        FatalError("Could not create server lock file: %s\n", LockFile);
389    StillLocking = FALSE;
390}
391
392/*
393 * UnlockServer --
394 *      Remove the server lock file.
395 */
396void
397UnlockServer(void)
398{
399    if (nolock || NoListenAll)
400        return;
401
402    if (!StillLocking) {
403
404        (void) unlink(LockFile);
405    }
406}
407#endif /* LOCK_SERVER */
408
409/* Force connections to close on SIGHUP from init */
410
411void
412AutoResetServer(int sig)
413{
414    int olderrno = errno;
415
416    dispatchException |= DE_RESET;
417    isItTimeToYield = TRUE;
418    errno = olderrno;
419}
420
421/* Force connections to close and then exit on SIGTERM, SIGINT */
422
423void
424GiveUp(int sig)
425{
426    int olderrno = errno;
427
428    dispatchException |= DE_TERMINATE;
429    isItTimeToYield = TRUE;
430    errno = olderrno;
431}
432
433#ifdef MONOTONIC_CLOCK
434void
435ForceClockId(clockid_t forced_clockid)
436{
437    struct timespec tp;
438
439    BUG_RETURN (clockid);
440
441    clockid = forced_clockid;
442
443    if (clock_gettime(clockid, &tp) != 0) {
444        FatalError("Forced clock id failed to retrieve current time: %s\n",
445                   strerror(errno));
446        return;
447    }
448}
449#endif
450
451#if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__)
452CARD32
453GetTimeInMillis(void)
454{
455    return GetTickCount();
456}
457CARD64
458GetTimeInMicros(void)
459{
460    return (CARD64) GetTickCount() * 1000;
461}
462#else
463CARD32
464GetTimeInMillis(void)
465{
466    struct timeval tv;
467
468#ifdef MONOTONIC_CLOCK
469    struct timespec tp;
470
471    if (!clockid) {
472#ifdef CLOCK_MONOTONIC_COARSE
473        if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
474            (tp.tv_nsec / 1000) <= 1000 &&
475            clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
476            clockid = CLOCK_MONOTONIC_COARSE;
477        else
478#endif
479        if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
480            clockid = CLOCK_MONOTONIC;
481        else
482            clockid = ~0L;
483    }
484    if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
485        return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
486#endif
487
488    X_GETTIMEOFDAY(&tv);
489    return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
490}
491
492CARD64
493GetTimeInMicros(void)
494{
495    struct timeval tv;
496#ifdef MONOTONIC_CLOCK
497    struct timespec tp;
498    static clockid_t uclockid;
499
500    if (!uclockid) {
501        if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
502            uclockid = CLOCK_MONOTONIC;
503        else
504            uclockid = ~0L;
505    }
506    if (uclockid != ~0L && clock_gettime(uclockid, &tp) == 0)
507        return (CARD64) tp.tv_sec * (CARD64)1000000 + tp.tv_nsec / 1000;
508#endif
509
510    X_GETTIMEOFDAY(&tv);
511    return (CARD64) tv.tv_sec * (CARD64)1000000 + (CARD64) tv.tv_usec;
512}
513#endif
514
515void
516UseMsg(void)
517{
518    ErrorF("use: X [:<display>] [option]\n");
519    ErrorF("-a #                   default pointer acceleration (factor)\n");
520    ErrorF("-ac                    disable access control restrictions\n");
521    ErrorF("-audit int             set audit trail level\n");
522    ErrorF("-auth file             select authorization file\n");
523    ErrorF("-br                    create root window with black background\n");
524    ErrorF("+bs                    enable any backing store support\n");
525    ErrorF("-bs                    disable any backing store support\n");
526    ErrorF("-c                     turns off key-click\n");
527    ErrorF("c #                    key-click volume (0-100)\n");
528    ErrorF("-cc int                default color visual class\n");
529    ErrorF("-nocursor              disable the cursor\n");
530    ErrorF("-core                  generate core dump on fatal error\n");
531    ErrorF("-displayfd fd          file descriptor to write display number to when ready to connect\n");
532    ErrorF("-dpi int               screen resolution in dots per inch\n");
533#ifdef DPMSExtension
534    ErrorF("-dpms                  disables VESA DPMS monitor control\n");
535#endif
536    ErrorF
537        ("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n");
538    ErrorF("-f #                   bell base (0-100)\n");
539    ErrorF("-fakescreenfps #       fake screen default fps (1-600)\n");
540    ErrorF("-fp string             default font path\n");
541    ErrorF("-help                  prints message with these options\n");
542    ErrorF("+iglx                  Allow creating indirect GLX contexts\n");
543    ErrorF("-iglx                  Prohibit creating indirect GLX contexts (default)\n");
544    ErrorF("-I                     ignore all remaining arguments\n");
545#ifdef RLIMIT_DATA
546    ErrorF("-ld int                limit data space to N Kb\n");
547#endif
548#ifdef RLIMIT_NOFILE
549    ErrorF("-lf int                limit number of open files to N\n");
550#endif
551#ifdef RLIMIT_STACK
552    ErrorF("-ls int                limit stack space to N Kb\n");
553#endif
554#ifdef LOCK_SERVER
555    ErrorF("-nolock                disable the locking mechanism\n");
556#endif
557    ErrorF("-maxclients n          set maximum number of clients (power of two)\n");
558    ErrorF("-nolisten string       don't listen on protocol\n");
559    ErrorF("-listen string         listen on protocol\n");
560    ErrorF("-noreset               don't reset after last client exists\n");
561    ErrorF("-background [none]     create root window with no background\n");
562    ErrorF("-reset                 reset after last client exists\n");
563    ErrorF("-p #                   screen-saver pattern duration (minutes)\n");
564    ErrorF("-pn                    accept failure to listen on all ports\n");
565    ErrorF("-nopn                  reject failure to listen on all ports\n");
566    ErrorF("-r                     turns off auto-repeat\n");
567    ErrorF("r                      turns on auto-repeat \n");
568    ErrorF("-render [default|mono|gray|color] set render color alloc policy\n");
569    ErrorF("-retro                 start with classic stipple and cursor\n");
570    ErrorF("-noretro               start with black background and no cursor\n");
571    ErrorF("-s #                   screen-saver timeout (minutes)\n");
572    ErrorF("-seat string           seat to run on\n");
573    ErrorF("-t #                   default pointer threshold (pixels/t)\n");
574    ErrorF("-terminate [delay]     terminate at server reset (optional delay in sec)\n");
575    ErrorF("-tst                   disable testing extensions\n");
576    ErrorF("ttyxx                  server started from init on /dev/ttyxx\n");
577    ErrorF("v                      video blanking for screen-saver\n");
578    ErrorF("-v                     screen-saver without video blanking\n");
579    ErrorF("-wr                    create root window with white background\n");
580    ErrorF("-maxbigreqsize         set maximal bigrequest size \n");
581#ifdef PANORAMIX
582    ErrorF("+xinerama              Enable XINERAMA extension\n");
583    ErrorF("-xinerama              Disable XINERAMA extension\n");
584#endif
585    ErrorF
586        ("-dumbSched             Disable smart scheduling and threaded input, enable old behavior\n");
587    ErrorF("-schedInterval int     Set scheduler interval in msec\n");
588    ErrorF("-sigstop               Enable SIGSTOP based startup\n");
589    ErrorF("+extension name        Enable extension\n");
590    ErrorF("-extension name        Disable extension\n");
591    ListStaticExtensions();
592#ifdef XDMCP
593    XdmcpUseMsg();
594#endif
595    XkbUseMsg();
596    ddxUseMsg();
597}
598
599/*  This function performs a rudimentary sanity check
600 *  on the display name passed in on the command-line,
601 *  since this string is used to generate filenames.
602 *  It is especially important that the display name
603 *  not contain a "/" and not start with a "-".
604 *                                            --kvajk
605 */
606static int
607VerifyDisplayName(const char *d)
608{
609    int i;
610    int period_found = FALSE;
611    int after_period = 0;
612
613    if (d == (char *) 0)
614        return 0;               /*  null  */
615    if (*d == '\0')
616        return 0;               /*  empty  */
617    if (*d == '-')
618        return 0;               /*  could be confused for an option  */
619    if (*d == '.')
620        return 0;               /*  must not equal "." or ".."  */
621    if (strchr(d, '/') != (char *) 0)
622        return 0;               /*  very important!!!  */
623
624    /* Since we run atoi() on the display later, only allow
625       for digits, or exception of :0.0 and similar (two decimal points max)
626       */
627    for (i = 0; i < strlen(d); i++) {
628        if (!isdigit(d[i])) {
629            if (d[i] != '.' || period_found)
630                return 0;
631            period_found = TRUE;
632        } else if (period_found)
633            after_period++;
634
635        if (after_period > 2)
636            return 0;
637    }
638
639    /* don't allow for :0. */
640    if (period_found && after_period == 0)
641        return 0;
642
643    if (atol(d) > INT_MAX)
644        return 0;
645
646    return 1;
647}
648
649static const char *defaultNoListenList[] = {
650#ifndef LISTEN_TCP
651    "tcp",
652#endif
653#ifndef LISTEN_UNIX
654    "unix",
655#endif
656#ifndef LISTEN_LOCAL
657    "local",
658#endif
659    NULL
660};
661
662/*
663 * This function parses the command line. Handles device-independent fields
664 * and allows ddx to handle additional fields.  It is not allowed to modify
665 * argc or any of the strings pointed to by argv.
666 */
667void
668ProcessCommandLine(int argc, char *argv[])
669{
670    int i, skip;
671
672    defaultKeyboardControl.autoRepeat = TRUE;
673
674#ifdef NO_PART_NET
675    PartialNetwork = FALSE;
676#else
677    PartialNetwork = TRUE;
678#endif
679
680    for (i = 0; defaultNoListenList[i] != NULL; i++) {
681        if (_XSERVTransNoListen(defaultNoListenList[i]))
682                    ErrorF("Failed to disable listen for %s transport",
683                           defaultNoListenList[i]);
684    }
685
686    for (i = 1; i < argc; i++) {
687        /* call ddx first, so it can peek/override if it wants */
688        if ((skip = ddxProcessArgument(argc, argv, i))) {
689            i += (skip - 1);
690        }
691        else if (argv[i][0] == ':') {
692            /* initialize display */
693            display = argv[i];
694            explicit_display = TRUE;
695            display++;
696            if (!VerifyDisplayName(display)) {
697                ErrorF("Bad display name: %s\n", display);
698                UseMsg();
699                FatalError("Bad display name, exiting: %s\n", display);
700            }
701        }
702        else if (strcmp(argv[i], "-a") == 0) {
703            if (++i < argc)
704                defaultPointerControl.num = atoi(argv[i]);
705            else
706                UseMsg();
707        }
708        else if (strcmp(argv[i], "-ac") == 0) {
709            defeatAccessControl = TRUE;
710        }
711        else if (strcmp(argv[i], "-audit") == 0) {
712            if (++i < argc)
713                auditTrailLevel = atoi(argv[i]);
714            else
715                UseMsg();
716        }
717        else if (strcmp(argv[i], "-auth") == 0) {
718            if (++i < argc)
719                InitAuthorization(argv[i]);
720            else
721                UseMsg();
722        }
723        else if (strcmp(argv[i], "-br") == 0);  /* default */
724        else if (strcmp(argv[i], "+bs") == 0)
725            enableBackingStore = TRUE;
726        else if (strcmp(argv[i], "-bs") == 0)
727            disableBackingStore = TRUE;
728        else if (strcmp(argv[i], "c") == 0) {
729            if (++i < argc)
730                defaultKeyboardControl.click = atoi(argv[i]);
731            else
732                UseMsg();
733        }
734        else if (strcmp(argv[i], "-c") == 0) {
735            defaultKeyboardControl.click = 0;
736        }
737        else if (strcmp(argv[i], "-cc") == 0) {
738            if (++i < argc)
739                defaultColorVisualClass = atoi(argv[i]);
740            else
741                UseMsg();
742        }
743        else if (strcmp(argv[i], "-core") == 0) {
744#if !defined(WIN32) || !defined(__MINGW32__)
745            struct rlimit core_limit;
746
747            if (getrlimit(RLIMIT_CORE, &core_limit) != -1) {
748                core_limit.rlim_cur = core_limit.rlim_max;
749                setrlimit(RLIMIT_CORE, &core_limit);
750            }
751#endif
752            CoreDump = TRUE;
753        }
754        else if (strcmp(argv[i], "-nocursor") == 0) {
755            EnableCursor = FALSE;
756        }
757        else if (strcmp(argv[i], "-dpi") == 0) {
758            if (++i < argc)
759                monitorResolution = atoi(argv[i]);
760            else
761                UseMsg();
762        }
763        else if (strcmp(argv[i], "-displayfd") == 0) {
764            if (++i < argc) {
765                displayfd = atoi(argv[i]);
766#ifdef LOCK_SERVER
767                nolock = TRUE;
768#endif
769            }
770            else
771                UseMsg();
772        }
773#ifdef DPMSExtension
774        else if (strcmp(argv[i], "dpms") == 0)
775            /* ignored for compatibility */ ;
776        else if (strcmp(argv[i], "-dpms") == 0)
777            DPMSDisabledSwitch = TRUE;
778#endif
779        else if (strcmp(argv[i], "-deferglyphs") == 0) {
780            if (++i >= argc || !xfont2_parse_glyph_caching_mode(argv[i]))
781                UseMsg();
782        }
783        else if (strcmp(argv[i], "-f") == 0) {
784            if (++i < argc)
785                defaultKeyboardControl.bell = atoi(argv[i]);
786            else
787                UseMsg();
788        }
789        else if (strcmp(argv[i], "-fakescreenfps") == 0) {
790#ifdef PRESENT
791            if (++i < argc) {
792                FakeScreenFps = (uint32_t) atoi(argv[i]);
793                if (FakeScreenFps < 1 || FakeScreenFps > 600)
794                    FatalError("fakescreenfps must be an integer in [1;600] range\n");
795            }
796            else
797                UseMsg();
798#else
799            FatalError("fakescreenfps not available without PRESENT\n");
800            UseMsg();
801#endif
802        }
803        else if (strcmp(argv[i], "-fp") == 0) {
804            if (++i < argc) {
805                defaultFontPath = argv[i];
806            }
807            else
808                UseMsg();
809        }
810        else if (strcmp(argv[i], "-help") == 0) {
811            UseMsg();
812            exit(0);
813        }
814        else if (strcmp(argv[i], "+iglx") == 0)
815            enableIndirectGLX = TRUE;
816        else if (strcmp(argv[i], "-iglx") == 0)
817            enableIndirectGLX = FALSE;
818        else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) {
819            if (skip > 0)
820                i += skip - 1;
821            else
822                UseMsg();
823        }
824#ifdef RLIMIT_DATA
825        else if (strcmp(argv[i], "-ld") == 0) {
826            if (++i < argc) {
827                limitDataSpace = atoi(argv[i]);
828                if (limitDataSpace > 0)
829                    limitDataSpace *= 1024;
830            }
831            else
832                UseMsg();
833        }
834#endif
835#ifdef RLIMIT_NOFILE
836        else if (strcmp(argv[i], "-lf") == 0) {
837            if (++i < argc)
838                limitNoFile = atoi(argv[i]);
839            else
840                UseMsg();
841        }
842#endif
843#ifdef RLIMIT_STACK
844        else if (strcmp(argv[i], "-ls") == 0) {
845            if (++i < argc) {
846                limitStackSpace = atoi(argv[i]);
847                if (limitStackSpace > 0)
848                    limitStackSpace *= 1024;
849            }
850            else
851                UseMsg();
852        }
853#endif
854#ifdef LOCK_SERVER
855        else if (strcmp(argv[i], "-nolock") == 0) {
856#if !defined(WIN32) && !defined(__CYGWIN__)
857            if (getuid() != 0)
858                ErrorF
859                    ("Warning: the -nolock option can only be used by root\n");
860            else
861#endif
862                nolock = TRUE;
863        }
864#endif
865	else if ( strcmp( argv[i], "-maxclients") == 0)
866	{
867	    if (++i < argc) {
868		LimitClients = atoi(argv[i]);
869		if (LimitClients != 64 &&
870		    LimitClients != 128 &&
871		    LimitClients != 256 &&
872		    LimitClients != 512 &&
873                    LimitClients != 1024 &&
874                    LimitClients != 2048) {
875		    FatalError("maxclients must be one of 64, 128, 256, 512, 1024 or 2048\n");
876		}
877	    } else
878		UseMsg();
879	}
880        else if (strcmp(argv[i], "-nolisten") == 0) {
881            if (++i < argc) {
882                if (_XSERVTransNoListen(argv[i]))
883                    ErrorF("Failed to disable listen for %s transport",
884                           argv[i]);
885            }
886            else
887                UseMsg();
888        }
889        else if (strcmp(argv[i], "-listen") == 0) {
890            if (++i < argc) {
891                if (_XSERVTransListen(argv[i]))
892                    ErrorF("Failed to enable listen for %s transport",
893                           argv[i]);
894            }
895            else
896                UseMsg();
897        }
898        else if (strcmp(argv[i], "-noreset") == 0) {
899            dispatchExceptionAtReset = 0;
900        }
901        else if (strcmp(argv[i], "-reset") == 0) {
902            dispatchExceptionAtReset = DE_RESET;
903        }
904        else if (strcmp(argv[i], "-p") == 0) {
905            if (++i < argc)
906                defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) *
907                    MILLI_PER_MIN;
908            else
909                UseMsg();
910        }
911        else if (strcmp(argv[i], "-pogo") == 0) {
912            dispatchException = DE_TERMINATE;
913        }
914        else if (strcmp(argv[i], "-pn") == 0)
915            PartialNetwork = TRUE;
916        else if (strcmp(argv[i], "-nopn") == 0)
917            PartialNetwork = FALSE;
918        else if (strcmp(argv[i], "r") == 0)
919            defaultKeyboardControl.autoRepeat = TRUE;
920        else if (strcmp(argv[i], "-r") == 0)
921            defaultKeyboardControl.autoRepeat = FALSE;
922        else if (strcmp(argv[i], "-retro") == 0)
923            party_like_its_1989 = TRUE;
924	else if (strcmp(argv[i], "-noretro") == 0)
925	    party_like_its_1989 = FALSE;
926        else if (strcmp(argv[i], "-s") == 0) {
927            if (++i < argc)
928                defaultScreenSaverTime = ((CARD32) atoi(argv[i])) *
929                    MILLI_PER_MIN;
930            else
931                UseMsg();
932        }
933        else if (strcmp(argv[i], "-seat") == 0) {
934            if (++i < argc)
935                SeatId = argv[i];
936            else
937                UseMsg();
938        }
939        else if (strcmp(argv[i], "-t") == 0) {
940            if (++i < argc)
941                defaultPointerControl.threshold = atoi(argv[i]);
942            else
943                UseMsg();
944        }
945        else if (strcmp(argv[i], "-terminate") == 0) {
946            dispatchExceptionAtReset = DE_TERMINATE;
947            terminateDelay = -1;
948            if ((i + 1 < argc) && (isdigit(*argv[i + 1])))
949               terminateDelay = atoi(argv[++i]);
950            terminateDelay = max(0, terminateDelay);
951        }
952        else if (strcmp(argv[i], "-tst") == 0) {
953            noTestExtensions = TRUE;
954        }
955        else if (strcmp(argv[i], "v") == 0)
956            defaultScreenSaverBlanking = PreferBlanking;
957        else if (strcmp(argv[i], "-v") == 0)
958            defaultScreenSaverBlanking = DontPreferBlanking;
959        else if (strcmp(argv[i], "-wr") == 0)
960            whiteRoot = TRUE;
961        else if (strcmp(argv[i], "-background") == 0) {
962            if (++i < argc) {
963                if (!strcmp(argv[i], "none"))
964                    bgNoneRoot = TRUE;
965                else
966                    UseMsg();
967            }
968        }
969        else if (strcmp(argv[i], "-maxbigreqsize") == 0) {
970            if (++i < argc) {
971                long reqSizeArg = atol(argv[i]);
972
973                /* Request size > 128MB does not make much sense... */
974                if (reqSizeArg > 0L && reqSizeArg < 128L) {
975                    maxBigRequestSize = (reqSizeArg * 1048576L) - 1L;
976                }
977                else {
978                    UseMsg();
979                }
980            }
981            else {
982                UseMsg();
983            }
984        }
985#ifdef PANORAMIX
986        else if (strcmp(argv[i], "+xinerama") == 0) {
987            noPanoramiXExtension = FALSE;
988        }
989        else if (strcmp(argv[i], "-xinerama") == 0) {
990            noPanoramiXExtension = TRUE;
991        }
992        else if (strcmp(argv[i], "-disablexineramaextension") == 0) {
993            PanoramiXExtensionDisabledHack = TRUE;
994        }
995#endif
996        else if (strcmp(argv[i], "-I") == 0) {
997            /* ignore all remaining arguments */
998            break;
999        }
1000        else if (strncmp(argv[i], "tty", 3) == 0) {
1001            /* init supplies us with this useless information */
1002        }
1003#ifdef XDMCP
1004        else if ((skip = XdmcpOptions(argc, argv, i)) != i) {
1005            i = skip - 1;
1006        }
1007#endif
1008        else if (strcmp(argv[i], "-dumbSched") == 0) {
1009            InputThreadEnable = FALSE;
1010#ifdef HAVE_SETITIMER
1011            SmartScheduleSignalEnable = FALSE;
1012#endif
1013        }
1014        else if (strcmp(argv[i], "-schedInterval") == 0) {
1015            if (++i < argc) {
1016                SmartScheduleInterval = atoi(argv[i]);
1017                SmartScheduleSlice = SmartScheduleInterval;
1018            }
1019            else
1020                UseMsg();
1021        }
1022        else if (strcmp(argv[i], "-schedMax") == 0) {
1023            if (++i < argc) {
1024                SmartScheduleMaxSlice = atoi(argv[i]);
1025            }
1026            else
1027                UseMsg();
1028        }
1029        else if (strcmp(argv[i], "-render") == 0) {
1030            if (++i < argc) {
1031                int policy = PictureParseCmapPolicy(argv[i]);
1032
1033                if (policy != PictureCmapPolicyInvalid)
1034                    PictureCmapPolicy = policy;
1035                else
1036                    UseMsg();
1037            }
1038            else
1039                UseMsg();
1040        }
1041        else if (strcmp(argv[i], "-sigstop") == 0) {
1042            RunFromSigStopParent = TRUE;
1043        }
1044        else if (strcmp(argv[i], "+extension") == 0) {
1045            if (++i < argc) {
1046                if (!EnableDisableExtension(argv[i], TRUE))
1047                    EnableDisableExtensionError(argv[i], TRUE);
1048            }
1049            else
1050                UseMsg();
1051        }
1052        else if (strcmp(argv[i], "-extension") == 0) {
1053            if (++i < argc) {
1054                if (!EnableDisableExtension(argv[i], FALSE))
1055                    EnableDisableExtensionError(argv[i], FALSE);
1056            }
1057            else
1058                UseMsg();
1059        }
1060        else {
1061            ErrorF("Unrecognized option: %s\n", argv[i]);
1062            UseMsg();
1063            FatalError("Unrecognized option: %s\n", argv[i]);
1064        }
1065    }
1066}
1067
1068/* Implement a simple-minded font authorization scheme.  The authorization
1069   name is "hp-hostname-1", the contents are simply the host name. */
1070int
1071set_font_authorizations(char **authorizations, int *authlen, void *client)
1072{
1073#define AUTHORIZATION_NAME "hp-hostname-1"
1074#if defined(TCPCONN)
1075    static char *result = NULL;
1076    static char *p = NULL;
1077
1078    if (p == NULL) {
1079        char hname[1024], *hnameptr;
1080        unsigned int len;
1081
1082#if defined(IPv6) && defined(AF_INET6)
1083        struct addrinfo hints, *ai = NULL;
1084#else
1085        struct hostent *host;
1086
1087#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1088        _Xgethostbynameparams hparams;
1089#endif
1090#endif
1091
1092        gethostname(hname, 1024);
1093#if defined(IPv6) && defined(AF_INET6)
1094        memset(&hints, 0, sizeof(hints));
1095        hints.ai_flags = AI_CANONNAME;
1096        if (getaddrinfo(hname, NULL, &hints, &ai) == 0) {
1097            hnameptr = ai->ai_canonname;
1098        }
1099        else {
1100            hnameptr = hname;
1101        }
1102#else
1103        host = _XGethostbyname(hname, hparams);
1104        if (host == NULL)
1105            hnameptr = hname;
1106        else
1107            hnameptr = host->h_name;
1108#endif
1109
1110        len = strlen(hnameptr) + 1;
1111        result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4);
1112
1113        p = result;
1114        *p++ = sizeof(AUTHORIZATION_NAME) >> 8;
1115        *p++ = sizeof(AUTHORIZATION_NAME) & 0xff;
1116        *p++ = (len) >> 8;
1117        *p++ = (len & 0xff);
1118
1119        memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME));
1120        p += sizeof(AUTHORIZATION_NAME);
1121        memmove(p, hnameptr, len);
1122        p += len;
1123#if defined(IPv6) && defined(AF_INET6)
1124        if (ai) {
1125            freeaddrinfo(ai);
1126        }
1127#endif
1128    }
1129    *authlen = p - result;
1130    *authorizations = result;
1131    return 1;
1132#else                           /* TCPCONN */
1133    return 0;
1134#endif                          /* TCPCONN */
1135}
1136
1137void *
1138XNFalloc(unsigned long amount)
1139{
1140    void *ptr = malloc(amount);
1141
1142    if (!ptr)
1143        FatalError("Out of memory");
1144    return ptr;
1145}
1146
1147/* The original XNFcalloc was used with the xnfcalloc macro which multiplied
1148 * the arguments at the call site without allowing calloc to check for overflow.
1149 * XNFcallocarray was added to fix that without breaking ABI.
1150 */
1151void *
1152XNFcalloc(unsigned long amount)
1153{
1154    return XNFcallocarray(1, amount);
1155}
1156
1157void *
1158XNFcallocarray(size_t nmemb, size_t size)
1159{
1160    void *ret = calloc(nmemb, size);
1161
1162    if (!ret)
1163        FatalError("XNFcalloc: Out of memory");
1164    return ret;
1165}
1166
1167void *
1168XNFrealloc(void *ptr, unsigned long amount)
1169{
1170    void *ret = realloc(ptr, amount);
1171
1172    if (!ret)
1173        FatalError("XNFrealloc: Out of memory");
1174    return ret;
1175}
1176
1177void *
1178XNFreallocarray(void *ptr, size_t nmemb, size_t size)
1179{
1180    void *ret = reallocarray(ptr, nmemb, size);
1181
1182    if (!ret)
1183        FatalError("XNFreallocarray: Out of memory");
1184    return ret;
1185}
1186
1187char *
1188Xstrdup(const char *s)
1189{
1190    if (s == NULL)
1191        return NULL;
1192    return strdup(s);
1193}
1194
1195char *
1196XNFstrdup(const char *s)
1197{
1198    char *ret;
1199
1200    if (s == NULL)
1201        return NULL;
1202
1203    ret = strdup(s);
1204    if (!ret)
1205        FatalError("XNFstrdup: Out of memory");
1206    return ret;
1207}
1208
1209void
1210SmartScheduleStopTimer(void)
1211{
1212#ifdef HAVE_SETITIMER
1213    struct itimerval timer;
1214
1215    if (!SmartScheduleSignalEnable)
1216        return;
1217    timer.it_interval.tv_sec = 0;
1218    timer.it_interval.tv_usec = 0;
1219    timer.it_value.tv_sec = 0;
1220    timer.it_value.tv_usec = 0;
1221    (void) setitimer(ITIMER_REAL, &timer, 0);
1222#endif
1223}
1224
1225void
1226SmartScheduleStartTimer(void)
1227{
1228#ifdef HAVE_SETITIMER
1229    struct itimerval timer;
1230
1231    if (!SmartScheduleSignalEnable)
1232        return;
1233    timer.it_interval.tv_sec = 0;
1234    timer.it_interval.tv_usec = SmartScheduleInterval * 1000;
1235    timer.it_value.tv_sec = 0;
1236    timer.it_value.tv_usec = SmartScheduleInterval * 1000;
1237    setitimer(ITIMER_REAL, &timer, 0);
1238#endif
1239}
1240
1241#ifdef HAVE_SETITIMER
1242static void
1243SmartScheduleTimer(int sig)
1244{
1245    SmartScheduleTime += SmartScheduleInterval;
1246}
1247
1248static int
1249SmartScheduleEnable(void)
1250{
1251    int ret = 0;
1252    struct sigaction act;
1253
1254    if (!SmartScheduleSignalEnable)
1255        return 0;
1256
1257    memset((char *) &act, 0, sizeof(struct sigaction));
1258
1259    /* Set up the timer signal function */
1260    act.sa_flags = SA_RESTART;
1261    act.sa_handler = SmartScheduleTimer;
1262    sigemptyset(&act.sa_mask);
1263    sigaddset(&act.sa_mask, SIGALRM);
1264    ret = sigaction(SIGALRM, &act, 0);
1265    return ret;
1266}
1267
1268static int
1269SmartSchedulePause(void)
1270{
1271    int ret = 0;
1272    struct sigaction act;
1273
1274    if (!SmartScheduleSignalEnable)
1275        return 0;
1276
1277    memset((char *) &act, 0, sizeof(struct sigaction));
1278
1279    act.sa_handler = SIG_IGN;
1280    sigemptyset(&act.sa_mask);
1281    ret = sigaction(SIGALRM, &act, 0);
1282    return ret;
1283}
1284#endif
1285
1286void
1287SmartScheduleInit(void)
1288{
1289#ifdef HAVE_SETITIMER
1290    if (SmartScheduleEnable() < 0) {
1291        perror("sigaction for smart scheduler");
1292        SmartScheduleSignalEnable = FALSE;
1293    }
1294#endif
1295}
1296
1297#ifdef HAVE_SIGPROCMASK
1298static sigset_t PreviousSignalMask;
1299static int BlockedSignalCount;
1300#endif
1301
1302void
1303OsBlockSignals(void)
1304{
1305#ifdef HAVE_SIGPROCMASK
1306    if (BlockedSignalCount++ == 0) {
1307        sigset_t set;
1308
1309        sigemptyset(&set);
1310        sigaddset(&set, SIGALRM);
1311        sigaddset(&set, SIGVTALRM);
1312#ifdef SIGWINCH
1313        sigaddset(&set, SIGWINCH);
1314#endif
1315        sigaddset(&set, SIGTSTP);
1316        sigaddset(&set, SIGTTIN);
1317        sigaddset(&set, SIGTTOU);
1318        sigaddset(&set, SIGCHLD);
1319        xthread_sigmask(SIG_BLOCK, &set, &PreviousSignalMask);
1320    }
1321#endif
1322}
1323
1324void
1325OsReleaseSignals(void)
1326{
1327#ifdef HAVE_SIGPROCMASK
1328    if (--BlockedSignalCount == 0) {
1329        xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0);
1330    }
1331#endif
1332}
1333
1334void
1335OsResetSignals(void)
1336{
1337#ifdef HAVE_SIGPROCMASK
1338    while (BlockedSignalCount > 0)
1339        OsReleaseSignals();
1340    input_force_unlock();
1341#endif
1342}
1343
1344/*
1345 * Pending signals may interfere with core dumping. Provide a
1346 * mechanism to block signals when aborting.
1347 */
1348
1349void
1350OsAbort(void)
1351{
1352#ifndef __APPLE__
1353    OsBlockSignals();
1354#endif
1355#if !defined(WIN32) || defined(__CYGWIN__)
1356    /* abort() raises SIGABRT, so we have to stop handling that to prevent
1357     * recursion
1358     */
1359    OsSignal(SIGABRT, SIG_DFL);
1360#endif
1361    abort();
1362}
1363
1364#if !defined(WIN32)
1365/*
1366 * "safer" versions of system(3), popen(3) and pclose(3) which give up
1367 * all privs before running a command.
1368 *
1369 * This is based on the code in FreeBSD 2.2 libc.
1370 *
1371 * XXX It'd be good to redirect stderr so that it ends up in the log file
1372 * as well.  As it is now, xkbcomp messages don't end up in the log file.
1373 */
1374
1375int
1376System(const char *command)
1377{
1378    int pid, p;
1379    void (*csig) (int);
1380    int status;
1381
1382    if (!command)
1383        return 1;
1384
1385    csig = OsSignal(SIGCHLD, SIG_DFL);
1386    if (csig == SIG_ERR) {
1387        perror("signal");
1388        return -1;
1389    }
1390    DebugF("System: `%s'\n", command);
1391
1392    switch (pid = fork()) {
1393    case -1:                   /* error */
1394        p = -1;
1395        break;
1396    case 0:                    /* child */
1397        if (setgid(getgid()) == -1)
1398            _exit(127);
1399        if (setuid(getuid()) == -1)
1400            _exit(127);
1401        execl("/bin/sh", "sh", "-c", command, (char *) NULL);
1402        _exit(127);
1403    default:                   /* parent */
1404        do {
1405            p = waitpid(pid, &status, 0);
1406        } while (p == -1 && errno == EINTR);
1407
1408    }
1409
1410    if (OsSignal(SIGCHLD, csig) == SIG_ERR) {
1411        perror("signal");
1412        return -1;
1413    }
1414
1415    return p == -1 ? -1 : status;
1416}
1417
1418static struct pid {
1419    struct pid *next;
1420    FILE *fp;
1421    int pid;
1422} *pidlist;
1423
1424void *
1425Popen(const char *command, const char *type)
1426{
1427    struct pid *cur;
1428    FILE *iop;
1429    int pdes[2], pid;
1430
1431    if (command == NULL || type == NULL)
1432        return NULL;
1433
1434    if ((*type != 'r' && *type != 'w') || type[1])
1435        return NULL;
1436
1437    if ((cur = malloc(sizeof(struct pid))) == NULL)
1438        return NULL;
1439
1440    if (pipe(pdes) < 0) {
1441        free(cur);
1442        return NULL;
1443    }
1444
1445    /* Ignore the smart scheduler while this is going on */
1446#ifdef HAVE_SETITIMER
1447    if (SmartSchedulePause() < 0) {
1448        close(pdes[0]);
1449        close(pdes[1]);
1450        free(cur);
1451        perror("signal");
1452        return NULL;
1453    }
1454#endif
1455
1456    switch (pid = fork()) {
1457    case -1:                   /* error */
1458        close(pdes[0]);
1459        close(pdes[1]);
1460        free(cur);
1461#ifdef HAVE_SETITIMER
1462        if (SmartScheduleEnable() < 0)
1463            perror("signal");
1464#endif
1465        return NULL;
1466    case 0:                    /* child */
1467        if (setgid(getgid()) == -1)
1468            _exit(127);
1469        if (setuid(getuid()) == -1)
1470            _exit(127);
1471        if (*type == 'r') {
1472            if (pdes[1] != 1) {
1473                /* stdout */
1474                dup2(pdes[1], 1);
1475                close(pdes[1]);
1476            }
1477            close(pdes[0]);
1478        }
1479        else {
1480            if (pdes[0] != 0) {
1481                /* stdin */
1482                dup2(pdes[0], 0);
1483                close(pdes[0]);
1484            }
1485            close(pdes[1]);
1486        }
1487        execl("/bin/sh", "sh", "-c", command, (char *) NULL);
1488        _exit(127);
1489    }
1490
1491    /* Avoid EINTR during stdio calls */
1492    OsBlockSignals();
1493
1494    /* parent */
1495    if (*type == 'r') {
1496        iop = fdopen(pdes[0], type);
1497        close(pdes[1]);
1498    }
1499    else {
1500        iop = fdopen(pdes[1], type);
1501        close(pdes[0]);
1502    }
1503
1504    cur->fp = iop;
1505    cur->pid = pid;
1506    cur->next = pidlist;
1507    pidlist = cur;
1508
1509    DebugF("Popen: `%s', fp = %p\n", command, iop);
1510
1511    return iop;
1512}
1513
1514/* fopen that drops privileges */
1515void *
1516Fopen(const char *file, const char *type)
1517{
1518    FILE *iop;
1519
1520#ifndef HAS_SAVED_IDS_AND_SETEUID
1521    struct pid *cur;
1522    int pdes[2], pid;
1523
1524    if (file == NULL || type == NULL)
1525        return NULL;
1526
1527    if ((*type != 'r' && *type != 'w') || type[1])
1528        return NULL;
1529
1530    if ((cur = malloc(sizeof(struct pid))) == NULL)
1531        return NULL;
1532
1533    if (pipe(pdes) < 0) {
1534        free(cur);
1535        return NULL;
1536    }
1537
1538    switch (pid = fork()) {
1539    case -1:                   /* error */
1540        close(pdes[0]);
1541        close(pdes[1]);
1542        free(cur);
1543        return NULL;
1544    case 0:                    /* child */
1545        if (setgid(getgid()) == -1)
1546            _exit(127);
1547        if (setuid(getuid()) == -1)
1548            _exit(127);
1549        if (*type == 'r') {
1550            if (pdes[1] != 1) {
1551                /* stdout */
1552                dup2(pdes[1], 1);
1553                close(pdes[1]);
1554            }
1555            close(pdes[0]);
1556        }
1557        else {
1558            if (pdes[0] != 0) {
1559                /* stdin */
1560                dup2(pdes[0], 0);
1561                close(pdes[0]);
1562            }
1563            close(pdes[1]);
1564        }
1565        execl("/bin/cat", "cat", file, (char *) NULL);
1566        _exit(127);
1567    }
1568
1569    /* Avoid EINTR during stdio calls */
1570    OsBlockSignals();
1571
1572    /* parent */
1573    if (*type == 'r') {
1574        iop = fdopen(pdes[0], type);
1575        close(pdes[1]);
1576    }
1577    else {
1578        iop = fdopen(pdes[1], type);
1579        close(pdes[0]);
1580    }
1581
1582    cur->fp = iop;
1583    cur->pid = pid;
1584    cur->next = pidlist;
1585    pidlist = cur;
1586
1587    DebugF("Fopen(%s), fp = %p\n", file, iop);
1588
1589    return iop;
1590#else
1591    int ruid, euid;
1592
1593    ruid = getuid();
1594    euid = geteuid();
1595
1596    if (seteuid(ruid) == -1) {
1597        return NULL;
1598    }
1599    iop = fopen(file, type);
1600
1601    if (seteuid(euid) == -1) {
1602        fclose(iop);
1603        return NULL;
1604    }
1605    return iop;
1606#endif                          /* HAS_SAVED_IDS_AND_SETEUID */
1607}
1608
1609int
1610Pclose(void *iop)
1611{
1612    struct pid *cur, *last;
1613    int pstat;
1614    int pid;
1615
1616    DebugF("Pclose: fp = %p\n", iop);
1617    fclose(iop);
1618
1619    for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
1620        if (cur->fp == iop)
1621            break;
1622    if (cur == NULL)
1623        return -1;
1624
1625    do {
1626        pid = waitpid(cur->pid, &pstat, 0);
1627    } while (pid == -1 && errno == EINTR);
1628
1629    if (last == NULL)
1630        pidlist = cur->next;
1631    else
1632        last->next = cur->next;
1633    free(cur);
1634
1635    /* allow EINTR again */
1636    OsReleaseSignals();
1637
1638#ifdef HAVE_SETITIMER
1639    if (SmartScheduleEnable() < 0) {
1640        perror("signal");
1641        return -1;
1642    }
1643#endif
1644
1645    return pid == -1 ? -1 : pstat;
1646}
1647
1648int
1649Fclose(void *iop)
1650{
1651#ifdef HAS_SAVED_IDS_AND_SETEUID
1652    return fclose(iop);
1653#else
1654    return Pclose(iop);
1655#endif
1656}
1657
1658#endif                          /* !WIN32 */
1659
1660#ifdef WIN32
1661
1662#include <X11/Xwindows.h>
1663
1664const char *
1665Win32TempDir(void)
1666{
1667    static char buffer[PATH_MAX];
1668
1669    if (GetTempPath(sizeof(buffer), buffer)) {
1670        int len;
1671
1672        buffer[sizeof(buffer) - 1] = 0;
1673        len = strlen(buffer);
1674        if (len > 0)
1675            if (buffer[len - 1] == '\\')
1676                buffer[len - 1] = 0;
1677        return buffer;
1678    }
1679    if (getenv("TEMP") != NULL)
1680        return getenv("TEMP");
1681    else if (getenv("TMP") != NULL)
1682        return getenv("TMP");
1683    else
1684        return "/tmp";
1685}
1686
1687int
1688System(const char *cmdline)
1689{
1690    STARTUPINFO si;
1691    PROCESS_INFORMATION pi;
1692    DWORD dwExitCode;
1693    char *cmd = strdup(cmdline);
1694
1695    ZeroMemory(&si, sizeof(si));
1696    si.cb = sizeof(si);
1697    ZeroMemory(&pi, sizeof(pi));
1698
1699    if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
1700        LPVOID buffer;
1701
1702        if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1703                           FORMAT_MESSAGE_FROM_SYSTEM |
1704                           FORMAT_MESSAGE_IGNORE_INSERTS,
1705                           NULL,
1706                           GetLastError(),
1707                           MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1708                           (LPTSTR) &buffer, 0, NULL)) {
1709            ErrorF("[xkb] Starting '%s' failed!\n", cmdline);
1710        }
1711        else {
1712            ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer);
1713            LocalFree(buffer);
1714        }
1715
1716        free(cmd);
1717        return -1;
1718    }
1719    /* Wait until child process exits. */
1720    WaitForSingleObject(pi.hProcess, INFINITE);
1721
1722    GetExitCodeProcess(pi.hProcess, &dwExitCode);
1723
1724    /* Close process and thread handles. */
1725    CloseHandle(pi.hProcess);
1726    CloseHandle(pi.hThread);
1727    free(cmd);
1728
1729    return dwExitCode;
1730}
1731#endif
1732
1733Bool
1734PrivsElevated(void)
1735{
1736    static Bool privsTested = FALSE;
1737    static Bool privsElevated = TRUE;
1738
1739    if (!privsTested) {
1740#if defined(WIN32)
1741        privsElevated = FALSE;
1742#else
1743        if ((getuid() != geteuid()) || (getgid() != getegid())) {
1744            privsElevated = TRUE;
1745        }
1746        else {
1747#if defined(HAVE_ISSETUGID)
1748            privsElevated = issetugid();
1749#elif defined(HAVE_GETRESUID)
1750            uid_t ruid, euid, suid;
1751            gid_t rgid, egid, sgid;
1752
1753            if ((getresuid(&ruid, &euid, &suid) == 0) &&
1754                (getresgid(&rgid, &egid, &sgid) == 0)) {
1755                privsElevated = (euid != suid) || (egid != sgid);
1756            }
1757            else {
1758                printf("Failed getresuid or getresgid");
1759                /* Something went wrong, make defensive assumption */
1760                privsElevated = TRUE;
1761            }
1762#else
1763            if (getuid() == 0) {
1764                /* running as root: uid==euid==0 */
1765                privsElevated = FALSE;
1766            }
1767            else {
1768                /*
1769                 * If there are saved ID's the process might still be privileged
1770                 * even though the above test succeeded. If issetugid() and
1771                 * getresgid() aren't available, test this by trying to set
1772                 * euid to 0.
1773                 */
1774                unsigned int oldeuid;
1775
1776                oldeuid = geteuid();
1777
1778                if (seteuid(0) != 0) {
1779                    privsElevated = FALSE;
1780                }
1781                else {
1782                    if (seteuid(oldeuid) != 0) {
1783                        FatalError("Failed to drop privileges.  Exiting\n");
1784                    }
1785                    privsElevated = TRUE;
1786                }
1787            }
1788#endif
1789        }
1790#endif
1791        privsTested = TRUE;
1792    }
1793    return privsElevated;
1794}
1795
1796/*
1797 * CheckUserParameters: check for long command line arguments and long
1798 * environment variables.  By default, these checks are only done when
1799 * the server's euid != ruid.  In 3.3.x, these checks were done in an
1800 * external wrapper utility.
1801 */
1802
1803/* Consider LD* variables insecure? */
1804#ifndef REMOVE_ENV_LD
1805#define REMOVE_ENV_LD 1
1806#endif
1807
1808/* Remove long environment variables? */
1809#ifndef REMOVE_LONG_ENV
1810#define REMOVE_LONG_ENV 1
1811#endif
1812
1813/*
1814 * Disallow stdout or stderr as pipes?  It's possible to block the X server
1815 * when piping stdout+stderr to a pipe.
1816 *
1817 * Don't enable this because it looks like it's going to cause problems.
1818 */
1819#ifndef NO_OUTPUT_PIPES
1820#define NO_OUTPUT_PIPES 0
1821#endif
1822
1823/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
1824#ifndef CHECK_EUID
1825#ifndef WIN32
1826#define CHECK_EUID 1
1827#else
1828#define CHECK_EUID 0
1829#endif
1830#endif
1831
1832/*
1833 * Maybe the locale can be faked to make isprint(3) report that everything
1834 * is printable?  Avoid it by default.
1835 */
1836#ifndef USE_ISPRINT
1837#define USE_ISPRINT 0
1838#endif
1839
1840#define MAX_ARG_LENGTH          128
1841#define MAX_ENV_LENGTH          256
1842#define MAX_ENV_PATH_LENGTH     2048    /* Limit for *PATH and TERMCAP */
1843
1844#if USE_ISPRINT
1845#include <ctype.h>
1846#define checkPrintable(c) isprint(c)
1847#else
1848#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
1849#endif
1850
1851enum BadCode {
1852    NotBad = 0,
1853    UnsafeArg,
1854    ArgTooLong,
1855    UnprintableArg,
1856    EnvTooLong,
1857    OutputIsPipe,
1858    InternalError
1859};
1860
1861#if defined(VENDORSUPPORT)
1862#define BUGADDRESS VENDORSUPPORT
1863#elif defined(BUILDERADDR)
1864#define BUGADDRESS BUILDERADDR
1865#else
1866#define BUGADDRESS "xorg@freedesktop.org"
1867#endif
1868
1869void
1870CheckUserParameters(int argc, char **argv, char **envp)
1871{
1872    enum BadCode bad = NotBad;
1873    int i = 0, j;
1874    char *a, *e = NULL;
1875
1876#if CHECK_EUID
1877    if (PrivsElevated())
1878#endif
1879    {
1880        /* Check each argv[] */
1881        for (i = 1; i < argc; i++) {
1882            if (strcmp(argv[i], "-fp") == 0) {
1883                i++;            /* continue with next argument. skip the length check */
1884                if (i >= argc)
1885                    break;
1886            }
1887            else {
1888                if (strlen(argv[i]) > MAX_ARG_LENGTH) {
1889                    bad = ArgTooLong;
1890                    break;
1891                }
1892            }
1893            a = argv[i];
1894            while (*a) {
1895                if (checkPrintable(*a) == 0) {
1896                    bad = UnprintableArg;
1897                    break;
1898                }
1899                a++;
1900            }
1901            if (bad)
1902                break;
1903        }
1904        if (!bad) {
1905            /* Check each envp[] */
1906            for (i = 0; envp[i]; i++) {
1907
1908                /* Check for bad environment variables and values */
1909#if REMOVE_ENV_LD
1910                while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
1911                    for (j = i; envp[j]; j++) {
1912                        envp[j] = envp[j + 1];
1913                    }
1914                }
1915#endif
1916                if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
1917#if REMOVE_LONG_ENV
1918                    for (j = i; envp[j]; j++) {
1919                        envp[j] = envp[j + 1];
1920                    }
1921                    i--;
1922#else
1923                    char *eq;
1924                    int len;
1925
1926                    eq = strchr(envp[i], '=');
1927                    if (!eq)
1928                        continue;
1929                    len = eq - envp[i];
1930                    e = strndup(envp[i], len);
1931                    if (!e) {
1932                        bad = InternalError;
1933                        break;
1934                    }
1935                    if (len >= 4 &&
1936                        (strcmp(e + len - 4, "PATH") == 0 ||
1937                         strcmp(e, "TERMCAP") == 0)) {
1938                        if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
1939                            bad = EnvTooLong;
1940                            break;
1941                        }
1942                        else {
1943                            free(e);
1944                        }
1945                    }
1946                    else {
1947                        bad = EnvTooLong;
1948                        break;
1949                    }
1950#endif
1951                }
1952            }
1953        }
1954#if NO_OUTPUT_PIPES
1955        if (!bad) {
1956            struct stat buf;
1957
1958            if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode))
1959                bad = OutputIsPipe;
1960            if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode))
1961                bad = OutputIsPipe;
1962        }
1963#endif
1964    }
1965    switch (bad) {
1966    case NotBad:
1967        return;
1968    case UnsafeArg:
1969        ErrorF("Command line argument number %d is unsafe\n", i);
1970        break;
1971    case ArgTooLong:
1972        ErrorF("Command line argument number %d is too long\n", i);
1973        break;
1974    case UnprintableArg:
1975        ErrorF("Command line argument number %d contains unprintable"
1976               " characters\n", i);
1977        break;
1978    case EnvTooLong:
1979        ErrorF("Environment variable `%s' is too long\n", e);
1980        break;
1981    case OutputIsPipe:
1982        ErrorF("Stdout and/or stderr is a pipe\n");
1983        break;
1984    case InternalError:
1985        ErrorF("Internal Error\n");
1986        break;
1987    default:
1988        ErrorF("Unknown error\n");
1989        break;
1990    }
1991    FatalError("X server aborted because of unsafe environment\n");
1992}
1993
1994/*
1995 * CheckUserAuthorization: check if the user is allowed to start the
1996 * X server.  This usually means some sort of PAM checking, and it is
1997 * usually only done for setuid servers (uid != euid).
1998 */
1999
2000#ifdef USE_PAM
2001#include <security/pam_appl.h>
2002#include <security/pam_misc.h>
2003#include <pwd.h>
2004#endif                          /* USE_PAM */
2005
2006void
2007CheckUserAuthorization(void)
2008{
2009#ifdef USE_PAM
2010    static struct pam_conv conv = {
2011        misc_conv,
2012        NULL
2013    };
2014
2015    pam_handle_t *pamh = NULL;
2016    struct passwd *pw;
2017    int retval;
2018
2019    if (getuid() != geteuid()) {
2020        pw = getpwuid(getuid());
2021        if (pw == NULL)
2022            FatalError("getpwuid() failed for uid %d\n", getuid());
2023
2024        retval = pam_start("xserver", pw->pw_name, &conv, &pamh);
2025        if (retval != PAM_SUCCESS)
2026            FatalError("pam_start() failed.\n"
2027                       "\tMissing or mangled PAM config file or module?\n");
2028
2029        retval = pam_authenticate(pamh, 0);
2030        if (retval != PAM_SUCCESS) {
2031            pam_end(pamh, retval);
2032            FatalError("PAM authentication failed, cannot start X server.\n"
2033                       "\tPerhaps you do not have console ownership?\n");
2034        }
2035
2036        retval = pam_acct_mgmt(pamh, 0);
2037        if (retval != PAM_SUCCESS) {
2038            pam_end(pamh, retval);
2039            FatalError("PAM authentication failed, cannot start X server.\n"
2040                       "\tPerhaps you do not have console ownership?\n");
2041        }
2042
2043        /* this is not a session, so do not do session management */
2044        pam_end(pamh, PAM_SUCCESS);
2045    }
2046#endif
2047}
2048
2049/*
2050 * Tokenize a string into a NULL terminated array of strings. Always returns
2051 * an allocated array unless an error occurs.
2052 */
2053char **
2054xstrtokenize(const char *str, const char *separators)
2055{
2056    char **list, **nlist;
2057    char *tok, *tmp;
2058    unsigned num = 0, n;
2059
2060    if (!str)
2061        return NULL;
2062    list = calloc(1, sizeof(*list));
2063    if (!list)
2064        return NULL;
2065    tmp = strdup(str);
2066    if (!tmp)
2067        goto error;
2068    for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) {
2069        nlist = reallocarray(list, num + 2, sizeof(*list));
2070        if (!nlist)
2071            goto error;
2072        list = nlist;
2073        list[num] = strdup(tok);
2074        if (!list[num])
2075            goto error;
2076        list[++num] = NULL;
2077    }
2078    free(tmp);
2079    return list;
2080
2081 error:
2082    free(tmp);
2083    for (n = 0; n < num; n++)
2084        free(list[n]);
2085    free(list);
2086    return NULL;
2087}
2088
2089/* Format a signed number into a string in a signal safe manner. The string
2090 * should be at least 21 characters in order to handle all int64_t values.
2091 */
2092void
2093FormatInt64(int64_t num, char *string)
2094{
2095    if (num < 0) {
2096        string[0] = '-';
2097        num *= -1;
2098        string++;
2099    }
2100    FormatUInt64(num, string);
2101}
2102
2103/* Format a number into a string in a signal safe manner. The string should be
2104 * at least 21 characters in order to handle all uint64_t values. */
2105void
2106FormatUInt64(uint64_t num, char *string)
2107{
2108    uint64_t divisor;
2109    int len;
2110    int i;
2111
2112    for (len = 1, divisor = 10;
2113         len < 20 && num / divisor;
2114         len++, divisor *= 10);
2115
2116    for (i = len, divisor = 1; i > 0; i--, divisor *= 10)
2117        string[i - 1] = '0' + ((num / divisor) % 10);
2118
2119    string[len] = '\0';
2120}
2121
2122/**
2123 * Format a double number as %.2f.
2124 */
2125void
2126FormatDouble(double dbl, char *string)
2127{
2128    int slen = 0;
2129    uint64_t frac;
2130
2131    frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5;
2132    frac %= 100;
2133
2134    /* write decimal part to string */
2135    if (dbl < 0 && dbl > -1)
2136        string[slen++] = '-';
2137    FormatInt64((int64_t)dbl, &string[slen]);
2138
2139    while(string[slen] != '\0')
2140        slen++;
2141
2142    /* append fractional part, but only if we have enough characters. We
2143     * expect string to be 21 chars (incl trailing \0) */
2144    if (slen <= 17) {
2145        string[slen++] = '.';
2146        if (frac < 10)
2147            string[slen++] = '0';
2148
2149        FormatUInt64(frac, &string[slen]);
2150    }
2151}
2152
2153
2154/* Format a number into a hexadecimal string in a signal safe manner. The string
2155 * should be at least 17 characters in order to handle all uint64_t values. */
2156void
2157FormatUInt64Hex(uint64_t num, char *string)
2158{
2159    uint64_t divisor;
2160    int len;
2161    int i;
2162
2163    for (len = 1, divisor = 0x10;
2164         len < 16 && num / divisor;
2165         len++, divisor *= 0x10);
2166
2167    for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) {
2168        int val = (num / divisor) % 0x10;
2169
2170        if (val < 10)
2171            string[i - 1] = '0' + val;
2172        else
2173            string[i - 1] = 'a' + val - 10;
2174    }
2175
2176    string[len] = '\0';
2177}
2178
2179#if !defined(WIN32) || defined(__CYGWIN__)
2180/* Move a file descriptor out of the way of our select mask; this
2181 * is useful for file descriptors which will never appear in the
2182 * select mask to avoid reducing the number of clients that can
2183 * connect to the server
2184 */
2185int
2186os_move_fd(int fd)
2187{
2188    int newfd;
2189
2190#ifdef F_DUPFD_CLOEXEC
2191    newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS);
2192#else
2193    newfd = fcntl(fd, F_DUPFD, MAXCLIENTS);
2194#endif
2195    if (newfd < 0)
2196        return fd;
2197#ifndef F_DUPFD_CLOEXEC
2198    fcntl(newfd, F_SETFD, FD_CLOEXEC);
2199#endif
2200    close(fd);
2201    return newfd;
2202}
2203#endif
2204