utils.c revision 7e31ba66
105b261ecSmrg/*
205b261ecSmrg
305b261ecSmrgCopyright 1987, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included
1205b261ecSmrgin all copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1505b261ecSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1605b261ecSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1705b261ecSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
1805b261ecSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1905b261ecSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2005b261ecSmrgOTHER DEALINGS IN THE SOFTWARE.
2105b261ecSmrg
2205b261ecSmrgExcept as contained in this notice, the name of The Open Group shall
2305b261ecSmrgnot be used in advertising or otherwise to promote the sale, use or
2405b261ecSmrgother dealings in this Software without prior written authorization
2505b261ecSmrgfrom The Open Group.
2605b261ecSmrg
2705b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
2805b261ecSmrgCopyright 1994 Quarterdeck Office Systems.
2905b261ecSmrg
3005b261ecSmrg                        All Rights Reserved
3105b261ecSmrg
3205b261ecSmrgPermission to use, copy, modify, and distribute this software and its
3305b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
3405b261ecSmrgprovided that the above copyright notice appear in all copies and that
3505b261ecSmrgboth that copyright notice and this permission notice appear in
3605b261ecSmrgsupporting documentation, and that the names of Digital and
3705b261ecSmrgQuarterdeck not be used in advertising or publicity pertaining to
3805b261ecSmrgdistribution of the software without specific, written prior
3905b261ecSmrgpermission.
4005b261ecSmrg
4105b261ecSmrgDIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
4205b261ecSmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
4305b261ecSmrgFITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
4405b261ecSmrgOR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
4505b261ecSmrgOF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
4605b261ecSmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
4705b261ecSmrgOR PERFORMANCE OF THIS SOFTWARE.
4805b261ecSmrg
4905b261ecSmrg*/
5005b261ecSmrg
5105b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
5205b261ecSmrg#include <dix-config.h>
5305b261ecSmrg#endif
5405b261ecSmrg
5505b261ecSmrg#ifdef __CYGWIN__
5605b261ecSmrg#include <stdlib.h>
5705b261ecSmrg#include <signal.h>
584202a189Smrg/*
594202a189Smrg   Sigh... We really need a prototype for this to know it is stdcall,
604202a189Smrg   but #include-ing <windows.h> here is not a good idea...
614202a189Smrg*/
624202a189Smrg__stdcall unsigned long GetTickCount(void);
6305b261ecSmrg#endif
6405b261ecSmrg
6505b261ecSmrg#if defined(WIN32) && !defined(__CYGWIN__)
6605b261ecSmrg#include <X11/Xwinsock.h>
6705b261ecSmrg#endif
6805b261ecSmrg#include <X11/Xos.h>
6905b261ecSmrg#include <stdio.h>
7005b261ecSmrg#include <time.h>
7105b261ecSmrg#if !defined(WIN32) || !defined(__MINGW32__)
7205b261ecSmrg#include <sys/time.h>
7305b261ecSmrg#include <sys/resource.h>
7405b261ecSmrg#endif
7505b261ecSmrg#include "misc.h"
7605b261ecSmrg#include <X11/X.h>
7705b261ecSmrg#define XSERV_t
7805b261ecSmrg#define TRANS_SERVER
7905b261ecSmrg#define TRANS_REOPEN
8005b261ecSmrg#include <X11/Xtrans/Xtrans.h>
8105b261ecSmrg#include "input.h"
8205b261ecSmrg#include "dixfont.h"
837e31ba66Smrg#include <X11/fonts/libxfont2.h>
8405b261ecSmrg#include "osdep.h"
8505b261ecSmrg#include "extension.h"
8605b261ecSmrg#include <signal.h>
8705b261ecSmrg#ifndef WIN32
8805b261ecSmrg#include <sys/wait.h>
8905b261ecSmrg#endif
90f7df2e56Smrg#if !defined(SYSV) && !defined(WIN32)
9105b261ecSmrg#include <sys/resource.h>
9205b261ecSmrg#endif
9305b261ecSmrg#include <sys/stat.h>
94f7df2e56Smrg#include <ctype.h>              /* for isspace */
9505b261ecSmrg#include <stdarg.h>
9605b261ecSmrg
97f7df2e56Smrg#include <stdlib.h>             /* for malloc() */
9805b261ecSmrg
997e31ba66Smrg#if defined(TCPCONN)
100f7df2e56Smrg#ifndef WIN32
101f7df2e56Smrg#include <netdb.h>
102f7df2e56Smrg#endif
10305b261ecSmrg#endif
10405b261ecSmrg
10505b261ecSmrg#include "opaque.h"
10605b261ecSmrg
10705b261ecSmrg#include "dixstruct.h"
10805b261ecSmrg
1094202a189Smrg#include "xkbsrv.h"
11005b261ecSmrg
11105b261ecSmrg#include "picture.h"
11205b261ecSmrg
1134202a189SmrgBool noTestExtensions;
114f7df2e56Smrg
11505b261ecSmrg#ifdef COMPOSITE
1164202a189SmrgBool noCompositeExtension = FALSE;
11705b261ecSmrg#endif
11805b261ecSmrg
11905b261ecSmrg#ifdef DAMAGE
1204202a189SmrgBool noDamageExtension = FALSE;
12105b261ecSmrg#endif
12205b261ecSmrg#ifdef DBE
1234202a189SmrgBool noDbeExtension = FALSE;
12405b261ecSmrg#endif
12505b261ecSmrg#ifdef DPMSExtension
1267e31ba66Smrg#include "dpmsproc.h"
1274202a189SmrgBool noDPMSExtension = FALSE;
12805b261ecSmrg#endif
12905b261ecSmrg#ifdef GLXEXT
1304202a189SmrgBool noGlxExtension = FALSE;
13105b261ecSmrg#endif
13205b261ecSmrg#ifdef SCREENSAVER
1334202a189SmrgBool noScreenSaverExtension = FALSE;
13405b261ecSmrg#endif
13505b261ecSmrg#ifdef MITSHM
1364202a189SmrgBool noMITShmExtension = FALSE;
13705b261ecSmrg#endif
13805b261ecSmrg#ifdef RANDR
1394202a189SmrgBool noRRExtension = FALSE;
14005b261ecSmrg#endif
1414202a189SmrgBool noRenderExtension = FALSE;
142f7df2e56Smrg
14305b261ecSmrg#ifdef XCSECURITY
1444202a189SmrgBool noSecurityExtension = FALSE;
14505b261ecSmrg#endif
14605b261ecSmrg#ifdef RES
1474202a189SmrgBool noResExtension = FALSE;
14805b261ecSmrg#endif
14905b261ecSmrg#ifdef XF86BIGFONT
1504202a189SmrgBool noXFree86BigfontExtension = FALSE;
15105b261ecSmrg#endif
15205b261ecSmrg#ifdef XFreeXDGA
1534202a189SmrgBool noXFree86DGAExtension = FALSE;
15405b261ecSmrg#endif
15505b261ecSmrg#ifdef XF86DRI
1564202a189SmrgBool noXFree86DRIExtension = FALSE;
15705b261ecSmrg#endif
15805b261ecSmrg#ifdef XF86VIDMODE
1594202a189SmrgBool noXFree86VidModeExtension = FALSE;
16005b261ecSmrg#endif
1614202a189SmrgBool noXFixesExtension = FALSE;
16205b261ecSmrg#ifdef PANORAMIX
16305b261ecSmrg/* Xinerama is disabled by default unless enabled via +xinerama */
1644202a189SmrgBool noPanoramiXExtension = TRUE;
16505b261ecSmrg#endif
1664642e01fSmrg#ifdef XSELINUX
1674202a189SmrgBool noSELinuxExtension = FALSE;
1684202a189Smrgint selinuxEnforcingState = SELINUX_MODE_DEFAULT;
16905b261ecSmrg#endif
17005b261ecSmrg#ifdef XV
1714202a189SmrgBool noXvExtension = FALSE;
17205b261ecSmrg#endif
1734642e01fSmrg#ifdef DRI2
1744202a189SmrgBool noDRI2Extension = FALSE;
1754642e01fSmrg#endif
1764642e01fSmrg
1774202a189SmrgBool noGEExtension = FALSE;
17805b261ecSmrg
17905b261ecSmrg#define X_INCLUDE_NETDB_H
18005b261ecSmrg#include <X11/Xos_r.h>
18105b261ecSmrg
18205b261ecSmrg#include <errno.h>
18305b261ecSmrg
18405b261ecSmrgBool CoreDump;
18505b261ecSmrg
186f7df2e56SmrgBool enableIndirectGLX = FALSE;
187f7df2e56Smrg
18805b261ecSmrg#ifdef PANORAMIX
18905b261ecSmrgBool PanoramiXExtensionDisabledHack = FALSE;
19005b261ecSmrg#endif
19105b261ecSmrg
19205b261ecSmrgint auditTrailLevel = 1;
19305b261ecSmrg
194f7df2e56Smrgchar *SeatId = NULL;
195f7df2e56Smrg
196f7df2e56Smrgsig_atomic_t inSignalContext = FALSE;
197f7df2e56Smrg
19805b261ecSmrg#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
19905b261ecSmrg#define HAS_SAVED_IDS_AND_SETEUID
20005b261ecSmrg#endif
20105b261ecSmrg
2027e31ba66Smrg#ifdef MONOTONIC_CLOCK
2037e31ba66Smrgstatic clockid_t clockid;
2047e31ba66Smrg#endif
2057e31ba66Smrg
20605b261ecSmrgOsSigHandlerPtr
2074202a189SmrgOsSignal(int sig, OsSigHandlerPtr handler)
20805b261ecSmrg{
209f7df2e56Smrg#if defined(WIN32) && !defined(__CYGWIN__)
210f7df2e56Smrg    return signal(sig, handler);
211f7df2e56Smrg#else
21205b261ecSmrg    struct sigaction act, oact;
21305b261ecSmrg
21405b261ecSmrg    sigemptyset(&act.sa_mask);
21505b261ecSmrg    if (handler != SIG_IGN)
216f7df2e56Smrg        sigaddset(&act.sa_mask, sig);
21705b261ecSmrg    act.sa_flags = 0;
21805b261ecSmrg    act.sa_handler = handler;
21905b261ecSmrg    if (sigaction(sig, &act, &oact))
220f7df2e56Smrg        perror("sigaction");
22105b261ecSmrg    return oact.sa_handler;
222f7df2e56Smrg#endif
22305b261ecSmrg}
2244642e01fSmrg
22505b261ecSmrg/*
22605b261ecSmrg * Explicit support for a server lock file like the ones used for UUCP.
22705b261ecSmrg * For architectures with virtual terminals that can run more than one
22805b261ecSmrg * server at a time.  This keeps the servers from stomping on each other
22905b261ecSmrg * if the user forgets to give them different display numbers.
23005b261ecSmrg */
23105b261ecSmrg#define LOCK_DIR "/tmp"
23205b261ecSmrg#define LOCK_TMP_PREFIX "/.tX"
23305b261ecSmrg#define LOCK_PREFIX "/.X"
23405b261ecSmrg#define LOCK_SUFFIX "-lock"
23505b261ecSmrg
236f7df2e56Smrg#if !defined(WIN32) || defined(__CYGWIN__)
237f7df2e56Smrg#define LOCK_SERVER
23805b261ecSmrg#endif
23905b261ecSmrg
240f7df2e56Smrg#ifndef LOCK_SERVER
241f7df2e56Smrgvoid
242f7df2e56SmrgLockServer(void)
243f7df2e56Smrg{}
244f7df2e56Smrg
245f7df2e56Smrgvoid
246f7df2e56SmrgUnlockServer(void)
247f7df2e56Smrg{}
248f7df2e56Smrg#else /* LOCK_SERVER */
24905b261ecSmrgstatic Bool StillLocking = FALSE;
25005b261ecSmrgstatic char LockFile[PATH_MAX];
25105b261ecSmrgstatic Bool nolock = FALSE;
25205b261ecSmrg
25305b261ecSmrg/*
25405b261ecSmrg * LockServer --
25505b261ecSmrg *      Check if the server lock file exists.  If so, check if the PID
25605b261ecSmrg *      contained inside is valid.  If so, then die.  Otherwise, create
25705b261ecSmrg *      the lock file containing the PID.
25805b261ecSmrg */
25905b261ecSmrgvoid
26005b261ecSmrgLockServer(void)
26105b261ecSmrg{
262f7df2e56Smrg    char tmp[PATH_MAX], pid_str[12];
263f7df2e56Smrg    int lfd, i, haslock, l_pid, t;
264f7df2e56Smrg    const char *tmppath = LOCK_DIR;
265f7df2e56Smrg    int len;
266f7df2e56Smrg    char port[20];
267f7df2e56Smrg
268f7df2e56Smrg    if (nolock || NoListenAll)
269f7df2e56Smrg        return;
270f7df2e56Smrg    /*
271f7df2e56Smrg     * Path names
272f7df2e56Smrg     */
273f7df2e56Smrg    snprintf(port, sizeof(port), "%d", atoi(display));
274f7df2e56Smrg    len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) :
275f7df2e56Smrg        strlen(LOCK_TMP_PREFIX);
276f7df2e56Smrg    len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1;
277f7df2e56Smrg    if (len > sizeof(LockFile))
278f7df2e56Smrg        FatalError("Display name `%s' is too long\n", port);
279f7df2e56Smrg    (void) sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
280f7df2e56Smrg    (void) sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
281f7df2e56Smrg
282f7df2e56Smrg    /*
283f7df2e56Smrg     * Create a temporary file containing our PID.  Attempt three times
284f7df2e56Smrg     * to create the file.
285f7df2e56Smrg     */
286f7df2e56Smrg    StillLocking = TRUE;
28705b261ecSmrg    i = 0;
28805b261ecSmrg    do {
289f7df2e56Smrg        i++;
290f7df2e56Smrg        lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
291f7df2e56Smrg        if (lfd < 0)
292f7df2e56Smrg            sleep(2);
293f7df2e56Smrg        else
294f7df2e56Smrg            break;
29505b261ecSmrg    } while (i < 3);
296f7df2e56Smrg    if (lfd < 0) {
29705b261ecSmrg        unlink(tmp);
298f7df2e56Smrg        i = 0;
299f7df2e56Smrg        do {
300f7df2e56Smrg            i++;
301f7df2e56Smrg            lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
302f7df2e56Smrg            if (lfd < 0)
303f7df2e56Smrg                sleep(2);
304f7df2e56Smrg            else
305f7df2e56Smrg                break;
306f7df2e56Smrg        } while (i < 3);
30705b261ecSmrg    }
308f7df2e56Smrg    if (lfd < 0)
309f7df2e56Smrg        FatalError("Could not create lock file in %s\n", tmp);
3107e31ba66Smrg    snprintf(pid_str, sizeof(pid_str), "%10lu\n", (unsigned long) getpid());
311f7df2e56Smrg    if (write(lfd, pid_str, 11) != 11)
312f7df2e56Smrg        FatalError("Could not write pid to lock file in %s\n", tmp);
313f7df2e56Smrg    (void) fchmod(lfd, 0444);
314f7df2e56Smrg    (void) close(lfd);
315f7df2e56Smrg
316f7df2e56Smrg    /*
317f7df2e56Smrg     * OK.  Now the tmp file exists.  Try three times to move it in place
318f7df2e56Smrg     * for the lock.
319f7df2e56Smrg     */
320f7df2e56Smrg    i = 0;
321f7df2e56Smrg    haslock = 0;
322f7df2e56Smrg    while ((!haslock) && (i++ < 3)) {
323f7df2e56Smrg        haslock = (link(tmp, LockFile) == 0);
324f7df2e56Smrg        if (haslock) {
325f7df2e56Smrg            /*
326f7df2e56Smrg             * We're done.
327f7df2e56Smrg             */
328f7df2e56Smrg            break;
329f7df2e56Smrg        }
330f7df2e56Smrg        else {
331f7df2e56Smrg            /*
332f7df2e56Smrg             * Read the pid from the existing file
333f7df2e56Smrg             */
334f7df2e56Smrg            lfd = open(LockFile, O_RDONLY | O_NOFOLLOW);
335f7df2e56Smrg            if (lfd < 0) {
336f7df2e56Smrg                unlink(tmp);
337f7df2e56Smrg                FatalError("Can't read lock file %s\n", LockFile);
338f7df2e56Smrg            }
339f7df2e56Smrg            pid_str[0] = '\0';
340f7df2e56Smrg            if (read(lfd, pid_str, 11) != 11) {
341f7df2e56Smrg                /*
342f7df2e56Smrg                 * Bogus lock file.
343f7df2e56Smrg                 */
344f7df2e56Smrg                unlink(LockFile);
345f7df2e56Smrg                close(lfd);
346f7df2e56Smrg                continue;
347f7df2e56Smrg            }
348f7df2e56Smrg            pid_str[11] = '\0';
349f7df2e56Smrg            sscanf(pid_str, "%d", &l_pid);
350f7df2e56Smrg            close(lfd);
351f7df2e56Smrg
352f7df2e56Smrg            /*
353f7df2e56Smrg             * Now try to kill the PID to see if it exists.
354f7df2e56Smrg             */
355f7df2e56Smrg            errno = 0;
356f7df2e56Smrg            t = kill(l_pid, 0);
357f7df2e56Smrg            if ((t < 0) && (errno == ESRCH)) {
358f7df2e56Smrg                /*
359f7df2e56Smrg                 * Stale lock file.
360f7df2e56Smrg                 */
361f7df2e56Smrg                unlink(LockFile);
362f7df2e56Smrg                continue;
363f7df2e56Smrg            }
364f7df2e56Smrg            else if (((t < 0) && (errno == EPERM)) || (t == 0)) {
365f7df2e56Smrg                /*
366f7df2e56Smrg                 * Process is still active.
367f7df2e56Smrg                 */
368f7df2e56Smrg                unlink(tmp);
369f7df2e56Smrg                FatalError
370f7df2e56Smrg                    ("Server is already active for display %s\n%s %s\n%s\n",
371f7df2e56Smrg                     port, "\tIf this server is no longer running, remove",
372f7df2e56Smrg                     LockFile, "\tand start again.");
373f7df2e56Smrg            }
374f7df2e56Smrg        }
375f7df2e56Smrg    }
376f7df2e56Smrg    unlink(tmp);
377f7df2e56Smrg    if (!haslock)
378f7df2e56Smrg        FatalError("Could not create server lock file: %s\n", LockFile);
379f7df2e56Smrg    StillLocking = FALSE;
38005b261ecSmrg}
38105b261ecSmrg
38205b261ecSmrg/*
38305b261ecSmrg * UnlockServer --
38405b261ecSmrg *      Remove the server lock file.
38505b261ecSmrg */
38605b261ecSmrgvoid
38705b261ecSmrgUnlockServer(void)
38805b261ecSmrg{
389f7df2e56Smrg    if (nolock || NoListenAll)
390f7df2e56Smrg        return;
39105b261ecSmrg
392f7df2e56Smrg    if (!StillLocking) {
39305b261ecSmrg
394f7df2e56Smrg        (void) unlink(LockFile);
395f7df2e56Smrg    }
39605b261ecSmrg}
397f7df2e56Smrg#endif /* LOCK_SERVER */
39805b261ecSmrg
39905b261ecSmrg/* Force connections to close on SIGHUP from init */
40005b261ecSmrg
4014202a189Smrgvoid
402f7df2e56SmrgAutoResetServer(int sig)
40305b261ecSmrg{
40405b261ecSmrg    int olderrno = errno;
40505b261ecSmrg
40605b261ecSmrg    dispatchException |= DE_RESET;
40705b261ecSmrg    isItTimeToYield = TRUE;
40805b261ecSmrg    errno = olderrno;
40905b261ecSmrg}
41005b261ecSmrg
41105b261ecSmrg/* Force connections to close and then exit on SIGTERM, SIGINT */
41205b261ecSmrg
4134202a189Smrgvoid
41405b261ecSmrgGiveUp(int sig)
41505b261ecSmrg{
41605b261ecSmrg    int olderrno = errno;
41705b261ecSmrg
41805b261ecSmrg    dispatchException |= DE_TERMINATE;
41905b261ecSmrg    isItTimeToYield = TRUE;
42005b261ecSmrg    errno = olderrno;
42105b261ecSmrg}
42205b261ecSmrg
4237e31ba66Smrg#ifdef MONOTONIC_CLOCK
4247e31ba66Smrgvoid
4257e31ba66SmrgForceClockId(clockid_t forced_clockid)
4267e31ba66Smrg{
4277e31ba66Smrg    struct timespec tp;
4287e31ba66Smrg
4297e31ba66Smrg    BUG_RETURN (clockid);
4307e31ba66Smrg
4317e31ba66Smrg    clockid = forced_clockid;
4327e31ba66Smrg
4337e31ba66Smrg    if (clock_gettime(clockid, &tp) != 0) {
4347e31ba66Smrg        FatalError("Forced clock id failed to retrieve current time: %s\n",
4357e31ba66Smrg                   strerror(errno));
4367e31ba66Smrg        return;
4377e31ba66Smrg    }
4387e31ba66Smrg}
4397e31ba66Smrg#endif
4407e31ba66Smrg
4414202a189Smrg#if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__)
4424202a189SmrgCARD32
443f7df2e56SmrgGetTimeInMillis(void)
444f7df2e56Smrg{
445f7df2e56Smrg    return GetTickCount();
446f7df2e56Smrg}
447f7df2e56SmrgCARD64
448f7df2e56SmrgGetTimeInMicros(void)
44905b261ecSmrg{
450f7df2e56Smrg    return (CARD64) GetTickCount() * 1000;
45105b261ecSmrg}
45205b261ecSmrg#else
4534202a189SmrgCARD32
45405b261ecSmrgGetTimeInMillis(void)
45505b261ecSmrg{
45605b261ecSmrg    struct timeval tv;
45705b261ecSmrg
45805b261ecSmrg#ifdef MONOTONIC_CLOCK
45905b261ecSmrg    struct timespec tp;
460f7df2e56Smrg
4611b684552Smrg    if (!clockid) {
4621b684552Smrg#ifdef CLOCK_MONOTONIC_COARSE
4631b684552Smrg        if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
4641b684552Smrg            (tp.tv_nsec / 1000) <= 1000 &&
4651b684552Smrg            clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
4661b684552Smrg            clockid = CLOCK_MONOTONIC_COARSE;
4671b684552Smrg        else
4681b684552Smrg#endif
4691b684552Smrg        if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
4701b684552Smrg            clockid = CLOCK_MONOTONIC;
4711b684552Smrg        else
4721b684552Smrg            clockid = ~0L;
4731b684552Smrg    }
4741b684552Smrg    if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
47505b261ecSmrg        return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
47605b261ecSmrg#endif
47705b261ecSmrg
47805b261ecSmrg    X_GETTIMEOFDAY(&tv);
479f7df2e56Smrg    return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
480f7df2e56Smrg}
481f7df2e56Smrg
482f7df2e56SmrgCARD64
483f7df2e56SmrgGetTimeInMicros(void)
484f7df2e56Smrg{
485f7df2e56Smrg    struct timeval tv;
486f7df2e56Smrg#ifdef MONOTONIC_CLOCK
487f7df2e56Smrg    struct timespec tp;
488f7df2e56Smrg
489f7df2e56Smrg    if (!clockid) {
490f7df2e56Smrg        if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
491f7df2e56Smrg            clockid = CLOCK_MONOTONIC;
492f7df2e56Smrg        else
493f7df2e56Smrg            clockid = ~0L;
494f7df2e56Smrg    }
495f7df2e56Smrg    if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
496f7df2e56Smrg        return (CARD64) tp.tv_sec * (CARD64)1000000 + tp.tv_nsec / 1000;
497f7df2e56Smrg#endif
498f7df2e56Smrg
499f7df2e56Smrg    X_GETTIMEOFDAY(&tv);
5007e31ba66Smrg    return (CARD64) tv.tv_sec * (CARD64)1000000 + (CARD64) tv.tv_usec;
50105b261ecSmrg}
50205b261ecSmrg#endif
50305b261ecSmrg
504f7df2e56Smrgvoid
505f7df2e56SmrgUseMsg(void)
50605b261ecSmrg{
50705b261ecSmrg    ErrorF("use: X [:<display>] [option]\n");
5084202a189Smrg    ErrorF("-a #                   default pointer acceleration (factor)\n");
50905b261ecSmrg    ErrorF("-ac                    disable access control restrictions\n");
510f7df2e56Smrg    ErrorF("-audit int             set audit trail level\n");
511f7df2e56Smrg    ErrorF("-auth file             select authorization file\n");
51205b261ecSmrg    ErrorF("-br                    create root window with black background\n");
51305b261ecSmrg    ErrorF("+bs                    enable any backing store support\n");
51405b261ecSmrg    ErrorF("-bs                    disable any backing store support\n");
51505b261ecSmrg    ErrorF("-c                     turns off key-click\n");
51605b261ecSmrg    ErrorF("c #                    key-click volume (0-100)\n");
51705b261ecSmrg    ErrorF("-cc int                default color visual class\n");
5184202a189Smrg    ErrorF("-nocursor              disable the cursor\n");
51905b261ecSmrg    ErrorF("-core                  generate core dump on fatal error\n");
520f7df2e56Smrg    ErrorF("-displayfd fd          file descriptor to write display number to when ready to connect\n");
52105b261ecSmrg    ErrorF("-dpi int               screen resolution in dots per inch\n");
52205b261ecSmrg#ifdef DPMSExtension
52305b261ecSmrg    ErrorF("-dpms                  disables VESA DPMS monitor control\n");
52405b261ecSmrg#endif
525f7df2e56Smrg    ErrorF
526f7df2e56Smrg        ("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n");
52705b261ecSmrg    ErrorF("-f #                   bell base (0-100)\n");
52805b261ecSmrg    ErrorF("-fc string             cursor font\n");
52905b261ecSmrg    ErrorF("-fn string             default font name\n");
53005b261ecSmrg    ErrorF("-fp string             default font path\n");
53105b261ecSmrg    ErrorF("-help                  prints message with these options\n");
532f7df2e56Smrg    ErrorF("+iglx                  Allow creating indirect GLX contexts\n");
533f7df2e56Smrg    ErrorF("-iglx                  Prohibit creating indirect GLX contexts (default)\n");
53405b261ecSmrg    ErrorF("-I                     ignore all remaining arguments\n");
53505b261ecSmrg#ifdef RLIMIT_DATA
53605b261ecSmrg    ErrorF("-ld int                limit data space to N Kb\n");
53705b261ecSmrg#endif
53805b261ecSmrg#ifdef RLIMIT_NOFILE
53905b261ecSmrg    ErrorF("-lf int                limit number of open files to N\n");
54005b261ecSmrg#endif
54105b261ecSmrg#ifdef RLIMIT_STACK
54205b261ecSmrg    ErrorF("-ls int                limit stack space to N Kb\n");
54305b261ecSmrg#endif
544f7df2e56Smrg#ifdef LOCK_SERVER
54505b261ecSmrg    ErrorF("-nolock                disable the locking mechanism\n");
546f7df2e56Smrg#endif
547f7df2e56Smrg    ErrorF("-maxclients n          set maximum number of clients (power of two)\n");
54805b261ecSmrg    ErrorF("-nolisten string       don't listen on protocol\n");
549f7df2e56Smrg    ErrorF("-listen string         listen on protocol\n");
55005b261ecSmrg    ErrorF("-noreset               don't reset after last client exists\n");
55165b04b38Smrg    ErrorF("-background [none]     create root window with no background\n");
55205b261ecSmrg    ErrorF("-reset                 reset after last client exists\n");
55305b261ecSmrg    ErrorF("-p #                   screen-saver pattern duration (minutes)\n");
55405b261ecSmrg    ErrorF("-pn                    accept failure to listen on all ports\n");
55505b261ecSmrg    ErrorF("-nopn                  reject failure to listen on all ports\n");
55605b261ecSmrg    ErrorF("-r                     turns off auto-repeat\n");
55705b261ecSmrg    ErrorF("r                      turns on auto-repeat \n");
55805b261ecSmrg    ErrorF("-render [default|mono|gray|color] set render color alloc policy\n");
5594642e01fSmrg    ErrorF("-retro                 start with classic stipple and cursor\n");
560daf23d7fSsnj    ErrorF("-noretro               start with black background and no cursor\n");
56105b261ecSmrg    ErrorF("-s #                   screen-saver timeout (minutes)\n");
562f7df2e56Smrg    ErrorF("-seat string           seat to run on\n");
5634202a189Smrg    ErrorF("-t #                   default pointer threshold (pixels/t)\n");
56405b261ecSmrg    ErrorF("-terminate             terminate at server reset\n");
56505b261ecSmrg    ErrorF("-to #                  connection time out\n");
56605b261ecSmrg    ErrorF("-tst                   disable testing extensions\n");
56705b261ecSmrg    ErrorF("ttyxx                  server started from init on /dev/ttyxx\n");
56805b261ecSmrg    ErrorF("v                      video blanking for screen-saver\n");
56905b261ecSmrg    ErrorF("-v                     screen-saver without video blanking\n");
57005b261ecSmrg    ErrorF("-wm                    WhenMapped default backing-store\n");
57105b261ecSmrg    ErrorF("-wr                    create root window with white background\n");
57205b261ecSmrg    ErrorF("-maxbigreqsize         set maximal bigrequest size \n");
57305b261ecSmrg#ifdef PANORAMIX
57405b261ecSmrg    ErrorF("+xinerama              Enable XINERAMA extension\n");
57505b261ecSmrg    ErrorF("-xinerama              Disable XINERAMA extension\n");
57605b261ecSmrg#endif
577f7df2e56Smrg    ErrorF
5787e31ba66Smrg        ("-dumbSched             Disable smart scheduling and threaded input, enable old behavior\n");
57905b261ecSmrg    ErrorF("-schedInterval int     Set scheduler interval in msec\n");
58065b04b38Smrg    ErrorF("-sigstop               Enable SIGSTOP based startup\n");
58105b261ecSmrg    ErrorF("+extension name        Enable extension\n");
58205b261ecSmrg    ErrorF("-extension name        Disable extension\n");
58305b261ecSmrg#ifdef XDMCP
58405b261ecSmrg    XdmcpUseMsg();
58505b261ecSmrg#endif
58605b261ecSmrg    XkbUseMsg();
58705b261ecSmrg    ddxUseMsg();
58805b261ecSmrg}
58905b261ecSmrg
59005b261ecSmrg/*  This function performs a rudimentary sanity check
59105b261ecSmrg *  on the display name passed in on the command-line,
59205b261ecSmrg *  since this string is used to generate filenames.
59305b261ecSmrg *  It is especially important that the display name
59405b261ecSmrg *  not contain a "/" and not start with a "-".
59505b261ecSmrg *                                            --kvajk
59605b261ecSmrg */
597f7df2e56Smrgstatic int
59805b261ecSmrgVerifyDisplayName(const char *d)
59905b261ecSmrg{
600f7df2e56Smrg    int i;
601f7df2e56Smrg    int period_found = FALSE;
602f7df2e56Smrg    int after_period = 0;
603f7df2e56Smrg
604f7df2e56Smrg    if (d == (char *) 0)
605f7df2e56Smrg        return 0;               /*  null  */
606f7df2e56Smrg    if (*d == '\0')
607f7df2e56Smrg        return 0;               /*  empty  */
608f7df2e56Smrg    if (*d == '-')
609f7df2e56Smrg        return 0;               /*  could be confused for an option  */
610f7df2e56Smrg    if (*d == '.')
611f7df2e56Smrg        return 0;               /*  must not equal "." or ".."  */
612f7df2e56Smrg    if (strchr(d, '/') != (char *) 0)
613f7df2e56Smrg        return 0;               /*  very important!!!  */
614f7df2e56Smrg
615f7df2e56Smrg    /* Since we run atoi() on the display later, only allow
616f7df2e56Smrg       for digits, or exception of :0.0 and similar (two decimal points max)
617f7df2e56Smrg       */
618f7df2e56Smrg    for (i = 0; i < strlen(d); i++) {
619f7df2e56Smrg        if (!isdigit(d[i])) {
620f7df2e56Smrg            if (d[i] != '.' || period_found)
621f7df2e56Smrg                return 0;
622f7df2e56Smrg            period_found = TRUE;
623f7df2e56Smrg        } else if (period_found)
624f7df2e56Smrg            after_period++;
625f7df2e56Smrg
626f7df2e56Smrg        if (after_period > 2)
627f7df2e56Smrg            return 0;
628f7df2e56Smrg    }
629f7df2e56Smrg
630f7df2e56Smrg    /* don't allow for :0. */
631f7df2e56Smrg    if (period_found && after_period == 0)
632f7df2e56Smrg        return 0;
633f7df2e56Smrg
634f7df2e56Smrg    if (atol(d) > INT_MAX)
635f7df2e56Smrg        return 0;
636f7df2e56Smrg
6374202a189Smrg    return 1;
63805b261ecSmrg}
63905b261ecSmrg
640f7df2e56Smrgstatic const char *defaultNoListenList[] = {
641f7df2e56Smrg#ifndef LISTEN_TCP
642f7df2e56Smrg    "tcp",
643f7df2e56Smrg#endif
644f7df2e56Smrg#ifndef LISTEN_UNIX
645f7df2e56Smrg    "unix",
646f7df2e56Smrg#endif
647f7df2e56Smrg#ifndef LISTEN_LOCAL
648f7df2e56Smrg    "local",
649f7df2e56Smrg#endif
650f7df2e56Smrg    NULL
651f7df2e56Smrg};
652f7df2e56Smrg
65305b261ecSmrg/*
65405b261ecSmrg * This function parses the command line. Handles device-independent fields
65505b261ecSmrg * and allows ddx to handle additional fields.  It is not allowed to modify
65605b261ecSmrg * argc or any of the strings pointed to by argv.
65705b261ecSmrg */
65805b261ecSmrgvoid
65905b261ecSmrgProcessCommandLine(int argc, char *argv[])
66005b261ecSmrg{
66105b261ecSmrg    int i, skip;
66205b261ecSmrg
66305b261ecSmrg    defaultKeyboardControl.autoRepeat = TRUE;
66405b261ecSmrg
66505b261ecSmrg#ifdef NO_PART_NET
66605b261ecSmrg    PartialNetwork = FALSE;
66705b261ecSmrg#else
66805b261ecSmrg    PartialNetwork = TRUE;
66905b261ecSmrg#endif
67005b261ecSmrg
671f7df2e56Smrg    for (i = 0; defaultNoListenList[i] != NULL; i++) {
672f7df2e56Smrg        if (_XSERVTransNoListen(defaultNoListenList[i]))
673f7df2e56Smrg                    ErrorF("Failed to disable listen for %s transport",
674f7df2e56Smrg                           defaultNoListenList[i]);
675f7df2e56Smrg    }
676f7df2e56Smrg
677f7df2e56Smrg    for (i = 1; i < argc; i++) {
678f7df2e56Smrg        /* call ddx first, so it can peek/override if it wants */
679f7df2e56Smrg        if ((skip = ddxProcessArgument(argc, argv, i))) {
680f7df2e56Smrg            i += (skip - 1);
681f7df2e56Smrg        }
682f7df2e56Smrg        else if (argv[i][0] == ':') {
683f7df2e56Smrg            /* initialize display */
684f7df2e56Smrg            display = argv[i];
685f7df2e56Smrg            explicit_display = TRUE;
686f7df2e56Smrg            display++;
687f7df2e56Smrg            if (!VerifyDisplayName(display)) {
68805b261ecSmrg                ErrorF("Bad display name: %s\n", display);
68905b261ecSmrg                UseMsg();
690f7df2e56Smrg                FatalError("Bad display name, exiting: %s\n", display);
69105b261ecSmrg            }
692f7df2e56Smrg        }
693f7df2e56Smrg        else if (strcmp(argv[i], "-a") == 0) {
694f7df2e56Smrg            if (++i < argc)
695f7df2e56Smrg                defaultPointerControl.num = atoi(argv[i]);
696f7df2e56Smrg            else
697f7df2e56Smrg                UseMsg();
698f7df2e56Smrg        }
699f7df2e56Smrg        else if (strcmp(argv[i], "-ac") == 0) {
700f7df2e56Smrg            defeatAccessControl = TRUE;
701f7df2e56Smrg        }
702f7df2e56Smrg        else if (strcmp(argv[i], "-audit") == 0) {
703f7df2e56Smrg            if (++i < argc)
704f7df2e56Smrg                auditTrailLevel = atoi(argv[i]);
705f7df2e56Smrg            else
706f7df2e56Smrg                UseMsg();
707f7df2e56Smrg        }
708f7df2e56Smrg        else if (strcmp(argv[i], "-auth") == 0) {
709f7df2e56Smrg            if (++i < argc)
710f7df2e56Smrg                InitAuthorization(argv[i]);
711f7df2e56Smrg            else
712f7df2e56Smrg                UseMsg();
713f7df2e56Smrg        }
714f7df2e56Smrg        else if (strcmp(argv[i], "-br") == 0);  /* default */
715f7df2e56Smrg        else if (strcmp(argv[i], "+bs") == 0)
716f7df2e56Smrg            enableBackingStore = TRUE;
717f7df2e56Smrg        else if (strcmp(argv[i], "-bs") == 0)
718f7df2e56Smrg            disableBackingStore = TRUE;
719f7df2e56Smrg        else if (strcmp(argv[i], "c") == 0) {
720f7df2e56Smrg            if (++i < argc)
721f7df2e56Smrg                defaultKeyboardControl.click = atoi(argv[i]);
722f7df2e56Smrg            else
723f7df2e56Smrg                UseMsg();
724f7df2e56Smrg        }
725f7df2e56Smrg        else if (strcmp(argv[i], "-c") == 0) {
726f7df2e56Smrg            defaultKeyboardControl.click = 0;
727f7df2e56Smrg        }
728f7df2e56Smrg        else if (strcmp(argv[i], "-cc") == 0) {
729f7df2e56Smrg            if (++i < argc)
730f7df2e56Smrg                defaultColorVisualClass = atoi(argv[i]);
731f7df2e56Smrg            else
732f7df2e56Smrg                UseMsg();
733f7df2e56Smrg        }
734f7df2e56Smrg        else if (strcmp(argv[i], "-core") == 0) {
73505b261ecSmrg#if !defined(WIN32) || !defined(__MINGW32__)
736f7df2e56Smrg            struct rlimit core_limit;
737f7df2e56Smrg
738f7df2e56Smrg            if (getrlimit(RLIMIT_CORE, &core_limit) != -1) {
739f7df2e56Smrg                core_limit.rlim_cur = core_limit.rlim_max;
740f7df2e56Smrg                setrlimit(RLIMIT_CORE, &core_limit);
741f7df2e56Smrg            }
74205b261ecSmrg#endif
743f7df2e56Smrg            CoreDump = TRUE;
744f7df2e56Smrg        }
745f7df2e56Smrg        else if (strcmp(argv[i], "-nocursor") == 0) {
7464202a189Smrg            EnableCursor = FALSE;
7474202a189Smrg        }
748f7df2e56Smrg        else if (strcmp(argv[i], "-dpi") == 0) {
749f7df2e56Smrg            if (++i < argc)
750f7df2e56Smrg                monitorResolution = atoi(argv[i]);
751f7df2e56Smrg            else
752f7df2e56Smrg                UseMsg();
753f7df2e56Smrg        }
754f7df2e56Smrg        else if (strcmp(argv[i], "-displayfd") == 0) {
755f7df2e56Smrg            if (++i < argc) {
756f7df2e56Smrg                displayfd = atoi(argv[i]);
757f7df2e56Smrg#ifdef LOCK_SERVER
758f7df2e56Smrg                nolock = TRUE;
759f7df2e56Smrg#endif
760f7df2e56Smrg            }
761f7df2e56Smrg            else
762f7df2e56Smrg                UseMsg();
763f7df2e56Smrg        }
76405b261ecSmrg#ifdef DPMSExtension
765f7df2e56Smrg        else if (strcmp(argv[i], "dpms") == 0)
766f7df2e56Smrg            /* ignored for compatibility */ ;
767f7df2e56Smrg        else if (strcmp(argv[i], "-dpms") == 0)
768f7df2e56Smrg            DPMSDisabledSwitch = TRUE;
76905b261ecSmrg#endif
770f7df2e56Smrg        else if (strcmp(argv[i], "-deferglyphs") == 0) {
7717e31ba66Smrg            if (++i >= argc || !xfont2_parse_glyph_caching_mode(argv[i]))
772f7df2e56Smrg                UseMsg();
773f7df2e56Smrg        }
774f7df2e56Smrg        else if (strcmp(argv[i], "-f") == 0) {
775f7df2e56Smrg            if (++i < argc)
776f7df2e56Smrg                defaultKeyboardControl.bell = atoi(argv[i]);
777f7df2e56Smrg            else
778f7df2e56Smrg                UseMsg();
779f7df2e56Smrg        }
780f7df2e56Smrg        else if (strcmp(argv[i], "-fc") == 0) {
781f7df2e56Smrg            if (++i < argc)
782f7df2e56Smrg                defaultCursorFont = argv[i];
783f7df2e56Smrg            else
784f7df2e56Smrg                UseMsg();
785f7df2e56Smrg        }
786f7df2e56Smrg        else if (strcmp(argv[i], "-fn") == 0) {
787f7df2e56Smrg            if (++i < argc)
788f7df2e56Smrg                defaultTextFont = argv[i];
789f7df2e56Smrg            else
790f7df2e56Smrg                UseMsg();
791f7df2e56Smrg        }
792f7df2e56Smrg        else if (strcmp(argv[i], "-fp") == 0) {
793f7df2e56Smrg            if (++i < argc) {
794f7df2e56Smrg                defaultFontPath = argv[i];
795f7df2e56Smrg            }
796f7df2e56Smrg            else
797f7df2e56Smrg                UseMsg();
798f7df2e56Smrg        }
799f7df2e56Smrg        else if (strcmp(argv[i], "-help") == 0) {
800f7df2e56Smrg            UseMsg();
801f7df2e56Smrg            exit(0);
802f7df2e56Smrg        }
803f7df2e56Smrg        else if (strcmp(argv[i], "+iglx") == 0)
804f7df2e56Smrg            enableIndirectGLX = TRUE;
805f7df2e56Smrg        else if (strcmp(argv[i], "-iglx") == 0)
806f7df2e56Smrg            enableIndirectGLX = FALSE;
807f7df2e56Smrg        else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) {
808f7df2e56Smrg            if (skip > 0)
809f7df2e56Smrg                i += skip - 1;
810f7df2e56Smrg            else
811f7df2e56Smrg                UseMsg();
812f7df2e56Smrg        }
81305b261ecSmrg#ifdef RLIMIT_DATA
814f7df2e56Smrg        else if (strcmp(argv[i], "-ld") == 0) {
815f7df2e56Smrg            if (++i < argc) {
816f7df2e56Smrg                limitDataSpace = atoi(argv[i]);
817f7df2e56Smrg                if (limitDataSpace > 0)
818f7df2e56Smrg                    limitDataSpace *= 1024;
819f7df2e56Smrg            }
820f7df2e56Smrg            else
821f7df2e56Smrg                UseMsg();
822f7df2e56Smrg        }
82305b261ecSmrg#endif
82405b261ecSmrg#ifdef RLIMIT_NOFILE
825f7df2e56Smrg        else if (strcmp(argv[i], "-lf") == 0) {
826f7df2e56Smrg            if (++i < argc)
827f7df2e56Smrg                limitNoFile = atoi(argv[i]);
828f7df2e56Smrg            else
829f7df2e56Smrg                UseMsg();
830f7df2e56Smrg        }
83105b261ecSmrg#endif
83205b261ecSmrg#ifdef RLIMIT_STACK
833f7df2e56Smrg        else if (strcmp(argv[i], "-ls") == 0) {
834f7df2e56Smrg            if (++i < argc) {
835f7df2e56Smrg                limitStackSpace = atoi(argv[i]);
836f7df2e56Smrg                if (limitStackSpace > 0)
837f7df2e56Smrg                    limitStackSpace *= 1024;
838f7df2e56Smrg            }
839f7df2e56Smrg            else
840f7df2e56Smrg                UseMsg();
841f7df2e56Smrg        }
84205b261ecSmrg#endif
843f7df2e56Smrg#ifdef LOCK_SERVER
844f7df2e56Smrg        else if (strcmp(argv[i], "-nolock") == 0) {
84505b261ecSmrg#if !defined(WIN32) && !defined(__CYGWIN__)
846f7df2e56Smrg            if (getuid() != 0)
847f7df2e56Smrg                ErrorF
848f7df2e56Smrg                    ("Warning: the -nolock option can only be used by root\n");
849f7df2e56Smrg            else
85005b261ecSmrg#endif
851f7df2e56Smrg                nolock = TRUE;
852f7df2e56Smrg        }
853f7df2e56Smrg#endif
854f7df2e56Smrg	else if ( strcmp( argv[i], "-maxclients") == 0)
85505b261ecSmrg	{
856f7df2e56Smrg	    if (++i < argc) {
857f7df2e56Smrg		LimitClients = atoi(argv[i]);
858f7df2e56Smrg		if (LimitClients != 64 &&
859f7df2e56Smrg		    LimitClients != 128 &&
860f7df2e56Smrg		    LimitClients != 256 &&
8617e31ba66Smrg		    LimitClients != 512 &&
8627e31ba66Smrg                    LimitClients != 1024 &&
8637e31ba66Smrg                    LimitClients != 2048) {
8647e31ba66Smrg		    FatalError("maxclients must be one of 64, 128, 256, 512, 1024 or 2048\n");
865f7df2e56Smrg		}
866f7df2e56Smrg	    } else
86705b261ecSmrg		UseMsg();
86805b261ecSmrg	}
869f7df2e56Smrg        else if (strcmp(argv[i], "-nolisten") == 0) {
870f7df2e56Smrg            if (++i < argc) {
871f7df2e56Smrg                if (_XSERVTransNoListen(argv[i]))
872f7df2e56Smrg                    ErrorF("Failed to disable listen for %s transport",
873f7df2e56Smrg                           argv[i]);
874f7df2e56Smrg            }
875f7df2e56Smrg            else
876f7df2e56Smrg                UseMsg();
877f7df2e56Smrg        }
878f7df2e56Smrg        else if (strcmp(argv[i], "-listen") == 0) {
879f7df2e56Smrg            if (++i < argc) {
880f7df2e56Smrg                if (_XSERVTransListen(argv[i]))
881f7df2e56Smrg                    ErrorF("Failed to enable listen for %s transport",
882f7df2e56Smrg                           argv[i]);
883f7df2e56Smrg            }
884f7df2e56Smrg            else
885f7df2e56Smrg                UseMsg();
886f7df2e56Smrg        }
887f7df2e56Smrg        else if (strcmp(argv[i], "-noreset") == 0) {
888f7df2e56Smrg            dispatchExceptionAtReset = 0;
889f7df2e56Smrg        }
890f7df2e56Smrg        else if (strcmp(argv[i], "-reset") == 0) {
891f7df2e56Smrg            dispatchExceptionAtReset = DE_RESET;
892f7df2e56Smrg        }
893f7df2e56Smrg        else if (strcmp(argv[i], "-p") == 0) {
894f7df2e56Smrg            if (++i < argc)
895f7df2e56Smrg                defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) *
896f7df2e56Smrg                    MILLI_PER_MIN;
897f7df2e56Smrg            else
898f7df2e56Smrg                UseMsg();
899f7df2e56Smrg        }
900f7df2e56Smrg        else if (strcmp(argv[i], "-pogo") == 0) {
901f7df2e56Smrg            dispatchException = DE_TERMINATE;
902f7df2e56Smrg        }
903f7df2e56Smrg        else if (strcmp(argv[i], "-pn") == 0)
904f7df2e56Smrg            PartialNetwork = TRUE;
905f7df2e56Smrg        else if (strcmp(argv[i], "-nopn") == 0)
906f7df2e56Smrg            PartialNetwork = FALSE;
907f7df2e56Smrg        else if (strcmp(argv[i], "r") == 0)
908f7df2e56Smrg            defaultKeyboardControl.autoRepeat = TRUE;
909f7df2e56Smrg        else if (strcmp(argv[i], "-r") == 0)
910f7df2e56Smrg            defaultKeyboardControl.autoRepeat = FALSE;
911f7df2e56Smrg        else if (strcmp(argv[i], "-retro") == 0)
912f7df2e56Smrg            party_like_its_1989 = TRUE;
913f7df2e56Smrg	else if (strcmp(argv[i], "-noretro") == 0)
914daf23d7fSsnj	    party_like_its_1989 = FALSE;
915f7df2e56Smrg        else if (strcmp(argv[i], "-s") == 0) {
916f7df2e56Smrg            if (++i < argc)
917f7df2e56Smrg                defaultScreenSaverTime = ((CARD32) atoi(argv[i])) *
918f7df2e56Smrg                    MILLI_PER_MIN;
919f7df2e56Smrg            else
920f7df2e56Smrg                UseMsg();
921f7df2e56Smrg        }
922f7df2e56Smrg        else if (strcmp(argv[i], "-seat") == 0) {
923f7df2e56Smrg            if (++i < argc)
924f7df2e56Smrg                SeatId = argv[i];
925f7df2e56Smrg            else
926f7df2e56Smrg                UseMsg();
927f7df2e56Smrg        }
928f7df2e56Smrg        else if (strcmp(argv[i], "-t") == 0) {
929f7df2e56Smrg            if (++i < argc)
930f7df2e56Smrg                defaultPointerControl.threshold = atoi(argv[i]);
931f7df2e56Smrg            else
932f7df2e56Smrg                UseMsg();
933f7df2e56Smrg        }
934f7df2e56Smrg        else if (strcmp(argv[i], "-terminate") == 0) {
935f7df2e56Smrg            dispatchExceptionAtReset = DE_TERMINATE;
936f7df2e56Smrg        }
937f7df2e56Smrg        else if (strcmp(argv[i], "-to") == 0) {
938f7df2e56Smrg            if (++i < argc)
939f7df2e56Smrg                TimeOutValue = ((CARD32) atoi(argv[i])) * MILLI_PER_SECOND;
940f7df2e56Smrg            else
941f7df2e56Smrg                UseMsg();
942f7df2e56Smrg        }
943f7df2e56Smrg        else if (strcmp(argv[i], "-tst") == 0) {
944f7df2e56Smrg            noTestExtensions = TRUE;
945f7df2e56Smrg        }
946f7df2e56Smrg        else if (strcmp(argv[i], "v") == 0)
947f7df2e56Smrg            defaultScreenSaverBlanking = PreferBlanking;
948f7df2e56Smrg        else if (strcmp(argv[i], "-v") == 0)
949f7df2e56Smrg            defaultScreenSaverBlanking = DontPreferBlanking;
950f7df2e56Smrg        else if (strcmp(argv[i], "-wm") == 0)
951f7df2e56Smrg            defaultBackingStore = WhenMapped;
952f7df2e56Smrg        else if (strcmp(argv[i], "-wr") == 0)
95305b261ecSmrg            whiteRoot = TRUE;
954f7df2e56Smrg        else if (strcmp(argv[i], "-background") == 0) {
955f7df2e56Smrg            if (++i < argc) {
956f7df2e56Smrg                if (!strcmp(argv[i], "none"))
95765b04b38Smrg                    bgNoneRoot = TRUE;
95865b04b38Smrg                else
95965b04b38Smrg                    UseMsg();
96065b04b38Smrg            }
96165b04b38Smrg        }
962f7df2e56Smrg        else if (strcmp(argv[i], "-maxbigreqsize") == 0) {
963f7df2e56Smrg            if (++i < argc) {
964f7df2e56Smrg                long reqSizeArg = atol(argv[i]);
965f7df2e56Smrg
966f7df2e56Smrg                /* Request size > 128MB does not make much sense... */
967f7df2e56Smrg                if (reqSizeArg > 0L && reqSizeArg < 128L) {
968f7df2e56Smrg                    maxBigRequestSize = (reqSizeArg * 1048576L) - 1L;
969f7df2e56Smrg                }
970f7df2e56Smrg                else {
971f7df2e56Smrg                    UseMsg();
972f7df2e56Smrg                }
973f7df2e56Smrg            }
974f7df2e56Smrg            else {
975f7df2e56Smrg                UseMsg();
976f7df2e56Smrg            }
977f7df2e56Smrg        }
978f7df2e56Smrg#ifdef PANORAMIX
979f7df2e56Smrg        else if (strcmp(argv[i], "+xinerama") == 0) {
980f7df2e56Smrg            noPanoramiXExtension = FALSE;
981f7df2e56Smrg        }
982f7df2e56Smrg        else if (strcmp(argv[i], "-xinerama") == 0) {
983f7df2e56Smrg            noPanoramiXExtension = TRUE;
984f7df2e56Smrg        }
985f7df2e56Smrg        else if (strcmp(argv[i], "-disablexineramaextension") == 0) {
986f7df2e56Smrg            PanoramiXExtensionDisabledHack = TRUE;
987f7df2e56Smrg        }
988f7df2e56Smrg#endif
989f7df2e56Smrg        else if (strcmp(argv[i], "-I") == 0) {
990f7df2e56Smrg            /* ignore all remaining arguments */
991f7df2e56Smrg            break;
992f7df2e56Smrg        }
993f7df2e56Smrg        else if (strncmp(argv[i], "tty", 3) == 0) {
994f7df2e56Smrg            /* init supplies us with this useless information */
995f7df2e56Smrg        }
996f7df2e56Smrg#ifdef XDMCP
997f7df2e56Smrg        else if ((skip = XdmcpOptions(argc, argv, i)) != i) {
998f7df2e56Smrg            i = skip - 1;
999f7df2e56Smrg        }
1000f7df2e56Smrg#endif
1001f7df2e56Smrg        else if (strcmp(argv[i], "-dumbSched") == 0) {
10027e31ba66Smrg            InputThreadEnable = FALSE;
10037e31ba66Smrg#ifdef HAVE_SETITIMER
10047e31ba66Smrg            SmartScheduleSignalEnable = FALSE;
10057e31ba66Smrg#endif
1006f7df2e56Smrg        }
1007f7df2e56Smrg        else if (strcmp(argv[i], "-schedInterval") == 0) {
1008f7df2e56Smrg            if (++i < argc) {
1009f7df2e56Smrg                SmartScheduleInterval = atoi(argv[i]);
1010f7df2e56Smrg                SmartScheduleSlice = SmartScheduleInterval;
1011f7df2e56Smrg            }
1012f7df2e56Smrg            else
1013f7df2e56Smrg                UseMsg();
1014f7df2e56Smrg        }
1015f7df2e56Smrg        else if (strcmp(argv[i], "-schedMax") == 0) {
1016f7df2e56Smrg            if (++i < argc) {
1017f7df2e56Smrg                SmartScheduleMaxSlice = atoi(argv[i]);
1018f7df2e56Smrg            }
1019f7df2e56Smrg            else
1020f7df2e56Smrg                UseMsg();
1021f7df2e56Smrg        }
1022f7df2e56Smrg        else if (strcmp(argv[i], "-render") == 0) {
1023f7df2e56Smrg            if (++i < argc) {
1024f7df2e56Smrg                int policy = PictureParseCmapPolicy(argv[i]);
1025f7df2e56Smrg
1026f7df2e56Smrg                if (policy != PictureCmapPolicyInvalid)
1027f7df2e56Smrg                    PictureCmapPolicy = policy;
1028f7df2e56Smrg                else
1029f7df2e56Smrg                    UseMsg();
1030f7df2e56Smrg            }
1031f7df2e56Smrg            else
1032f7df2e56Smrg                UseMsg();
1033f7df2e56Smrg        }
1034f7df2e56Smrg        else if (strcmp(argv[i], "-sigstop") == 0) {
1035f7df2e56Smrg            RunFromSigStopParent = TRUE;
1036f7df2e56Smrg        }
1037f7df2e56Smrg        else if (strcmp(argv[i], "+extension") == 0) {
1038f7df2e56Smrg            if (++i < argc) {
1039f7df2e56Smrg                if (!EnableDisableExtension(argv[i], TRUE))
1040f7df2e56Smrg                    EnableDisableExtensionError(argv[i], TRUE);
1041f7df2e56Smrg            }
1042f7df2e56Smrg            else
1043f7df2e56Smrg                UseMsg();
1044f7df2e56Smrg        }
1045f7df2e56Smrg        else if (strcmp(argv[i], "-extension") == 0) {
1046f7df2e56Smrg            if (++i < argc) {
1047f7df2e56Smrg                if (!EnableDisableExtension(argv[i], FALSE))
1048f7df2e56Smrg                    EnableDisableExtensionError(argv[i], FALSE);
1049f7df2e56Smrg            }
1050f7df2e56Smrg            else
1051f7df2e56Smrg                UseMsg();
1052f7df2e56Smrg        }
1053f7df2e56Smrg        else {
1054f7df2e56Smrg            ErrorF("Unrecognized option: %s\n", argv[i]);
1055f7df2e56Smrg            UseMsg();
1056f7df2e56Smrg            FatalError("Unrecognized option: %s\n", argv[i]);
105705b261ecSmrg        }
105805b261ecSmrg    }
105905b261ecSmrg}
106005b261ecSmrg
106105b261ecSmrg/* Implement a simple-minded font authorization scheme.  The authorization
106205b261ecSmrg   name is "hp-hostname-1", the contents are simply the host name. */
106305b261ecSmrgint
1064f7df2e56Smrgset_font_authorizations(char **authorizations, int *authlen, void *client)
106505b261ecSmrg{
106605b261ecSmrg#define AUTHORIZATION_NAME "hp-hostname-1"
10677e31ba66Smrg#if defined(TCPCONN)
106805b261ecSmrg    static char *result = NULL;
106905b261ecSmrg    static char *p = NULL;
107005b261ecSmrg
1071f7df2e56Smrg    if (p == NULL) {
1072f7df2e56Smrg        char hname[1024], *hnameptr;
1073f7df2e56Smrg        unsigned int len;
1074f7df2e56Smrg
107505b261ecSmrg#if defined(IPv6) && defined(AF_INET6)
1076f7df2e56Smrg        struct addrinfo hints, *ai = NULL;
107705b261ecSmrg#else
1078f7df2e56Smrg        struct hostent *host;
1079f7df2e56Smrg
108005b261ecSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1081f7df2e56Smrg        _Xgethostbynameparams hparams;
108205b261ecSmrg#endif
108305b261ecSmrg#endif
108405b261ecSmrg
1085f7df2e56Smrg        gethostname(hname, 1024);
108605b261ecSmrg#if defined(IPv6) && defined(AF_INET6)
1087f7df2e56Smrg        memset(&hints, 0, sizeof(hints));
1088f7df2e56Smrg        hints.ai_flags = AI_CANONNAME;
1089f7df2e56Smrg        if (getaddrinfo(hname, NULL, &hints, &ai) == 0) {
1090f7df2e56Smrg            hnameptr = ai->ai_canonname;
1091f7df2e56Smrg        }
1092f7df2e56Smrg        else {
1093f7df2e56Smrg            hnameptr = hname;
1094f7df2e56Smrg        }
109505b261ecSmrg#else
1096f7df2e56Smrg        host = _XGethostbyname(hname, hparams);
1097f7df2e56Smrg        if (host == NULL)
1098f7df2e56Smrg            hnameptr = hname;
1099f7df2e56Smrg        else
1100f7df2e56Smrg            hnameptr = host->h_name;
110105b261ecSmrg#endif
110205b261ecSmrg
1103f7df2e56Smrg        len = strlen(hnameptr) + 1;
1104f7df2e56Smrg        result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4);
110505b261ecSmrg
1106f7df2e56Smrg        p = result;
110705b261ecSmrg        *p++ = sizeof(AUTHORIZATION_NAME) >> 8;
110805b261ecSmrg        *p++ = sizeof(AUTHORIZATION_NAME) & 0xff;
110905b261ecSmrg        *p++ = (len) >> 8;
111005b261ecSmrg        *p++ = (len & 0xff);
111105b261ecSmrg
1112f7df2e56Smrg        memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME));
1113f7df2e56Smrg        p += sizeof(AUTHORIZATION_NAME);
1114f7df2e56Smrg        memmove(p, hnameptr, len);
1115f7df2e56Smrg        p += len;
111605b261ecSmrg#if defined(IPv6) && defined(AF_INET6)
1117f7df2e56Smrg        if (ai) {
1118f7df2e56Smrg            freeaddrinfo(ai);
1119f7df2e56Smrg        }
112005b261ecSmrg#endif
112105b261ecSmrg    }
112205b261ecSmrg    *authlen = p - result;
112305b261ecSmrg    *authorizations = result;
112405b261ecSmrg    return 1;
1125f7df2e56Smrg#else                           /* TCPCONN */
112605b261ecSmrg    return 0;
1127f7df2e56Smrg#endif                          /* TCPCONN */
112805b261ecSmrg}
112905b261ecSmrg
11304202a189Smrgvoid *
113105b261ecSmrgXNFalloc(unsigned long amount)
113205b261ecSmrg{
11334202a189Smrg    void *ptr = malloc(amount);
1134f7df2e56Smrg
113505b261ecSmrg    if (!ptr)
113605b261ecSmrg        FatalError("Out of memory");
11374642e01fSmrg    return ptr;
113805b261ecSmrg}
113905b261ecSmrg
1140f7df2e56Smrg/* The original XNFcalloc was used with the xnfcalloc macro which multiplied
1141f7df2e56Smrg * the arguments at the call site without allowing calloc to check for overflow.
1142f7df2e56Smrg * XNFcallocarray was added to fix that without breaking ABI.
1143f7df2e56Smrg */
11444202a189Smrgvoid *
1145f7df2e56SmrgXNFcalloc(unsigned long amount)
114605b261ecSmrg{
1147f7df2e56Smrg    return XNFcallocarray(1, amount);
114805b261ecSmrg}
114905b261ecSmrg
11504202a189Smrgvoid *
1151f7df2e56SmrgXNFcallocarray(size_t nmemb, size_t size)
115205b261ecSmrg{
1153f7df2e56Smrg    void *ret = calloc(nmemb, size);
1154f7df2e56Smrg
11554202a189Smrg    if (!ret)
11564202a189Smrg        FatalError("XNFcalloc: Out of memory");
115705b261ecSmrg    return ret;
115805b261ecSmrg}
115905b261ecSmrg
11604202a189Smrgvoid *
11614202a189SmrgXNFrealloc(void *ptr, unsigned long amount)
116205b261ecSmrg{
11634202a189Smrg    void *ret = realloc(ptr, amount);
1164f7df2e56Smrg
11654202a189Smrg    if (!ret)
1166f7df2e56Smrg        FatalError("XNFrealloc: Out of memory");
11674202a189Smrg    return ret;
116805b261ecSmrg}
116905b261ecSmrg
1170f7df2e56Smrgvoid *
1171f7df2e56SmrgXNFreallocarray(void *ptr, size_t nmemb, size_t size)
117205b261ecSmrg{
1173f7df2e56Smrg    void *ret = reallocarray(ptr, nmemb, size);
117405b261ecSmrg
1175f7df2e56Smrg    if (!ret)
1176f7df2e56Smrg        FatalError("XNFreallocarray: Out of memory");
1177f7df2e56Smrg    return ret;
1178f7df2e56Smrg}
117905b261ecSmrg
118005b261ecSmrgchar *
118105b261ecSmrgXstrdup(const char *s)
118205b261ecSmrg{
118305b261ecSmrg    if (s == NULL)
1184f7df2e56Smrg        return NULL;
11854202a189Smrg    return strdup(s);
118605b261ecSmrg}
118705b261ecSmrg
11884202a189Smrgchar *
118905b261ecSmrgXNFstrdup(const char *s)
119005b261ecSmrg{
11914202a189Smrg    char *ret;
119205b261ecSmrg
119305b261ecSmrg    if (s == NULL)
1194f7df2e56Smrg        return NULL;
119505b261ecSmrg
11964202a189Smrg    ret = strdup(s);
11974202a189Smrg    if (!ret)
1198f7df2e56Smrg        FatalError("XNFstrdup: Out of memory");
11994202a189Smrg    return ret;
120005b261ecSmrg}
120105b261ecSmrg
12024642e01fSmrgvoid
1203f7df2e56SmrgSmartScheduleStopTimer(void)
120405b261ecSmrg{
12057e31ba66Smrg#ifdef HAVE_SETITIMER
1206f7df2e56Smrg    struct itimerval timer;
1207f7df2e56Smrg
12087e31ba66Smrg    if (!SmartScheduleSignalEnable)
1209f7df2e56Smrg        return;
121005b261ecSmrg    timer.it_interval.tv_sec = 0;
121105b261ecSmrg    timer.it_interval.tv_usec = 0;
121205b261ecSmrg    timer.it_value.tv_sec = 0;
121305b261ecSmrg    timer.it_value.tv_usec = 0;
1214f7df2e56Smrg    (void) setitimer(ITIMER_REAL, &timer, 0);
1215f7df2e56Smrg#endif
121605b261ecSmrg}
121705b261ecSmrg
12184642e01fSmrgvoid
1219f7df2e56SmrgSmartScheduleStartTimer(void)
122005b261ecSmrg{
12217e31ba66Smrg#ifdef HAVE_SETITIMER
1222f7df2e56Smrg    struct itimerval timer;
1223f7df2e56Smrg
12247e31ba66Smrg    if (!SmartScheduleSignalEnable)
1225f7df2e56Smrg        return;
122605b261ecSmrg    timer.it_interval.tv_sec = 0;
122705b261ecSmrg    timer.it_interval.tv_usec = SmartScheduleInterval * 1000;
122805b261ecSmrg    timer.it_value.tv_sec = 0;
122905b261ecSmrg    timer.it_value.tv_usec = SmartScheduleInterval * 1000;
1230f7df2e56Smrg    setitimer(ITIMER_REAL, &timer, 0);
1231f7df2e56Smrg#endif
123205b261ecSmrg}
123305b261ecSmrg
12347e31ba66Smrg#ifdef HAVE_SETITIMER
123505b261ecSmrgstatic void
1236f7df2e56SmrgSmartScheduleTimer(int sig)
123705b261ecSmrg{
123805b261ecSmrg    SmartScheduleTime += SmartScheduleInterval;
123905b261ecSmrg}
124005b261ecSmrg
1241f7df2e56Smrgstatic int
1242f7df2e56SmrgSmartScheduleEnable(void)
124305b261ecSmrg{
1244f7df2e56Smrg    int ret = 0;
1245f7df2e56Smrg    struct sigaction act;
124605b261ecSmrg
12477e31ba66Smrg    if (!SmartScheduleSignalEnable)
1248f7df2e56Smrg        return 0;
124965b04b38Smrg
12504202a189Smrg    memset((char *) &act, 0, sizeof(struct sigaction));
125105b261ecSmrg
125205b261ecSmrg    /* Set up the timer signal function */
1253f7df2e56Smrg    act.sa_flags = SA_RESTART;
125405b261ecSmrg    act.sa_handler = SmartScheduleTimer;
1255f7df2e56Smrg    sigemptyset(&act.sa_mask);
1256f7df2e56Smrg    sigaddset(&act.sa_mask, SIGALRM);
1257f7df2e56Smrg    ret = sigaction(SIGALRM, &act, 0);
1258f7df2e56Smrg    return ret;
1259f7df2e56Smrg}
1260f7df2e56Smrg
1261f7df2e56Smrgstatic int
1262f7df2e56SmrgSmartSchedulePause(void)
1263f7df2e56Smrg{
1264f7df2e56Smrg    int ret = 0;
1265f7df2e56Smrg    struct sigaction act;
1266f7df2e56Smrg
12677e31ba66Smrg    if (!SmartScheduleSignalEnable)
1268f7df2e56Smrg        return 0;
1269f7df2e56Smrg
1270f7df2e56Smrg    memset((char *) &act, 0, sizeof(struct sigaction));
1271f7df2e56Smrg
1272f7df2e56Smrg    act.sa_handler = SIG_IGN;
1273f7df2e56Smrg    sigemptyset(&act.sa_mask);
1274f7df2e56Smrg    ret = sigaction(SIGALRM, &act, 0);
1275f7df2e56Smrg    return ret;
1276f7df2e56Smrg}
12777e31ba66Smrg#endif
1278f7df2e56Smrg
1279f7df2e56Smrgvoid
1280f7df2e56SmrgSmartScheduleInit(void)
1281f7df2e56Smrg{
12827e31ba66Smrg#ifdef HAVE_SETITIMER
1283f7df2e56Smrg    if (SmartScheduleEnable() < 0) {
1284f7df2e56Smrg        perror("sigaction for smart scheduler");
12857e31ba66Smrg        SmartScheduleSignalEnable = FALSE;
128605b261ecSmrg    }
12877e31ba66Smrg#endif
128805b261ecSmrg}
128905b261ecSmrg
129005b261ecSmrg#ifdef SIG_BLOCK
1291f7df2e56Smrgstatic sigset_t PreviousSignalMask;
1292f7df2e56Smrgstatic int BlockedSignalCount;
129305b261ecSmrg#endif
129405b261ecSmrg
129505b261ecSmrgvoid
1296f7df2e56SmrgOsBlockSignals(void)
129705b261ecSmrg{
129805b261ecSmrg#ifdef SIG_BLOCK
1299f7df2e56Smrg    if (BlockedSignalCount++ == 0) {
1300f7df2e56Smrg        sigset_t set;
1301f7df2e56Smrg
1302f7df2e56Smrg        sigemptyset(&set);
1303f7df2e56Smrg        sigaddset(&set, SIGALRM);
1304f7df2e56Smrg        sigaddset(&set, SIGVTALRM);
130505b261ecSmrg#ifdef SIGWINCH
1306f7df2e56Smrg        sigaddset(&set, SIGWINCH);
1307f7df2e56Smrg#endif
1308f7df2e56Smrg        sigaddset(&set, SIGTSTP);
1309f7df2e56Smrg        sigaddset(&set, SIGTTIN);
1310f7df2e56Smrg        sigaddset(&set, SIGTTOU);
1311f7df2e56Smrg        sigaddset(&set, SIGCHLD);
13127e31ba66Smrg        xthread_sigmask(SIG_BLOCK, &set, &PreviousSignalMask);
131305b261ecSmrg    }
131405b261ecSmrg#endif
131505b261ecSmrg}
131605b261ecSmrg
131705b261ecSmrgvoid
1318f7df2e56SmrgOsReleaseSignals(void)
131905b261ecSmrg{
132005b261ecSmrg#ifdef SIG_BLOCK
1321f7df2e56Smrg    if (--BlockedSignalCount == 0) {
13227e31ba66Smrg        xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0);
132305b261ecSmrg    }
132405b261ecSmrg#endif
132505b261ecSmrg}
132605b261ecSmrg
1327f7df2e56Smrgvoid
1328f7df2e56SmrgOsResetSignals(void)
1329f7df2e56Smrg{
1330f7df2e56Smrg#ifdef SIG_BLOCK
1331f7df2e56Smrg    while (BlockedSignalCount > 0)
1332f7df2e56Smrg        OsReleaseSignals();
13337e31ba66Smrg    input_force_unlock();
1334f7df2e56Smrg#endif
1335f7df2e56Smrg}
1336f7df2e56Smrg
13374202a189Smrg/*
13384202a189Smrg * Pending signals may interfere with core dumping. Provide a
13394202a189Smrg * mechanism to block signals when aborting.
13404202a189Smrg */
13414202a189Smrg
13424202a189Smrgvoid
1343f7df2e56SmrgOsAbort(void)
13444202a189Smrg{
13454202a189Smrg#ifndef __APPLE__
13464202a189Smrg    OsBlockSignals();
13477e31ba66Smrg#endif
13487e31ba66Smrg#if !defined(WIN32) || defined(__CYGWIN__)
13497e31ba66Smrg    /* abort() raises SIGABRT, so we have to stop handling that to prevent
13507e31ba66Smrg     * recursion
13517e31ba66Smrg     */
13527e31ba66Smrg    OsSignal(SIGABRT, SIG_DFL);
13534202a189Smrg#endif
13544202a189Smrg    abort();
13554202a189Smrg}
13564202a189Smrg
135705b261ecSmrg#if !defined(WIN32)
135805b261ecSmrg/*
135905b261ecSmrg * "safer" versions of system(3), popen(3) and pclose(3) which give up
136005b261ecSmrg * all privs before running a command.
136105b261ecSmrg *
136205b261ecSmrg * This is based on the code in FreeBSD 2.2 libc.
136305b261ecSmrg *
136405b261ecSmrg * XXX It'd be good to redirect stderr so that it ends up in the log file
136505b261ecSmrg * as well.  As it is now, xkbcomp messages don't end up in the log file.
136605b261ecSmrg */
136705b261ecSmrg
136805b261ecSmrgint
1369f7df2e56SmrgSystem(const char *command)
137005b261ecSmrg{
137105b261ecSmrg    int pid, p;
1372f7df2e56Smrg    void (*csig) (int);
137305b261ecSmrg    int status;
137405b261ecSmrg
137505b261ecSmrg    if (!command)
1376f7df2e56Smrg        return 1;
137705b261ecSmrg
13787e31ba66Smrg    csig = OsSignal(SIGCHLD, SIG_DFL);
137905b261ecSmrg    if (csig == SIG_ERR) {
1380f7df2e56Smrg        perror("signal");
1381f7df2e56Smrg        return -1;
138205b261ecSmrg    }
138365b04b38Smrg    DebugF("System: `%s'\n", command);
138405b261ecSmrg
138505b261ecSmrg    switch (pid = fork()) {
1386f7df2e56Smrg    case -1:                   /* error */
1387f7df2e56Smrg        p = -1;
1388f7df2e56Smrg        break;
1389f7df2e56Smrg    case 0:                    /* child */
1390f7df2e56Smrg        if (setgid(getgid()) == -1)
1391f7df2e56Smrg            _exit(127);
1392f7df2e56Smrg        if (setuid(getuid()) == -1)
1393f7df2e56Smrg            _exit(127);
1394f7df2e56Smrg        execl("/bin/sh", "sh", "-c", command, (char *) NULL);
1395f7df2e56Smrg        _exit(127);
1396f7df2e56Smrg    default:                   /* parent */
1397f7df2e56Smrg        do {
1398f7df2e56Smrg            p = waitpid(pid, &status, 0);
1399f7df2e56Smrg        } while (p == -1 && errno == EINTR);
1400f7df2e56Smrg
140105b261ecSmrg    }
140205b261ecSmrg
14037e31ba66Smrg    if (OsSignal(SIGCHLD, csig) == SIG_ERR) {
1404f7df2e56Smrg        perror("signal");
1405f7df2e56Smrg        return -1;
140605b261ecSmrg    }
140705b261ecSmrg
140805b261ecSmrg    return p == -1 ? -1 : status;
140905b261ecSmrg}
141005b261ecSmrg
141105b261ecSmrgstatic struct pid {
141205b261ecSmrg    struct pid *next;
141305b261ecSmrg    FILE *fp;
141405b261ecSmrg    int pid;
141505b261ecSmrg} *pidlist;
141605b261ecSmrg
1417f7df2e56Smrgvoid *
1418f7df2e56SmrgPopen(const char *command, const char *type)
141905b261ecSmrg{
142005b261ecSmrg    struct pid *cur;
142105b261ecSmrg    FILE *iop;
142205b261ecSmrg    int pdes[2], pid;
142305b261ecSmrg
142405b261ecSmrg    if (command == NULL || type == NULL)
1425f7df2e56Smrg        return NULL;
142605b261ecSmrg
142705b261ecSmrg    if ((*type != 'r' && *type != 'w') || type[1])
1428f7df2e56Smrg        return NULL;
142905b261ecSmrg
14304202a189Smrg    if ((cur = malloc(sizeof(struct pid))) == NULL)
1431f7df2e56Smrg        return NULL;
143205b261ecSmrg
143305b261ecSmrg    if (pipe(pdes) < 0) {
1434f7df2e56Smrg        free(cur);
1435f7df2e56Smrg        return NULL;
143605b261ecSmrg    }
143705b261ecSmrg
143805b261ecSmrg    /* Ignore the smart scheduler while this is going on */
14397e31ba66Smrg#ifdef HAVE_SETITIMER
1440f7df2e56Smrg    if (SmartSchedulePause() < 0) {
1441f7df2e56Smrg        close(pdes[0]);
1442f7df2e56Smrg        close(pdes[1]);
1443f7df2e56Smrg        free(cur);
1444f7df2e56Smrg        perror("signal");
1445f7df2e56Smrg        return NULL;
144605b261ecSmrg    }
14477e31ba66Smrg#endif
144805b261ecSmrg
144905b261ecSmrg    switch (pid = fork()) {
1450f7df2e56Smrg    case -1:                   /* error */
1451f7df2e56Smrg        close(pdes[0]);
1452f7df2e56Smrg        close(pdes[1]);
1453f7df2e56Smrg        free(cur);
14547e31ba66Smrg#ifdef HAVE_SETITIMER
1455f7df2e56Smrg        if (SmartScheduleEnable() < 0)
1456f7df2e56Smrg            perror("signal");
14577e31ba66Smrg#endif
1458f7df2e56Smrg        return NULL;
1459f7df2e56Smrg    case 0:                    /* child */
1460f7df2e56Smrg        if (setgid(getgid()) == -1)
1461f7df2e56Smrg            _exit(127);
1462f7df2e56Smrg        if (setuid(getuid()) == -1)
1463f7df2e56Smrg            _exit(127);
1464f7df2e56Smrg        if (*type == 'r') {
1465f7df2e56Smrg            if (pdes[1] != 1) {
1466f7df2e56Smrg                /* stdout */
1467f7df2e56Smrg                dup2(pdes[1], 1);
1468f7df2e56Smrg                close(pdes[1]);
1469f7df2e56Smrg            }
1470f7df2e56Smrg            close(pdes[0]);
1471f7df2e56Smrg        }
1472f7df2e56Smrg        else {
1473f7df2e56Smrg            if (pdes[0] != 0) {
1474f7df2e56Smrg                /* stdin */
1475f7df2e56Smrg                dup2(pdes[0], 0);
1476f7df2e56Smrg                close(pdes[0]);
1477f7df2e56Smrg            }
1478f7df2e56Smrg            close(pdes[1]);
1479f7df2e56Smrg        }
1480f7df2e56Smrg        execl("/bin/sh", "sh", "-c", command, (char *) NULL);
1481f7df2e56Smrg        _exit(127);
148205b261ecSmrg    }
148305b261ecSmrg
148405b261ecSmrg    /* Avoid EINTR during stdio calls */
1485f7df2e56Smrg    OsBlockSignals();
1486f7df2e56Smrg
148705b261ecSmrg    /* parent */
148805b261ecSmrg    if (*type == 'r') {
1489f7df2e56Smrg        iop = fdopen(pdes[0], type);
1490f7df2e56Smrg        close(pdes[1]);
1491f7df2e56Smrg    }
1492f7df2e56Smrg    else {
1493f7df2e56Smrg        iop = fdopen(pdes[1], type);
1494f7df2e56Smrg        close(pdes[0]);
149505b261ecSmrg    }
149605b261ecSmrg
149705b261ecSmrg    cur->fp = iop;
149805b261ecSmrg    cur->pid = pid;
149905b261ecSmrg    cur->next = pidlist;
150005b261ecSmrg    pidlist = cur;
150105b261ecSmrg
150265b04b38Smrg    DebugF("Popen: `%s', fp = %p\n", command, iop);
150305b261ecSmrg
150405b261ecSmrg    return iop;
150505b261ecSmrg}
150605b261ecSmrg
150705b261ecSmrg/* fopen that drops privileges */
1508f7df2e56Smrgvoid *
1509f7df2e56SmrgFopen(const char *file, const char *type)
151005b261ecSmrg{
151105b261ecSmrg    FILE *iop;
1512f7df2e56Smrg
151305b261ecSmrg#ifndef HAS_SAVED_IDS_AND_SETEUID
151405b261ecSmrg    struct pid *cur;
151505b261ecSmrg    int pdes[2], pid;
151605b261ecSmrg
151705b261ecSmrg    if (file == NULL || type == NULL)
1518f7df2e56Smrg        return NULL;
151905b261ecSmrg
152005b261ecSmrg    if ((*type != 'r' && *type != 'w') || type[1])
1521f7df2e56Smrg        return NULL;
152205b261ecSmrg
15234202a189Smrg    if ((cur = malloc(sizeof(struct pid))) == NULL)
1524f7df2e56Smrg        return NULL;
152505b261ecSmrg
152605b261ecSmrg    if (pipe(pdes) < 0) {
1527f7df2e56Smrg        free(cur);
1528f7df2e56Smrg        return NULL;
152905b261ecSmrg    }
153005b261ecSmrg
153105b261ecSmrg    switch (pid = fork()) {
1532f7df2e56Smrg    case -1:                   /* error */
1533f7df2e56Smrg        close(pdes[0]);
1534f7df2e56Smrg        close(pdes[1]);
1535f7df2e56Smrg        free(cur);
1536f7df2e56Smrg        return NULL;
1537f7df2e56Smrg    case 0:                    /* child */
1538f7df2e56Smrg        if (setgid(getgid()) == -1)
1539f7df2e56Smrg            _exit(127);
1540f7df2e56Smrg        if (setuid(getuid()) == -1)
1541f7df2e56Smrg            _exit(127);
1542f7df2e56Smrg        if (*type == 'r') {
1543f7df2e56Smrg            if (pdes[1] != 1) {
1544f7df2e56Smrg                /* stdout */
1545f7df2e56Smrg                dup2(pdes[1], 1);
1546f7df2e56Smrg                close(pdes[1]);
1547f7df2e56Smrg            }
1548f7df2e56Smrg            close(pdes[0]);
1549f7df2e56Smrg        }
1550f7df2e56Smrg        else {
1551f7df2e56Smrg            if (pdes[0] != 0) {
1552f7df2e56Smrg                /* stdin */
1553f7df2e56Smrg                dup2(pdes[0], 0);
1554f7df2e56Smrg                close(pdes[0]);
1555f7df2e56Smrg            }
1556f7df2e56Smrg            close(pdes[1]);
1557f7df2e56Smrg        }
1558f7df2e56Smrg        execl("/bin/cat", "cat", file, (char *) NULL);
1559f7df2e56Smrg        _exit(127);
156005b261ecSmrg    }
156105b261ecSmrg
156205b261ecSmrg    /* Avoid EINTR during stdio calls */
1563f7df2e56Smrg    OsBlockSignals();
1564f7df2e56Smrg
156505b261ecSmrg    /* parent */
156605b261ecSmrg    if (*type == 'r') {
1567f7df2e56Smrg        iop = fdopen(pdes[0], type);
1568f7df2e56Smrg        close(pdes[1]);
1569f7df2e56Smrg    }
1570f7df2e56Smrg    else {
1571f7df2e56Smrg        iop = fdopen(pdes[1], type);
1572f7df2e56Smrg        close(pdes[0]);
157305b261ecSmrg    }
157405b261ecSmrg
157505b261ecSmrg    cur->fp = iop;
157605b261ecSmrg    cur->pid = pid;
157705b261ecSmrg    cur->next = pidlist;
157805b261ecSmrg    pidlist = cur;
157905b261ecSmrg
158065b04b38Smrg    DebugF("Fopen(%s), fp = %p\n", file, iop);
158105b261ecSmrg
158205b261ecSmrg    return iop;
158305b261ecSmrg#else
158405b261ecSmrg    int ruid, euid;
158505b261ecSmrg
158605b261ecSmrg    ruid = getuid();
158705b261ecSmrg    euid = geteuid();
1588f7df2e56Smrg
158905b261ecSmrg    if (seteuid(ruid) == -1) {
1590f7df2e56Smrg        return NULL;
159105b261ecSmrg    }
159205b261ecSmrg    iop = fopen(file, type);
159305b261ecSmrg
159405b261ecSmrg    if (seteuid(euid) == -1) {
1595f7df2e56Smrg        fclose(iop);
1596f7df2e56Smrg        return NULL;
159705b261ecSmrg    }
159805b261ecSmrg    return iop;
1599f7df2e56Smrg#endif                          /* HAS_SAVED_IDS_AND_SETEUID */
160005b261ecSmrg}
160105b261ecSmrg
160205b261ecSmrgint
1603f7df2e56SmrgPclose(void *iop)
160405b261ecSmrg{
160505b261ecSmrg    struct pid *cur, *last;
160605b261ecSmrg    int pstat;
160705b261ecSmrg    int pid;
160805b261ecSmrg
160965b04b38Smrg    DebugF("Pclose: fp = %p\n", iop);
161005b261ecSmrg    fclose(iop);
161105b261ecSmrg
161205b261ecSmrg    for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
1613f7df2e56Smrg        if (cur->fp == iop)
1614f7df2e56Smrg            break;
161505b261ecSmrg    if (cur == NULL)
1616f7df2e56Smrg        return -1;
161705b261ecSmrg
161805b261ecSmrg    do {
1619f7df2e56Smrg        pid = waitpid(cur->pid, &pstat, 0);
162005b261ecSmrg    } while (pid == -1 && errno == EINTR);
162105b261ecSmrg
162205b261ecSmrg    if (last == NULL)
1623f7df2e56Smrg        pidlist = cur->next;
162405b261ecSmrg    else
1625f7df2e56Smrg        last->next = cur->next;
16264202a189Smrg    free(cur);
162705b261ecSmrg
162805b261ecSmrg    /* allow EINTR again */
1629f7df2e56Smrg    OsReleaseSignals();
1630f7df2e56Smrg
16317e31ba66Smrg#ifdef HAVE_SETITIMER
1632f7df2e56Smrg    if (SmartScheduleEnable() < 0) {
1633f7df2e56Smrg        perror("signal");
1634f7df2e56Smrg        return -1;
163505b261ecSmrg    }
16367e31ba66Smrg#endif
163705b261ecSmrg
163805b261ecSmrg    return pid == -1 ? -1 : pstat;
163905b261ecSmrg}
164005b261ecSmrg
16414202a189Smrgint
1642f7df2e56SmrgFclose(void *iop)
164305b261ecSmrg{
164405b261ecSmrg#ifdef HAS_SAVED_IDS_AND_SETEUID
164505b261ecSmrg    return fclose(iop);
164605b261ecSmrg#else
164705b261ecSmrg    return Pclose(iop);
164805b261ecSmrg#endif
164905b261ecSmrg}
165005b261ecSmrg
1651f7df2e56Smrg#endif                          /* !WIN32 */
1652f7df2e56Smrg
1653f7df2e56Smrg#ifdef WIN32
1654f7df2e56Smrg
1655f7df2e56Smrg#include <X11/Xwindows.h>
1656f7df2e56Smrg
1657f7df2e56Smrgconst char *
1658f7df2e56SmrgWin32TempDir(void)
1659f7df2e56Smrg{
1660f7df2e56Smrg    static char buffer[PATH_MAX];
1661f7df2e56Smrg
1662f7df2e56Smrg    if (GetTempPath(sizeof(buffer), buffer)) {
1663f7df2e56Smrg        int len;
1664f7df2e56Smrg
1665f7df2e56Smrg        buffer[sizeof(buffer) - 1] = 0;
1666f7df2e56Smrg        len = strlen(buffer);
1667f7df2e56Smrg        if (len > 0)
1668f7df2e56Smrg            if (buffer[len - 1] == '\\')
1669f7df2e56Smrg                buffer[len - 1] = 0;
1670f7df2e56Smrg        return buffer;
1671f7df2e56Smrg    }
1672f7df2e56Smrg    if (getenv("TEMP") != NULL)
1673f7df2e56Smrg        return getenv("TEMP");
1674f7df2e56Smrg    else if (getenv("TMP") != NULL)
1675f7df2e56Smrg        return getenv("TMP");
1676f7df2e56Smrg    else
1677f7df2e56Smrg        return "/tmp";
1678f7df2e56Smrg}
1679f7df2e56Smrg
1680f7df2e56Smrgint
1681f7df2e56SmrgSystem(const char *cmdline)
1682f7df2e56Smrg{
1683f7df2e56Smrg    STARTUPINFO si;
1684f7df2e56Smrg    PROCESS_INFORMATION pi;
1685f7df2e56Smrg    DWORD dwExitCode;
1686f7df2e56Smrg    char *cmd = strdup(cmdline);
1687f7df2e56Smrg
1688f7df2e56Smrg    ZeroMemory(&si, sizeof(si));
1689f7df2e56Smrg    si.cb = sizeof(si);
1690f7df2e56Smrg    ZeroMemory(&pi, sizeof(pi));
1691f7df2e56Smrg
1692f7df2e56Smrg    if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
1693f7df2e56Smrg        LPVOID buffer;
1694f7df2e56Smrg
1695f7df2e56Smrg        if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1696f7df2e56Smrg                           FORMAT_MESSAGE_FROM_SYSTEM |
1697f7df2e56Smrg                           FORMAT_MESSAGE_IGNORE_INSERTS,
1698f7df2e56Smrg                           NULL,
1699f7df2e56Smrg                           GetLastError(),
1700f7df2e56Smrg                           MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1701f7df2e56Smrg                           (LPTSTR) &buffer, 0, NULL)) {
1702f7df2e56Smrg            ErrorF("[xkb] Starting '%s' failed!\n", cmdline);
1703f7df2e56Smrg        }
1704f7df2e56Smrg        else {
1705f7df2e56Smrg            ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer);
1706f7df2e56Smrg            LocalFree(buffer);
1707f7df2e56Smrg        }
1708f7df2e56Smrg
1709f7df2e56Smrg        free(cmd);
1710f7df2e56Smrg        return -1;
1711f7df2e56Smrg    }
1712f7df2e56Smrg    /* Wait until child process exits. */
1713f7df2e56Smrg    WaitForSingleObject(pi.hProcess, INFINITE);
1714f7df2e56Smrg
1715f7df2e56Smrg    GetExitCodeProcess(pi.hProcess, &dwExitCode);
171605b261ecSmrg
1717f7df2e56Smrg    /* Close process and thread handles. */
1718f7df2e56Smrg    CloseHandle(pi.hProcess);
1719f7df2e56Smrg    CloseHandle(pi.hThread);
1720f7df2e56Smrg    free(cmd);
1721f7df2e56Smrg
1722f7df2e56Smrg    return dwExitCode;
1723f7df2e56Smrg}
1724f7df2e56Smrg#endif
172505b261ecSmrg
17267e31ba66SmrgBool
17277e31ba66SmrgPrivsElevated(void)
17287e31ba66Smrg{
17297e31ba66Smrg    static Bool privsTested = FALSE;
17307e31ba66Smrg    static Bool privsElevated = TRUE;
17317e31ba66Smrg
17327e31ba66Smrg    if (!privsTested) {
17337e31ba66Smrg#if defined(WIN32)
17347e31ba66Smrg        privsElevated = FALSE;
17357e31ba66Smrg#else
17367e31ba66Smrg        if ((getuid() != geteuid()) || (getgid() != getegid())) {
17377e31ba66Smrg            privsElevated = TRUE;
17387e31ba66Smrg        }
17397e31ba66Smrg        else {
17407e31ba66Smrg#if defined(HAVE_ISSETUGID)
17417e31ba66Smrg            privsElevated = issetugid();
17427e31ba66Smrg#elif defined(HAVE_GETRESUID)
17437e31ba66Smrg            uid_t ruid, euid, suid;
17447e31ba66Smrg            gid_t rgid, egid, sgid;
17457e31ba66Smrg
17467e31ba66Smrg            if ((getresuid(&ruid, &euid, &suid) == 0) &&
17477e31ba66Smrg                (getresgid(&rgid, &egid, &sgid) == 0)) {
17487e31ba66Smrg                privsElevated = (euid != suid) || (egid != sgid);
17497e31ba66Smrg            }
17507e31ba66Smrg            else {
17517e31ba66Smrg                printf("Failed getresuid or getresgid");
17527e31ba66Smrg                /* Something went wrong, make defensive assumption */
17537e31ba66Smrg                privsElevated = TRUE;
17547e31ba66Smrg            }
17557e31ba66Smrg#else
17567e31ba66Smrg            if (getuid() == 0) {
17577e31ba66Smrg                /* running as root: uid==euid==0 */
17587e31ba66Smrg                privsElevated = FALSE;
17597e31ba66Smrg            }
17607e31ba66Smrg            else {
17617e31ba66Smrg                /*
17627e31ba66Smrg                 * If there are saved ID's the process might still be privileged
17637e31ba66Smrg                 * even though the above test succeeded. If issetugid() and
17647e31ba66Smrg                 * getresgid() aren't available, test this by trying to set
17657e31ba66Smrg                 * euid to 0.
17667e31ba66Smrg                 */
17677e31ba66Smrg                unsigned int oldeuid;
17687e31ba66Smrg
17697e31ba66Smrg                oldeuid = geteuid();
17707e31ba66Smrg
17717e31ba66Smrg                if (seteuid(0) != 0) {
17727e31ba66Smrg                    privsElevated = FALSE;
17737e31ba66Smrg                }
17747e31ba66Smrg                else {
17757e31ba66Smrg                    if (seteuid(oldeuid) != 0) {
17767e31ba66Smrg                        FatalError("Failed to drop privileges.  Exiting\n");
17777e31ba66Smrg                    }
17787e31ba66Smrg                    privsElevated = TRUE;
17797e31ba66Smrg                }
17807e31ba66Smrg            }
17817e31ba66Smrg#endif
17827e31ba66Smrg        }
17837e31ba66Smrg#endif
17847e31ba66Smrg        privsTested = TRUE;
17857e31ba66Smrg    }
17867e31ba66Smrg    return privsElevated;
17877e31ba66Smrg}
17887e31ba66Smrg
178905b261ecSmrg/*
179005b261ecSmrg * CheckUserParameters: check for long command line arguments and long
179105b261ecSmrg * environment variables.  By default, these checks are only done when
179205b261ecSmrg * the server's euid != ruid.  In 3.3.x, these checks were done in an
179305b261ecSmrg * external wrapper utility.
179405b261ecSmrg */
179505b261ecSmrg
179605b261ecSmrg/* Consider LD* variables insecure? */
179705b261ecSmrg#ifndef REMOVE_ENV_LD
179805b261ecSmrg#define REMOVE_ENV_LD 1
179905b261ecSmrg#endif
180005b261ecSmrg
180105b261ecSmrg/* Remove long environment variables? */
180205b261ecSmrg#ifndef REMOVE_LONG_ENV
180305b261ecSmrg#define REMOVE_LONG_ENV 1
180405b261ecSmrg#endif
180505b261ecSmrg
180605b261ecSmrg/*
180705b261ecSmrg * Disallow stdout or stderr as pipes?  It's possible to block the X server
180805b261ecSmrg * when piping stdout+stderr to a pipe.
180905b261ecSmrg *
181005b261ecSmrg * Don't enable this because it looks like it's going to cause problems.
181105b261ecSmrg */
181205b261ecSmrg#ifndef NO_OUTPUT_PIPES
181305b261ecSmrg#define NO_OUTPUT_PIPES 0
181405b261ecSmrg#endif
181505b261ecSmrg
181605b261ecSmrg/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
181705b261ecSmrg#ifndef CHECK_EUID
181805b261ecSmrg#ifndef WIN32
181905b261ecSmrg#define CHECK_EUID 1
182005b261ecSmrg#else
182105b261ecSmrg#define CHECK_EUID 0
182205b261ecSmrg#endif
182305b261ecSmrg#endif
182405b261ecSmrg
182505b261ecSmrg/*
182605b261ecSmrg * Maybe the locale can be faked to make isprint(3) report that everything
182705b261ecSmrg * is printable?  Avoid it by default.
182805b261ecSmrg */
182905b261ecSmrg#ifndef USE_ISPRINT
183005b261ecSmrg#define USE_ISPRINT 0
183105b261ecSmrg#endif
183205b261ecSmrg
183305b261ecSmrg#define MAX_ARG_LENGTH          128
183405b261ecSmrg#define MAX_ENV_LENGTH          256
1835f7df2e56Smrg#define MAX_ENV_PATH_LENGTH     2048    /* Limit for *PATH and TERMCAP */
183605b261ecSmrg
183705b261ecSmrg#if USE_ISPRINT
183805b261ecSmrg#include <ctype.h>
183905b261ecSmrg#define checkPrintable(c) isprint(c)
184005b261ecSmrg#else
184105b261ecSmrg#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
184205b261ecSmrg#endif
184305b261ecSmrg
184405b261ecSmrgenum BadCode {
184505b261ecSmrg    NotBad = 0,
184605b261ecSmrg    UnsafeArg,
184705b261ecSmrg    ArgTooLong,
184805b261ecSmrg    UnprintableArg,
184905b261ecSmrg    EnvTooLong,
185005b261ecSmrg    OutputIsPipe,
185105b261ecSmrg    InternalError
185205b261ecSmrg};
185305b261ecSmrg
185405b261ecSmrg#if defined(VENDORSUPPORT)
185505b261ecSmrg#define BUGADDRESS VENDORSUPPORT
185605b261ecSmrg#elif defined(BUILDERADDR)
185705b261ecSmrg#define BUGADDRESS BUILDERADDR
185805b261ecSmrg#else
185905b261ecSmrg#define BUGADDRESS "xorg@freedesktop.org"
186005b261ecSmrg#endif
186105b261ecSmrg
186205b261ecSmrgvoid
186305b261ecSmrgCheckUserParameters(int argc, char **argv, char **envp)
186405b261ecSmrg{
186505b261ecSmrg    enum BadCode bad = NotBad;
186605b261ecSmrg    int i = 0, j;
186705b261ecSmrg    char *a, *e = NULL;
186805b261ecSmrg
186905b261ecSmrg#if CHECK_EUID
18707e31ba66Smrg    if (PrivsElevated())
187105b261ecSmrg#endif
187205b261ecSmrg    {
1873f7df2e56Smrg        /* Check each argv[] */
1874f7df2e56Smrg        for (i = 1; i < argc; i++) {
1875f7df2e56Smrg            if (strcmp(argv[i], "-fp") == 0) {
1876f7df2e56Smrg                i++;            /* continue with next argument. skip the length check */
1877f7df2e56Smrg                if (i >= argc)
1878f7df2e56Smrg                    break;
1879f7df2e56Smrg            }
1880f7df2e56Smrg            else {
1881f7df2e56Smrg                if (strlen(argv[i]) > MAX_ARG_LENGTH) {
1882f7df2e56Smrg                    bad = ArgTooLong;
1883f7df2e56Smrg                    break;
1884f7df2e56Smrg                }
1885f7df2e56Smrg            }
1886f7df2e56Smrg            a = argv[i];
1887f7df2e56Smrg            while (*a) {
1888f7df2e56Smrg                if (checkPrintable(*a) == 0) {
1889f7df2e56Smrg                    bad = UnprintableArg;
1890f7df2e56Smrg                    break;
1891f7df2e56Smrg                }
1892f7df2e56Smrg                a++;
1893f7df2e56Smrg            }
1894f7df2e56Smrg            if (bad)
1895f7df2e56Smrg                break;
1896f7df2e56Smrg        }
1897f7df2e56Smrg        if (!bad) {
1898f7df2e56Smrg            /* Check each envp[] */
1899f7df2e56Smrg            for (i = 0; envp[i]; i++) {
190005b261ecSmrg
1901f7df2e56Smrg                /* Check for bad environment variables and values */
190205b261ecSmrg#if REMOVE_ENV_LD
1903f7df2e56Smrg                while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
1904f7df2e56Smrg                    for (j = i; envp[j]; j++) {
1905f7df2e56Smrg                        envp[j] = envp[j + 1];
1906f7df2e56Smrg                    }
1907f7df2e56Smrg                }
1908f7df2e56Smrg#endif
1909f7df2e56Smrg                if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
191005b261ecSmrg#if REMOVE_LONG_ENV
1911f7df2e56Smrg                    for (j = i; envp[j]; j++) {
1912f7df2e56Smrg                        envp[j] = envp[j + 1];
1913f7df2e56Smrg                    }
1914f7df2e56Smrg                    i--;
191505b261ecSmrg#else
1916f7df2e56Smrg                    char *eq;
1917f7df2e56Smrg                    int len;
1918f7df2e56Smrg
1919f7df2e56Smrg                    eq = strchr(envp[i], '=');
1920f7df2e56Smrg                    if (!eq)
1921f7df2e56Smrg                        continue;
1922f7df2e56Smrg                    len = eq - envp[i];
1923f7df2e56Smrg                    e = strndup(envp[i], len);
1924f7df2e56Smrg                    if (!e) {
1925f7df2e56Smrg                        bad = InternalError;
1926f7df2e56Smrg                        break;
1927f7df2e56Smrg                    }
1928f7df2e56Smrg                    if (len >= 4 &&
1929f7df2e56Smrg                        (strcmp(e + len - 4, "PATH") == 0 ||
1930f7df2e56Smrg                         strcmp(e, "TERMCAP") == 0)) {
1931f7df2e56Smrg                        if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
1932f7df2e56Smrg                            bad = EnvTooLong;
1933f7df2e56Smrg                            break;
1934f7df2e56Smrg                        }
1935f7df2e56Smrg                        else {
1936f7df2e56Smrg                            free(e);
1937f7df2e56Smrg                        }
1938f7df2e56Smrg                    }
1939f7df2e56Smrg                    else {
1940f7df2e56Smrg                        bad = EnvTooLong;
1941f7df2e56Smrg                        break;
1942f7df2e56Smrg                    }
1943f7df2e56Smrg#endif
1944f7df2e56Smrg                }
1945f7df2e56Smrg            }
1946f7df2e56Smrg        }
194705b261ecSmrg#if NO_OUTPUT_PIPES
1948f7df2e56Smrg        if (!bad) {
1949f7df2e56Smrg            struct stat buf;
195005b261ecSmrg
1951f7df2e56Smrg            if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode))
1952f7df2e56Smrg                bad = OutputIsPipe;
1953f7df2e56Smrg            if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode))
1954f7df2e56Smrg                bad = OutputIsPipe;
1955f7df2e56Smrg        }
195605b261ecSmrg#endif
195705b261ecSmrg    }
195805b261ecSmrg    switch (bad) {
195905b261ecSmrg    case NotBad:
1960f7df2e56Smrg        return;
196105b261ecSmrg    case UnsafeArg:
1962f7df2e56Smrg        ErrorF("Command line argument number %d is unsafe\n", i);
1963f7df2e56Smrg        break;
196405b261ecSmrg    case ArgTooLong:
1965f7df2e56Smrg        ErrorF("Command line argument number %d is too long\n", i);
1966f7df2e56Smrg        break;
196705b261ecSmrg    case UnprintableArg:
1968f7df2e56Smrg        ErrorF("Command line argument number %d contains unprintable"
1969f7df2e56Smrg               " characters\n", i);
1970f7df2e56Smrg        break;
197105b261ecSmrg    case EnvTooLong:
1972f7df2e56Smrg        ErrorF("Environment variable `%s' is too long\n", e);
1973f7df2e56Smrg        break;
197405b261ecSmrg    case OutputIsPipe:
1975f7df2e56Smrg        ErrorF("Stdout and/or stderr is a pipe\n");
1976f7df2e56Smrg        break;
197705b261ecSmrg    case InternalError:
1978f7df2e56Smrg        ErrorF("Internal Error\n");
1979f7df2e56Smrg        break;
198005b261ecSmrg    default:
1981f7df2e56Smrg        ErrorF("Unknown error\n");
1982f7df2e56Smrg        break;
198305b261ecSmrg    }
198405b261ecSmrg    FatalError("X server aborted because of unsafe environment\n");
198505b261ecSmrg}
198605b261ecSmrg
198705b261ecSmrg/*
198805b261ecSmrg * CheckUserAuthorization: check if the user is allowed to start the
198905b261ecSmrg * X server.  This usually means some sort of PAM checking, and it is
199005b261ecSmrg * usually only done for setuid servers (uid != euid).
199105b261ecSmrg */
199205b261ecSmrg
199305b261ecSmrg#ifdef USE_PAM
199405b261ecSmrg#include <security/pam_appl.h>
199505b261ecSmrg#include <security/pam_misc.h>
199605b261ecSmrg#include <pwd.h>
1997f7df2e56Smrg#endif                          /* USE_PAM */
199805b261ecSmrg
199905b261ecSmrgvoid
200005b261ecSmrgCheckUserAuthorization(void)
200105b261ecSmrg{
200205b261ecSmrg#ifdef USE_PAM
200305b261ecSmrg    static struct pam_conv conv = {
2004f7df2e56Smrg        misc_conv,
2005f7df2e56Smrg        NULL
200605b261ecSmrg    };
200705b261ecSmrg
200805b261ecSmrg    pam_handle_t *pamh = NULL;
200905b261ecSmrg    struct passwd *pw;
201005b261ecSmrg    int retval;
201105b261ecSmrg
201205b261ecSmrg    if (getuid() != geteuid()) {
2013f7df2e56Smrg        pw = getpwuid(getuid());
2014f7df2e56Smrg        if (pw == NULL)
2015f7df2e56Smrg            FatalError("getpwuid() failed for uid %d\n", getuid());
2016f7df2e56Smrg
2017f7df2e56Smrg        retval = pam_start("xserver", pw->pw_name, &conv, &pamh);
2018f7df2e56Smrg        if (retval != PAM_SUCCESS)
2019f7df2e56Smrg            FatalError("pam_start() failed.\n"
2020f7df2e56Smrg                       "\tMissing or mangled PAM config file or module?\n");
2021f7df2e56Smrg
2022f7df2e56Smrg        retval = pam_authenticate(pamh, 0);
2023f7df2e56Smrg        if (retval != PAM_SUCCESS) {
2024f7df2e56Smrg            pam_end(pamh, retval);
2025f7df2e56Smrg            FatalError("PAM authentication failed, cannot start X server.\n"
2026f7df2e56Smrg                       "\tPerhaps you do not have console ownership?\n");
2027f7df2e56Smrg        }
202805b261ecSmrg
2029f7df2e56Smrg        retval = pam_acct_mgmt(pamh, 0);
2030f7df2e56Smrg        if (retval != PAM_SUCCESS) {
2031f7df2e56Smrg            pam_end(pamh, retval);
2032f7df2e56Smrg            FatalError("PAM authentication failed, cannot start X server.\n"
2033f7df2e56Smrg                       "\tPerhaps you do not have console ownership?\n");
2034f7df2e56Smrg        }
203505b261ecSmrg
2036f7df2e56Smrg        /* this is not a session, so do not do session management */
2037f7df2e56Smrg        pam_end(pamh, PAM_SUCCESS);
203805b261ecSmrg    }
203905b261ecSmrg#endif
204005b261ecSmrg}
204105b261ecSmrg
20424202a189Smrg/*
20434202a189Smrg * Tokenize a string into a NULL terminated array of strings. Always returns
20444202a189Smrg * an allocated array unless an error occurs.
20454202a189Smrg */
2046f7df2e56Smrgchar **
20474202a189Smrgxstrtokenize(const char *str, const char *separators)
204805b261ecSmrg{
20494202a189Smrg    char **list, **nlist;
20504202a189Smrg    char *tok, *tmp;
20514202a189Smrg    unsigned num = 0, n;
205205b261ecSmrg
20534202a189Smrg    if (!str)
20544202a189Smrg        return NULL;
20554202a189Smrg    list = calloc(1, sizeof(*list));
20564202a189Smrg    if (!list)
20574202a189Smrg        return NULL;
20584202a189Smrg    tmp = strdup(str);
20594202a189Smrg    if (!tmp)
20604202a189Smrg        goto error;
20614202a189Smrg    for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) {
2062f7df2e56Smrg        nlist = reallocarray(list, num + 2, sizeof(*list));
20634202a189Smrg        if (!nlist)
20644202a189Smrg            goto error;
20654202a189Smrg        list = nlist;
20664202a189Smrg        list[num] = strdup(tok);
20674202a189Smrg        if (!list[num])
20684202a189Smrg            goto error;
20694202a189Smrg        list[++num] = NULL;
20704202a189Smrg    }
20714202a189Smrg    free(tmp);
20724202a189Smrg    return list;
20734202a189Smrg
2074f7df2e56Smrg error:
20754202a189Smrg    free(tmp);
20764202a189Smrg    for (n = 0; n < num; n++)
20774202a189Smrg        free(list[n]);
20784202a189Smrg    free(list);
20794202a189Smrg    return NULL;
208005b261ecSmrg}
2081f7df2e56Smrg
2082f7df2e56Smrg/* Format a signed number into a string in a signal safe manner. The string
2083f7df2e56Smrg * should be at least 21 characters in order to handle all int64_t values.
2084f7df2e56Smrg */
2085f7df2e56Smrgvoid
2086f7df2e56SmrgFormatInt64(int64_t num, char *string)
2087f7df2e56Smrg{
2088f7df2e56Smrg    if (num < 0) {
2089f7df2e56Smrg        string[0] = '-';
2090f7df2e56Smrg        num *= -1;
2091f7df2e56Smrg        string++;
2092f7df2e56Smrg    }
2093f7df2e56Smrg    FormatUInt64(num, string);
2094f7df2e56Smrg}
2095f7df2e56Smrg
2096f7df2e56Smrg/* Format a number into a string in a signal safe manner. The string should be
2097f7df2e56Smrg * at least 21 characters in order to handle all uint64_t values. */
2098f7df2e56Smrgvoid
2099f7df2e56SmrgFormatUInt64(uint64_t num, char *string)
2100f7df2e56Smrg{
2101f7df2e56Smrg    uint64_t divisor;
2102f7df2e56Smrg    int len;
2103f7df2e56Smrg    int i;
2104f7df2e56Smrg
2105f7df2e56Smrg    for (len = 1, divisor = 10;
2106f7df2e56Smrg         len < 20 && num / divisor;
2107f7df2e56Smrg         len++, divisor *= 10);
2108f7df2e56Smrg
2109f7df2e56Smrg    for (i = len, divisor = 1; i > 0; i--, divisor *= 10)
2110f7df2e56Smrg        string[i - 1] = '0' + ((num / divisor) % 10);
2111f7df2e56Smrg
2112f7df2e56Smrg    string[len] = '\0';
2113f7df2e56Smrg}
2114f7df2e56Smrg
2115f7df2e56Smrg/**
2116f7df2e56Smrg * Format a double number as %.2f.
2117f7df2e56Smrg */
2118f7df2e56Smrgvoid
2119f7df2e56SmrgFormatDouble(double dbl, char *string)
2120f7df2e56Smrg{
2121f7df2e56Smrg    int slen = 0;
2122f7df2e56Smrg    uint64_t frac;
2123f7df2e56Smrg
2124f7df2e56Smrg    frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5;
2125f7df2e56Smrg    frac %= 100;
2126f7df2e56Smrg
2127f7df2e56Smrg    /* write decimal part to string */
2128f7df2e56Smrg    if (dbl < 0 && dbl > -1)
2129f7df2e56Smrg        string[slen++] = '-';
2130f7df2e56Smrg    FormatInt64((int64_t)dbl, &string[slen]);
2131f7df2e56Smrg
2132f7df2e56Smrg    while(string[slen] != '\0')
2133f7df2e56Smrg        slen++;
2134f7df2e56Smrg
2135f7df2e56Smrg    /* append fractional part, but only if we have enough characters. We
2136f7df2e56Smrg     * expect string to be 21 chars (incl trailing \0) */
2137f7df2e56Smrg    if (slen <= 17) {
2138f7df2e56Smrg        string[slen++] = '.';
2139f7df2e56Smrg        if (frac < 10)
2140f7df2e56Smrg            string[slen++] = '0';
2141f7df2e56Smrg
2142f7df2e56Smrg        FormatUInt64(frac, &string[slen]);
2143f7df2e56Smrg    }
2144f7df2e56Smrg}
2145f7df2e56Smrg
2146f7df2e56Smrg
2147f7df2e56Smrg/* Format a number into a hexadecimal string in a signal safe manner. The string
2148f7df2e56Smrg * should be at least 17 characters in order to handle all uint64_t values. */
2149f7df2e56Smrgvoid
2150f7df2e56SmrgFormatUInt64Hex(uint64_t num, char *string)
2151f7df2e56Smrg{
2152f7df2e56Smrg    uint64_t divisor;
2153f7df2e56Smrg    int len;
2154f7df2e56Smrg    int i;
2155f7df2e56Smrg
2156f7df2e56Smrg    for (len = 1, divisor = 0x10;
2157f7df2e56Smrg         len < 16 && num / divisor;
2158f7df2e56Smrg         len++, divisor *= 0x10);
2159f7df2e56Smrg
2160f7df2e56Smrg    for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) {
2161f7df2e56Smrg        int val = (num / divisor) % 0x10;
2162f7df2e56Smrg
2163f7df2e56Smrg        if (val < 10)
2164f7df2e56Smrg            string[i - 1] = '0' + val;
2165f7df2e56Smrg        else
2166f7df2e56Smrg            string[i - 1] = 'a' + val - 10;
2167f7df2e56Smrg    }
2168f7df2e56Smrg
2169f7df2e56Smrg    string[len] = '\0';
2170f7df2e56Smrg}
2171f7df2e56Smrg
2172f7df2e56Smrg#if !defined(WIN32) || defined(__CYGWIN__)
2173f7df2e56Smrg/* Move a file descriptor out of the way of our select mask; this
2174f7df2e56Smrg * is useful for file descriptors which will never appear in the
2175f7df2e56Smrg * select mask to avoid reducing the number of clients that can
2176f7df2e56Smrg * connect to the server
2177f7df2e56Smrg */
2178f7df2e56Smrgint
2179f7df2e56Smrgos_move_fd(int fd)
2180f7df2e56Smrg{
2181f7df2e56Smrg    int newfd;
2182f7df2e56Smrg
2183f7df2e56Smrg#ifdef F_DUPFD_CLOEXEC
2184f7df2e56Smrg    newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS);
2185f7df2e56Smrg#else
2186f7df2e56Smrg    newfd = fcntl(fd, F_DUPFD, MAXCLIENTS);
2187f7df2e56Smrg#endif
2188f7df2e56Smrg    if (newfd < 0)
2189f7df2e56Smrg        return fd;
2190f7df2e56Smrg#ifndef F_DUPFD_CLOEXEC
2191f7df2e56Smrg    fcntl(newfd, F_SETFD, FD_CLOEXEC);
2192f7df2e56Smrg#endif
2193f7df2e56Smrg    close(fd);
2194f7df2e56Smrg    return newfd;
2195f7df2e56Smrg}
2196f7df2e56Smrg#endif
2197