utils.c revision 6b007147
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
1135a112b11Smrg#include "miinitext.h"
1145a112b11Smrg
1155a112b11Smrg#include "present.h"
1165a112b11Smrg
1174202a189SmrgBool noTestExtensions;
118f7df2e56Smrg
11905b261ecSmrg#ifdef COMPOSITE
1204202a189SmrgBool noCompositeExtension = FALSE;
12105b261ecSmrg#endif
12205b261ecSmrg
12305b261ecSmrg#ifdef DAMAGE
1244202a189SmrgBool noDamageExtension = FALSE;
12505b261ecSmrg#endif
12605b261ecSmrg#ifdef DBE
1274202a189SmrgBool noDbeExtension = FALSE;
12805b261ecSmrg#endif
12905b261ecSmrg#ifdef DPMSExtension
1307e31ba66Smrg#include "dpmsproc.h"
1314202a189SmrgBool noDPMSExtension = FALSE;
13205b261ecSmrg#endif
13305b261ecSmrg#ifdef GLXEXT
1344202a189SmrgBool noGlxExtension = FALSE;
13505b261ecSmrg#endif
13605b261ecSmrg#ifdef SCREENSAVER
1374202a189SmrgBool noScreenSaverExtension = FALSE;
13805b261ecSmrg#endif
13905b261ecSmrg#ifdef MITSHM
1404202a189SmrgBool noMITShmExtension = FALSE;
14105b261ecSmrg#endif
14205b261ecSmrg#ifdef RANDR
1434202a189SmrgBool noRRExtension = FALSE;
14405b261ecSmrg#endif
1454202a189SmrgBool noRenderExtension = FALSE;
146f7df2e56Smrg
14705b261ecSmrg#ifdef XCSECURITY
1484202a189SmrgBool noSecurityExtension = FALSE;
14905b261ecSmrg#endif
15005b261ecSmrg#ifdef RES
1514202a189SmrgBool noResExtension = FALSE;
15205b261ecSmrg#endif
15305b261ecSmrg#ifdef XF86BIGFONT
1544202a189SmrgBool noXFree86BigfontExtension = FALSE;
15505b261ecSmrg#endif
15605b261ecSmrg#ifdef XFreeXDGA
1574202a189SmrgBool noXFree86DGAExtension = FALSE;
15805b261ecSmrg#endif
15905b261ecSmrg#ifdef XF86DRI
1604202a189SmrgBool noXFree86DRIExtension = FALSE;
16105b261ecSmrg#endif
16205b261ecSmrg#ifdef XF86VIDMODE
1634202a189SmrgBool noXFree86VidModeExtension = FALSE;
16405b261ecSmrg#endif
1654202a189SmrgBool noXFixesExtension = FALSE;
16605b261ecSmrg#ifdef PANORAMIX
16705b261ecSmrg/* Xinerama is disabled by default unless enabled via +xinerama */
1684202a189SmrgBool noPanoramiXExtension = TRUE;
16905b261ecSmrg#endif
1704642e01fSmrg#ifdef XSELINUX
1714202a189SmrgBool noSELinuxExtension = FALSE;
1724202a189Smrgint selinuxEnforcingState = SELINUX_MODE_DEFAULT;
17305b261ecSmrg#endif
17405b261ecSmrg#ifdef XV
1754202a189SmrgBool noXvExtension = FALSE;
17605b261ecSmrg#endif
1774642e01fSmrg#ifdef DRI2
1784202a189SmrgBool noDRI2Extension = FALSE;
1794642e01fSmrg#endif
1804642e01fSmrg
1814202a189SmrgBool noGEExtension = FALSE;
18205b261ecSmrg
18305b261ecSmrg#define X_INCLUDE_NETDB_H
18405b261ecSmrg#include <X11/Xos_r.h>
18505b261ecSmrg
18605b261ecSmrg#include <errno.h>
18705b261ecSmrg
18805b261ecSmrgBool CoreDump;
18905b261ecSmrg
190f7df2e56SmrgBool enableIndirectGLX = FALSE;
191f7df2e56Smrg
19205b261ecSmrg#ifdef PANORAMIX
19305b261ecSmrgBool PanoramiXExtensionDisabledHack = FALSE;
19405b261ecSmrg#endif
19505b261ecSmrg
19605b261ecSmrgint auditTrailLevel = 1;
19705b261ecSmrg
198f7df2e56Smrgchar *SeatId = NULL;
199f7df2e56Smrg
200f7df2e56Smrgsig_atomic_t inSignalContext = FALSE;
201f7df2e56Smrg
20205b261ecSmrg#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
20305b261ecSmrg#define HAS_SAVED_IDS_AND_SETEUID
20405b261ecSmrg#endif
20505b261ecSmrg
2067e31ba66Smrg#ifdef MONOTONIC_CLOCK
2077e31ba66Smrgstatic clockid_t clockid;
2087e31ba66Smrg#endif
2097e31ba66Smrg
21005b261ecSmrgOsSigHandlerPtr
2114202a189SmrgOsSignal(int sig, OsSigHandlerPtr handler)
21205b261ecSmrg{
213f7df2e56Smrg#if defined(WIN32) && !defined(__CYGWIN__)
214f7df2e56Smrg    return signal(sig, handler);
215f7df2e56Smrg#else
21605b261ecSmrg    struct sigaction act, oact;
21705b261ecSmrg
21805b261ecSmrg    sigemptyset(&act.sa_mask);
21905b261ecSmrg    if (handler != SIG_IGN)
220f7df2e56Smrg        sigaddset(&act.sa_mask, sig);
22105b261ecSmrg    act.sa_flags = 0;
22205b261ecSmrg    act.sa_handler = handler;
22305b261ecSmrg    if (sigaction(sig, &act, &oact))
224f7df2e56Smrg        perror("sigaction");
22505b261ecSmrg    return oact.sa_handler;
226f7df2e56Smrg#endif
22705b261ecSmrg}
2284642e01fSmrg
22905b261ecSmrg/*
23005b261ecSmrg * Explicit support for a server lock file like the ones used for UUCP.
23105b261ecSmrg * For architectures with virtual terminals that can run more than one
23205b261ecSmrg * server at a time.  This keeps the servers from stomping on each other
23305b261ecSmrg * if the user forgets to give them different display numbers.
23405b261ecSmrg */
23505b261ecSmrg#define LOCK_DIR "/tmp"
23605b261ecSmrg#define LOCK_TMP_PREFIX "/.tX"
23705b261ecSmrg#define LOCK_PREFIX "/.X"
23805b261ecSmrg#define LOCK_SUFFIX "-lock"
23905b261ecSmrg
240f7df2e56Smrg#if !defined(WIN32) || defined(__CYGWIN__)
241f7df2e56Smrg#define LOCK_SERVER
24205b261ecSmrg#endif
24305b261ecSmrg
244f7df2e56Smrg#ifndef LOCK_SERVER
245f7df2e56Smrgvoid
246f7df2e56SmrgLockServer(void)
247f7df2e56Smrg{}
248f7df2e56Smrg
249f7df2e56Smrgvoid
250f7df2e56SmrgUnlockServer(void)
251f7df2e56Smrg{}
252f7df2e56Smrg#else /* LOCK_SERVER */
25305b261ecSmrgstatic Bool StillLocking = FALSE;
25405b261ecSmrgstatic char LockFile[PATH_MAX];
25505b261ecSmrgstatic Bool nolock = FALSE;
25605b261ecSmrg
25705b261ecSmrg/*
25805b261ecSmrg * LockServer --
25905b261ecSmrg *      Check if the server lock file exists.  If so, check if the PID
26005b261ecSmrg *      contained inside is valid.  If so, then die.  Otherwise, create
26105b261ecSmrg *      the lock file containing the PID.
26205b261ecSmrg */
26305b261ecSmrgvoid
26405b261ecSmrgLockServer(void)
26505b261ecSmrg{
266f7df2e56Smrg    char tmp[PATH_MAX], pid_str[12];
267f7df2e56Smrg    int lfd, i, haslock, l_pid, t;
268f7df2e56Smrg    const char *tmppath = LOCK_DIR;
269f7df2e56Smrg    int len;
270f7df2e56Smrg    char port[20];
271f7df2e56Smrg
272f7df2e56Smrg    if (nolock || NoListenAll)
273f7df2e56Smrg        return;
274f7df2e56Smrg    /*
275f7df2e56Smrg     * Path names
276f7df2e56Smrg     */
277f7df2e56Smrg    snprintf(port, sizeof(port), "%d", atoi(display));
278f7df2e56Smrg    len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) :
279f7df2e56Smrg        strlen(LOCK_TMP_PREFIX);
280f7df2e56Smrg    len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1;
281f7df2e56Smrg    if (len > sizeof(LockFile))
282f7df2e56Smrg        FatalError("Display name `%s' is too long\n", port);
283f7df2e56Smrg    (void) sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
284f7df2e56Smrg    (void) sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
285f7df2e56Smrg
286f7df2e56Smrg    /*
287f7df2e56Smrg     * Create a temporary file containing our PID.  Attempt three times
288f7df2e56Smrg     * to create the file.
289f7df2e56Smrg     */
290f7df2e56Smrg    StillLocking = TRUE;
29105b261ecSmrg    i = 0;
29205b261ecSmrg    do {
293f7df2e56Smrg        i++;
294f7df2e56Smrg        lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
295f7df2e56Smrg        if (lfd < 0)
296f7df2e56Smrg            sleep(2);
297f7df2e56Smrg        else
298f7df2e56Smrg            break;
29905b261ecSmrg    } while (i < 3);
300f7df2e56Smrg    if (lfd < 0) {
30105b261ecSmrg        unlink(tmp);
302f7df2e56Smrg        i = 0;
303f7df2e56Smrg        do {
304f7df2e56Smrg            i++;
305f7df2e56Smrg            lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
306f7df2e56Smrg            if (lfd < 0)
307f7df2e56Smrg                sleep(2);
308f7df2e56Smrg            else
309f7df2e56Smrg                break;
310f7df2e56Smrg        } while (i < 3);
31105b261ecSmrg    }
312f7df2e56Smrg    if (lfd < 0)
313f7df2e56Smrg        FatalError("Could not create lock file in %s\n", tmp);
3147e31ba66Smrg    snprintf(pid_str, sizeof(pid_str), "%10lu\n", (unsigned long) getpid());
315f7df2e56Smrg    if (write(lfd, pid_str, 11) != 11)
316f7df2e56Smrg        FatalError("Could not write pid to lock file in %s\n", tmp);
317f7df2e56Smrg    (void) fchmod(lfd, 0444);
318f7df2e56Smrg    (void) close(lfd);
319f7df2e56Smrg
320f7df2e56Smrg    /*
321f7df2e56Smrg     * OK.  Now the tmp file exists.  Try three times to move it in place
322f7df2e56Smrg     * for the lock.
323f7df2e56Smrg     */
324f7df2e56Smrg    i = 0;
325f7df2e56Smrg    haslock = 0;
326f7df2e56Smrg    while ((!haslock) && (i++ < 3)) {
327f7df2e56Smrg        haslock = (link(tmp, LockFile) == 0);
328f7df2e56Smrg        if (haslock) {
329f7df2e56Smrg            /*
330f7df2e56Smrg             * We're done.
331f7df2e56Smrg             */
332f7df2e56Smrg            break;
333f7df2e56Smrg        }
3345a112b11Smrg        else if (errno == EEXIST) {
335f7df2e56Smrg            /*
336f7df2e56Smrg             * Read the pid from the existing file
337f7df2e56Smrg             */
338f7df2e56Smrg            lfd = open(LockFile, O_RDONLY | O_NOFOLLOW);
339f7df2e56Smrg            if (lfd < 0) {
340f7df2e56Smrg                unlink(tmp);
341f7df2e56Smrg                FatalError("Can't read lock file %s\n", LockFile);
342f7df2e56Smrg            }
343f7df2e56Smrg            pid_str[0] = '\0';
344f7df2e56Smrg            if (read(lfd, pid_str, 11) != 11) {
345f7df2e56Smrg                /*
346f7df2e56Smrg                 * Bogus lock file.
347f7df2e56Smrg                 */
348f7df2e56Smrg                unlink(LockFile);
349f7df2e56Smrg                close(lfd);
350f7df2e56Smrg                continue;
351f7df2e56Smrg            }
352f7df2e56Smrg            pid_str[11] = '\0';
353f7df2e56Smrg            sscanf(pid_str, "%d", &l_pid);
354f7df2e56Smrg            close(lfd);
355f7df2e56Smrg
356f7df2e56Smrg            /*
357f7df2e56Smrg             * Now try to kill the PID to see if it exists.
358f7df2e56Smrg             */
359f7df2e56Smrg            errno = 0;
360f7df2e56Smrg            t = kill(l_pid, 0);
361f7df2e56Smrg            if ((t < 0) && (errno == ESRCH)) {
362f7df2e56Smrg                /*
363f7df2e56Smrg                 * Stale lock file.
364f7df2e56Smrg                 */
365f7df2e56Smrg                unlink(LockFile);
366f7df2e56Smrg                continue;
367f7df2e56Smrg            }
368f7df2e56Smrg            else if (((t < 0) && (errno == EPERM)) || (t == 0)) {
369f7df2e56Smrg                /*
370f7df2e56Smrg                 * Process is still active.
371f7df2e56Smrg                 */
372f7df2e56Smrg                unlink(tmp);
373f7df2e56Smrg                FatalError
374f7df2e56Smrg                    ("Server is already active for display %s\n%s %s\n%s\n",
375f7df2e56Smrg                     port, "\tIf this server is no longer running, remove",
376f7df2e56Smrg                     LockFile, "\tand start again.");
377f7df2e56Smrg            }
378f7df2e56Smrg        }
3795a112b11Smrg        else {
3805a112b11Smrg            unlink(tmp);
3815a112b11Smrg            FatalError
3825a112b11Smrg                ("Linking lock file (%s) in place failed: %s\n",
3835a112b11Smrg                 LockFile, strerror(errno));
3845a112b11Smrg        }
385f7df2e56Smrg    }
386f7df2e56Smrg    unlink(tmp);
387f7df2e56Smrg    if (!haslock)
388f7df2e56Smrg        FatalError("Could not create server lock file: %s\n", LockFile);
389f7df2e56Smrg    StillLocking = FALSE;
39005b261ecSmrg}
39105b261ecSmrg
39205b261ecSmrg/*
39305b261ecSmrg * UnlockServer --
39405b261ecSmrg *      Remove the server lock file.
39505b261ecSmrg */
39605b261ecSmrgvoid
39705b261ecSmrgUnlockServer(void)
39805b261ecSmrg{
399f7df2e56Smrg    if (nolock || NoListenAll)
400f7df2e56Smrg        return;
40105b261ecSmrg
402f7df2e56Smrg    if (!StillLocking) {
40305b261ecSmrg
404f7df2e56Smrg        (void) unlink(LockFile);
405f7df2e56Smrg    }
40605b261ecSmrg}
407f7df2e56Smrg#endif /* LOCK_SERVER */
40805b261ecSmrg
40905b261ecSmrg/* Force connections to close on SIGHUP from init */
41005b261ecSmrg
4114202a189Smrgvoid
412f7df2e56SmrgAutoResetServer(int sig)
41305b261ecSmrg{
41405b261ecSmrg    int olderrno = errno;
41505b261ecSmrg
41605b261ecSmrg    dispatchException |= DE_RESET;
41705b261ecSmrg    isItTimeToYield = TRUE;
41805b261ecSmrg    errno = olderrno;
41905b261ecSmrg}
42005b261ecSmrg
42105b261ecSmrg/* Force connections to close and then exit on SIGTERM, SIGINT */
42205b261ecSmrg
4234202a189Smrgvoid
42405b261ecSmrgGiveUp(int sig)
42505b261ecSmrg{
42605b261ecSmrg    int olderrno = errno;
42705b261ecSmrg
42805b261ecSmrg    dispatchException |= DE_TERMINATE;
42905b261ecSmrg    isItTimeToYield = TRUE;
43005b261ecSmrg    errno = olderrno;
43105b261ecSmrg}
43205b261ecSmrg
4337e31ba66Smrg#ifdef MONOTONIC_CLOCK
4347e31ba66Smrgvoid
4357e31ba66SmrgForceClockId(clockid_t forced_clockid)
4367e31ba66Smrg{
4377e31ba66Smrg    struct timespec tp;
4387e31ba66Smrg
4397e31ba66Smrg    BUG_RETURN (clockid);
4407e31ba66Smrg
4417e31ba66Smrg    clockid = forced_clockid;
4427e31ba66Smrg
4437e31ba66Smrg    if (clock_gettime(clockid, &tp) != 0) {
4447e31ba66Smrg        FatalError("Forced clock id failed to retrieve current time: %s\n",
4457e31ba66Smrg                   strerror(errno));
4467e31ba66Smrg        return;
4477e31ba66Smrg    }
4487e31ba66Smrg}
4497e31ba66Smrg#endif
4507e31ba66Smrg
4514202a189Smrg#if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__)
4524202a189SmrgCARD32
453f7df2e56SmrgGetTimeInMillis(void)
454f7df2e56Smrg{
455f7df2e56Smrg    return GetTickCount();
456f7df2e56Smrg}
457f7df2e56SmrgCARD64
458f7df2e56SmrgGetTimeInMicros(void)
45905b261ecSmrg{
460f7df2e56Smrg    return (CARD64) GetTickCount() * 1000;
46105b261ecSmrg}
46205b261ecSmrg#else
4634202a189SmrgCARD32
46405b261ecSmrgGetTimeInMillis(void)
46505b261ecSmrg{
46605b261ecSmrg    struct timeval tv;
46705b261ecSmrg
46805b261ecSmrg#ifdef MONOTONIC_CLOCK
46905b261ecSmrg    struct timespec tp;
470f7df2e56Smrg
4711b684552Smrg    if (!clockid) {
4721b684552Smrg#ifdef CLOCK_MONOTONIC_COARSE
4731b684552Smrg        if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
4741b684552Smrg            (tp.tv_nsec / 1000) <= 1000 &&
4751b684552Smrg            clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
4761b684552Smrg            clockid = CLOCK_MONOTONIC_COARSE;
4771b684552Smrg        else
4781b684552Smrg#endif
4791b684552Smrg        if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
4801b684552Smrg            clockid = CLOCK_MONOTONIC;
4811b684552Smrg        else
4821b684552Smrg            clockid = ~0L;
4831b684552Smrg    }
4841b684552Smrg    if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
48505b261ecSmrg        return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
48605b261ecSmrg#endif
48705b261ecSmrg
48805b261ecSmrg    X_GETTIMEOFDAY(&tv);
489f7df2e56Smrg    return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
490f7df2e56Smrg}
491f7df2e56Smrg
492f7df2e56SmrgCARD64
493f7df2e56SmrgGetTimeInMicros(void)
494f7df2e56Smrg{
495f7df2e56Smrg    struct timeval tv;
496f7df2e56Smrg#ifdef MONOTONIC_CLOCK
497f7df2e56Smrg    struct timespec tp;
498bf8e669cSmrg    static clockid_t uclockid;
499f7df2e56Smrg
500bf8e669cSmrg    if (!uclockid) {
501f7df2e56Smrg        if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
502bf8e669cSmrg            uclockid = CLOCK_MONOTONIC;
503f7df2e56Smrg        else
504bf8e669cSmrg            uclockid = ~0L;
505f7df2e56Smrg    }
506bf8e669cSmrg    if (uclockid != ~0L && clock_gettime(uclockid, &tp) == 0)
507f7df2e56Smrg        return (CARD64) tp.tv_sec * (CARD64)1000000 + tp.tv_nsec / 1000;
508f7df2e56Smrg#endif
509f7df2e56Smrg
510f7df2e56Smrg    X_GETTIMEOFDAY(&tv);
5117e31ba66Smrg    return (CARD64) tv.tv_sec * (CARD64)1000000 + (CARD64) tv.tv_usec;
51205b261ecSmrg}
51305b261ecSmrg#endif
51405b261ecSmrg
515f7df2e56Smrgvoid
516f7df2e56SmrgUseMsg(void)
51705b261ecSmrg{
51805b261ecSmrg    ErrorF("use: X [:<display>] [option]\n");
5194202a189Smrg    ErrorF("-a #                   default pointer acceleration (factor)\n");
52005b261ecSmrg    ErrorF("-ac                    disable access control restrictions\n");
521f7df2e56Smrg    ErrorF("-audit int             set audit trail level\n");
522f7df2e56Smrg    ErrorF("-auth file             select authorization file\n");
52305b261ecSmrg    ErrorF("-br                    create root window with black background\n");
52405b261ecSmrg    ErrorF("+bs                    enable any backing store support\n");
52505b261ecSmrg    ErrorF("-bs                    disable any backing store support\n");
52605b261ecSmrg    ErrorF("-c                     turns off key-click\n");
52705b261ecSmrg    ErrorF("c #                    key-click volume (0-100)\n");
52805b261ecSmrg    ErrorF("-cc int                default color visual class\n");
5294202a189Smrg    ErrorF("-nocursor              disable the cursor\n");
53005b261ecSmrg    ErrorF("-core                  generate core dump on fatal error\n");
531f7df2e56Smrg    ErrorF("-displayfd fd          file descriptor to write display number to when ready to connect\n");
53205b261ecSmrg    ErrorF("-dpi int               screen resolution in dots per inch\n");
53305b261ecSmrg#ifdef DPMSExtension
53405b261ecSmrg    ErrorF("-dpms                  disables VESA DPMS monitor control\n");
53505b261ecSmrg#endif
536f7df2e56Smrg    ErrorF
537f7df2e56Smrg        ("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n");
53805b261ecSmrg    ErrorF("-f #                   bell base (0-100)\n");
5395a112b11Smrg    ErrorF("-fakescreenfps #       fake screen default fps (1-600)\n");
54005b261ecSmrg    ErrorF("-fp string             default font path\n");
54105b261ecSmrg    ErrorF("-help                  prints message with these options\n");
542f7df2e56Smrg    ErrorF("+iglx                  Allow creating indirect GLX contexts\n");
543f7df2e56Smrg    ErrorF("-iglx                  Prohibit creating indirect GLX contexts (default)\n");
54405b261ecSmrg    ErrorF("-I                     ignore all remaining arguments\n");
54505b261ecSmrg#ifdef RLIMIT_DATA
54605b261ecSmrg    ErrorF("-ld int                limit data space to N Kb\n");
54705b261ecSmrg#endif
54805b261ecSmrg#ifdef RLIMIT_NOFILE
54905b261ecSmrg    ErrorF("-lf int                limit number of open files to N\n");
55005b261ecSmrg#endif
55105b261ecSmrg#ifdef RLIMIT_STACK
55205b261ecSmrg    ErrorF("-ls int                limit stack space to N Kb\n");
55305b261ecSmrg#endif
554f7df2e56Smrg#ifdef LOCK_SERVER
55505b261ecSmrg    ErrorF("-nolock                disable the locking mechanism\n");
556f7df2e56Smrg#endif
557f7df2e56Smrg    ErrorF("-maxclients n          set maximum number of clients (power of two)\n");
55805b261ecSmrg    ErrorF("-nolisten string       don't listen on protocol\n");
559f7df2e56Smrg    ErrorF("-listen string         listen on protocol\n");
56005b261ecSmrg    ErrorF("-noreset               don't reset after last client exists\n");
56165b04b38Smrg    ErrorF("-background [none]     create root window with no background\n");
56205b261ecSmrg    ErrorF("-reset                 reset after last client exists\n");
56305b261ecSmrg    ErrorF("-p #                   screen-saver pattern duration (minutes)\n");
56405b261ecSmrg    ErrorF("-pn                    accept failure to listen on all ports\n");
56505b261ecSmrg    ErrorF("-nopn                  reject failure to listen on all ports\n");
56605b261ecSmrg    ErrorF("-r                     turns off auto-repeat\n");
56705b261ecSmrg    ErrorF("r                      turns on auto-repeat \n");
56805b261ecSmrg    ErrorF("-render [default|mono|gray|color] set render color alloc policy\n");
5694642e01fSmrg    ErrorF("-retro                 start with classic stipple and cursor\n");
570daf23d7fSsnj    ErrorF("-noretro               start with black background and no cursor\n");
57105b261ecSmrg    ErrorF("-s #                   screen-saver timeout (minutes)\n");
572f7df2e56Smrg    ErrorF("-seat string           seat to run on\n");
5734202a189Smrg    ErrorF("-t #                   default pointer threshold (pixels/t)\n");
5745a112b11Smrg    ErrorF("-terminate [delay]     terminate at server reset (optional delay in sec)\n");
57505b261ecSmrg    ErrorF("-tst                   disable testing extensions\n");
57605b261ecSmrg    ErrorF("ttyxx                  server started from init on /dev/ttyxx\n");
57705b261ecSmrg    ErrorF("v                      video blanking for screen-saver\n");
57805b261ecSmrg    ErrorF("-v                     screen-saver without video blanking\n");
57905b261ecSmrg    ErrorF("-wr                    create root window with white background\n");
58005b261ecSmrg    ErrorF("-maxbigreqsize         set maximal bigrequest size \n");
58105b261ecSmrg#ifdef PANORAMIX
58205b261ecSmrg    ErrorF("+xinerama              Enable XINERAMA extension\n");
58305b261ecSmrg    ErrorF("-xinerama              Disable XINERAMA extension\n");
58405b261ecSmrg#endif
585f7df2e56Smrg    ErrorF
5867e31ba66Smrg        ("-dumbSched             Disable smart scheduling and threaded input, enable old behavior\n");
58705b261ecSmrg    ErrorF("-schedInterval int     Set scheduler interval in msec\n");
58865b04b38Smrg    ErrorF("-sigstop               Enable SIGSTOP based startup\n");
58905b261ecSmrg    ErrorF("+extension name        Enable extension\n");
59005b261ecSmrg    ErrorF("-extension name        Disable extension\n");
5915a112b11Smrg    ListStaticExtensions();
59205b261ecSmrg#ifdef XDMCP
59305b261ecSmrg    XdmcpUseMsg();
59405b261ecSmrg#endif
59505b261ecSmrg    XkbUseMsg();
59605b261ecSmrg    ddxUseMsg();
59705b261ecSmrg}
59805b261ecSmrg
59905b261ecSmrg/*  This function performs a rudimentary sanity check
60005b261ecSmrg *  on the display name passed in on the command-line,
60105b261ecSmrg *  since this string is used to generate filenames.
60205b261ecSmrg *  It is especially important that the display name
60305b261ecSmrg *  not contain a "/" and not start with a "-".
60405b261ecSmrg *                                            --kvajk
60505b261ecSmrg */
606f7df2e56Smrgstatic int
60705b261ecSmrgVerifyDisplayName(const char *d)
60805b261ecSmrg{
609f7df2e56Smrg    int i;
610f7df2e56Smrg    int period_found = FALSE;
611f7df2e56Smrg    int after_period = 0;
612f7df2e56Smrg
613f7df2e56Smrg    if (d == (char *) 0)
614f7df2e56Smrg        return 0;               /*  null  */
615f7df2e56Smrg    if (*d == '\0')
616f7df2e56Smrg        return 0;               /*  empty  */
617f7df2e56Smrg    if (*d == '-')
618f7df2e56Smrg        return 0;               /*  could be confused for an option  */
619f7df2e56Smrg    if (*d == '.')
620f7df2e56Smrg        return 0;               /*  must not equal "." or ".."  */
621f7df2e56Smrg    if (strchr(d, '/') != (char *) 0)
622f7df2e56Smrg        return 0;               /*  very important!!!  */
623f7df2e56Smrg
624f7df2e56Smrg    /* Since we run atoi() on the display later, only allow
625f7df2e56Smrg       for digits, or exception of :0.0 and similar (two decimal points max)
626f7df2e56Smrg       */
627f7df2e56Smrg    for (i = 0; i < strlen(d); i++) {
628f7df2e56Smrg        if (!isdigit(d[i])) {
629f7df2e56Smrg            if (d[i] != '.' || period_found)
630f7df2e56Smrg                return 0;
631f7df2e56Smrg            period_found = TRUE;
632f7df2e56Smrg        } else if (period_found)
633f7df2e56Smrg            after_period++;
634f7df2e56Smrg
635f7df2e56Smrg        if (after_period > 2)
636f7df2e56Smrg            return 0;
637f7df2e56Smrg    }
638f7df2e56Smrg
639f7df2e56Smrg    /* don't allow for :0. */
640f7df2e56Smrg    if (period_found && after_period == 0)
641f7df2e56Smrg        return 0;
642f7df2e56Smrg
643f7df2e56Smrg    if (atol(d) > INT_MAX)
644f7df2e56Smrg        return 0;
645f7df2e56Smrg
6464202a189Smrg    return 1;
64705b261ecSmrg}
64805b261ecSmrg
649f7df2e56Smrgstatic const char *defaultNoListenList[] = {
650f7df2e56Smrg#ifndef LISTEN_TCP
651f7df2e56Smrg    "tcp",
652f7df2e56Smrg#endif
653f7df2e56Smrg#ifndef LISTEN_UNIX
654f7df2e56Smrg    "unix",
655f7df2e56Smrg#endif
656f7df2e56Smrg#ifndef LISTEN_LOCAL
657f7df2e56Smrg    "local",
658f7df2e56Smrg#endif
659f7df2e56Smrg    NULL
660f7df2e56Smrg};
661f7df2e56Smrg
66205b261ecSmrg/*
66305b261ecSmrg * This function parses the command line. Handles device-independent fields
66405b261ecSmrg * and allows ddx to handle additional fields.  It is not allowed to modify
66505b261ecSmrg * argc or any of the strings pointed to by argv.
66605b261ecSmrg */
66705b261ecSmrgvoid
66805b261ecSmrgProcessCommandLine(int argc, char *argv[])
66905b261ecSmrg{
67005b261ecSmrg    int i, skip;
67105b261ecSmrg
67205b261ecSmrg    defaultKeyboardControl.autoRepeat = TRUE;
67305b261ecSmrg
67405b261ecSmrg#ifdef NO_PART_NET
67505b261ecSmrg    PartialNetwork = FALSE;
67605b261ecSmrg#else
67705b261ecSmrg    PartialNetwork = TRUE;
67805b261ecSmrg#endif
67905b261ecSmrg
680f7df2e56Smrg    for (i = 0; defaultNoListenList[i] != NULL; i++) {
681f7df2e56Smrg        if (_XSERVTransNoListen(defaultNoListenList[i]))
682f7df2e56Smrg                    ErrorF("Failed to disable listen for %s transport",
683f7df2e56Smrg                           defaultNoListenList[i]);
684f7df2e56Smrg    }
685f7df2e56Smrg
686f7df2e56Smrg    for (i = 1; i < argc; i++) {
687f7df2e56Smrg        /* call ddx first, so it can peek/override if it wants */
688f7df2e56Smrg        if ((skip = ddxProcessArgument(argc, argv, i))) {
689f7df2e56Smrg            i += (skip - 1);
690f7df2e56Smrg        }
691f7df2e56Smrg        else if (argv[i][0] == ':') {
692f7df2e56Smrg            /* initialize display */
693f7df2e56Smrg            display = argv[i];
694f7df2e56Smrg            explicit_display = TRUE;
695f7df2e56Smrg            display++;
696f7df2e56Smrg            if (!VerifyDisplayName(display)) {
69705b261ecSmrg                ErrorF("Bad display name: %s\n", display);
69805b261ecSmrg                UseMsg();
699f7df2e56Smrg                FatalError("Bad display name, exiting: %s\n", display);
70005b261ecSmrg            }
701f7df2e56Smrg        }
702f7df2e56Smrg        else if (strcmp(argv[i], "-a") == 0) {
703f7df2e56Smrg            if (++i < argc)
704f7df2e56Smrg                defaultPointerControl.num = atoi(argv[i]);
705f7df2e56Smrg            else
706f7df2e56Smrg                UseMsg();
707f7df2e56Smrg        }
708f7df2e56Smrg        else if (strcmp(argv[i], "-ac") == 0) {
709f7df2e56Smrg            defeatAccessControl = TRUE;
710f7df2e56Smrg        }
711f7df2e56Smrg        else if (strcmp(argv[i], "-audit") == 0) {
712f7df2e56Smrg            if (++i < argc)
713f7df2e56Smrg                auditTrailLevel = atoi(argv[i]);
714f7df2e56Smrg            else
715f7df2e56Smrg                UseMsg();
716f7df2e56Smrg        }
717f7df2e56Smrg        else if (strcmp(argv[i], "-auth") == 0) {
718f7df2e56Smrg            if (++i < argc)
719f7df2e56Smrg                InitAuthorization(argv[i]);
720f7df2e56Smrg            else
721f7df2e56Smrg                UseMsg();
722f7df2e56Smrg        }
723f7df2e56Smrg        else if (strcmp(argv[i], "-br") == 0);  /* default */
724f7df2e56Smrg        else if (strcmp(argv[i], "+bs") == 0)
725f7df2e56Smrg            enableBackingStore = TRUE;
726f7df2e56Smrg        else if (strcmp(argv[i], "-bs") == 0)
727f7df2e56Smrg            disableBackingStore = TRUE;
728f7df2e56Smrg        else if (strcmp(argv[i], "c") == 0) {
729f7df2e56Smrg            if (++i < argc)
730f7df2e56Smrg                defaultKeyboardControl.click = atoi(argv[i]);
731f7df2e56Smrg            else
732f7df2e56Smrg                UseMsg();
733f7df2e56Smrg        }
734f7df2e56Smrg        else if (strcmp(argv[i], "-c") == 0) {
735f7df2e56Smrg            defaultKeyboardControl.click = 0;
736f7df2e56Smrg        }
737f7df2e56Smrg        else if (strcmp(argv[i], "-cc") == 0) {
738f7df2e56Smrg            if (++i < argc)
739f7df2e56Smrg                defaultColorVisualClass = atoi(argv[i]);
740f7df2e56Smrg            else
741f7df2e56Smrg                UseMsg();
742f7df2e56Smrg        }
743f7df2e56Smrg        else if (strcmp(argv[i], "-core") == 0) {
74405b261ecSmrg#if !defined(WIN32) || !defined(__MINGW32__)
745f7df2e56Smrg            struct rlimit core_limit;
746f7df2e56Smrg
747f7df2e56Smrg            if (getrlimit(RLIMIT_CORE, &core_limit) != -1) {
748f7df2e56Smrg                core_limit.rlim_cur = core_limit.rlim_max;
749f7df2e56Smrg                setrlimit(RLIMIT_CORE, &core_limit);
750f7df2e56Smrg            }
75105b261ecSmrg#endif
752f7df2e56Smrg            CoreDump = TRUE;
753f7df2e56Smrg        }
754f7df2e56Smrg        else if (strcmp(argv[i], "-nocursor") == 0) {
7554202a189Smrg            EnableCursor = FALSE;
7564202a189Smrg        }
757f7df2e56Smrg        else if (strcmp(argv[i], "-dpi") == 0) {
758f7df2e56Smrg            if (++i < argc)
759f7df2e56Smrg                monitorResolution = atoi(argv[i]);
760f7df2e56Smrg            else
761f7df2e56Smrg                UseMsg();
762f7df2e56Smrg        }
763f7df2e56Smrg        else if (strcmp(argv[i], "-displayfd") == 0) {
764f7df2e56Smrg            if (++i < argc) {
765f7df2e56Smrg                displayfd = atoi(argv[i]);
766f7df2e56Smrg#ifdef LOCK_SERVER
767f7df2e56Smrg                nolock = TRUE;
768f7df2e56Smrg#endif
769f7df2e56Smrg            }
770f7df2e56Smrg            else
771f7df2e56Smrg                UseMsg();
772f7df2e56Smrg        }
77305b261ecSmrg#ifdef DPMSExtension
774f7df2e56Smrg        else if (strcmp(argv[i], "dpms") == 0)
775f7df2e56Smrg            /* ignored for compatibility */ ;
776f7df2e56Smrg        else if (strcmp(argv[i], "-dpms") == 0)
777f7df2e56Smrg            DPMSDisabledSwitch = TRUE;
77805b261ecSmrg#endif
779f7df2e56Smrg        else if (strcmp(argv[i], "-deferglyphs") == 0) {
7807e31ba66Smrg            if (++i >= argc || !xfont2_parse_glyph_caching_mode(argv[i]))
781f7df2e56Smrg                UseMsg();
782f7df2e56Smrg        }
783f7df2e56Smrg        else if (strcmp(argv[i], "-f") == 0) {
784f7df2e56Smrg            if (++i < argc)
785f7df2e56Smrg                defaultKeyboardControl.bell = atoi(argv[i]);
786f7df2e56Smrg            else
787f7df2e56Smrg                UseMsg();
788f7df2e56Smrg        }
7895a112b11Smrg        else if (strcmp(argv[i], "-fakescreenfps") == 0) {
7906b007147Smrg#ifdef PRESENT
7915a112b11Smrg            if (++i < argc) {
7925a112b11Smrg                FakeScreenFps = (uint32_t) atoi(argv[i]);
7935a112b11Smrg                if (FakeScreenFps < 1 || FakeScreenFps > 600)
7945a112b11Smrg                    FatalError("fakescreenfps must be an integer in [1;600] range\n");
7955a112b11Smrg            }
796f7df2e56Smrg            else
797f7df2e56Smrg                UseMsg();
7986b007147Smrg#else
7996b007147Smrg            FatalError("fakescreenfps not available without PRESENT\n");
8006b007147Smrg            UseMsg();
8016b007147Smrg#endif
802f7df2e56Smrg        }
803f7df2e56Smrg        else if (strcmp(argv[i], "-fp") == 0) {
804f7df2e56Smrg            if (++i < argc) {
805f7df2e56Smrg                defaultFontPath = argv[i];
806f7df2e56Smrg            }
807f7df2e56Smrg            else
808f7df2e56Smrg                UseMsg();
809f7df2e56Smrg        }
810f7df2e56Smrg        else if (strcmp(argv[i], "-help") == 0) {
811f7df2e56Smrg            UseMsg();
812f7df2e56Smrg            exit(0);
813f7df2e56Smrg        }
814f7df2e56Smrg        else if (strcmp(argv[i], "+iglx") == 0)
815f7df2e56Smrg            enableIndirectGLX = TRUE;
816f7df2e56Smrg        else if (strcmp(argv[i], "-iglx") == 0)
817f7df2e56Smrg            enableIndirectGLX = FALSE;
818f7df2e56Smrg        else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) {
819f7df2e56Smrg            if (skip > 0)
820f7df2e56Smrg                i += skip - 1;
821f7df2e56Smrg            else
822f7df2e56Smrg                UseMsg();
823f7df2e56Smrg        }
82405b261ecSmrg#ifdef RLIMIT_DATA
825f7df2e56Smrg        else if (strcmp(argv[i], "-ld") == 0) {
826f7df2e56Smrg            if (++i < argc) {
827f7df2e56Smrg                limitDataSpace = atoi(argv[i]);
828f7df2e56Smrg                if (limitDataSpace > 0)
829f7df2e56Smrg                    limitDataSpace *= 1024;
830f7df2e56Smrg            }
831f7df2e56Smrg            else
832f7df2e56Smrg                UseMsg();
833f7df2e56Smrg        }
83405b261ecSmrg#endif
83505b261ecSmrg#ifdef RLIMIT_NOFILE
836f7df2e56Smrg        else if (strcmp(argv[i], "-lf") == 0) {
837f7df2e56Smrg            if (++i < argc)
838f7df2e56Smrg                limitNoFile = atoi(argv[i]);
839f7df2e56Smrg            else
840f7df2e56Smrg                UseMsg();
841f7df2e56Smrg        }
84205b261ecSmrg#endif
84305b261ecSmrg#ifdef RLIMIT_STACK
844f7df2e56Smrg        else if (strcmp(argv[i], "-ls") == 0) {
845f7df2e56Smrg            if (++i < argc) {
846f7df2e56Smrg                limitStackSpace = atoi(argv[i]);
847f7df2e56Smrg                if (limitStackSpace > 0)
848f7df2e56Smrg                    limitStackSpace *= 1024;
849f7df2e56Smrg            }
850f7df2e56Smrg            else
851f7df2e56Smrg                UseMsg();
852f7df2e56Smrg        }
85305b261ecSmrg#endif
854f7df2e56Smrg#ifdef LOCK_SERVER
855f7df2e56Smrg        else if (strcmp(argv[i], "-nolock") == 0) {
85605b261ecSmrg#if !defined(WIN32) && !defined(__CYGWIN__)
857f7df2e56Smrg            if (getuid() != 0)
858f7df2e56Smrg                ErrorF
859f7df2e56Smrg                    ("Warning: the -nolock option can only be used by root\n");
860f7df2e56Smrg            else
86105b261ecSmrg#endif
862f7df2e56Smrg                nolock = TRUE;
863f7df2e56Smrg        }
864f7df2e56Smrg#endif
865f7df2e56Smrg	else if ( strcmp( argv[i], "-maxclients") == 0)
86605b261ecSmrg	{
867f7df2e56Smrg	    if (++i < argc) {
868f7df2e56Smrg		LimitClients = atoi(argv[i]);
869f7df2e56Smrg		if (LimitClients != 64 &&
870f7df2e56Smrg		    LimitClients != 128 &&
871f7df2e56Smrg		    LimitClients != 256 &&
8727e31ba66Smrg		    LimitClients != 512 &&
8737e31ba66Smrg                    LimitClients != 1024 &&
8747e31ba66Smrg                    LimitClients != 2048) {
8757e31ba66Smrg		    FatalError("maxclients must be one of 64, 128, 256, 512, 1024 or 2048\n");
876f7df2e56Smrg		}
877f7df2e56Smrg	    } else
87805b261ecSmrg		UseMsg();
87905b261ecSmrg	}
880f7df2e56Smrg        else if (strcmp(argv[i], "-nolisten") == 0) {
881f7df2e56Smrg            if (++i < argc) {
882f7df2e56Smrg                if (_XSERVTransNoListen(argv[i]))
883f7df2e56Smrg                    ErrorF("Failed to disable listen for %s transport",
884f7df2e56Smrg                           argv[i]);
885f7df2e56Smrg            }
886f7df2e56Smrg            else
887f7df2e56Smrg                UseMsg();
888f7df2e56Smrg        }
889f7df2e56Smrg        else if (strcmp(argv[i], "-listen") == 0) {
890f7df2e56Smrg            if (++i < argc) {
891f7df2e56Smrg                if (_XSERVTransListen(argv[i]))
892f7df2e56Smrg                    ErrorF("Failed to enable listen for %s transport",
893f7df2e56Smrg                           argv[i]);
894f7df2e56Smrg            }
895f7df2e56Smrg            else
896f7df2e56Smrg                UseMsg();
897f7df2e56Smrg        }
898f7df2e56Smrg        else if (strcmp(argv[i], "-noreset") == 0) {
899f7df2e56Smrg            dispatchExceptionAtReset = 0;
900f7df2e56Smrg        }
901f7df2e56Smrg        else if (strcmp(argv[i], "-reset") == 0) {
902f7df2e56Smrg            dispatchExceptionAtReset = DE_RESET;
903f7df2e56Smrg        }
904f7df2e56Smrg        else if (strcmp(argv[i], "-p") == 0) {
905f7df2e56Smrg            if (++i < argc)
906f7df2e56Smrg                defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) *
907f7df2e56Smrg                    MILLI_PER_MIN;
908f7df2e56Smrg            else
909f7df2e56Smrg                UseMsg();
910f7df2e56Smrg        }
911f7df2e56Smrg        else if (strcmp(argv[i], "-pogo") == 0) {
912f7df2e56Smrg            dispatchException = DE_TERMINATE;
913f7df2e56Smrg        }
914f7df2e56Smrg        else if (strcmp(argv[i], "-pn") == 0)
915f7df2e56Smrg            PartialNetwork = TRUE;
916f7df2e56Smrg        else if (strcmp(argv[i], "-nopn") == 0)
917f7df2e56Smrg            PartialNetwork = FALSE;
918f7df2e56Smrg        else if (strcmp(argv[i], "r") == 0)
919f7df2e56Smrg            defaultKeyboardControl.autoRepeat = TRUE;
920f7df2e56Smrg        else if (strcmp(argv[i], "-r") == 0)
921f7df2e56Smrg            defaultKeyboardControl.autoRepeat = FALSE;
922f7df2e56Smrg        else if (strcmp(argv[i], "-retro") == 0)
923f7df2e56Smrg            party_like_its_1989 = TRUE;
924f7df2e56Smrg	else if (strcmp(argv[i], "-noretro") == 0)
925daf23d7fSsnj	    party_like_its_1989 = FALSE;
926f7df2e56Smrg        else if (strcmp(argv[i], "-s") == 0) {
927f7df2e56Smrg            if (++i < argc)
928f7df2e56Smrg                defaultScreenSaverTime = ((CARD32) atoi(argv[i])) *
929f7df2e56Smrg                    MILLI_PER_MIN;
930f7df2e56Smrg            else
931f7df2e56Smrg                UseMsg();
932f7df2e56Smrg        }
933f7df2e56Smrg        else if (strcmp(argv[i], "-seat") == 0) {
934f7df2e56Smrg            if (++i < argc)
935f7df2e56Smrg                SeatId = argv[i];
936f7df2e56Smrg            else
937f7df2e56Smrg                UseMsg();
938f7df2e56Smrg        }
939f7df2e56Smrg        else if (strcmp(argv[i], "-t") == 0) {
940f7df2e56Smrg            if (++i < argc)
941f7df2e56Smrg                defaultPointerControl.threshold = atoi(argv[i]);
942f7df2e56Smrg            else
943f7df2e56Smrg                UseMsg();
944f7df2e56Smrg        }
945f7df2e56Smrg        else if (strcmp(argv[i], "-terminate") == 0) {
946f7df2e56Smrg            dispatchExceptionAtReset = DE_TERMINATE;
9475a112b11Smrg            terminateDelay = -1;
9485a112b11Smrg            if ((i + 1 < argc) && (isdigit(*argv[i + 1])))
9495a112b11Smrg               terminateDelay = atoi(argv[++i]);
9505a112b11Smrg            terminateDelay = max(0, terminateDelay);
951f7df2e56Smrg        }
952f7df2e56Smrg        else if (strcmp(argv[i], "-tst") == 0) {
953f7df2e56Smrg            noTestExtensions = TRUE;
954f7df2e56Smrg        }
955f7df2e56Smrg        else if (strcmp(argv[i], "v") == 0)
956f7df2e56Smrg            defaultScreenSaverBlanking = PreferBlanking;
957f7df2e56Smrg        else if (strcmp(argv[i], "-v") == 0)
958f7df2e56Smrg            defaultScreenSaverBlanking = DontPreferBlanking;
959f7df2e56Smrg        else if (strcmp(argv[i], "-wr") == 0)
96005b261ecSmrg            whiteRoot = TRUE;
961f7df2e56Smrg        else if (strcmp(argv[i], "-background") == 0) {
962f7df2e56Smrg            if (++i < argc) {
963f7df2e56Smrg                if (!strcmp(argv[i], "none"))
96465b04b38Smrg                    bgNoneRoot = TRUE;
96565b04b38Smrg                else
96665b04b38Smrg                    UseMsg();
96765b04b38Smrg            }
96865b04b38Smrg        }
969f7df2e56Smrg        else if (strcmp(argv[i], "-maxbigreqsize") == 0) {
970f7df2e56Smrg            if (++i < argc) {
971f7df2e56Smrg                long reqSizeArg = atol(argv[i]);
972f7df2e56Smrg
973f7df2e56Smrg                /* Request size > 128MB does not make much sense... */
974f7df2e56Smrg                if (reqSizeArg > 0L && reqSizeArg < 128L) {
975f7df2e56Smrg                    maxBigRequestSize = (reqSizeArg * 1048576L) - 1L;
976f7df2e56Smrg                }
977f7df2e56Smrg                else {
978f7df2e56Smrg                    UseMsg();
979f7df2e56Smrg                }
980f7df2e56Smrg            }
981f7df2e56Smrg            else {
982f7df2e56Smrg                UseMsg();
983f7df2e56Smrg            }
984f7df2e56Smrg        }
985f7df2e56Smrg#ifdef PANORAMIX
986f7df2e56Smrg        else if (strcmp(argv[i], "+xinerama") == 0) {
987f7df2e56Smrg            noPanoramiXExtension = FALSE;
988f7df2e56Smrg        }
989f7df2e56Smrg        else if (strcmp(argv[i], "-xinerama") == 0) {
990f7df2e56Smrg            noPanoramiXExtension = TRUE;
991f7df2e56Smrg        }
992f7df2e56Smrg        else if (strcmp(argv[i], "-disablexineramaextension") == 0) {
993f7df2e56Smrg            PanoramiXExtensionDisabledHack = TRUE;
994f7df2e56Smrg        }
995f7df2e56Smrg#endif
996f7df2e56Smrg        else if (strcmp(argv[i], "-I") == 0) {
997f7df2e56Smrg            /* ignore all remaining arguments */
998f7df2e56Smrg            break;
999f7df2e56Smrg        }
1000f7df2e56Smrg        else if (strncmp(argv[i], "tty", 3) == 0) {
1001f7df2e56Smrg            /* init supplies us with this useless information */
1002f7df2e56Smrg        }
1003f7df2e56Smrg#ifdef XDMCP
1004f7df2e56Smrg        else if ((skip = XdmcpOptions(argc, argv, i)) != i) {
1005f7df2e56Smrg            i = skip - 1;
1006f7df2e56Smrg        }
1007f7df2e56Smrg#endif
1008f7df2e56Smrg        else if (strcmp(argv[i], "-dumbSched") == 0) {
10097e31ba66Smrg            InputThreadEnable = FALSE;
10107e31ba66Smrg#ifdef HAVE_SETITIMER
10117e31ba66Smrg            SmartScheduleSignalEnable = FALSE;
10127e31ba66Smrg#endif
1013f7df2e56Smrg        }
1014f7df2e56Smrg        else if (strcmp(argv[i], "-schedInterval") == 0) {
1015f7df2e56Smrg            if (++i < argc) {
1016f7df2e56Smrg                SmartScheduleInterval = atoi(argv[i]);
1017f7df2e56Smrg                SmartScheduleSlice = SmartScheduleInterval;
1018f7df2e56Smrg            }
1019f7df2e56Smrg            else
1020f7df2e56Smrg                UseMsg();
1021f7df2e56Smrg        }
1022f7df2e56Smrg        else if (strcmp(argv[i], "-schedMax") == 0) {
1023f7df2e56Smrg            if (++i < argc) {
1024f7df2e56Smrg                SmartScheduleMaxSlice = atoi(argv[i]);
1025f7df2e56Smrg            }
1026f7df2e56Smrg            else
1027f7df2e56Smrg                UseMsg();
1028f7df2e56Smrg        }
1029f7df2e56Smrg        else if (strcmp(argv[i], "-render") == 0) {
1030f7df2e56Smrg            if (++i < argc) {
1031f7df2e56Smrg                int policy = PictureParseCmapPolicy(argv[i]);
1032f7df2e56Smrg
1033f7df2e56Smrg                if (policy != PictureCmapPolicyInvalid)
1034f7df2e56Smrg                    PictureCmapPolicy = policy;
1035f7df2e56Smrg                else
1036f7df2e56Smrg                    UseMsg();
1037f7df2e56Smrg            }
1038f7df2e56Smrg            else
1039f7df2e56Smrg                UseMsg();
1040f7df2e56Smrg        }
1041f7df2e56Smrg        else if (strcmp(argv[i], "-sigstop") == 0) {
1042f7df2e56Smrg            RunFromSigStopParent = TRUE;
1043f7df2e56Smrg        }
1044f7df2e56Smrg        else if (strcmp(argv[i], "+extension") == 0) {
1045f7df2e56Smrg            if (++i < argc) {
1046f7df2e56Smrg                if (!EnableDisableExtension(argv[i], TRUE))
1047f7df2e56Smrg                    EnableDisableExtensionError(argv[i], TRUE);
1048f7df2e56Smrg            }
1049f7df2e56Smrg            else
1050f7df2e56Smrg                UseMsg();
1051f7df2e56Smrg        }
1052f7df2e56Smrg        else if (strcmp(argv[i], "-extension") == 0) {
1053f7df2e56Smrg            if (++i < argc) {
1054f7df2e56Smrg                if (!EnableDisableExtension(argv[i], FALSE))
1055f7df2e56Smrg                    EnableDisableExtensionError(argv[i], FALSE);
1056f7df2e56Smrg            }
1057f7df2e56Smrg            else
1058f7df2e56Smrg                UseMsg();
1059f7df2e56Smrg        }
1060f7df2e56Smrg        else {
1061f7df2e56Smrg            ErrorF("Unrecognized option: %s\n", argv[i]);
1062f7df2e56Smrg            UseMsg();
1063f7df2e56Smrg            FatalError("Unrecognized option: %s\n", argv[i]);
106405b261ecSmrg        }
106505b261ecSmrg    }
106605b261ecSmrg}
106705b261ecSmrg
106805b261ecSmrg/* Implement a simple-minded font authorization scheme.  The authorization
106905b261ecSmrg   name is "hp-hostname-1", the contents are simply the host name. */
107005b261ecSmrgint
1071f7df2e56Smrgset_font_authorizations(char **authorizations, int *authlen, void *client)
107205b261ecSmrg{
107305b261ecSmrg#define AUTHORIZATION_NAME "hp-hostname-1"
10747e31ba66Smrg#if defined(TCPCONN)
107505b261ecSmrg    static char *result = NULL;
107605b261ecSmrg    static char *p = NULL;
107705b261ecSmrg
1078f7df2e56Smrg    if (p == NULL) {
1079f7df2e56Smrg        char hname[1024], *hnameptr;
1080f7df2e56Smrg        unsigned int len;
1081f7df2e56Smrg
108205b261ecSmrg#if defined(IPv6) && defined(AF_INET6)
1083f7df2e56Smrg        struct addrinfo hints, *ai = NULL;
108405b261ecSmrg#else
1085f7df2e56Smrg        struct hostent *host;
1086f7df2e56Smrg
108705b261ecSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1088f7df2e56Smrg        _Xgethostbynameparams hparams;
108905b261ecSmrg#endif
109005b261ecSmrg#endif
109105b261ecSmrg
1092f7df2e56Smrg        gethostname(hname, 1024);
109305b261ecSmrg#if defined(IPv6) && defined(AF_INET6)
1094f7df2e56Smrg        memset(&hints, 0, sizeof(hints));
1095f7df2e56Smrg        hints.ai_flags = AI_CANONNAME;
1096f7df2e56Smrg        if (getaddrinfo(hname, NULL, &hints, &ai) == 0) {
1097f7df2e56Smrg            hnameptr = ai->ai_canonname;
1098f7df2e56Smrg        }
1099f7df2e56Smrg        else {
1100f7df2e56Smrg            hnameptr = hname;
1101f7df2e56Smrg        }
110205b261ecSmrg#else
1103f7df2e56Smrg        host = _XGethostbyname(hname, hparams);
1104f7df2e56Smrg        if (host == NULL)
1105f7df2e56Smrg            hnameptr = hname;
1106f7df2e56Smrg        else
1107f7df2e56Smrg            hnameptr = host->h_name;
110805b261ecSmrg#endif
110905b261ecSmrg
1110f7df2e56Smrg        len = strlen(hnameptr) + 1;
1111f7df2e56Smrg        result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4);
111205b261ecSmrg
1113f7df2e56Smrg        p = result;
111405b261ecSmrg        *p++ = sizeof(AUTHORIZATION_NAME) >> 8;
111505b261ecSmrg        *p++ = sizeof(AUTHORIZATION_NAME) & 0xff;
111605b261ecSmrg        *p++ = (len) >> 8;
111705b261ecSmrg        *p++ = (len & 0xff);
111805b261ecSmrg
1119f7df2e56Smrg        memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME));
1120f7df2e56Smrg        p += sizeof(AUTHORIZATION_NAME);
1121f7df2e56Smrg        memmove(p, hnameptr, len);
1122f7df2e56Smrg        p += len;
112305b261ecSmrg#if defined(IPv6) && defined(AF_INET6)
1124f7df2e56Smrg        if (ai) {
1125f7df2e56Smrg            freeaddrinfo(ai);
1126f7df2e56Smrg        }
112705b261ecSmrg#endif
112805b261ecSmrg    }
112905b261ecSmrg    *authlen = p - result;
113005b261ecSmrg    *authorizations = result;
113105b261ecSmrg    return 1;
1132f7df2e56Smrg#else                           /* TCPCONN */
113305b261ecSmrg    return 0;
1134f7df2e56Smrg#endif                          /* TCPCONN */
113505b261ecSmrg}
113605b261ecSmrg
11374202a189Smrgvoid *
113805b261ecSmrgXNFalloc(unsigned long amount)
113905b261ecSmrg{
11404202a189Smrg    void *ptr = malloc(amount);
1141f7df2e56Smrg
114205b261ecSmrg    if (!ptr)
114305b261ecSmrg        FatalError("Out of memory");
11444642e01fSmrg    return ptr;
114505b261ecSmrg}
114605b261ecSmrg
1147f7df2e56Smrg/* The original XNFcalloc was used with the xnfcalloc macro which multiplied
1148f7df2e56Smrg * the arguments at the call site without allowing calloc to check for overflow.
1149f7df2e56Smrg * XNFcallocarray was added to fix that without breaking ABI.
1150f7df2e56Smrg */
11514202a189Smrgvoid *
1152f7df2e56SmrgXNFcalloc(unsigned long amount)
115305b261ecSmrg{
1154f7df2e56Smrg    return XNFcallocarray(1, amount);
115505b261ecSmrg}
115605b261ecSmrg
11574202a189Smrgvoid *
1158f7df2e56SmrgXNFcallocarray(size_t nmemb, size_t size)
115905b261ecSmrg{
1160f7df2e56Smrg    void *ret = calloc(nmemb, size);
1161f7df2e56Smrg
11624202a189Smrg    if (!ret)
11634202a189Smrg        FatalError("XNFcalloc: Out of memory");
116405b261ecSmrg    return ret;
116505b261ecSmrg}
116605b261ecSmrg
11674202a189Smrgvoid *
11684202a189SmrgXNFrealloc(void *ptr, unsigned long amount)
116905b261ecSmrg{
11704202a189Smrg    void *ret = realloc(ptr, amount);
1171f7df2e56Smrg
11724202a189Smrg    if (!ret)
1173f7df2e56Smrg        FatalError("XNFrealloc: Out of memory");
11744202a189Smrg    return ret;
117505b261ecSmrg}
117605b261ecSmrg
1177f7df2e56Smrgvoid *
1178f7df2e56SmrgXNFreallocarray(void *ptr, size_t nmemb, size_t size)
117905b261ecSmrg{
1180f7df2e56Smrg    void *ret = reallocarray(ptr, nmemb, size);
118105b261ecSmrg
1182f7df2e56Smrg    if (!ret)
1183f7df2e56Smrg        FatalError("XNFreallocarray: Out of memory");
1184f7df2e56Smrg    return ret;
1185f7df2e56Smrg}
118605b261ecSmrg
118705b261ecSmrgchar *
118805b261ecSmrgXstrdup(const char *s)
118905b261ecSmrg{
119005b261ecSmrg    if (s == NULL)
1191f7df2e56Smrg        return NULL;
11924202a189Smrg    return strdup(s);
119305b261ecSmrg}
119405b261ecSmrg
11954202a189Smrgchar *
119605b261ecSmrgXNFstrdup(const char *s)
119705b261ecSmrg{
11984202a189Smrg    char *ret;
119905b261ecSmrg
120005b261ecSmrg    if (s == NULL)
1201f7df2e56Smrg        return NULL;
120205b261ecSmrg
12034202a189Smrg    ret = strdup(s);
12044202a189Smrg    if (!ret)
1205f7df2e56Smrg        FatalError("XNFstrdup: Out of memory");
12064202a189Smrg    return ret;
120705b261ecSmrg}
120805b261ecSmrg
12094642e01fSmrgvoid
1210f7df2e56SmrgSmartScheduleStopTimer(void)
121105b261ecSmrg{
12127e31ba66Smrg#ifdef HAVE_SETITIMER
1213f7df2e56Smrg    struct itimerval timer;
1214f7df2e56Smrg
12157e31ba66Smrg    if (!SmartScheduleSignalEnable)
1216f7df2e56Smrg        return;
121705b261ecSmrg    timer.it_interval.tv_sec = 0;
121805b261ecSmrg    timer.it_interval.tv_usec = 0;
121905b261ecSmrg    timer.it_value.tv_sec = 0;
122005b261ecSmrg    timer.it_value.tv_usec = 0;
1221f7df2e56Smrg    (void) setitimer(ITIMER_REAL, &timer, 0);
1222f7df2e56Smrg#endif
122305b261ecSmrg}
122405b261ecSmrg
12254642e01fSmrgvoid
1226f7df2e56SmrgSmartScheduleStartTimer(void)
122705b261ecSmrg{
12287e31ba66Smrg#ifdef HAVE_SETITIMER
1229f7df2e56Smrg    struct itimerval timer;
1230f7df2e56Smrg
12317e31ba66Smrg    if (!SmartScheduleSignalEnable)
1232f7df2e56Smrg        return;
123305b261ecSmrg    timer.it_interval.tv_sec = 0;
123405b261ecSmrg    timer.it_interval.tv_usec = SmartScheduleInterval * 1000;
123505b261ecSmrg    timer.it_value.tv_sec = 0;
123605b261ecSmrg    timer.it_value.tv_usec = SmartScheduleInterval * 1000;
1237f7df2e56Smrg    setitimer(ITIMER_REAL, &timer, 0);
1238f7df2e56Smrg#endif
123905b261ecSmrg}
124005b261ecSmrg
12417e31ba66Smrg#ifdef HAVE_SETITIMER
124205b261ecSmrgstatic void
1243f7df2e56SmrgSmartScheduleTimer(int sig)
124405b261ecSmrg{
124505b261ecSmrg    SmartScheduleTime += SmartScheduleInterval;
124605b261ecSmrg}
124705b261ecSmrg
1248f7df2e56Smrgstatic int
1249f7df2e56SmrgSmartScheduleEnable(void)
125005b261ecSmrg{
1251f7df2e56Smrg    int ret = 0;
1252f7df2e56Smrg    struct sigaction act;
125305b261ecSmrg
12547e31ba66Smrg    if (!SmartScheduleSignalEnable)
1255f7df2e56Smrg        return 0;
125665b04b38Smrg
12574202a189Smrg    memset((char *) &act, 0, sizeof(struct sigaction));
125805b261ecSmrg
125905b261ecSmrg    /* Set up the timer signal function */
1260f7df2e56Smrg    act.sa_flags = SA_RESTART;
126105b261ecSmrg    act.sa_handler = SmartScheduleTimer;
1262f7df2e56Smrg    sigemptyset(&act.sa_mask);
1263f7df2e56Smrg    sigaddset(&act.sa_mask, SIGALRM);
1264f7df2e56Smrg    ret = sigaction(SIGALRM, &act, 0);
1265f7df2e56Smrg    return ret;
1266f7df2e56Smrg}
1267f7df2e56Smrg
1268f7df2e56Smrgstatic int
1269f7df2e56SmrgSmartSchedulePause(void)
1270f7df2e56Smrg{
1271f7df2e56Smrg    int ret = 0;
1272f7df2e56Smrg    struct sigaction act;
1273f7df2e56Smrg
12747e31ba66Smrg    if (!SmartScheduleSignalEnable)
1275f7df2e56Smrg        return 0;
1276f7df2e56Smrg
1277f7df2e56Smrg    memset((char *) &act, 0, sizeof(struct sigaction));
1278f7df2e56Smrg
1279f7df2e56Smrg    act.sa_handler = SIG_IGN;
1280f7df2e56Smrg    sigemptyset(&act.sa_mask);
1281f7df2e56Smrg    ret = sigaction(SIGALRM, &act, 0);
1282f7df2e56Smrg    return ret;
1283f7df2e56Smrg}
12847e31ba66Smrg#endif
1285f7df2e56Smrg
1286f7df2e56Smrgvoid
1287f7df2e56SmrgSmartScheduleInit(void)
1288f7df2e56Smrg{
12897e31ba66Smrg#ifdef HAVE_SETITIMER
1290f7df2e56Smrg    if (SmartScheduleEnable() < 0) {
1291f7df2e56Smrg        perror("sigaction for smart scheduler");
12927e31ba66Smrg        SmartScheduleSignalEnable = FALSE;
129305b261ecSmrg    }
12947e31ba66Smrg#endif
129505b261ecSmrg}
129605b261ecSmrg
12975a112b11Smrg#ifdef HAVE_SIGPROCMASK
1298f7df2e56Smrgstatic sigset_t PreviousSignalMask;
1299f7df2e56Smrgstatic int BlockedSignalCount;
130005b261ecSmrg#endif
130105b261ecSmrg
130205b261ecSmrgvoid
1303f7df2e56SmrgOsBlockSignals(void)
130405b261ecSmrg{
13055a112b11Smrg#ifdef HAVE_SIGPROCMASK
1306f7df2e56Smrg    if (BlockedSignalCount++ == 0) {
1307f7df2e56Smrg        sigset_t set;
1308f7df2e56Smrg
1309f7df2e56Smrg        sigemptyset(&set);
1310f7df2e56Smrg        sigaddset(&set, SIGALRM);
1311f7df2e56Smrg        sigaddset(&set, SIGVTALRM);
131205b261ecSmrg#ifdef SIGWINCH
1313f7df2e56Smrg        sigaddset(&set, SIGWINCH);
1314f7df2e56Smrg#endif
1315f7df2e56Smrg        sigaddset(&set, SIGTSTP);
1316f7df2e56Smrg        sigaddset(&set, SIGTTIN);
1317f7df2e56Smrg        sigaddset(&set, SIGTTOU);
1318f7df2e56Smrg        sigaddset(&set, SIGCHLD);
13197e31ba66Smrg        xthread_sigmask(SIG_BLOCK, &set, &PreviousSignalMask);
132005b261ecSmrg    }
132105b261ecSmrg#endif
132205b261ecSmrg}
132305b261ecSmrg
132405b261ecSmrgvoid
1325f7df2e56SmrgOsReleaseSignals(void)
132605b261ecSmrg{
13275a112b11Smrg#ifdef HAVE_SIGPROCMASK
1328f7df2e56Smrg    if (--BlockedSignalCount == 0) {
13297e31ba66Smrg        xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0);
133005b261ecSmrg    }
133105b261ecSmrg#endif
133205b261ecSmrg}
133305b261ecSmrg
1334f7df2e56Smrgvoid
1335f7df2e56SmrgOsResetSignals(void)
1336f7df2e56Smrg{
13375a112b11Smrg#ifdef HAVE_SIGPROCMASK
1338f7df2e56Smrg    while (BlockedSignalCount > 0)
1339f7df2e56Smrg        OsReleaseSignals();
13407e31ba66Smrg    input_force_unlock();
1341f7df2e56Smrg#endif
1342f7df2e56Smrg}
1343f7df2e56Smrg
13444202a189Smrg/*
13454202a189Smrg * Pending signals may interfere with core dumping. Provide a
13464202a189Smrg * mechanism to block signals when aborting.
13474202a189Smrg */
13484202a189Smrg
13494202a189Smrgvoid
1350f7df2e56SmrgOsAbort(void)
13514202a189Smrg{
13524202a189Smrg#ifndef __APPLE__
13534202a189Smrg    OsBlockSignals();
13547e31ba66Smrg#endif
13557e31ba66Smrg#if !defined(WIN32) || defined(__CYGWIN__)
13567e31ba66Smrg    /* abort() raises SIGABRT, so we have to stop handling that to prevent
13577e31ba66Smrg     * recursion
13587e31ba66Smrg     */
13597e31ba66Smrg    OsSignal(SIGABRT, SIG_DFL);
13604202a189Smrg#endif
13614202a189Smrg    abort();
13624202a189Smrg}
13634202a189Smrg
136405b261ecSmrg#if !defined(WIN32)
136505b261ecSmrg/*
136605b261ecSmrg * "safer" versions of system(3), popen(3) and pclose(3) which give up
136705b261ecSmrg * all privs before running a command.
136805b261ecSmrg *
136905b261ecSmrg * This is based on the code in FreeBSD 2.2 libc.
137005b261ecSmrg *
137105b261ecSmrg * XXX It'd be good to redirect stderr so that it ends up in the log file
137205b261ecSmrg * as well.  As it is now, xkbcomp messages don't end up in the log file.
137305b261ecSmrg */
137405b261ecSmrg
137505b261ecSmrgint
1376f7df2e56SmrgSystem(const char *command)
137705b261ecSmrg{
137805b261ecSmrg    int pid, p;
1379f7df2e56Smrg    void (*csig) (int);
138005b261ecSmrg    int status;
138105b261ecSmrg
138205b261ecSmrg    if (!command)
1383f7df2e56Smrg        return 1;
138405b261ecSmrg
13857e31ba66Smrg    csig = OsSignal(SIGCHLD, SIG_DFL);
138605b261ecSmrg    if (csig == SIG_ERR) {
1387f7df2e56Smrg        perror("signal");
1388f7df2e56Smrg        return -1;
138905b261ecSmrg    }
139065b04b38Smrg    DebugF("System: `%s'\n", command);
139105b261ecSmrg
139205b261ecSmrg    switch (pid = fork()) {
1393f7df2e56Smrg    case -1:                   /* error */
1394f7df2e56Smrg        p = -1;
1395f7df2e56Smrg        break;
1396f7df2e56Smrg    case 0:                    /* child */
1397f7df2e56Smrg        if (setgid(getgid()) == -1)
1398f7df2e56Smrg            _exit(127);
1399f7df2e56Smrg        if (setuid(getuid()) == -1)
1400f7df2e56Smrg            _exit(127);
1401f7df2e56Smrg        execl("/bin/sh", "sh", "-c", command, (char *) NULL);
1402f7df2e56Smrg        _exit(127);
1403f7df2e56Smrg    default:                   /* parent */
1404f7df2e56Smrg        do {
1405f7df2e56Smrg            p = waitpid(pid, &status, 0);
1406f7df2e56Smrg        } while (p == -1 && errno == EINTR);
1407f7df2e56Smrg
140805b261ecSmrg    }
140905b261ecSmrg
14107e31ba66Smrg    if (OsSignal(SIGCHLD, csig) == SIG_ERR) {
1411f7df2e56Smrg        perror("signal");
1412f7df2e56Smrg        return -1;
141305b261ecSmrg    }
141405b261ecSmrg
141505b261ecSmrg    return p == -1 ? -1 : status;
141605b261ecSmrg}
141705b261ecSmrg
141805b261ecSmrgstatic struct pid {
141905b261ecSmrg    struct pid *next;
142005b261ecSmrg    FILE *fp;
142105b261ecSmrg    int pid;
142205b261ecSmrg} *pidlist;
142305b261ecSmrg
1424f7df2e56Smrgvoid *
1425f7df2e56SmrgPopen(const char *command, const char *type)
142605b261ecSmrg{
142705b261ecSmrg    struct pid *cur;
142805b261ecSmrg    FILE *iop;
142905b261ecSmrg    int pdes[2], pid;
143005b261ecSmrg
143105b261ecSmrg    if (command == NULL || type == NULL)
1432f7df2e56Smrg        return NULL;
143305b261ecSmrg
143405b261ecSmrg    if ((*type != 'r' && *type != 'w') || type[1])
1435f7df2e56Smrg        return NULL;
143605b261ecSmrg
14374202a189Smrg    if ((cur = malloc(sizeof(struct pid))) == NULL)
1438f7df2e56Smrg        return NULL;
143905b261ecSmrg
144005b261ecSmrg    if (pipe(pdes) < 0) {
1441f7df2e56Smrg        free(cur);
1442f7df2e56Smrg        return NULL;
144305b261ecSmrg    }
144405b261ecSmrg
144505b261ecSmrg    /* Ignore the smart scheduler while this is going on */
14467e31ba66Smrg#ifdef HAVE_SETITIMER
1447f7df2e56Smrg    if (SmartSchedulePause() < 0) {
1448f7df2e56Smrg        close(pdes[0]);
1449f7df2e56Smrg        close(pdes[1]);
1450f7df2e56Smrg        free(cur);
1451f7df2e56Smrg        perror("signal");
1452f7df2e56Smrg        return NULL;
145305b261ecSmrg    }
14547e31ba66Smrg#endif
145505b261ecSmrg
145605b261ecSmrg    switch (pid = fork()) {
1457f7df2e56Smrg    case -1:                   /* error */
1458f7df2e56Smrg        close(pdes[0]);
1459f7df2e56Smrg        close(pdes[1]);
1460f7df2e56Smrg        free(cur);
14617e31ba66Smrg#ifdef HAVE_SETITIMER
1462f7df2e56Smrg        if (SmartScheduleEnable() < 0)
1463f7df2e56Smrg            perror("signal");
14647e31ba66Smrg#endif
1465f7df2e56Smrg        return NULL;
1466f7df2e56Smrg    case 0:                    /* child */
1467f7df2e56Smrg        if (setgid(getgid()) == -1)
1468f7df2e56Smrg            _exit(127);
1469f7df2e56Smrg        if (setuid(getuid()) == -1)
1470f7df2e56Smrg            _exit(127);
1471f7df2e56Smrg        if (*type == 'r') {
1472f7df2e56Smrg            if (pdes[1] != 1) {
1473f7df2e56Smrg                /* stdout */
1474f7df2e56Smrg                dup2(pdes[1], 1);
1475f7df2e56Smrg                close(pdes[1]);
1476f7df2e56Smrg            }
1477f7df2e56Smrg            close(pdes[0]);
1478f7df2e56Smrg        }
1479f7df2e56Smrg        else {
1480f7df2e56Smrg            if (pdes[0] != 0) {
1481f7df2e56Smrg                /* stdin */
1482f7df2e56Smrg                dup2(pdes[0], 0);
1483f7df2e56Smrg                close(pdes[0]);
1484f7df2e56Smrg            }
1485f7df2e56Smrg            close(pdes[1]);
1486f7df2e56Smrg        }
1487f7df2e56Smrg        execl("/bin/sh", "sh", "-c", command, (char *) NULL);
1488f7df2e56Smrg        _exit(127);
148905b261ecSmrg    }
149005b261ecSmrg
149105b261ecSmrg    /* Avoid EINTR during stdio calls */
1492f7df2e56Smrg    OsBlockSignals();
1493f7df2e56Smrg
149405b261ecSmrg    /* parent */
149505b261ecSmrg    if (*type == 'r') {
1496f7df2e56Smrg        iop = fdopen(pdes[0], type);
1497f7df2e56Smrg        close(pdes[1]);
1498f7df2e56Smrg    }
1499f7df2e56Smrg    else {
1500f7df2e56Smrg        iop = fdopen(pdes[1], type);
1501f7df2e56Smrg        close(pdes[0]);
150205b261ecSmrg    }
150305b261ecSmrg
150405b261ecSmrg    cur->fp = iop;
150505b261ecSmrg    cur->pid = pid;
150605b261ecSmrg    cur->next = pidlist;
150705b261ecSmrg    pidlist = cur;
150805b261ecSmrg
150965b04b38Smrg    DebugF("Popen: `%s', fp = %p\n", command, iop);
151005b261ecSmrg
151105b261ecSmrg    return iop;
151205b261ecSmrg}
151305b261ecSmrg
151405b261ecSmrg/* fopen that drops privileges */
1515f7df2e56Smrgvoid *
1516f7df2e56SmrgFopen(const char *file, const char *type)
151705b261ecSmrg{
151805b261ecSmrg    FILE *iop;
1519f7df2e56Smrg
152005b261ecSmrg#ifndef HAS_SAVED_IDS_AND_SETEUID
152105b261ecSmrg    struct pid *cur;
152205b261ecSmrg    int pdes[2], pid;
152305b261ecSmrg
152405b261ecSmrg    if (file == NULL || type == NULL)
1525f7df2e56Smrg        return NULL;
152605b261ecSmrg
152705b261ecSmrg    if ((*type != 'r' && *type != 'w') || type[1])
1528f7df2e56Smrg        return NULL;
152905b261ecSmrg
15304202a189Smrg    if ((cur = malloc(sizeof(struct pid))) == NULL)
1531f7df2e56Smrg        return NULL;
153205b261ecSmrg
153305b261ecSmrg    if (pipe(pdes) < 0) {
1534f7df2e56Smrg        free(cur);
1535f7df2e56Smrg        return NULL;
153605b261ecSmrg    }
153705b261ecSmrg
153805b261ecSmrg    switch (pid = fork()) {
1539f7df2e56Smrg    case -1:                   /* error */
1540f7df2e56Smrg        close(pdes[0]);
1541f7df2e56Smrg        close(pdes[1]);
1542f7df2e56Smrg        free(cur);
1543f7df2e56Smrg        return NULL;
1544f7df2e56Smrg    case 0:                    /* child */
1545f7df2e56Smrg        if (setgid(getgid()) == -1)
1546f7df2e56Smrg            _exit(127);
1547f7df2e56Smrg        if (setuid(getuid()) == -1)
1548f7df2e56Smrg            _exit(127);
1549f7df2e56Smrg        if (*type == 'r') {
1550f7df2e56Smrg            if (pdes[1] != 1) {
1551f7df2e56Smrg                /* stdout */
1552f7df2e56Smrg                dup2(pdes[1], 1);
1553f7df2e56Smrg                close(pdes[1]);
1554f7df2e56Smrg            }
1555f7df2e56Smrg            close(pdes[0]);
1556f7df2e56Smrg        }
1557f7df2e56Smrg        else {
1558f7df2e56Smrg            if (pdes[0] != 0) {
1559f7df2e56Smrg                /* stdin */
1560f7df2e56Smrg                dup2(pdes[0], 0);
1561f7df2e56Smrg                close(pdes[0]);
1562f7df2e56Smrg            }
1563f7df2e56Smrg            close(pdes[1]);
1564f7df2e56Smrg        }
1565f7df2e56Smrg        execl("/bin/cat", "cat", file, (char *) NULL);
1566f7df2e56Smrg        _exit(127);
156705b261ecSmrg    }
156805b261ecSmrg
156905b261ecSmrg    /* Avoid EINTR during stdio calls */
1570f7df2e56Smrg    OsBlockSignals();
1571f7df2e56Smrg
157205b261ecSmrg    /* parent */
157305b261ecSmrg    if (*type == 'r') {
1574f7df2e56Smrg        iop = fdopen(pdes[0], type);
1575f7df2e56Smrg        close(pdes[1]);
1576f7df2e56Smrg    }
1577f7df2e56Smrg    else {
1578f7df2e56Smrg        iop = fdopen(pdes[1], type);
1579f7df2e56Smrg        close(pdes[0]);
158005b261ecSmrg    }
158105b261ecSmrg
158205b261ecSmrg    cur->fp = iop;
158305b261ecSmrg    cur->pid = pid;
158405b261ecSmrg    cur->next = pidlist;
158505b261ecSmrg    pidlist = cur;
158605b261ecSmrg
158765b04b38Smrg    DebugF("Fopen(%s), fp = %p\n", file, iop);
158805b261ecSmrg
158905b261ecSmrg    return iop;
159005b261ecSmrg#else
159105b261ecSmrg    int ruid, euid;
159205b261ecSmrg
159305b261ecSmrg    ruid = getuid();
159405b261ecSmrg    euid = geteuid();
1595f7df2e56Smrg
159605b261ecSmrg    if (seteuid(ruid) == -1) {
1597f7df2e56Smrg        return NULL;
159805b261ecSmrg    }
159905b261ecSmrg    iop = fopen(file, type);
160005b261ecSmrg
160105b261ecSmrg    if (seteuid(euid) == -1) {
1602f7df2e56Smrg        fclose(iop);
1603f7df2e56Smrg        return NULL;
160405b261ecSmrg    }
160505b261ecSmrg    return iop;
1606f7df2e56Smrg#endif                          /* HAS_SAVED_IDS_AND_SETEUID */
160705b261ecSmrg}
160805b261ecSmrg
160905b261ecSmrgint
1610f7df2e56SmrgPclose(void *iop)
161105b261ecSmrg{
161205b261ecSmrg    struct pid *cur, *last;
161305b261ecSmrg    int pstat;
161405b261ecSmrg    int pid;
161505b261ecSmrg
161665b04b38Smrg    DebugF("Pclose: fp = %p\n", iop);
161705b261ecSmrg    fclose(iop);
161805b261ecSmrg
161905b261ecSmrg    for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
1620f7df2e56Smrg        if (cur->fp == iop)
1621f7df2e56Smrg            break;
162205b261ecSmrg    if (cur == NULL)
1623f7df2e56Smrg        return -1;
162405b261ecSmrg
162505b261ecSmrg    do {
1626f7df2e56Smrg        pid = waitpid(cur->pid, &pstat, 0);
162705b261ecSmrg    } while (pid == -1 && errno == EINTR);
162805b261ecSmrg
162905b261ecSmrg    if (last == NULL)
1630f7df2e56Smrg        pidlist = cur->next;
163105b261ecSmrg    else
1632f7df2e56Smrg        last->next = cur->next;
16334202a189Smrg    free(cur);
163405b261ecSmrg
163505b261ecSmrg    /* allow EINTR again */
1636f7df2e56Smrg    OsReleaseSignals();
1637f7df2e56Smrg
16387e31ba66Smrg#ifdef HAVE_SETITIMER
1639f7df2e56Smrg    if (SmartScheduleEnable() < 0) {
1640f7df2e56Smrg        perror("signal");
1641f7df2e56Smrg        return -1;
164205b261ecSmrg    }
16437e31ba66Smrg#endif
164405b261ecSmrg
164505b261ecSmrg    return pid == -1 ? -1 : pstat;
164605b261ecSmrg}
164705b261ecSmrg
16484202a189Smrgint
1649f7df2e56SmrgFclose(void *iop)
165005b261ecSmrg{
165105b261ecSmrg#ifdef HAS_SAVED_IDS_AND_SETEUID
165205b261ecSmrg    return fclose(iop);
165305b261ecSmrg#else
165405b261ecSmrg    return Pclose(iop);
165505b261ecSmrg#endif
165605b261ecSmrg}
165705b261ecSmrg
1658f7df2e56Smrg#endif                          /* !WIN32 */
1659f7df2e56Smrg
1660f7df2e56Smrg#ifdef WIN32
1661f7df2e56Smrg
1662f7df2e56Smrg#include <X11/Xwindows.h>
1663f7df2e56Smrg
1664f7df2e56Smrgconst char *
1665f7df2e56SmrgWin32TempDir(void)
1666f7df2e56Smrg{
1667f7df2e56Smrg    static char buffer[PATH_MAX];
1668f7df2e56Smrg
1669f7df2e56Smrg    if (GetTempPath(sizeof(buffer), buffer)) {
1670f7df2e56Smrg        int len;
1671f7df2e56Smrg
1672f7df2e56Smrg        buffer[sizeof(buffer) - 1] = 0;
1673f7df2e56Smrg        len = strlen(buffer);
1674f7df2e56Smrg        if (len > 0)
1675f7df2e56Smrg            if (buffer[len - 1] == '\\')
1676f7df2e56Smrg                buffer[len - 1] = 0;
1677f7df2e56Smrg        return buffer;
1678f7df2e56Smrg    }
1679f7df2e56Smrg    if (getenv("TEMP") != NULL)
1680f7df2e56Smrg        return getenv("TEMP");
1681f7df2e56Smrg    else if (getenv("TMP") != NULL)
1682f7df2e56Smrg        return getenv("TMP");
1683f7df2e56Smrg    else
1684f7df2e56Smrg        return "/tmp";
1685f7df2e56Smrg}
1686f7df2e56Smrg
1687f7df2e56Smrgint
1688f7df2e56SmrgSystem(const char *cmdline)
1689f7df2e56Smrg{
1690f7df2e56Smrg    STARTUPINFO si;
1691f7df2e56Smrg    PROCESS_INFORMATION pi;
1692f7df2e56Smrg    DWORD dwExitCode;
1693f7df2e56Smrg    char *cmd = strdup(cmdline);
1694f7df2e56Smrg
1695f7df2e56Smrg    ZeroMemory(&si, sizeof(si));
1696f7df2e56Smrg    si.cb = sizeof(si);
1697f7df2e56Smrg    ZeroMemory(&pi, sizeof(pi));
1698f7df2e56Smrg
1699f7df2e56Smrg    if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
1700f7df2e56Smrg        LPVOID buffer;
1701f7df2e56Smrg
1702f7df2e56Smrg        if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1703f7df2e56Smrg                           FORMAT_MESSAGE_FROM_SYSTEM |
1704f7df2e56Smrg                           FORMAT_MESSAGE_IGNORE_INSERTS,
1705f7df2e56Smrg                           NULL,
1706f7df2e56Smrg                           GetLastError(),
1707f7df2e56Smrg                           MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1708f7df2e56Smrg                           (LPTSTR) &buffer, 0, NULL)) {
1709f7df2e56Smrg            ErrorF("[xkb] Starting '%s' failed!\n", cmdline);
1710f7df2e56Smrg        }
1711f7df2e56Smrg        else {
1712f7df2e56Smrg            ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer);
1713f7df2e56Smrg            LocalFree(buffer);
1714f7df2e56Smrg        }
1715f7df2e56Smrg
1716f7df2e56Smrg        free(cmd);
1717f7df2e56Smrg        return -1;
1718f7df2e56Smrg    }
1719f7df2e56Smrg    /* Wait until child process exits. */
1720f7df2e56Smrg    WaitForSingleObject(pi.hProcess, INFINITE);
1721f7df2e56Smrg
1722f7df2e56Smrg    GetExitCodeProcess(pi.hProcess, &dwExitCode);
172305b261ecSmrg
1724f7df2e56Smrg    /* Close process and thread handles. */
1725f7df2e56Smrg    CloseHandle(pi.hProcess);
1726f7df2e56Smrg    CloseHandle(pi.hThread);
1727f7df2e56Smrg    free(cmd);
1728f7df2e56Smrg
1729f7df2e56Smrg    return dwExitCode;
1730f7df2e56Smrg}
1731f7df2e56Smrg#endif
173205b261ecSmrg
17337e31ba66SmrgBool
17347e31ba66SmrgPrivsElevated(void)
17357e31ba66Smrg{
17367e31ba66Smrg    static Bool privsTested = FALSE;
17377e31ba66Smrg    static Bool privsElevated = TRUE;
17387e31ba66Smrg
17397e31ba66Smrg    if (!privsTested) {
17407e31ba66Smrg#if defined(WIN32)
17417e31ba66Smrg        privsElevated = FALSE;
17427e31ba66Smrg#else
17437e31ba66Smrg        if ((getuid() != geteuid()) || (getgid() != getegid())) {
17447e31ba66Smrg            privsElevated = TRUE;
17457e31ba66Smrg        }
17467e31ba66Smrg        else {
17477e31ba66Smrg#if defined(HAVE_ISSETUGID)
17487e31ba66Smrg            privsElevated = issetugid();
17497e31ba66Smrg#elif defined(HAVE_GETRESUID)
17507e31ba66Smrg            uid_t ruid, euid, suid;
17517e31ba66Smrg            gid_t rgid, egid, sgid;
17527e31ba66Smrg
17537e31ba66Smrg            if ((getresuid(&ruid, &euid, &suid) == 0) &&
17547e31ba66Smrg                (getresgid(&rgid, &egid, &sgid) == 0)) {
17557e31ba66Smrg                privsElevated = (euid != suid) || (egid != sgid);
17567e31ba66Smrg            }
17577e31ba66Smrg            else {
17587e31ba66Smrg                printf("Failed getresuid or getresgid");
17597e31ba66Smrg                /* Something went wrong, make defensive assumption */
17607e31ba66Smrg                privsElevated = TRUE;
17617e31ba66Smrg            }
17627e31ba66Smrg#else
17637e31ba66Smrg            if (getuid() == 0) {
17647e31ba66Smrg                /* running as root: uid==euid==0 */
17657e31ba66Smrg                privsElevated = FALSE;
17667e31ba66Smrg            }
17677e31ba66Smrg            else {
17687e31ba66Smrg                /*
17697e31ba66Smrg                 * If there are saved ID's the process might still be privileged
17707e31ba66Smrg                 * even though the above test succeeded. If issetugid() and
17717e31ba66Smrg                 * getresgid() aren't available, test this by trying to set
17727e31ba66Smrg                 * euid to 0.
17737e31ba66Smrg                 */
17747e31ba66Smrg                unsigned int oldeuid;
17757e31ba66Smrg
17767e31ba66Smrg                oldeuid = geteuid();
17777e31ba66Smrg
17787e31ba66Smrg                if (seteuid(0) != 0) {
17797e31ba66Smrg                    privsElevated = FALSE;
17807e31ba66Smrg                }
17817e31ba66Smrg                else {
17827e31ba66Smrg                    if (seteuid(oldeuid) != 0) {
17837e31ba66Smrg                        FatalError("Failed to drop privileges.  Exiting\n");
17847e31ba66Smrg                    }
17857e31ba66Smrg                    privsElevated = TRUE;
17867e31ba66Smrg                }
17877e31ba66Smrg            }
17887e31ba66Smrg#endif
17897e31ba66Smrg        }
17907e31ba66Smrg#endif
17917e31ba66Smrg        privsTested = TRUE;
17927e31ba66Smrg    }
17937e31ba66Smrg    return privsElevated;
17947e31ba66Smrg}
17957e31ba66Smrg
179605b261ecSmrg/*
179705b261ecSmrg * CheckUserParameters: check for long command line arguments and long
179805b261ecSmrg * environment variables.  By default, these checks are only done when
179905b261ecSmrg * the server's euid != ruid.  In 3.3.x, these checks were done in an
180005b261ecSmrg * external wrapper utility.
180105b261ecSmrg */
180205b261ecSmrg
180305b261ecSmrg/* Consider LD* variables insecure? */
180405b261ecSmrg#ifndef REMOVE_ENV_LD
180505b261ecSmrg#define REMOVE_ENV_LD 1
180605b261ecSmrg#endif
180705b261ecSmrg
180805b261ecSmrg/* Remove long environment variables? */
180905b261ecSmrg#ifndef REMOVE_LONG_ENV
181005b261ecSmrg#define REMOVE_LONG_ENV 1
181105b261ecSmrg#endif
181205b261ecSmrg
181305b261ecSmrg/*
181405b261ecSmrg * Disallow stdout or stderr as pipes?  It's possible to block the X server
181505b261ecSmrg * when piping stdout+stderr to a pipe.
181605b261ecSmrg *
181705b261ecSmrg * Don't enable this because it looks like it's going to cause problems.
181805b261ecSmrg */
181905b261ecSmrg#ifndef NO_OUTPUT_PIPES
182005b261ecSmrg#define NO_OUTPUT_PIPES 0
182105b261ecSmrg#endif
182205b261ecSmrg
182305b261ecSmrg/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
182405b261ecSmrg#ifndef CHECK_EUID
182505b261ecSmrg#ifndef WIN32
182605b261ecSmrg#define CHECK_EUID 1
182705b261ecSmrg#else
182805b261ecSmrg#define CHECK_EUID 0
182905b261ecSmrg#endif
183005b261ecSmrg#endif
183105b261ecSmrg
183205b261ecSmrg/*
183305b261ecSmrg * Maybe the locale can be faked to make isprint(3) report that everything
183405b261ecSmrg * is printable?  Avoid it by default.
183505b261ecSmrg */
183605b261ecSmrg#ifndef USE_ISPRINT
183705b261ecSmrg#define USE_ISPRINT 0
183805b261ecSmrg#endif
183905b261ecSmrg
184005b261ecSmrg#define MAX_ARG_LENGTH          128
184105b261ecSmrg#define MAX_ENV_LENGTH          256
1842f7df2e56Smrg#define MAX_ENV_PATH_LENGTH     2048    /* Limit for *PATH and TERMCAP */
184305b261ecSmrg
184405b261ecSmrg#if USE_ISPRINT
184505b261ecSmrg#include <ctype.h>
184605b261ecSmrg#define checkPrintable(c) isprint(c)
184705b261ecSmrg#else
184805b261ecSmrg#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
184905b261ecSmrg#endif
185005b261ecSmrg
185105b261ecSmrgenum BadCode {
185205b261ecSmrg    NotBad = 0,
185305b261ecSmrg    UnsafeArg,
185405b261ecSmrg    ArgTooLong,
185505b261ecSmrg    UnprintableArg,
185605b261ecSmrg    EnvTooLong,
185705b261ecSmrg    OutputIsPipe,
185805b261ecSmrg    InternalError
185905b261ecSmrg};
186005b261ecSmrg
186105b261ecSmrg#if defined(VENDORSUPPORT)
186205b261ecSmrg#define BUGADDRESS VENDORSUPPORT
186305b261ecSmrg#elif defined(BUILDERADDR)
186405b261ecSmrg#define BUGADDRESS BUILDERADDR
186505b261ecSmrg#else
186605b261ecSmrg#define BUGADDRESS "xorg@freedesktop.org"
186705b261ecSmrg#endif
186805b261ecSmrg
186905b261ecSmrgvoid
187005b261ecSmrgCheckUserParameters(int argc, char **argv, char **envp)
187105b261ecSmrg{
187205b261ecSmrg    enum BadCode bad = NotBad;
187305b261ecSmrg    int i = 0, j;
187405b261ecSmrg    char *a, *e = NULL;
187505b261ecSmrg
187605b261ecSmrg#if CHECK_EUID
18777e31ba66Smrg    if (PrivsElevated())
187805b261ecSmrg#endif
187905b261ecSmrg    {
1880f7df2e56Smrg        /* Check each argv[] */
1881f7df2e56Smrg        for (i = 1; i < argc; i++) {
1882f7df2e56Smrg            if (strcmp(argv[i], "-fp") == 0) {
1883f7df2e56Smrg                i++;            /* continue with next argument. skip the length check */
1884f7df2e56Smrg                if (i >= argc)
1885f7df2e56Smrg                    break;
1886f7df2e56Smrg            }
1887f7df2e56Smrg            else {
1888f7df2e56Smrg                if (strlen(argv[i]) > MAX_ARG_LENGTH) {
1889f7df2e56Smrg                    bad = ArgTooLong;
1890f7df2e56Smrg                    break;
1891f7df2e56Smrg                }
1892f7df2e56Smrg            }
1893f7df2e56Smrg            a = argv[i];
1894f7df2e56Smrg            while (*a) {
1895f7df2e56Smrg                if (checkPrintable(*a) == 0) {
1896f7df2e56Smrg                    bad = UnprintableArg;
1897f7df2e56Smrg                    break;
1898f7df2e56Smrg                }
1899f7df2e56Smrg                a++;
1900f7df2e56Smrg            }
1901f7df2e56Smrg            if (bad)
1902f7df2e56Smrg                break;
1903f7df2e56Smrg        }
1904f7df2e56Smrg        if (!bad) {
1905f7df2e56Smrg            /* Check each envp[] */
1906f7df2e56Smrg            for (i = 0; envp[i]; i++) {
190705b261ecSmrg
1908f7df2e56Smrg                /* Check for bad environment variables and values */
190905b261ecSmrg#if REMOVE_ENV_LD
1910f7df2e56Smrg                while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
1911f7df2e56Smrg                    for (j = i; envp[j]; j++) {
1912f7df2e56Smrg                        envp[j] = envp[j + 1];
1913f7df2e56Smrg                    }
1914f7df2e56Smrg                }
1915f7df2e56Smrg#endif
1916f7df2e56Smrg                if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
191705b261ecSmrg#if REMOVE_LONG_ENV
1918f7df2e56Smrg                    for (j = i; envp[j]; j++) {
1919f7df2e56Smrg                        envp[j] = envp[j + 1];
1920f7df2e56Smrg                    }
1921f7df2e56Smrg                    i--;
192205b261ecSmrg#else
1923f7df2e56Smrg                    char *eq;
1924f7df2e56Smrg                    int len;
1925f7df2e56Smrg
1926f7df2e56Smrg                    eq = strchr(envp[i], '=');
1927f7df2e56Smrg                    if (!eq)
1928f7df2e56Smrg                        continue;
1929f7df2e56Smrg                    len = eq - envp[i];
1930f7df2e56Smrg                    e = strndup(envp[i], len);
1931f7df2e56Smrg                    if (!e) {
1932f7df2e56Smrg                        bad = InternalError;
1933f7df2e56Smrg                        break;
1934f7df2e56Smrg                    }
1935f7df2e56Smrg                    if (len >= 4 &&
1936f7df2e56Smrg                        (strcmp(e + len - 4, "PATH") == 0 ||
1937f7df2e56Smrg                         strcmp(e, "TERMCAP") == 0)) {
1938f7df2e56Smrg                        if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
1939f7df2e56Smrg                            bad = EnvTooLong;
1940f7df2e56Smrg                            break;
1941f7df2e56Smrg                        }
1942f7df2e56Smrg                        else {
1943f7df2e56Smrg                            free(e);
1944f7df2e56Smrg                        }
1945f7df2e56Smrg                    }
1946f7df2e56Smrg                    else {
1947f7df2e56Smrg                        bad = EnvTooLong;
1948f7df2e56Smrg                        break;
1949f7df2e56Smrg                    }
1950f7df2e56Smrg#endif
1951f7df2e56Smrg                }
1952f7df2e56Smrg            }
1953f7df2e56Smrg        }
195405b261ecSmrg#if NO_OUTPUT_PIPES
1955f7df2e56Smrg        if (!bad) {
1956f7df2e56Smrg            struct stat buf;
195705b261ecSmrg
1958f7df2e56Smrg            if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode))
1959f7df2e56Smrg                bad = OutputIsPipe;
1960f7df2e56Smrg            if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode))
1961f7df2e56Smrg                bad = OutputIsPipe;
1962f7df2e56Smrg        }
196305b261ecSmrg#endif
196405b261ecSmrg    }
196505b261ecSmrg    switch (bad) {
196605b261ecSmrg    case NotBad:
1967f7df2e56Smrg        return;
196805b261ecSmrg    case UnsafeArg:
1969f7df2e56Smrg        ErrorF("Command line argument number %d is unsafe\n", i);
1970f7df2e56Smrg        break;
197105b261ecSmrg    case ArgTooLong:
1972f7df2e56Smrg        ErrorF("Command line argument number %d is too long\n", i);
1973f7df2e56Smrg        break;
197405b261ecSmrg    case UnprintableArg:
1975f7df2e56Smrg        ErrorF("Command line argument number %d contains unprintable"
1976f7df2e56Smrg               " characters\n", i);
1977f7df2e56Smrg        break;
197805b261ecSmrg    case EnvTooLong:
1979f7df2e56Smrg        ErrorF("Environment variable `%s' is too long\n", e);
1980f7df2e56Smrg        break;
198105b261ecSmrg    case OutputIsPipe:
1982f7df2e56Smrg        ErrorF("Stdout and/or stderr is a pipe\n");
1983f7df2e56Smrg        break;
198405b261ecSmrg    case InternalError:
1985f7df2e56Smrg        ErrorF("Internal Error\n");
1986f7df2e56Smrg        break;
198705b261ecSmrg    default:
1988f7df2e56Smrg        ErrorF("Unknown error\n");
1989f7df2e56Smrg        break;
199005b261ecSmrg    }
199105b261ecSmrg    FatalError("X server aborted because of unsafe environment\n");
199205b261ecSmrg}
199305b261ecSmrg
199405b261ecSmrg/*
199505b261ecSmrg * CheckUserAuthorization: check if the user is allowed to start the
199605b261ecSmrg * X server.  This usually means some sort of PAM checking, and it is
199705b261ecSmrg * usually only done for setuid servers (uid != euid).
199805b261ecSmrg */
199905b261ecSmrg
200005b261ecSmrg#ifdef USE_PAM
200105b261ecSmrg#include <security/pam_appl.h>
200205b261ecSmrg#include <security/pam_misc.h>
200305b261ecSmrg#include <pwd.h>
2004f7df2e56Smrg#endif                          /* USE_PAM */
200505b261ecSmrg
200605b261ecSmrgvoid
200705b261ecSmrgCheckUserAuthorization(void)
200805b261ecSmrg{
200905b261ecSmrg#ifdef USE_PAM
201005b261ecSmrg    static struct pam_conv conv = {
2011f7df2e56Smrg        misc_conv,
2012f7df2e56Smrg        NULL
201305b261ecSmrg    };
201405b261ecSmrg
201505b261ecSmrg    pam_handle_t *pamh = NULL;
201605b261ecSmrg    struct passwd *pw;
201705b261ecSmrg    int retval;
201805b261ecSmrg
201905b261ecSmrg    if (getuid() != geteuid()) {
2020f7df2e56Smrg        pw = getpwuid(getuid());
2021f7df2e56Smrg        if (pw == NULL)
2022f7df2e56Smrg            FatalError("getpwuid() failed for uid %d\n", getuid());
2023f7df2e56Smrg
2024f7df2e56Smrg        retval = pam_start("xserver", pw->pw_name, &conv, &pamh);
2025f7df2e56Smrg        if (retval != PAM_SUCCESS)
2026f7df2e56Smrg            FatalError("pam_start() failed.\n"
2027f7df2e56Smrg                       "\tMissing or mangled PAM config file or module?\n");
2028f7df2e56Smrg
2029f7df2e56Smrg        retval = pam_authenticate(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        retval = pam_acct_mgmt(pamh, 0);
2037f7df2e56Smrg        if (retval != PAM_SUCCESS) {
2038f7df2e56Smrg            pam_end(pamh, retval);
2039f7df2e56Smrg            FatalError("PAM authentication failed, cannot start X server.\n"
2040f7df2e56Smrg                       "\tPerhaps you do not have console ownership?\n");
2041f7df2e56Smrg        }
204205b261ecSmrg
2043f7df2e56Smrg        /* this is not a session, so do not do session management */
2044f7df2e56Smrg        pam_end(pamh, PAM_SUCCESS);
204505b261ecSmrg    }
204605b261ecSmrg#endif
204705b261ecSmrg}
204805b261ecSmrg
20494202a189Smrg/*
20504202a189Smrg * Tokenize a string into a NULL terminated array of strings. Always returns
20514202a189Smrg * an allocated array unless an error occurs.
20524202a189Smrg */
2053f7df2e56Smrgchar **
20544202a189Smrgxstrtokenize(const char *str, const char *separators)
205505b261ecSmrg{
20564202a189Smrg    char **list, **nlist;
20574202a189Smrg    char *tok, *tmp;
20584202a189Smrg    unsigned num = 0, n;
205905b261ecSmrg
20604202a189Smrg    if (!str)
20614202a189Smrg        return NULL;
20624202a189Smrg    list = calloc(1, sizeof(*list));
20634202a189Smrg    if (!list)
20644202a189Smrg        return NULL;
20654202a189Smrg    tmp = strdup(str);
20664202a189Smrg    if (!tmp)
20674202a189Smrg        goto error;
20684202a189Smrg    for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) {
2069f7df2e56Smrg        nlist = reallocarray(list, num + 2, sizeof(*list));
20704202a189Smrg        if (!nlist)
20714202a189Smrg            goto error;
20724202a189Smrg        list = nlist;
20734202a189Smrg        list[num] = strdup(tok);
20744202a189Smrg        if (!list[num])
20754202a189Smrg            goto error;
20764202a189Smrg        list[++num] = NULL;
20774202a189Smrg    }
20784202a189Smrg    free(tmp);
20794202a189Smrg    return list;
20804202a189Smrg
2081f7df2e56Smrg error:
20824202a189Smrg    free(tmp);
20834202a189Smrg    for (n = 0; n < num; n++)
20844202a189Smrg        free(list[n]);
20854202a189Smrg    free(list);
20864202a189Smrg    return NULL;
208705b261ecSmrg}
2088f7df2e56Smrg
2089f7df2e56Smrg/* Format a signed number into a string in a signal safe manner. The string
2090f7df2e56Smrg * should be at least 21 characters in order to handle all int64_t values.
2091f7df2e56Smrg */
2092f7df2e56Smrgvoid
2093f7df2e56SmrgFormatInt64(int64_t num, char *string)
2094f7df2e56Smrg{
2095f7df2e56Smrg    if (num < 0) {
2096f7df2e56Smrg        string[0] = '-';
2097f7df2e56Smrg        num *= -1;
2098f7df2e56Smrg        string++;
2099f7df2e56Smrg    }
2100f7df2e56Smrg    FormatUInt64(num, string);
2101f7df2e56Smrg}
2102f7df2e56Smrg
2103f7df2e56Smrg/* Format a number into a string in a signal safe manner. The string should be
2104f7df2e56Smrg * at least 21 characters in order to handle all uint64_t values. */
2105f7df2e56Smrgvoid
2106f7df2e56SmrgFormatUInt64(uint64_t num, char *string)
2107f7df2e56Smrg{
2108f7df2e56Smrg    uint64_t divisor;
2109f7df2e56Smrg    int len;
2110f7df2e56Smrg    int i;
2111f7df2e56Smrg
2112f7df2e56Smrg    for (len = 1, divisor = 10;
2113f7df2e56Smrg         len < 20 && num / divisor;
2114f7df2e56Smrg         len++, divisor *= 10);
2115f7df2e56Smrg
2116f7df2e56Smrg    for (i = len, divisor = 1; i > 0; i--, divisor *= 10)
2117f7df2e56Smrg        string[i - 1] = '0' + ((num / divisor) % 10);
2118f7df2e56Smrg
2119f7df2e56Smrg    string[len] = '\0';
2120f7df2e56Smrg}
2121f7df2e56Smrg
2122f7df2e56Smrg/**
2123f7df2e56Smrg * Format a double number as %.2f.
2124f7df2e56Smrg */
2125f7df2e56Smrgvoid
2126f7df2e56SmrgFormatDouble(double dbl, char *string)
2127f7df2e56Smrg{
2128f7df2e56Smrg    int slen = 0;
2129f7df2e56Smrg    uint64_t frac;
2130f7df2e56Smrg
2131f7df2e56Smrg    frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5;
2132f7df2e56Smrg    frac %= 100;
2133f7df2e56Smrg
2134f7df2e56Smrg    /* write decimal part to string */
2135f7df2e56Smrg    if (dbl < 0 && dbl > -1)
2136f7df2e56Smrg        string[slen++] = '-';
2137f7df2e56Smrg    FormatInt64((int64_t)dbl, &string[slen]);
2138f7df2e56Smrg
2139f7df2e56Smrg    while(string[slen] != '\0')
2140f7df2e56Smrg        slen++;
2141f7df2e56Smrg
2142f7df2e56Smrg    /* append fractional part, but only if we have enough characters. We
2143f7df2e56Smrg     * expect string to be 21 chars (incl trailing \0) */
2144f7df2e56Smrg    if (slen <= 17) {
2145f7df2e56Smrg        string[slen++] = '.';
2146f7df2e56Smrg        if (frac < 10)
2147f7df2e56Smrg            string[slen++] = '0';
2148f7df2e56Smrg
2149f7df2e56Smrg        FormatUInt64(frac, &string[slen]);
2150f7df2e56Smrg    }
2151f7df2e56Smrg}
2152f7df2e56Smrg
2153f7df2e56Smrg
2154f7df2e56Smrg/* Format a number into a hexadecimal string in a signal safe manner. The string
2155f7df2e56Smrg * should be at least 17 characters in order to handle all uint64_t values. */
2156f7df2e56Smrgvoid
2157f7df2e56SmrgFormatUInt64Hex(uint64_t num, char *string)
2158f7df2e56Smrg{
2159f7df2e56Smrg    uint64_t divisor;
2160f7df2e56Smrg    int len;
2161f7df2e56Smrg    int i;
2162f7df2e56Smrg
2163f7df2e56Smrg    for (len = 1, divisor = 0x10;
2164f7df2e56Smrg         len < 16 && num / divisor;
2165f7df2e56Smrg         len++, divisor *= 0x10);
2166f7df2e56Smrg
2167f7df2e56Smrg    for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) {
2168f7df2e56Smrg        int val = (num / divisor) % 0x10;
2169f7df2e56Smrg
2170f7df2e56Smrg        if (val < 10)
2171f7df2e56Smrg            string[i - 1] = '0' + val;
2172f7df2e56Smrg        else
2173f7df2e56Smrg            string[i - 1] = 'a' + val - 10;
2174f7df2e56Smrg    }
2175f7df2e56Smrg
2176f7df2e56Smrg    string[len] = '\0';
2177f7df2e56Smrg}
2178f7df2e56Smrg
2179f7df2e56Smrg#if !defined(WIN32) || defined(__CYGWIN__)
2180f7df2e56Smrg/* Move a file descriptor out of the way of our select mask; this
2181f7df2e56Smrg * is useful for file descriptors which will never appear in the
2182f7df2e56Smrg * select mask to avoid reducing the number of clients that can
2183f7df2e56Smrg * connect to the server
2184f7df2e56Smrg */
2185f7df2e56Smrgint
2186f7df2e56Smrgos_move_fd(int fd)
2187f7df2e56Smrg{
2188f7df2e56Smrg    int newfd;
2189f7df2e56Smrg
2190f7df2e56Smrg#ifdef F_DUPFD_CLOEXEC
2191f7df2e56Smrg    newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS);
2192f7df2e56Smrg#else
2193f7df2e56Smrg    newfd = fcntl(fd, F_DUPFD, MAXCLIENTS);
2194f7df2e56Smrg#endif
2195f7df2e56Smrg    if (newfd < 0)
2196f7df2e56Smrg        return fd;
2197f7df2e56Smrg#ifndef F_DUPFD_CLOEXEC
2198f7df2e56Smrg    fcntl(newfd, F_SETFD, FD_CLOEXEC);
2199f7df2e56Smrg#endif
2200f7df2e56Smrg    close(fd);
2201f7df2e56Smrg    return newfd;
2202f7df2e56Smrg}
2203f7df2e56Smrg#endif
2204