utils.c revision 5a112b11
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    }
6855a112b11Smrg    SeatId = getenv("XDG_SEAT");
686f7df2e56Smrg
687f7df2e56Smrg    for (i = 1; i < argc; i++) {
688f7df2e56Smrg        /* call ddx first, so it can peek/override if it wants */
689f7df2e56Smrg        if ((skip = ddxProcessArgument(argc, argv, i))) {
690f7df2e56Smrg            i += (skip - 1);
691f7df2e56Smrg        }
692f7df2e56Smrg        else if (argv[i][0] == ':') {
693f7df2e56Smrg            /* initialize display */
694f7df2e56Smrg            display = argv[i];
695f7df2e56Smrg            explicit_display = TRUE;
696f7df2e56Smrg            display++;
697f7df2e56Smrg            if (!VerifyDisplayName(display)) {
69805b261ecSmrg                ErrorF("Bad display name: %s\n", display);
69905b261ecSmrg                UseMsg();
700f7df2e56Smrg                FatalError("Bad display name, exiting: %s\n", display);
70105b261ecSmrg            }
702f7df2e56Smrg        }
703f7df2e56Smrg        else if (strcmp(argv[i], "-a") == 0) {
704f7df2e56Smrg            if (++i < argc)
705f7df2e56Smrg                defaultPointerControl.num = atoi(argv[i]);
706f7df2e56Smrg            else
707f7df2e56Smrg                UseMsg();
708f7df2e56Smrg        }
709f7df2e56Smrg        else if (strcmp(argv[i], "-ac") == 0) {
710f7df2e56Smrg            defeatAccessControl = TRUE;
711f7df2e56Smrg        }
712f7df2e56Smrg        else if (strcmp(argv[i], "-audit") == 0) {
713f7df2e56Smrg            if (++i < argc)
714f7df2e56Smrg                auditTrailLevel = atoi(argv[i]);
715f7df2e56Smrg            else
716f7df2e56Smrg                UseMsg();
717f7df2e56Smrg        }
718f7df2e56Smrg        else if (strcmp(argv[i], "-auth") == 0) {
719f7df2e56Smrg            if (++i < argc)
720f7df2e56Smrg                InitAuthorization(argv[i]);
721f7df2e56Smrg            else
722f7df2e56Smrg                UseMsg();
723f7df2e56Smrg        }
724f7df2e56Smrg        else if (strcmp(argv[i], "-br") == 0);  /* default */
725f7df2e56Smrg        else if (strcmp(argv[i], "+bs") == 0)
726f7df2e56Smrg            enableBackingStore = TRUE;
727f7df2e56Smrg        else if (strcmp(argv[i], "-bs") == 0)
728f7df2e56Smrg            disableBackingStore = TRUE;
729f7df2e56Smrg        else if (strcmp(argv[i], "c") == 0) {
730f7df2e56Smrg            if (++i < argc)
731f7df2e56Smrg                defaultKeyboardControl.click = atoi(argv[i]);
732f7df2e56Smrg            else
733f7df2e56Smrg                UseMsg();
734f7df2e56Smrg        }
735f7df2e56Smrg        else if (strcmp(argv[i], "-c") == 0) {
736f7df2e56Smrg            defaultKeyboardControl.click = 0;
737f7df2e56Smrg        }
738f7df2e56Smrg        else if (strcmp(argv[i], "-cc") == 0) {
739f7df2e56Smrg            if (++i < argc)
740f7df2e56Smrg                defaultColorVisualClass = atoi(argv[i]);
741f7df2e56Smrg            else
742f7df2e56Smrg                UseMsg();
743f7df2e56Smrg        }
744f7df2e56Smrg        else if (strcmp(argv[i], "-core") == 0) {
74505b261ecSmrg#if !defined(WIN32) || !defined(__MINGW32__)
746f7df2e56Smrg            struct rlimit core_limit;
747f7df2e56Smrg
748f7df2e56Smrg            if (getrlimit(RLIMIT_CORE, &core_limit) != -1) {
749f7df2e56Smrg                core_limit.rlim_cur = core_limit.rlim_max;
750f7df2e56Smrg                setrlimit(RLIMIT_CORE, &core_limit);
751f7df2e56Smrg            }
75205b261ecSmrg#endif
753f7df2e56Smrg            CoreDump = TRUE;
754f7df2e56Smrg        }
755f7df2e56Smrg        else if (strcmp(argv[i], "-nocursor") == 0) {
7564202a189Smrg            EnableCursor = FALSE;
7574202a189Smrg        }
758f7df2e56Smrg        else if (strcmp(argv[i], "-dpi") == 0) {
759f7df2e56Smrg            if (++i < argc)
760f7df2e56Smrg                monitorResolution = atoi(argv[i]);
761f7df2e56Smrg            else
762f7df2e56Smrg                UseMsg();
763f7df2e56Smrg        }
764f7df2e56Smrg        else if (strcmp(argv[i], "-displayfd") == 0) {
765f7df2e56Smrg            if (++i < argc) {
766f7df2e56Smrg                displayfd = atoi(argv[i]);
767f7df2e56Smrg#ifdef LOCK_SERVER
768f7df2e56Smrg                nolock = TRUE;
769f7df2e56Smrg#endif
770f7df2e56Smrg            }
771f7df2e56Smrg            else
772f7df2e56Smrg                UseMsg();
773f7df2e56Smrg        }
77405b261ecSmrg#ifdef DPMSExtension
775f7df2e56Smrg        else if (strcmp(argv[i], "dpms") == 0)
776f7df2e56Smrg            /* ignored for compatibility */ ;
777f7df2e56Smrg        else if (strcmp(argv[i], "-dpms") == 0)
778f7df2e56Smrg            DPMSDisabledSwitch = TRUE;
77905b261ecSmrg#endif
780f7df2e56Smrg        else if (strcmp(argv[i], "-deferglyphs") == 0) {
7817e31ba66Smrg            if (++i >= argc || !xfont2_parse_glyph_caching_mode(argv[i]))
782f7df2e56Smrg                UseMsg();
783f7df2e56Smrg        }
784f7df2e56Smrg        else if (strcmp(argv[i], "-f") == 0) {
785f7df2e56Smrg            if (++i < argc)
786f7df2e56Smrg                defaultKeyboardControl.bell = atoi(argv[i]);
787f7df2e56Smrg            else
788f7df2e56Smrg                UseMsg();
789f7df2e56Smrg        }
7905a112b11Smrg        else if (strcmp(argv[i], "-fakescreenfps") == 0) {
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();
798f7df2e56Smrg        }
799f7df2e56Smrg        else if (strcmp(argv[i], "-fp") == 0) {
800f7df2e56Smrg            if (++i < argc) {
801f7df2e56Smrg                defaultFontPath = argv[i];
802f7df2e56Smrg            }
803f7df2e56Smrg            else
804f7df2e56Smrg                UseMsg();
805f7df2e56Smrg        }
806f7df2e56Smrg        else if (strcmp(argv[i], "-help") == 0) {
807f7df2e56Smrg            UseMsg();
808f7df2e56Smrg            exit(0);
809f7df2e56Smrg        }
810f7df2e56Smrg        else if (strcmp(argv[i], "+iglx") == 0)
811f7df2e56Smrg            enableIndirectGLX = TRUE;
812f7df2e56Smrg        else if (strcmp(argv[i], "-iglx") == 0)
813f7df2e56Smrg            enableIndirectGLX = FALSE;
814f7df2e56Smrg        else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) {
815f7df2e56Smrg            if (skip > 0)
816f7df2e56Smrg                i += skip - 1;
817f7df2e56Smrg            else
818f7df2e56Smrg                UseMsg();
819f7df2e56Smrg        }
82005b261ecSmrg#ifdef RLIMIT_DATA
821f7df2e56Smrg        else if (strcmp(argv[i], "-ld") == 0) {
822f7df2e56Smrg            if (++i < argc) {
823f7df2e56Smrg                limitDataSpace = atoi(argv[i]);
824f7df2e56Smrg                if (limitDataSpace > 0)
825f7df2e56Smrg                    limitDataSpace *= 1024;
826f7df2e56Smrg            }
827f7df2e56Smrg            else
828f7df2e56Smrg                UseMsg();
829f7df2e56Smrg        }
83005b261ecSmrg#endif
83105b261ecSmrg#ifdef RLIMIT_NOFILE
832f7df2e56Smrg        else if (strcmp(argv[i], "-lf") == 0) {
833f7df2e56Smrg            if (++i < argc)
834f7df2e56Smrg                limitNoFile = atoi(argv[i]);
835f7df2e56Smrg            else
836f7df2e56Smrg                UseMsg();
837f7df2e56Smrg        }
83805b261ecSmrg#endif
83905b261ecSmrg#ifdef RLIMIT_STACK
840f7df2e56Smrg        else if (strcmp(argv[i], "-ls") == 0) {
841f7df2e56Smrg            if (++i < argc) {
842f7df2e56Smrg                limitStackSpace = atoi(argv[i]);
843f7df2e56Smrg                if (limitStackSpace > 0)
844f7df2e56Smrg                    limitStackSpace *= 1024;
845f7df2e56Smrg            }
846f7df2e56Smrg            else
847f7df2e56Smrg                UseMsg();
848f7df2e56Smrg        }
84905b261ecSmrg#endif
850f7df2e56Smrg#ifdef LOCK_SERVER
851f7df2e56Smrg        else if (strcmp(argv[i], "-nolock") == 0) {
85205b261ecSmrg#if !defined(WIN32) && !defined(__CYGWIN__)
853f7df2e56Smrg            if (getuid() != 0)
854f7df2e56Smrg                ErrorF
855f7df2e56Smrg                    ("Warning: the -nolock option can only be used by root\n");
856f7df2e56Smrg            else
85705b261ecSmrg#endif
858f7df2e56Smrg                nolock = TRUE;
859f7df2e56Smrg        }
860f7df2e56Smrg#endif
861f7df2e56Smrg	else if ( strcmp( argv[i], "-maxclients") == 0)
86205b261ecSmrg	{
863f7df2e56Smrg	    if (++i < argc) {
864f7df2e56Smrg		LimitClients = atoi(argv[i]);
865f7df2e56Smrg		if (LimitClients != 64 &&
866f7df2e56Smrg		    LimitClients != 128 &&
867f7df2e56Smrg		    LimitClients != 256 &&
8687e31ba66Smrg		    LimitClients != 512 &&
8697e31ba66Smrg                    LimitClients != 1024 &&
8707e31ba66Smrg                    LimitClients != 2048) {
8717e31ba66Smrg		    FatalError("maxclients must be one of 64, 128, 256, 512, 1024 or 2048\n");
872f7df2e56Smrg		}
873f7df2e56Smrg	    } else
87405b261ecSmrg		UseMsg();
87505b261ecSmrg	}
876f7df2e56Smrg        else if (strcmp(argv[i], "-nolisten") == 0) {
877f7df2e56Smrg            if (++i < argc) {
878f7df2e56Smrg                if (_XSERVTransNoListen(argv[i]))
879f7df2e56Smrg                    ErrorF("Failed to disable listen for %s transport",
880f7df2e56Smrg                           argv[i]);
881f7df2e56Smrg            }
882f7df2e56Smrg            else
883f7df2e56Smrg                UseMsg();
884f7df2e56Smrg        }
885f7df2e56Smrg        else if (strcmp(argv[i], "-listen") == 0) {
886f7df2e56Smrg            if (++i < argc) {
887f7df2e56Smrg                if (_XSERVTransListen(argv[i]))
888f7df2e56Smrg                    ErrorF("Failed to enable listen for %s transport",
889f7df2e56Smrg                           argv[i]);
890f7df2e56Smrg            }
891f7df2e56Smrg            else
892f7df2e56Smrg                UseMsg();
893f7df2e56Smrg        }
894f7df2e56Smrg        else if (strcmp(argv[i], "-noreset") == 0) {
895f7df2e56Smrg            dispatchExceptionAtReset = 0;
896f7df2e56Smrg        }
897f7df2e56Smrg        else if (strcmp(argv[i], "-reset") == 0) {
898f7df2e56Smrg            dispatchExceptionAtReset = DE_RESET;
899f7df2e56Smrg        }
900f7df2e56Smrg        else if (strcmp(argv[i], "-p") == 0) {
901f7df2e56Smrg            if (++i < argc)
902f7df2e56Smrg                defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) *
903f7df2e56Smrg                    MILLI_PER_MIN;
904f7df2e56Smrg            else
905f7df2e56Smrg                UseMsg();
906f7df2e56Smrg        }
907f7df2e56Smrg        else if (strcmp(argv[i], "-pogo") == 0) {
908f7df2e56Smrg            dispatchException = DE_TERMINATE;
909f7df2e56Smrg        }
910f7df2e56Smrg        else if (strcmp(argv[i], "-pn") == 0)
911f7df2e56Smrg            PartialNetwork = TRUE;
912f7df2e56Smrg        else if (strcmp(argv[i], "-nopn") == 0)
913f7df2e56Smrg            PartialNetwork = FALSE;
914f7df2e56Smrg        else if (strcmp(argv[i], "r") == 0)
915f7df2e56Smrg            defaultKeyboardControl.autoRepeat = TRUE;
916f7df2e56Smrg        else if (strcmp(argv[i], "-r") == 0)
917f7df2e56Smrg            defaultKeyboardControl.autoRepeat = FALSE;
918f7df2e56Smrg        else if (strcmp(argv[i], "-retro") == 0)
919f7df2e56Smrg            party_like_its_1989 = TRUE;
920f7df2e56Smrg	else if (strcmp(argv[i], "-noretro") == 0)
921daf23d7fSsnj	    party_like_its_1989 = FALSE;
922f7df2e56Smrg        else if (strcmp(argv[i], "-s") == 0) {
923f7df2e56Smrg            if (++i < argc)
924f7df2e56Smrg                defaultScreenSaverTime = ((CARD32) atoi(argv[i])) *
925f7df2e56Smrg                    MILLI_PER_MIN;
926f7df2e56Smrg            else
927f7df2e56Smrg                UseMsg();
928f7df2e56Smrg        }
929f7df2e56Smrg        else if (strcmp(argv[i], "-seat") == 0) {
930f7df2e56Smrg            if (++i < argc)
931f7df2e56Smrg                SeatId = argv[i];
932f7df2e56Smrg            else
933f7df2e56Smrg                UseMsg();
934f7df2e56Smrg        }
935f7df2e56Smrg        else if (strcmp(argv[i], "-t") == 0) {
936f7df2e56Smrg            if (++i < argc)
937f7df2e56Smrg                defaultPointerControl.threshold = atoi(argv[i]);
938f7df2e56Smrg            else
939f7df2e56Smrg                UseMsg();
940f7df2e56Smrg        }
941f7df2e56Smrg        else if (strcmp(argv[i], "-terminate") == 0) {
942f7df2e56Smrg            dispatchExceptionAtReset = DE_TERMINATE;
9435a112b11Smrg            terminateDelay = -1;
9445a112b11Smrg            if ((i + 1 < argc) && (isdigit(*argv[i + 1])))
9455a112b11Smrg               terminateDelay = atoi(argv[++i]);
9465a112b11Smrg            terminateDelay = max(0, terminateDelay);
947f7df2e56Smrg        }
948f7df2e56Smrg        else if (strcmp(argv[i], "-tst") == 0) {
949f7df2e56Smrg            noTestExtensions = TRUE;
950f7df2e56Smrg        }
951f7df2e56Smrg        else if (strcmp(argv[i], "v") == 0)
952f7df2e56Smrg            defaultScreenSaverBlanking = PreferBlanking;
953f7df2e56Smrg        else if (strcmp(argv[i], "-v") == 0)
954f7df2e56Smrg            defaultScreenSaverBlanking = DontPreferBlanking;
955f7df2e56Smrg        else if (strcmp(argv[i], "-wr") == 0)
95605b261ecSmrg            whiteRoot = TRUE;
957f7df2e56Smrg        else if (strcmp(argv[i], "-background") == 0) {
958f7df2e56Smrg            if (++i < argc) {
959f7df2e56Smrg                if (!strcmp(argv[i], "none"))
96065b04b38Smrg                    bgNoneRoot = TRUE;
96165b04b38Smrg                else
96265b04b38Smrg                    UseMsg();
96365b04b38Smrg            }
96465b04b38Smrg        }
965f7df2e56Smrg        else if (strcmp(argv[i], "-maxbigreqsize") == 0) {
966f7df2e56Smrg            if (++i < argc) {
967f7df2e56Smrg                long reqSizeArg = atol(argv[i]);
968f7df2e56Smrg
969f7df2e56Smrg                /* Request size > 128MB does not make much sense... */
970f7df2e56Smrg                if (reqSizeArg > 0L && reqSizeArg < 128L) {
971f7df2e56Smrg                    maxBigRequestSize = (reqSizeArg * 1048576L) - 1L;
972f7df2e56Smrg                }
973f7df2e56Smrg                else {
974f7df2e56Smrg                    UseMsg();
975f7df2e56Smrg                }
976f7df2e56Smrg            }
977f7df2e56Smrg            else {
978f7df2e56Smrg                UseMsg();
979f7df2e56Smrg            }
980f7df2e56Smrg        }
981f7df2e56Smrg#ifdef PANORAMIX
982f7df2e56Smrg        else if (strcmp(argv[i], "+xinerama") == 0) {
983f7df2e56Smrg            noPanoramiXExtension = FALSE;
984f7df2e56Smrg        }
985f7df2e56Smrg        else if (strcmp(argv[i], "-xinerama") == 0) {
986f7df2e56Smrg            noPanoramiXExtension = TRUE;
987f7df2e56Smrg        }
988f7df2e56Smrg        else if (strcmp(argv[i], "-disablexineramaextension") == 0) {
989f7df2e56Smrg            PanoramiXExtensionDisabledHack = TRUE;
990f7df2e56Smrg        }
991f7df2e56Smrg#endif
992f7df2e56Smrg        else if (strcmp(argv[i], "-I") == 0) {
993f7df2e56Smrg            /* ignore all remaining arguments */
994f7df2e56Smrg            break;
995f7df2e56Smrg        }
996f7df2e56Smrg        else if (strncmp(argv[i], "tty", 3) == 0) {
997f7df2e56Smrg            /* init supplies us with this useless information */
998f7df2e56Smrg        }
999f7df2e56Smrg#ifdef XDMCP
1000f7df2e56Smrg        else if ((skip = XdmcpOptions(argc, argv, i)) != i) {
1001f7df2e56Smrg            i = skip - 1;
1002f7df2e56Smrg        }
1003f7df2e56Smrg#endif
1004f7df2e56Smrg        else if (strcmp(argv[i], "-dumbSched") == 0) {
10057e31ba66Smrg            InputThreadEnable = FALSE;
10067e31ba66Smrg#ifdef HAVE_SETITIMER
10077e31ba66Smrg            SmartScheduleSignalEnable = FALSE;
10087e31ba66Smrg#endif
1009f7df2e56Smrg        }
1010f7df2e56Smrg        else if (strcmp(argv[i], "-schedInterval") == 0) {
1011f7df2e56Smrg            if (++i < argc) {
1012f7df2e56Smrg                SmartScheduleInterval = atoi(argv[i]);
1013f7df2e56Smrg                SmartScheduleSlice = SmartScheduleInterval;
1014f7df2e56Smrg            }
1015f7df2e56Smrg            else
1016f7df2e56Smrg                UseMsg();
1017f7df2e56Smrg        }
1018f7df2e56Smrg        else if (strcmp(argv[i], "-schedMax") == 0) {
1019f7df2e56Smrg            if (++i < argc) {
1020f7df2e56Smrg                SmartScheduleMaxSlice = atoi(argv[i]);
1021f7df2e56Smrg            }
1022f7df2e56Smrg            else
1023f7df2e56Smrg                UseMsg();
1024f7df2e56Smrg        }
1025f7df2e56Smrg        else if (strcmp(argv[i], "-render") == 0) {
1026f7df2e56Smrg            if (++i < argc) {
1027f7df2e56Smrg                int policy = PictureParseCmapPolicy(argv[i]);
1028f7df2e56Smrg
1029f7df2e56Smrg                if (policy != PictureCmapPolicyInvalid)
1030f7df2e56Smrg                    PictureCmapPolicy = policy;
1031f7df2e56Smrg                else
1032f7df2e56Smrg                    UseMsg();
1033f7df2e56Smrg            }
1034f7df2e56Smrg            else
1035f7df2e56Smrg                UseMsg();
1036f7df2e56Smrg        }
1037f7df2e56Smrg        else if (strcmp(argv[i], "-sigstop") == 0) {
1038f7df2e56Smrg            RunFromSigStopParent = TRUE;
1039f7df2e56Smrg        }
1040f7df2e56Smrg        else if (strcmp(argv[i], "+extension") == 0) {
1041f7df2e56Smrg            if (++i < argc) {
1042f7df2e56Smrg                if (!EnableDisableExtension(argv[i], TRUE))
1043f7df2e56Smrg                    EnableDisableExtensionError(argv[i], TRUE);
1044f7df2e56Smrg            }
1045f7df2e56Smrg            else
1046f7df2e56Smrg                UseMsg();
1047f7df2e56Smrg        }
1048f7df2e56Smrg        else if (strcmp(argv[i], "-extension") == 0) {
1049f7df2e56Smrg            if (++i < argc) {
1050f7df2e56Smrg                if (!EnableDisableExtension(argv[i], FALSE))
1051f7df2e56Smrg                    EnableDisableExtensionError(argv[i], FALSE);
1052f7df2e56Smrg            }
1053f7df2e56Smrg            else
1054f7df2e56Smrg                UseMsg();
1055f7df2e56Smrg        }
1056f7df2e56Smrg        else {
1057f7df2e56Smrg            ErrorF("Unrecognized option: %s\n", argv[i]);
1058f7df2e56Smrg            UseMsg();
1059f7df2e56Smrg            FatalError("Unrecognized option: %s\n", argv[i]);
106005b261ecSmrg        }
106105b261ecSmrg    }
106205b261ecSmrg}
106305b261ecSmrg
106405b261ecSmrg/* Implement a simple-minded font authorization scheme.  The authorization
106505b261ecSmrg   name is "hp-hostname-1", the contents are simply the host name. */
106605b261ecSmrgint
1067f7df2e56Smrgset_font_authorizations(char **authorizations, int *authlen, void *client)
106805b261ecSmrg{
106905b261ecSmrg#define AUTHORIZATION_NAME "hp-hostname-1"
10707e31ba66Smrg#if defined(TCPCONN)
107105b261ecSmrg    static char *result = NULL;
107205b261ecSmrg    static char *p = NULL;
107305b261ecSmrg
1074f7df2e56Smrg    if (p == NULL) {
1075f7df2e56Smrg        char hname[1024], *hnameptr;
1076f7df2e56Smrg        unsigned int len;
1077f7df2e56Smrg
107805b261ecSmrg#if defined(IPv6) && defined(AF_INET6)
1079f7df2e56Smrg        struct addrinfo hints, *ai = NULL;
108005b261ecSmrg#else
1081f7df2e56Smrg        struct hostent *host;
1082f7df2e56Smrg
108305b261ecSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1084f7df2e56Smrg        _Xgethostbynameparams hparams;
108505b261ecSmrg#endif
108605b261ecSmrg#endif
108705b261ecSmrg
1088f7df2e56Smrg        gethostname(hname, 1024);
108905b261ecSmrg#if defined(IPv6) && defined(AF_INET6)
1090f7df2e56Smrg        memset(&hints, 0, sizeof(hints));
1091f7df2e56Smrg        hints.ai_flags = AI_CANONNAME;
1092f7df2e56Smrg        if (getaddrinfo(hname, NULL, &hints, &ai) == 0) {
1093f7df2e56Smrg            hnameptr = ai->ai_canonname;
1094f7df2e56Smrg        }
1095f7df2e56Smrg        else {
1096f7df2e56Smrg            hnameptr = hname;
1097f7df2e56Smrg        }
109805b261ecSmrg#else
1099f7df2e56Smrg        host = _XGethostbyname(hname, hparams);
1100f7df2e56Smrg        if (host == NULL)
1101f7df2e56Smrg            hnameptr = hname;
1102f7df2e56Smrg        else
1103f7df2e56Smrg            hnameptr = host->h_name;
110405b261ecSmrg#endif
110505b261ecSmrg
1106f7df2e56Smrg        len = strlen(hnameptr) + 1;
1107f7df2e56Smrg        result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4);
110805b261ecSmrg
1109f7df2e56Smrg        p = result;
111005b261ecSmrg        *p++ = sizeof(AUTHORIZATION_NAME) >> 8;
111105b261ecSmrg        *p++ = sizeof(AUTHORIZATION_NAME) & 0xff;
111205b261ecSmrg        *p++ = (len) >> 8;
111305b261ecSmrg        *p++ = (len & 0xff);
111405b261ecSmrg
1115f7df2e56Smrg        memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME));
1116f7df2e56Smrg        p += sizeof(AUTHORIZATION_NAME);
1117f7df2e56Smrg        memmove(p, hnameptr, len);
1118f7df2e56Smrg        p += len;
111905b261ecSmrg#if defined(IPv6) && defined(AF_INET6)
1120f7df2e56Smrg        if (ai) {
1121f7df2e56Smrg            freeaddrinfo(ai);
1122f7df2e56Smrg        }
112305b261ecSmrg#endif
112405b261ecSmrg    }
112505b261ecSmrg    *authlen = p - result;
112605b261ecSmrg    *authorizations = result;
112705b261ecSmrg    return 1;
1128f7df2e56Smrg#else                           /* TCPCONN */
112905b261ecSmrg    return 0;
1130f7df2e56Smrg#endif                          /* TCPCONN */
113105b261ecSmrg}
113205b261ecSmrg
11334202a189Smrgvoid *
113405b261ecSmrgXNFalloc(unsigned long amount)
113505b261ecSmrg{
11364202a189Smrg    void *ptr = malloc(amount);
1137f7df2e56Smrg
113805b261ecSmrg    if (!ptr)
113905b261ecSmrg        FatalError("Out of memory");
11404642e01fSmrg    return ptr;
114105b261ecSmrg}
114205b261ecSmrg
1143f7df2e56Smrg/* The original XNFcalloc was used with the xnfcalloc macro which multiplied
1144f7df2e56Smrg * the arguments at the call site without allowing calloc to check for overflow.
1145f7df2e56Smrg * XNFcallocarray was added to fix that without breaking ABI.
1146f7df2e56Smrg */
11474202a189Smrgvoid *
1148f7df2e56SmrgXNFcalloc(unsigned long amount)
114905b261ecSmrg{
1150f7df2e56Smrg    return XNFcallocarray(1, amount);
115105b261ecSmrg}
115205b261ecSmrg
11534202a189Smrgvoid *
1154f7df2e56SmrgXNFcallocarray(size_t nmemb, size_t size)
115505b261ecSmrg{
1156f7df2e56Smrg    void *ret = calloc(nmemb, size);
1157f7df2e56Smrg
11584202a189Smrg    if (!ret)
11594202a189Smrg        FatalError("XNFcalloc: Out of memory");
116005b261ecSmrg    return ret;
116105b261ecSmrg}
116205b261ecSmrg
11634202a189Smrgvoid *
11644202a189SmrgXNFrealloc(void *ptr, unsigned long amount)
116505b261ecSmrg{
11664202a189Smrg    void *ret = realloc(ptr, amount);
1167f7df2e56Smrg
11684202a189Smrg    if (!ret)
1169f7df2e56Smrg        FatalError("XNFrealloc: Out of memory");
11704202a189Smrg    return ret;
117105b261ecSmrg}
117205b261ecSmrg
1173f7df2e56Smrgvoid *
1174f7df2e56SmrgXNFreallocarray(void *ptr, size_t nmemb, size_t size)
117505b261ecSmrg{
1176f7df2e56Smrg    void *ret = reallocarray(ptr, nmemb, size);
117705b261ecSmrg
1178f7df2e56Smrg    if (!ret)
1179f7df2e56Smrg        FatalError("XNFreallocarray: Out of memory");
1180f7df2e56Smrg    return ret;
1181f7df2e56Smrg}
118205b261ecSmrg
118305b261ecSmrgchar *
118405b261ecSmrgXstrdup(const char *s)
118505b261ecSmrg{
118605b261ecSmrg    if (s == NULL)
1187f7df2e56Smrg        return NULL;
11884202a189Smrg    return strdup(s);
118905b261ecSmrg}
119005b261ecSmrg
11914202a189Smrgchar *
119205b261ecSmrgXNFstrdup(const char *s)
119305b261ecSmrg{
11944202a189Smrg    char *ret;
119505b261ecSmrg
119605b261ecSmrg    if (s == NULL)
1197f7df2e56Smrg        return NULL;
119805b261ecSmrg
11994202a189Smrg    ret = strdup(s);
12004202a189Smrg    if (!ret)
1201f7df2e56Smrg        FatalError("XNFstrdup: Out of memory");
12024202a189Smrg    return ret;
120305b261ecSmrg}
120405b261ecSmrg
12054642e01fSmrgvoid
1206f7df2e56SmrgSmartScheduleStopTimer(void)
120705b261ecSmrg{
12087e31ba66Smrg#ifdef HAVE_SETITIMER
1209f7df2e56Smrg    struct itimerval timer;
1210f7df2e56Smrg
12117e31ba66Smrg    if (!SmartScheduleSignalEnable)
1212f7df2e56Smrg        return;
121305b261ecSmrg    timer.it_interval.tv_sec = 0;
121405b261ecSmrg    timer.it_interval.tv_usec = 0;
121505b261ecSmrg    timer.it_value.tv_sec = 0;
121605b261ecSmrg    timer.it_value.tv_usec = 0;
1217f7df2e56Smrg    (void) setitimer(ITIMER_REAL, &timer, 0);
1218f7df2e56Smrg#endif
121905b261ecSmrg}
122005b261ecSmrg
12214642e01fSmrgvoid
1222f7df2e56SmrgSmartScheduleStartTimer(void)
122305b261ecSmrg{
12247e31ba66Smrg#ifdef HAVE_SETITIMER
1225f7df2e56Smrg    struct itimerval timer;
1226f7df2e56Smrg
12277e31ba66Smrg    if (!SmartScheduleSignalEnable)
1228f7df2e56Smrg        return;
122905b261ecSmrg    timer.it_interval.tv_sec = 0;
123005b261ecSmrg    timer.it_interval.tv_usec = SmartScheduleInterval * 1000;
123105b261ecSmrg    timer.it_value.tv_sec = 0;
123205b261ecSmrg    timer.it_value.tv_usec = SmartScheduleInterval * 1000;
1233f7df2e56Smrg    setitimer(ITIMER_REAL, &timer, 0);
1234f7df2e56Smrg#endif
123505b261ecSmrg}
123605b261ecSmrg
12377e31ba66Smrg#ifdef HAVE_SETITIMER
123805b261ecSmrgstatic void
1239f7df2e56SmrgSmartScheduleTimer(int sig)
124005b261ecSmrg{
124105b261ecSmrg    SmartScheduleTime += SmartScheduleInterval;
124205b261ecSmrg}
124305b261ecSmrg
1244f7df2e56Smrgstatic int
1245f7df2e56SmrgSmartScheduleEnable(void)
124605b261ecSmrg{
1247f7df2e56Smrg    int ret = 0;
1248f7df2e56Smrg    struct sigaction act;
124905b261ecSmrg
12507e31ba66Smrg    if (!SmartScheduleSignalEnable)
1251f7df2e56Smrg        return 0;
125265b04b38Smrg
12534202a189Smrg    memset((char *) &act, 0, sizeof(struct sigaction));
125405b261ecSmrg
125505b261ecSmrg    /* Set up the timer signal function */
1256f7df2e56Smrg    act.sa_flags = SA_RESTART;
125705b261ecSmrg    act.sa_handler = SmartScheduleTimer;
1258f7df2e56Smrg    sigemptyset(&act.sa_mask);
1259f7df2e56Smrg    sigaddset(&act.sa_mask, SIGALRM);
1260f7df2e56Smrg    ret = sigaction(SIGALRM, &act, 0);
1261f7df2e56Smrg    return ret;
1262f7df2e56Smrg}
1263f7df2e56Smrg
1264f7df2e56Smrgstatic int
1265f7df2e56SmrgSmartSchedulePause(void)
1266f7df2e56Smrg{
1267f7df2e56Smrg    int ret = 0;
1268f7df2e56Smrg    struct sigaction act;
1269f7df2e56Smrg
12707e31ba66Smrg    if (!SmartScheduleSignalEnable)
1271f7df2e56Smrg        return 0;
1272f7df2e56Smrg
1273f7df2e56Smrg    memset((char *) &act, 0, sizeof(struct sigaction));
1274f7df2e56Smrg
1275f7df2e56Smrg    act.sa_handler = SIG_IGN;
1276f7df2e56Smrg    sigemptyset(&act.sa_mask);
1277f7df2e56Smrg    ret = sigaction(SIGALRM, &act, 0);
1278f7df2e56Smrg    return ret;
1279f7df2e56Smrg}
12807e31ba66Smrg#endif
1281f7df2e56Smrg
1282f7df2e56Smrgvoid
1283f7df2e56SmrgSmartScheduleInit(void)
1284f7df2e56Smrg{
12857e31ba66Smrg#ifdef HAVE_SETITIMER
1286f7df2e56Smrg    if (SmartScheduleEnable() < 0) {
1287f7df2e56Smrg        perror("sigaction for smart scheduler");
12887e31ba66Smrg        SmartScheduleSignalEnable = FALSE;
128905b261ecSmrg    }
12907e31ba66Smrg#endif
129105b261ecSmrg}
129205b261ecSmrg
12935a112b11Smrg#ifdef HAVE_SIGPROCMASK
1294f7df2e56Smrgstatic sigset_t PreviousSignalMask;
1295f7df2e56Smrgstatic int BlockedSignalCount;
129605b261ecSmrg#endif
129705b261ecSmrg
129805b261ecSmrgvoid
1299f7df2e56SmrgOsBlockSignals(void)
130005b261ecSmrg{
13015a112b11Smrg#ifdef HAVE_SIGPROCMASK
1302f7df2e56Smrg    if (BlockedSignalCount++ == 0) {
1303f7df2e56Smrg        sigset_t set;
1304f7df2e56Smrg
1305f7df2e56Smrg        sigemptyset(&set);
1306f7df2e56Smrg        sigaddset(&set, SIGALRM);
1307f7df2e56Smrg        sigaddset(&set, SIGVTALRM);
130805b261ecSmrg#ifdef SIGWINCH
1309f7df2e56Smrg        sigaddset(&set, SIGWINCH);
1310f7df2e56Smrg#endif
1311f7df2e56Smrg        sigaddset(&set, SIGTSTP);
1312f7df2e56Smrg        sigaddset(&set, SIGTTIN);
1313f7df2e56Smrg        sigaddset(&set, SIGTTOU);
1314f7df2e56Smrg        sigaddset(&set, SIGCHLD);
13157e31ba66Smrg        xthread_sigmask(SIG_BLOCK, &set, &PreviousSignalMask);
131605b261ecSmrg    }
131705b261ecSmrg#endif
131805b261ecSmrg}
131905b261ecSmrg
132005b261ecSmrgvoid
1321f7df2e56SmrgOsReleaseSignals(void)
132205b261ecSmrg{
13235a112b11Smrg#ifdef HAVE_SIGPROCMASK
1324f7df2e56Smrg    if (--BlockedSignalCount == 0) {
13257e31ba66Smrg        xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0);
132605b261ecSmrg    }
132705b261ecSmrg#endif
132805b261ecSmrg}
132905b261ecSmrg
1330f7df2e56Smrgvoid
1331f7df2e56SmrgOsResetSignals(void)
1332f7df2e56Smrg{
13335a112b11Smrg#ifdef HAVE_SIGPROCMASK
1334f7df2e56Smrg    while (BlockedSignalCount > 0)
1335f7df2e56Smrg        OsReleaseSignals();
13367e31ba66Smrg    input_force_unlock();
1337f7df2e56Smrg#endif
1338f7df2e56Smrg}
1339f7df2e56Smrg
13404202a189Smrg/*
13414202a189Smrg * Pending signals may interfere with core dumping. Provide a
13424202a189Smrg * mechanism to block signals when aborting.
13434202a189Smrg */
13444202a189Smrg
13454202a189Smrgvoid
1346f7df2e56SmrgOsAbort(void)
13474202a189Smrg{
13484202a189Smrg#ifndef __APPLE__
13494202a189Smrg    OsBlockSignals();
13507e31ba66Smrg#endif
13517e31ba66Smrg#if !defined(WIN32) || defined(__CYGWIN__)
13527e31ba66Smrg    /* abort() raises SIGABRT, so we have to stop handling that to prevent
13537e31ba66Smrg     * recursion
13547e31ba66Smrg     */
13557e31ba66Smrg    OsSignal(SIGABRT, SIG_DFL);
13564202a189Smrg#endif
13574202a189Smrg    abort();
13584202a189Smrg}
13594202a189Smrg
136005b261ecSmrg#if !defined(WIN32)
136105b261ecSmrg/*
136205b261ecSmrg * "safer" versions of system(3), popen(3) and pclose(3) which give up
136305b261ecSmrg * all privs before running a command.
136405b261ecSmrg *
136505b261ecSmrg * This is based on the code in FreeBSD 2.2 libc.
136605b261ecSmrg *
136705b261ecSmrg * XXX It'd be good to redirect stderr so that it ends up in the log file
136805b261ecSmrg * as well.  As it is now, xkbcomp messages don't end up in the log file.
136905b261ecSmrg */
137005b261ecSmrg
137105b261ecSmrgint
1372f7df2e56SmrgSystem(const char *command)
137305b261ecSmrg{
137405b261ecSmrg    int pid, p;
1375f7df2e56Smrg    void (*csig) (int);
137605b261ecSmrg    int status;
137705b261ecSmrg
137805b261ecSmrg    if (!command)
1379f7df2e56Smrg        return 1;
138005b261ecSmrg
13817e31ba66Smrg    csig = OsSignal(SIGCHLD, SIG_DFL);
138205b261ecSmrg    if (csig == SIG_ERR) {
1383f7df2e56Smrg        perror("signal");
1384f7df2e56Smrg        return -1;
138505b261ecSmrg    }
138665b04b38Smrg    DebugF("System: `%s'\n", command);
138705b261ecSmrg
138805b261ecSmrg    switch (pid = fork()) {
1389f7df2e56Smrg    case -1:                   /* error */
1390f7df2e56Smrg        p = -1;
1391f7df2e56Smrg        break;
1392f7df2e56Smrg    case 0:                    /* child */
1393f7df2e56Smrg        if (setgid(getgid()) == -1)
1394f7df2e56Smrg            _exit(127);
1395f7df2e56Smrg        if (setuid(getuid()) == -1)
1396f7df2e56Smrg            _exit(127);
1397f7df2e56Smrg        execl("/bin/sh", "sh", "-c", command, (char *) NULL);
1398f7df2e56Smrg        _exit(127);
1399f7df2e56Smrg    default:                   /* parent */
1400f7df2e56Smrg        do {
1401f7df2e56Smrg            p = waitpid(pid, &status, 0);
1402f7df2e56Smrg        } while (p == -1 && errno == EINTR);
1403f7df2e56Smrg
140405b261ecSmrg    }
140505b261ecSmrg
14067e31ba66Smrg    if (OsSignal(SIGCHLD, csig) == SIG_ERR) {
1407f7df2e56Smrg        perror("signal");
1408f7df2e56Smrg        return -1;
140905b261ecSmrg    }
141005b261ecSmrg
141105b261ecSmrg    return p == -1 ? -1 : status;
141205b261ecSmrg}
141305b261ecSmrg
141405b261ecSmrgstatic struct pid {
141505b261ecSmrg    struct pid *next;
141605b261ecSmrg    FILE *fp;
141705b261ecSmrg    int pid;
141805b261ecSmrg} *pidlist;
141905b261ecSmrg
1420f7df2e56Smrgvoid *
1421f7df2e56SmrgPopen(const char *command, const char *type)
142205b261ecSmrg{
142305b261ecSmrg    struct pid *cur;
142405b261ecSmrg    FILE *iop;
142505b261ecSmrg    int pdes[2], pid;
142605b261ecSmrg
142705b261ecSmrg    if (command == NULL || type == NULL)
1428f7df2e56Smrg        return NULL;
142905b261ecSmrg
143005b261ecSmrg    if ((*type != 'r' && *type != 'w') || type[1])
1431f7df2e56Smrg        return NULL;
143205b261ecSmrg
14334202a189Smrg    if ((cur = malloc(sizeof(struct pid))) == NULL)
1434f7df2e56Smrg        return NULL;
143505b261ecSmrg
143605b261ecSmrg    if (pipe(pdes) < 0) {
1437f7df2e56Smrg        free(cur);
1438f7df2e56Smrg        return NULL;
143905b261ecSmrg    }
144005b261ecSmrg
144105b261ecSmrg    /* Ignore the smart scheduler while this is going on */
14427e31ba66Smrg#ifdef HAVE_SETITIMER
1443f7df2e56Smrg    if (SmartSchedulePause() < 0) {
1444f7df2e56Smrg        close(pdes[0]);
1445f7df2e56Smrg        close(pdes[1]);
1446f7df2e56Smrg        free(cur);
1447f7df2e56Smrg        perror("signal");
1448f7df2e56Smrg        return NULL;
144905b261ecSmrg    }
14507e31ba66Smrg#endif
145105b261ecSmrg
145205b261ecSmrg    switch (pid = fork()) {
1453f7df2e56Smrg    case -1:                   /* error */
1454f7df2e56Smrg        close(pdes[0]);
1455f7df2e56Smrg        close(pdes[1]);
1456f7df2e56Smrg        free(cur);
14577e31ba66Smrg#ifdef HAVE_SETITIMER
1458f7df2e56Smrg        if (SmartScheduleEnable() < 0)
1459f7df2e56Smrg            perror("signal");
14607e31ba66Smrg#endif
1461f7df2e56Smrg        return NULL;
1462f7df2e56Smrg    case 0:                    /* child */
1463f7df2e56Smrg        if (setgid(getgid()) == -1)
1464f7df2e56Smrg            _exit(127);
1465f7df2e56Smrg        if (setuid(getuid()) == -1)
1466f7df2e56Smrg            _exit(127);
1467f7df2e56Smrg        if (*type == 'r') {
1468f7df2e56Smrg            if (pdes[1] != 1) {
1469f7df2e56Smrg                /* stdout */
1470f7df2e56Smrg                dup2(pdes[1], 1);
1471f7df2e56Smrg                close(pdes[1]);
1472f7df2e56Smrg            }
1473f7df2e56Smrg            close(pdes[0]);
1474f7df2e56Smrg        }
1475f7df2e56Smrg        else {
1476f7df2e56Smrg            if (pdes[0] != 0) {
1477f7df2e56Smrg                /* stdin */
1478f7df2e56Smrg                dup2(pdes[0], 0);
1479f7df2e56Smrg                close(pdes[0]);
1480f7df2e56Smrg            }
1481f7df2e56Smrg            close(pdes[1]);
1482f7df2e56Smrg        }
1483f7df2e56Smrg        execl("/bin/sh", "sh", "-c", command, (char *) NULL);
1484f7df2e56Smrg        _exit(127);
148505b261ecSmrg    }
148605b261ecSmrg
148705b261ecSmrg    /* Avoid EINTR during stdio calls */
1488f7df2e56Smrg    OsBlockSignals();
1489f7df2e56Smrg
149005b261ecSmrg    /* parent */
149105b261ecSmrg    if (*type == 'r') {
1492f7df2e56Smrg        iop = fdopen(pdes[0], type);
1493f7df2e56Smrg        close(pdes[1]);
1494f7df2e56Smrg    }
1495f7df2e56Smrg    else {
1496f7df2e56Smrg        iop = fdopen(pdes[1], type);
1497f7df2e56Smrg        close(pdes[0]);
149805b261ecSmrg    }
149905b261ecSmrg
150005b261ecSmrg    cur->fp = iop;
150105b261ecSmrg    cur->pid = pid;
150205b261ecSmrg    cur->next = pidlist;
150305b261ecSmrg    pidlist = cur;
150405b261ecSmrg
150565b04b38Smrg    DebugF("Popen: `%s', fp = %p\n", command, iop);
150605b261ecSmrg
150705b261ecSmrg    return iop;
150805b261ecSmrg}
150905b261ecSmrg
151005b261ecSmrg/* fopen that drops privileges */
1511f7df2e56Smrgvoid *
1512f7df2e56SmrgFopen(const char *file, const char *type)
151305b261ecSmrg{
151405b261ecSmrg    FILE *iop;
1515f7df2e56Smrg
151605b261ecSmrg#ifndef HAS_SAVED_IDS_AND_SETEUID
151705b261ecSmrg    struct pid *cur;
151805b261ecSmrg    int pdes[2], pid;
151905b261ecSmrg
152005b261ecSmrg    if (file == NULL || type == NULL)
1521f7df2e56Smrg        return NULL;
152205b261ecSmrg
152305b261ecSmrg    if ((*type != 'r' && *type != 'w') || type[1])
1524f7df2e56Smrg        return NULL;
152505b261ecSmrg
15264202a189Smrg    if ((cur = malloc(sizeof(struct pid))) == NULL)
1527f7df2e56Smrg        return NULL;
152805b261ecSmrg
152905b261ecSmrg    if (pipe(pdes) < 0) {
1530f7df2e56Smrg        free(cur);
1531f7df2e56Smrg        return NULL;
153205b261ecSmrg    }
153305b261ecSmrg
153405b261ecSmrg    switch (pid = fork()) {
1535f7df2e56Smrg    case -1:                   /* error */
1536f7df2e56Smrg        close(pdes[0]);
1537f7df2e56Smrg        close(pdes[1]);
1538f7df2e56Smrg        free(cur);
1539f7df2e56Smrg        return NULL;
1540f7df2e56Smrg    case 0:                    /* child */
1541f7df2e56Smrg        if (setgid(getgid()) == -1)
1542f7df2e56Smrg            _exit(127);
1543f7df2e56Smrg        if (setuid(getuid()) == -1)
1544f7df2e56Smrg            _exit(127);
1545f7df2e56Smrg        if (*type == 'r') {
1546f7df2e56Smrg            if (pdes[1] != 1) {
1547f7df2e56Smrg                /* stdout */
1548f7df2e56Smrg                dup2(pdes[1], 1);
1549f7df2e56Smrg                close(pdes[1]);
1550f7df2e56Smrg            }
1551f7df2e56Smrg            close(pdes[0]);
1552f7df2e56Smrg        }
1553f7df2e56Smrg        else {
1554f7df2e56Smrg            if (pdes[0] != 0) {
1555f7df2e56Smrg                /* stdin */
1556f7df2e56Smrg                dup2(pdes[0], 0);
1557f7df2e56Smrg                close(pdes[0]);
1558f7df2e56Smrg            }
1559f7df2e56Smrg            close(pdes[1]);
1560f7df2e56Smrg        }
1561f7df2e56Smrg        execl("/bin/cat", "cat", file, (char *) NULL);
1562f7df2e56Smrg        _exit(127);
156305b261ecSmrg    }
156405b261ecSmrg
156505b261ecSmrg    /* Avoid EINTR during stdio calls */
1566f7df2e56Smrg    OsBlockSignals();
1567f7df2e56Smrg
156805b261ecSmrg    /* parent */
156905b261ecSmrg    if (*type == 'r') {
1570f7df2e56Smrg        iop = fdopen(pdes[0], type);
1571f7df2e56Smrg        close(pdes[1]);
1572f7df2e56Smrg    }
1573f7df2e56Smrg    else {
1574f7df2e56Smrg        iop = fdopen(pdes[1], type);
1575f7df2e56Smrg        close(pdes[0]);
157605b261ecSmrg    }
157705b261ecSmrg
157805b261ecSmrg    cur->fp = iop;
157905b261ecSmrg    cur->pid = pid;
158005b261ecSmrg    cur->next = pidlist;
158105b261ecSmrg    pidlist = cur;
158205b261ecSmrg
158365b04b38Smrg    DebugF("Fopen(%s), fp = %p\n", file, iop);
158405b261ecSmrg
158505b261ecSmrg    return iop;
158605b261ecSmrg#else
158705b261ecSmrg    int ruid, euid;
158805b261ecSmrg
158905b261ecSmrg    ruid = getuid();
159005b261ecSmrg    euid = geteuid();
1591f7df2e56Smrg
159205b261ecSmrg    if (seteuid(ruid) == -1) {
1593f7df2e56Smrg        return NULL;
159405b261ecSmrg    }
159505b261ecSmrg    iop = fopen(file, type);
159605b261ecSmrg
159705b261ecSmrg    if (seteuid(euid) == -1) {
1598f7df2e56Smrg        fclose(iop);
1599f7df2e56Smrg        return NULL;
160005b261ecSmrg    }
160105b261ecSmrg    return iop;
1602f7df2e56Smrg#endif                          /* HAS_SAVED_IDS_AND_SETEUID */
160305b261ecSmrg}
160405b261ecSmrg
160505b261ecSmrgint
1606f7df2e56SmrgPclose(void *iop)
160705b261ecSmrg{
160805b261ecSmrg    struct pid *cur, *last;
160905b261ecSmrg    int pstat;
161005b261ecSmrg    int pid;
161105b261ecSmrg
161265b04b38Smrg    DebugF("Pclose: fp = %p\n", iop);
161305b261ecSmrg    fclose(iop);
161405b261ecSmrg
161505b261ecSmrg    for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
1616f7df2e56Smrg        if (cur->fp == iop)
1617f7df2e56Smrg            break;
161805b261ecSmrg    if (cur == NULL)
1619f7df2e56Smrg        return -1;
162005b261ecSmrg
162105b261ecSmrg    do {
1622f7df2e56Smrg        pid = waitpid(cur->pid, &pstat, 0);
162305b261ecSmrg    } while (pid == -1 && errno == EINTR);
162405b261ecSmrg
162505b261ecSmrg    if (last == NULL)
1626f7df2e56Smrg        pidlist = cur->next;
162705b261ecSmrg    else
1628f7df2e56Smrg        last->next = cur->next;
16294202a189Smrg    free(cur);
163005b261ecSmrg
163105b261ecSmrg    /* allow EINTR again */
1632f7df2e56Smrg    OsReleaseSignals();
1633f7df2e56Smrg
16347e31ba66Smrg#ifdef HAVE_SETITIMER
1635f7df2e56Smrg    if (SmartScheduleEnable() < 0) {
1636f7df2e56Smrg        perror("signal");
1637f7df2e56Smrg        return -1;
163805b261ecSmrg    }
16397e31ba66Smrg#endif
164005b261ecSmrg
164105b261ecSmrg    return pid == -1 ? -1 : pstat;
164205b261ecSmrg}
164305b261ecSmrg
16444202a189Smrgint
1645f7df2e56SmrgFclose(void *iop)
164605b261ecSmrg{
164705b261ecSmrg#ifdef HAS_SAVED_IDS_AND_SETEUID
164805b261ecSmrg    return fclose(iop);
164905b261ecSmrg#else
165005b261ecSmrg    return Pclose(iop);
165105b261ecSmrg#endif
165205b261ecSmrg}
165305b261ecSmrg
1654f7df2e56Smrg#endif                          /* !WIN32 */
1655f7df2e56Smrg
1656f7df2e56Smrg#ifdef WIN32
1657f7df2e56Smrg
1658f7df2e56Smrg#include <X11/Xwindows.h>
1659f7df2e56Smrg
1660f7df2e56Smrgconst char *
1661f7df2e56SmrgWin32TempDir(void)
1662f7df2e56Smrg{
1663f7df2e56Smrg    static char buffer[PATH_MAX];
1664f7df2e56Smrg
1665f7df2e56Smrg    if (GetTempPath(sizeof(buffer), buffer)) {
1666f7df2e56Smrg        int len;
1667f7df2e56Smrg
1668f7df2e56Smrg        buffer[sizeof(buffer) - 1] = 0;
1669f7df2e56Smrg        len = strlen(buffer);
1670f7df2e56Smrg        if (len > 0)
1671f7df2e56Smrg            if (buffer[len - 1] == '\\')
1672f7df2e56Smrg                buffer[len - 1] = 0;
1673f7df2e56Smrg        return buffer;
1674f7df2e56Smrg    }
1675f7df2e56Smrg    if (getenv("TEMP") != NULL)
1676f7df2e56Smrg        return getenv("TEMP");
1677f7df2e56Smrg    else if (getenv("TMP") != NULL)
1678f7df2e56Smrg        return getenv("TMP");
1679f7df2e56Smrg    else
1680f7df2e56Smrg        return "/tmp";
1681f7df2e56Smrg}
1682f7df2e56Smrg
1683f7df2e56Smrgint
1684f7df2e56SmrgSystem(const char *cmdline)
1685f7df2e56Smrg{
1686f7df2e56Smrg    STARTUPINFO si;
1687f7df2e56Smrg    PROCESS_INFORMATION pi;
1688f7df2e56Smrg    DWORD dwExitCode;
1689f7df2e56Smrg    char *cmd = strdup(cmdline);
1690f7df2e56Smrg
1691f7df2e56Smrg    ZeroMemory(&si, sizeof(si));
1692f7df2e56Smrg    si.cb = sizeof(si);
1693f7df2e56Smrg    ZeroMemory(&pi, sizeof(pi));
1694f7df2e56Smrg
1695f7df2e56Smrg    if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
1696f7df2e56Smrg        LPVOID buffer;
1697f7df2e56Smrg
1698f7df2e56Smrg        if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1699f7df2e56Smrg                           FORMAT_MESSAGE_FROM_SYSTEM |
1700f7df2e56Smrg                           FORMAT_MESSAGE_IGNORE_INSERTS,
1701f7df2e56Smrg                           NULL,
1702f7df2e56Smrg                           GetLastError(),
1703f7df2e56Smrg                           MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1704f7df2e56Smrg                           (LPTSTR) &buffer, 0, NULL)) {
1705f7df2e56Smrg            ErrorF("[xkb] Starting '%s' failed!\n", cmdline);
1706f7df2e56Smrg        }
1707f7df2e56Smrg        else {
1708f7df2e56Smrg            ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer);
1709f7df2e56Smrg            LocalFree(buffer);
1710f7df2e56Smrg        }
1711f7df2e56Smrg
1712f7df2e56Smrg        free(cmd);
1713f7df2e56Smrg        return -1;
1714f7df2e56Smrg    }
1715f7df2e56Smrg    /* Wait until child process exits. */
1716f7df2e56Smrg    WaitForSingleObject(pi.hProcess, INFINITE);
1717f7df2e56Smrg
1718f7df2e56Smrg    GetExitCodeProcess(pi.hProcess, &dwExitCode);
171905b261ecSmrg
1720f7df2e56Smrg    /* Close process and thread handles. */
1721f7df2e56Smrg    CloseHandle(pi.hProcess);
1722f7df2e56Smrg    CloseHandle(pi.hThread);
1723f7df2e56Smrg    free(cmd);
1724f7df2e56Smrg
1725f7df2e56Smrg    return dwExitCode;
1726f7df2e56Smrg}
1727f7df2e56Smrg#endif
172805b261ecSmrg
17297e31ba66SmrgBool
17307e31ba66SmrgPrivsElevated(void)
17317e31ba66Smrg{
17327e31ba66Smrg    static Bool privsTested = FALSE;
17337e31ba66Smrg    static Bool privsElevated = TRUE;
17347e31ba66Smrg
17357e31ba66Smrg    if (!privsTested) {
17367e31ba66Smrg#if defined(WIN32)
17377e31ba66Smrg        privsElevated = FALSE;
17387e31ba66Smrg#else
17397e31ba66Smrg        if ((getuid() != geteuid()) || (getgid() != getegid())) {
17407e31ba66Smrg            privsElevated = TRUE;
17417e31ba66Smrg        }
17427e31ba66Smrg        else {
17437e31ba66Smrg#if defined(HAVE_ISSETUGID)
17447e31ba66Smrg            privsElevated = issetugid();
17457e31ba66Smrg#elif defined(HAVE_GETRESUID)
17467e31ba66Smrg            uid_t ruid, euid, suid;
17477e31ba66Smrg            gid_t rgid, egid, sgid;
17487e31ba66Smrg
17497e31ba66Smrg            if ((getresuid(&ruid, &euid, &suid) == 0) &&
17507e31ba66Smrg                (getresgid(&rgid, &egid, &sgid) == 0)) {
17517e31ba66Smrg                privsElevated = (euid != suid) || (egid != sgid);
17527e31ba66Smrg            }
17537e31ba66Smrg            else {
17547e31ba66Smrg                printf("Failed getresuid or getresgid");
17557e31ba66Smrg                /* Something went wrong, make defensive assumption */
17567e31ba66Smrg                privsElevated = TRUE;
17577e31ba66Smrg            }
17587e31ba66Smrg#else
17597e31ba66Smrg            if (getuid() == 0) {
17607e31ba66Smrg                /* running as root: uid==euid==0 */
17617e31ba66Smrg                privsElevated = FALSE;
17627e31ba66Smrg            }
17637e31ba66Smrg            else {
17647e31ba66Smrg                /*
17657e31ba66Smrg                 * If there are saved ID's the process might still be privileged
17667e31ba66Smrg                 * even though the above test succeeded. If issetugid() and
17677e31ba66Smrg                 * getresgid() aren't available, test this by trying to set
17687e31ba66Smrg                 * euid to 0.
17697e31ba66Smrg                 */
17707e31ba66Smrg                unsigned int oldeuid;
17717e31ba66Smrg
17727e31ba66Smrg                oldeuid = geteuid();
17737e31ba66Smrg
17747e31ba66Smrg                if (seteuid(0) != 0) {
17757e31ba66Smrg                    privsElevated = FALSE;
17767e31ba66Smrg                }
17777e31ba66Smrg                else {
17787e31ba66Smrg                    if (seteuid(oldeuid) != 0) {
17797e31ba66Smrg                        FatalError("Failed to drop privileges.  Exiting\n");
17807e31ba66Smrg                    }
17817e31ba66Smrg                    privsElevated = TRUE;
17827e31ba66Smrg                }
17837e31ba66Smrg            }
17847e31ba66Smrg#endif
17857e31ba66Smrg        }
17867e31ba66Smrg#endif
17877e31ba66Smrg        privsTested = TRUE;
17887e31ba66Smrg    }
17897e31ba66Smrg    return privsElevated;
17907e31ba66Smrg}
17917e31ba66Smrg
179205b261ecSmrg/*
179305b261ecSmrg * CheckUserParameters: check for long command line arguments and long
179405b261ecSmrg * environment variables.  By default, these checks are only done when
179505b261ecSmrg * the server's euid != ruid.  In 3.3.x, these checks were done in an
179605b261ecSmrg * external wrapper utility.
179705b261ecSmrg */
179805b261ecSmrg
179905b261ecSmrg/* Consider LD* variables insecure? */
180005b261ecSmrg#ifndef REMOVE_ENV_LD
180105b261ecSmrg#define REMOVE_ENV_LD 1
180205b261ecSmrg#endif
180305b261ecSmrg
180405b261ecSmrg/* Remove long environment variables? */
180505b261ecSmrg#ifndef REMOVE_LONG_ENV
180605b261ecSmrg#define REMOVE_LONG_ENV 1
180705b261ecSmrg#endif
180805b261ecSmrg
180905b261ecSmrg/*
181005b261ecSmrg * Disallow stdout or stderr as pipes?  It's possible to block the X server
181105b261ecSmrg * when piping stdout+stderr to a pipe.
181205b261ecSmrg *
181305b261ecSmrg * Don't enable this because it looks like it's going to cause problems.
181405b261ecSmrg */
181505b261ecSmrg#ifndef NO_OUTPUT_PIPES
181605b261ecSmrg#define NO_OUTPUT_PIPES 0
181705b261ecSmrg#endif
181805b261ecSmrg
181905b261ecSmrg/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
182005b261ecSmrg#ifndef CHECK_EUID
182105b261ecSmrg#ifndef WIN32
182205b261ecSmrg#define CHECK_EUID 1
182305b261ecSmrg#else
182405b261ecSmrg#define CHECK_EUID 0
182505b261ecSmrg#endif
182605b261ecSmrg#endif
182705b261ecSmrg
182805b261ecSmrg/*
182905b261ecSmrg * Maybe the locale can be faked to make isprint(3) report that everything
183005b261ecSmrg * is printable?  Avoid it by default.
183105b261ecSmrg */
183205b261ecSmrg#ifndef USE_ISPRINT
183305b261ecSmrg#define USE_ISPRINT 0
183405b261ecSmrg#endif
183505b261ecSmrg
183605b261ecSmrg#define MAX_ARG_LENGTH          128
183705b261ecSmrg#define MAX_ENV_LENGTH          256
1838f7df2e56Smrg#define MAX_ENV_PATH_LENGTH     2048    /* Limit for *PATH and TERMCAP */
183905b261ecSmrg
184005b261ecSmrg#if USE_ISPRINT
184105b261ecSmrg#include <ctype.h>
184205b261ecSmrg#define checkPrintable(c) isprint(c)
184305b261ecSmrg#else
184405b261ecSmrg#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
184505b261ecSmrg#endif
184605b261ecSmrg
184705b261ecSmrgenum BadCode {
184805b261ecSmrg    NotBad = 0,
184905b261ecSmrg    UnsafeArg,
185005b261ecSmrg    ArgTooLong,
185105b261ecSmrg    UnprintableArg,
185205b261ecSmrg    EnvTooLong,
185305b261ecSmrg    OutputIsPipe,
185405b261ecSmrg    InternalError
185505b261ecSmrg};
185605b261ecSmrg
185705b261ecSmrg#if defined(VENDORSUPPORT)
185805b261ecSmrg#define BUGADDRESS VENDORSUPPORT
185905b261ecSmrg#elif defined(BUILDERADDR)
186005b261ecSmrg#define BUGADDRESS BUILDERADDR
186105b261ecSmrg#else
186205b261ecSmrg#define BUGADDRESS "xorg@freedesktop.org"
186305b261ecSmrg#endif
186405b261ecSmrg
186505b261ecSmrgvoid
186605b261ecSmrgCheckUserParameters(int argc, char **argv, char **envp)
186705b261ecSmrg{
186805b261ecSmrg    enum BadCode bad = NotBad;
186905b261ecSmrg    int i = 0, j;
187005b261ecSmrg    char *a, *e = NULL;
187105b261ecSmrg
187205b261ecSmrg#if CHECK_EUID
18737e31ba66Smrg    if (PrivsElevated())
187405b261ecSmrg#endif
187505b261ecSmrg    {
1876f7df2e56Smrg        /* Check each argv[] */
1877f7df2e56Smrg        for (i = 1; i < argc; i++) {
1878f7df2e56Smrg            if (strcmp(argv[i], "-fp") == 0) {
1879f7df2e56Smrg                i++;            /* continue with next argument. skip the length check */
1880f7df2e56Smrg                if (i >= argc)
1881f7df2e56Smrg                    break;
1882f7df2e56Smrg            }
1883f7df2e56Smrg            else {
1884f7df2e56Smrg                if (strlen(argv[i]) > MAX_ARG_LENGTH) {
1885f7df2e56Smrg                    bad = ArgTooLong;
1886f7df2e56Smrg                    break;
1887f7df2e56Smrg                }
1888f7df2e56Smrg            }
1889f7df2e56Smrg            a = argv[i];
1890f7df2e56Smrg            while (*a) {
1891f7df2e56Smrg                if (checkPrintable(*a) == 0) {
1892f7df2e56Smrg                    bad = UnprintableArg;
1893f7df2e56Smrg                    break;
1894f7df2e56Smrg                }
1895f7df2e56Smrg                a++;
1896f7df2e56Smrg            }
1897f7df2e56Smrg            if (bad)
1898f7df2e56Smrg                break;
1899f7df2e56Smrg        }
1900f7df2e56Smrg        if (!bad) {
1901f7df2e56Smrg            /* Check each envp[] */
1902f7df2e56Smrg            for (i = 0; envp[i]; i++) {
190305b261ecSmrg
1904f7df2e56Smrg                /* Check for bad environment variables and values */
190505b261ecSmrg#if REMOVE_ENV_LD
1906f7df2e56Smrg                while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
1907f7df2e56Smrg                    for (j = i; envp[j]; j++) {
1908f7df2e56Smrg                        envp[j] = envp[j + 1];
1909f7df2e56Smrg                    }
1910f7df2e56Smrg                }
1911f7df2e56Smrg#endif
1912f7df2e56Smrg                if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
191305b261ecSmrg#if REMOVE_LONG_ENV
1914f7df2e56Smrg                    for (j = i; envp[j]; j++) {
1915f7df2e56Smrg                        envp[j] = envp[j + 1];
1916f7df2e56Smrg                    }
1917f7df2e56Smrg                    i--;
191805b261ecSmrg#else
1919f7df2e56Smrg                    char *eq;
1920f7df2e56Smrg                    int len;
1921f7df2e56Smrg
1922f7df2e56Smrg                    eq = strchr(envp[i], '=');
1923f7df2e56Smrg                    if (!eq)
1924f7df2e56Smrg                        continue;
1925f7df2e56Smrg                    len = eq - envp[i];
1926f7df2e56Smrg                    e = strndup(envp[i], len);
1927f7df2e56Smrg                    if (!e) {
1928f7df2e56Smrg                        bad = InternalError;
1929f7df2e56Smrg                        break;
1930f7df2e56Smrg                    }
1931f7df2e56Smrg                    if (len >= 4 &&
1932f7df2e56Smrg                        (strcmp(e + len - 4, "PATH") == 0 ||
1933f7df2e56Smrg                         strcmp(e, "TERMCAP") == 0)) {
1934f7df2e56Smrg                        if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
1935f7df2e56Smrg                            bad = EnvTooLong;
1936f7df2e56Smrg                            break;
1937f7df2e56Smrg                        }
1938f7df2e56Smrg                        else {
1939f7df2e56Smrg                            free(e);
1940f7df2e56Smrg                        }
1941f7df2e56Smrg                    }
1942f7df2e56Smrg                    else {
1943f7df2e56Smrg                        bad = EnvTooLong;
1944f7df2e56Smrg                        break;
1945f7df2e56Smrg                    }
1946f7df2e56Smrg#endif
1947f7df2e56Smrg                }
1948f7df2e56Smrg            }
1949f7df2e56Smrg        }
195005b261ecSmrg#if NO_OUTPUT_PIPES
1951f7df2e56Smrg        if (!bad) {
1952f7df2e56Smrg            struct stat buf;
195305b261ecSmrg
1954f7df2e56Smrg            if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode))
1955f7df2e56Smrg                bad = OutputIsPipe;
1956f7df2e56Smrg            if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode))
1957f7df2e56Smrg                bad = OutputIsPipe;
1958f7df2e56Smrg        }
195905b261ecSmrg#endif
196005b261ecSmrg    }
196105b261ecSmrg    switch (bad) {
196205b261ecSmrg    case NotBad:
1963f7df2e56Smrg        return;
196405b261ecSmrg    case UnsafeArg:
1965f7df2e56Smrg        ErrorF("Command line argument number %d is unsafe\n", i);
1966f7df2e56Smrg        break;
196705b261ecSmrg    case ArgTooLong:
1968f7df2e56Smrg        ErrorF("Command line argument number %d is too long\n", i);
1969f7df2e56Smrg        break;
197005b261ecSmrg    case UnprintableArg:
1971f7df2e56Smrg        ErrorF("Command line argument number %d contains unprintable"
1972f7df2e56Smrg               " characters\n", i);
1973f7df2e56Smrg        break;
197405b261ecSmrg    case EnvTooLong:
1975f7df2e56Smrg        ErrorF("Environment variable `%s' is too long\n", e);
1976f7df2e56Smrg        break;
197705b261ecSmrg    case OutputIsPipe:
1978f7df2e56Smrg        ErrorF("Stdout and/or stderr is a pipe\n");
1979f7df2e56Smrg        break;
198005b261ecSmrg    case InternalError:
1981f7df2e56Smrg        ErrorF("Internal Error\n");
1982f7df2e56Smrg        break;
198305b261ecSmrg    default:
1984f7df2e56Smrg        ErrorF("Unknown error\n");
1985f7df2e56Smrg        break;
198605b261ecSmrg    }
198705b261ecSmrg    FatalError("X server aborted because of unsafe environment\n");
198805b261ecSmrg}
198905b261ecSmrg
199005b261ecSmrg/*
199105b261ecSmrg * CheckUserAuthorization: check if the user is allowed to start the
199205b261ecSmrg * X server.  This usually means some sort of PAM checking, and it is
199305b261ecSmrg * usually only done for setuid servers (uid != euid).
199405b261ecSmrg */
199505b261ecSmrg
199605b261ecSmrg#ifdef USE_PAM
199705b261ecSmrg#include <security/pam_appl.h>
199805b261ecSmrg#include <security/pam_misc.h>
199905b261ecSmrg#include <pwd.h>
2000f7df2e56Smrg#endif                          /* USE_PAM */
200105b261ecSmrg
200205b261ecSmrgvoid
200305b261ecSmrgCheckUserAuthorization(void)
200405b261ecSmrg{
200505b261ecSmrg#ifdef USE_PAM
200605b261ecSmrg    static struct pam_conv conv = {
2007f7df2e56Smrg        misc_conv,
2008f7df2e56Smrg        NULL
200905b261ecSmrg    };
201005b261ecSmrg
201105b261ecSmrg    pam_handle_t *pamh = NULL;
201205b261ecSmrg    struct passwd *pw;
201305b261ecSmrg    int retval;
201405b261ecSmrg
201505b261ecSmrg    if (getuid() != geteuid()) {
2016f7df2e56Smrg        pw = getpwuid(getuid());
2017f7df2e56Smrg        if (pw == NULL)
2018f7df2e56Smrg            FatalError("getpwuid() failed for uid %d\n", getuid());
2019f7df2e56Smrg
2020f7df2e56Smrg        retval = pam_start("xserver", pw->pw_name, &conv, &pamh);
2021f7df2e56Smrg        if (retval != PAM_SUCCESS)
2022f7df2e56Smrg            FatalError("pam_start() failed.\n"
2023f7df2e56Smrg                       "\tMissing or mangled PAM config file or module?\n");
2024f7df2e56Smrg
2025f7df2e56Smrg        retval = pam_authenticate(pamh, 0);
2026f7df2e56Smrg        if (retval != PAM_SUCCESS) {
2027f7df2e56Smrg            pam_end(pamh, retval);
2028f7df2e56Smrg            FatalError("PAM authentication failed, cannot start X server.\n"
2029f7df2e56Smrg                       "\tPerhaps you do not have console ownership?\n");
2030f7df2e56Smrg        }
203105b261ecSmrg
2032f7df2e56Smrg        retval = pam_acct_mgmt(pamh, 0);
2033f7df2e56Smrg        if (retval != PAM_SUCCESS) {
2034f7df2e56Smrg            pam_end(pamh, retval);
2035f7df2e56Smrg            FatalError("PAM authentication failed, cannot start X server.\n"
2036f7df2e56Smrg                       "\tPerhaps you do not have console ownership?\n");
2037f7df2e56Smrg        }
203805b261ecSmrg
2039f7df2e56Smrg        /* this is not a session, so do not do session management */
2040f7df2e56Smrg        pam_end(pamh, PAM_SUCCESS);
204105b261ecSmrg    }
204205b261ecSmrg#endif
204305b261ecSmrg}
204405b261ecSmrg
20454202a189Smrg/*
20464202a189Smrg * Tokenize a string into a NULL terminated array of strings. Always returns
20474202a189Smrg * an allocated array unless an error occurs.
20484202a189Smrg */
2049f7df2e56Smrgchar **
20504202a189Smrgxstrtokenize(const char *str, const char *separators)
205105b261ecSmrg{
20524202a189Smrg    char **list, **nlist;
20534202a189Smrg    char *tok, *tmp;
20544202a189Smrg    unsigned num = 0, n;
205505b261ecSmrg
20564202a189Smrg    if (!str)
20574202a189Smrg        return NULL;
20584202a189Smrg    list = calloc(1, sizeof(*list));
20594202a189Smrg    if (!list)
20604202a189Smrg        return NULL;
20614202a189Smrg    tmp = strdup(str);
20624202a189Smrg    if (!tmp)
20634202a189Smrg        goto error;
20644202a189Smrg    for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) {
2065f7df2e56Smrg        nlist = reallocarray(list, num + 2, sizeof(*list));
20664202a189Smrg        if (!nlist)
20674202a189Smrg            goto error;
20684202a189Smrg        list = nlist;
20694202a189Smrg        list[num] = strdup(tok);
20704202a189Smrg        if (!list[num])
20714202a189Smrg            goto error;
20724202a189Smrg        list[++num] = NULL;
20734202a189Smrg    }
20744202a189Smrg    free(tmp);
20754202a189Smrg    return list;
20764202a189Smrg
2077f7df2e56Smrg error:
20784202a189Smrg    free(tmp);
20794202a189Smrg    for (n = 0; n < num; n++)
20804202a189Smrg        free(list[n]);
20814202a189Smrg    free(list);
20824202a189Smrg    return NULL;
208305b261ecSmrg}
2084f7df2e56Smrg
2085f7df2e56Smrg/* Format a signed number into a string in a signal safe manner. The string
2086f7df2e56Smrg * should be at least 21 characters in order to handle all int64_t values.
2087f7df2e56Smrg */
2088f7df2e56Smrgvoid
2089f7df2e56SmrgFormatInt64(int64_t num, char *string)
2090f7df2e56Smrg{
2091f7df2e56Smrg    if (num < 0) {
2092f7df2e56Smrg        string[0] = '-';
2093f7df2e56Smrg        num *= -1;
2094f7df2e56Smrg        string++;
2095f7df2e56Smrg    }
2096f7df2e56Smrg    FormatUInt64(num, string);
2097f7df2e56Smrg}
2098f7df2e56Smrg
2099f7df2e56Smrg/* Format a number into a string in a signal safe manner. The string should be
2100f7df2e56Smrg * at least 21 characters in order to handle all uint64_t values. */
2101f7df2e56Smrgvoid
2102f7df2e56SmrgFormatUInt64(uint64_t num, char *string)
2103f7df2e56Smrg{
2104f7df2e56Smrg    uint64_t divisor;
2105f7df2e56Smrg    int len;
2106f7df2e56Smrg    int i;
2107f7df2e56Smrg
2108f7df2e56Smrg    for (len = 1, divisor = 10;
2109f7df2e56Smrg         len < 20 && num / divisor;
2110f7df2e56Smrg         len++, divisor *= 10);
2111f7df2e56Smrg
2112f7df2e56Smrg    for (i = len, divisor = 1; i > 0; i--, divisor *= 10)
2113f7df2e56Smrg        string[i - 1] = '0' + ((num / divisor) % 10);
2114f7df2e56Smrg
2115f7df2e56Smrg    string[len] = '\0';
2116f7df2e56Smrg}
2117f7df2e56Smrg
2118f7df2e56Smrg/**
2119f7df2e56Smrg * Format a double number as %.2f.
2120f7df2e56Smrg */
2121f7df2e56Smrgvoid
2122f7df2e56SmrgFormatDouble(double dbl, char *string)
2123f7df2e56Smrg{
2124f7df2e56Smrg    int slen = 0;
2125f7df2e56Smrg    uint64_t frac;
2126f7df2e56Smrg
2127f7df2e56Smrg    frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5;
2128f7df2e56Smrg    frac %= 100;
2129f7df2e56Smrg
2130f7df2e56Smrg    /* write decimal part to string */
2131f7df2e56Smrg    if (dbl < 0 && dbl > -1)
2132f7df2e56Smrg        string[slen++] = '-';
2133f7df2e56Smrg    FormatInt64((int64_t)dbl, &string[slen]);
2134f7df2e56Smrg
2135f7df2e56Smrg    while(string[slen] != '\0')
2136f7df2e56Smrg        slen++;
2137f7df2e56Smrg
2138f7df2e56Smrg    /* append fractional part, but only if we have enough characters. We
2139f7df2e56Smrg     * expect string to be 21 chars (incl trailing \0) */
2140f7df2e56Smrg    if (slen <= 17) {
2141f7df2e56Smrg        string[slen++] = '.';
2142f7df2e56Smrg        if (frac < 10)
2143f7df2e56Smrg            string[slen++] = '0';
2144f7df2e56Smrg
2145f7df2e56Smrg        FormatUInt64(frac, &string[slen]);
2146f7df2e56Smrg    }
2147f7df2e56Smrg}
2148f7df2e56Smrg
2149f7df2e56Smrg
2150f7df2e56Smrg/* Format a number into a hexadecimal string in a signal safe manner. The string
2151f7df2e56Smrg * should be at least 17 characters in order to handle all uint64_t values. */
2152f7df2e56Smrgvoid
2153f7df2e56SmrgFormatUInt64Hex(uint64_t num, char *string)
2154f7df2e56Smrg{
2155f7df2e56Smrg    uint64_t divisor;
2156f7df2e56Smrg    int len;
2157f7df2e56Smrg    int i;
2158f7df2e56Smrg
2159f7df2e56Smrg    for (len = 1, divisor = 0x10;
2160f7df2e56Smrg         len < 16 && num / divisor;
2161f7df2e56Smrg         len++, divisor *= 0x10);
2162f7df2e56Smrg
2163f7df2e56Smrg    for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) {
2164f7df2e56Smrg        int val = (num / divisor) % 0x10;
2165f7df2e56Smrg
2166f7df2e56Smrg        if (val < 10)
2167f7df2e56Smrg            string[i - 1] = '0' + val;
2168f7df2e56Smrg        else
2169f7df2e56Smrg            string[i - 1] = 'a' + val - 10;
2170f7df2e56Smrg    }
2171f7df2e56Smrg
2172f7df2e56Smrg    string[len] = '\0';
2173f7df2e56Smrg}
2174f7df2e56Smrg
2175f7df2e56Smrg#if !defined(WIN32) || defined(__CYGWIN__)
2176f7df2e56Smrg/* Move a file descriptor out of the way of our select mask; this
2177f7df2e56Smrg * is useful for file descriptors which will never appear in the
2178f7df2e56Smrg * select mask to avoid reducing the number of clients that can
2179f7df2e56Smrg * connect to the server
2180f7df2e56Smrg */
2181f7df2e56Smrgint
2182f7df2e56Smrgos_move_fd(int fd)
2183f7df2e56Smrg{
2184f7df2e56Smrg    int newfd;
2185f7df2e56Smrg
2186f7df2e56Smrg#ifdef F_DUPFD_CLOEXEC
2187f7df2e56Smrg    newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS);
2188f7df2e56Smrg#else
2189f7df2e56Smrg    newfd = fcntl(fd, F_DUPFD, MAXCLIENTS);
2190f7df2e56Smrg#endif
2191f7df2e56Smrg    if (newfd < 0)
2192f7df2e56Smrg        return fd;
2193f7df2e56Smrg#ifndef F_DUPFD_CLOEXEC
2194f7df2e56Smrg    fcntl(newfd, F_SETFD, FD_CLOEXEC);
2195f7df2e56Smrg#endif
2196f7df2e56Smrg    close(fd);
2197f7df2e56Smrg    return newfd;
2198f7df2e56Smrg}
2199f7df2e56Smrg#endif
2200