utils.c revision 1b684552
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
2705b261ecSmrg
2805b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
2905b261ecSmrgCopyright 1994 Quarterdeck Office Systems.
3005b261ecSmrg
3105b261ecSmrg                        All Rights Reserved
3205b261ecSmrg
3305b261ecSmrgPermission to use, copy, modify, and distribute this software and its
3405b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
3505b261ecSmrgprovided that the above copyright notice appear in all copies and that
3605b261ecSmrgboth that copyright notice and this permission notice appear in
3705b261ecSmrgsupporting documentation, and that the names of Digital and
3805b261ecSmrgQuarterdeck not be used in advertising or publicity pertaining to
3905b261ecSmrgdistribution of the software without specific, written prior
4005b261ecSmrgpermission.
4105b261ecSmrg
4205b261ecSmrgDIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
4305b261ecSmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
4405b261ecSmrgFITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
4505b261ecSmrgOR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
4605b261ecSmrgOF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
4705b261ecSmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
4805b261ecSmrgOR PERFORMANCE OF THIS SOFTWARE.
4905b261ecSmrg
5005b261ecSmrg*/
5105b261ecSmrg
5205b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
5305b261ecSmrg#include <dix-config.h>
5405b261ecSmrg#endif
5505b261ecSmrg
5605b261ecSmrg#ifdef __CYGWIN__
5705b261ecSmrg#include <stdlib.h>
5805b261ecSmrg#include <signal.h>
594202a189Smrg/*
604202a189Smrg   Sigh... We really need a prototype for this to know it is stdcall,
614202a189Smrg   but #include-ing <windows.h> here is not a good idea...
624202a189Smrg*/
634202a189Smrg__stdcall unsigned long GetTickCount(void);
6405b261ecSmrg#endif
6505b261ecSmrg
6605b261ecSmrg#if defined(WIN32) && !defined(__CYGWIN__)
6705b261ecSmrg#include <X11/Xwinsock.h>
6805b261ecSmrg#endif
6905b261ecSmrg#include <X11/Xos.h>
7005b261ecSmrg#include <stdio.h>
7105b261ecSmrg#include <time.h>
7205b261ecSmrg#if !defined(WIN32) || !defined(__MINGW32__)
7305b261ecSmrg#include <sys/time.h>
7405b261ecSmrg#include <sys/resource.h>
7505b261ecSmrg#endif
7605b261ecSmrg#include "misc.h"
7705b261ecSmrg#include <X11/X.h>
7805b261ecSmrg#define XSERV_t
7905b261ecSmrg#define TRANS_SERVER
8005b261ecSmrg#define TRANS_REOPEN
8105b261ecSmrg#include <X11/Xtrans/Xtrans.h>
8205b261ecSmrg#include "input.h"
8305b261ecSmrg#include "dixfont.h"
8405b261ecSmrg#include "osdep.h"
8505b261ecSmrg#include "extension.h"
8605b261ecSmrg#ifdef X_POSIX_C_SOURCE
8705b261ecSmrg#define _POSIX_C_SOURCE X_POSIX_C_SOURCE
8805b261ecSmrg#include <signal.h>
8905b261ecSmrg#undef _POSIX_C_SOURCE
9005b261ecSmrg#else
914642e01fSmrg#if defined(_POSIX_SOURCE)
9205b261ecSmrg#include <signal.h>
9305b261ecSmrg#else
9405b261ecSmrg#define _POSIX_SOURCE
9505b261ecSmrg#include <signal.h>
9605b261ecSmrg#undef _POSIX_SOURCE
9705b261ecSmrg#endif
9805b261ecSmrg#endif
9905b261ecSmrg#ifndef WIN32
10005b261ecSmrg#include <sys/wait.h>
10105b261ecSmrg#endif
1024642e01fSmrg#if !defined(SYSV) && !defined(WIN32)
10305b261ecSmrg#include <sys/resource.h>
10405b261ecSmrg#endif
10505b261ecSmrg#include <sys/stat.h>
10605b261ecSmrg#include <ctype.h>    /* for isspace */
10705b261ecSmrg#include <stdarg.h>
10805b261ecSmrg
10905b261ecSmrg#include <stdlib.h>	/* for malloc() */
11005b261ecSmrg
11105b261ecSmrg#if defined(TCPCONN) || defined(STREAMSCONN)
11205b261ecSmrg# ifndef WIN32
11305b261ecSmrg#  include <netdb.h>
11405b261ecSmrg# endif
11505b261ecSmrg#endif
11605b261ecSmrg
11705b261ecSmrg#include "opaque.h"
11805b261ecSmrg
11905b261ecSmrg#include "dixstruct.h"
12005b261ecSmrg
1214202a189Smrg#include "xkbsrv.h"
12205b261ecSmrg
12305b261ecSmrg#include "picture.h"
12405b261ecSmrg
1254202a189SmrgBool noTestExtensions;
12605b261ecSmrg#ifdef COMPOSITE
1274202a189SmrgBool noCompositeExtension = FALSE;
12805b261ecSmrg#endif
12905b261ecSmrg
13005b261ecSmrg#ifdef DAMAGE
1314202a189SmrgBool noDamageExtension = FALSE;
13205b261ecSmrg#endif
13305b261ecSmrg#ifdef DBE
1344202a189SmrgBool noDbeExtension = FALSE;
13505b261ecSmrg#endif
13605b261ecSmrg#ifdef DPMSExtension
1374202a189SmrgBool noDPMSExtension = FALSE;
13805b261ecSmrg#endif
13905b261ecSmrg#ifdef GLXEXT
1404202a189SmrgBool noGlxExtension = FALSE;
1414202a189SmrgBool noGlxVisualInit = FALSE;
14205b261ecSmrg#endif
14305b261ecSmrg#ifdef SCREENSAVER
1444202a189SmrgBool noScreenSaverExtension = FALSE;
14505b261ecSmrg#endif
14605b261ecSmrg#ifdef MITSHM
1474202a189SmrgBool noMITShmExtension = FALSE;
14805b261ecSmrg#endif
14905b261ecSmrg#ifdef RANDR
1504202a189SmrgBool noRRExtension = FALSE;
15105b261ecSmrg#endif
1524202a189SmrgBool noRenderExtension = FALSE;
15305b261ecSmrg#ifdef XCSECURITY
1544202a189SmrgBool noSecurityExtension = FALSE;
15505b261ecSmrg#endif
15605b261ecSmrg#ifdef RES
1574202a189SmrgBool noResExtension = FALSE;
15805b261ecSmrg#endif
15905b261ecSmrg#ifdef XF86BIGFONT
1604202a189SmrgBool noXFree86BigfontExtension = FALSE;
16105b261ecSmrg#endif
16205b261ecSmrg#ifdef XFreeXDGA
1634202a189SmrgBool noXFree86DGAExtension = FALSE;
16405b261ecSmrg#endif
16505b261ecSmrg#ifdef XF86DRI
1664202a189SmrgBool noXFree86DRIExtension = FALSE;
16705b261ecSmrg#endif
16805b261ecSmrg#ifdef XF86VIDMODE
1694202a189SmrgBool noXFree86VidModeExtension = FALSE;
17005b261ecSmrg#endif
17105b261ecSmrg#ifdef XFIXES
1724202a189SmrgBool noXFixesExtension = FALSE;
17305b261ecSmrg#endif
17405b261ecSmrg#ifdef PANORAMIX
17505b261ecSmrg/* Xinerama is disabled by default unless enabled via +xinerama */
1764202a189SmrgBool noPanoramiXExtension = TRUE;
17705b261ecSmrg#endif
1784642e01fSmrg#ifdef XSELINUX
1794202a189SmrgBool noSELinuxExtension = FALSE;
1804202a189Smrgint selinuxEnforcingState = SELINUX_MODE_DEFAULT;
18105b261ecSmrg#endif
18205b261ecSmrg#ifdef XV
1834202a189SmrgBool noXvExtension = FALSE;
18405b261ecSmrg#endif
1854642e01fSmrg#ifdef DRI2
1864202a189SmrgBool noDRI2Extension = FALSE;
1874642e01fSmrg#endif
1884642e01fSmrg
1894202a189SmrgBool noGEExtension = FALSE;
19005b261ecSmrg
19105b261ecSmrg#define X_INCLUDE_NETDB_H
19205b261ecSmrg#include <X11/Xos_r.h>
19305b261ecSmrg
19405b261ecSmrg#include <errno.h>
19505b261ecSmrg
19605b261ecSmrgBool CoreDump;
19705b261ecSmrg
19805b261ecSmrg#ifdef PANORAMIX
19905b261ecSmrgBool PanoramiXExtensionDisabledHack = FALSE;
20005b261ecSmrg#endif
20105b261ecSmrg
20205b261ecSmrgint auditTrailLevel = 1;
20305b261ecSmrg
20405b261ecSmrg#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
20505b261ecSmrg#define HAS_SAVED_IDS_AND_SETEUID
20605b261ecSmrg#endif
20705b261ecSmrg
20805b261ecSmrgOsSigHandlerPtr
2094202a189SmrgOsSignal(int sig, OsSigHandlerPtr handler)
21005b261ecSmrg{
21105b261ecSmrg    struct sigaction act, oact;
21205b261ecSmrg
21305b261ecSmrg    sigemptyset(&act.sa_mask);
21405b261ecSmrg    if (handler != SIG_IGN)
21505b261ecSmrg	sigaddset(&act.sa_mask, sig);
21605b261ecSmrg    act.sa_flags = 0;
21705b261ecSmrg    act.sa_handler = handler;
21805b261ecSmrg    if (sigaction(sig, &act, &oact))
21905b261ecSmrg      perror("sigaction");
22005b261ecSmrg    return oact.sa_handler;
22105b261ecSmrg}
2224642e01fSmrg
22305b261ecSmrg/*
22405b261ecSmrg * Explicit support for a server lock file like the ones used for UUCP.
22505b261ecSmrg * For architectures with virtual terminals that can run more than one
22605b261ecSmrg * server at a time.  This keeps the servers from stomping on each other
22705b261ecSmrg * if the user forgets to give them different display numbers.
22805b261ecSmrg */
22905b261ecSmrg#define LOCK_DIR "/tmp"
23005b261ecSmrg#define LOCK_TMP_PREFIX "/.tX"
23105b261ecSmrg#define LOCK_PREFIX "/.X"
23205b261ecSmrg#define LOCK_SUFFIX "-lock"
23305b261ecSmrg
23405b261ecSmrg#ifndef PATH_MAX
23505b261ecSmrg#include <sys/param.h>
23605b261ecSmrg#ifndef PATH_MAX
23705b261ecSmrg#ifdef MAXPATHLEN
23805b261ecSmrg#define PATH_MAX MAXPATHLEN
23905b261ecSmrg#else
24005b261ecSmrg#define PATH_MAX 1024
24105b261ecSmrg#endif
24205b261ecSmrg#endif
24305b261ecSmrg#endif
24405b261ecSmrg
24505b261ecSmrgstatic Bool StillLocking = FALSE;
24605b261ecSmrgstatic char LockFile[PATH_MAX];
24705b261ecSmrgstatic Bool nolock = FALSE;
24805b261ecSmrg
24905b261ecSmrg/*
25005b261ecSmrg * LockServer --
25105b261ecSmrg *      Check if the server lock file exists.  If so, check if the PID
25205b261ecSmrg *      contained inside is valid.  If so, then die.  Otherwise, create
25305b261ecSmrg *      the lock file containing the PID.
25405b261ecSmrg */
25505b261ecSmrgvoid
25605b261ecSmrgLockServer(void)
25705b261ecSmrg{
25805b261ecSmrg  char tmp[PATH_MAX], pid_str[12];
25905b261ecSmrg  int lfd, i, haslock, l_pid, t;
26005b261ecSmrg  char *tmppath = NULL;
26105b261ecSmrg  int len;
26205b261ecSmrg  char port[20];
26305b261ecSmrg
26405b261ecSmrg  if (nolock) return;
26505b261ecSmrg  /*
26605b261ecSmrg   * Path names
26705b261ecSmrg   */
26805b261ecSmrg  tmppath = LOCK_DIR;
26905b261ecSmrg
27005b261ecSmrg  sprintf(port, "%d", atoi(display));
27105b261ecSmrg  len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) :
27205b261ecSmrg						strlen(LOCK_TMP_PREFIX);
27305b261ecSmrg  len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1;
27405b261ecSmrg  if (len > sizeof(LockFile))
27505b261ecSmrg    FatalError("Display name `%s' is too long\n", port);
27605b261ecSmrg  (void)sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
27705b261ecSmrg  (void)sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
27805b261ecSmrg
27905b261ecSmrg  /*
28005b261ecSmrg   * Create a temporary file containing our PID.  Attempt three times
28105b261ecSmrg   * to create the file.
28205b261ecSmrg   */
28305b261ecSmrg  StillLocking = TRUE;
28405b261ecSmrg  i = 0;
28505b261ecSmrg  do {
28605b261ecSmrg    i++;
28705b261ecSmrg    lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
28805b261ecSmrg    if (lfd < 0)
28905b261ecSmrg       sleep(2);
29005b261ecSmrg    else
29105b261ecSmrg       break;
29205b261ecSmrg  } while (i < 3);
29305b261ecSmrg  if (lfd < 0) {
29405b261ecSmrg    unlink(tmp);
29505b261ecSmrg    i = 0;
29605b261ecSmrg    do {
29705b261ecSmrg      i++;
29805b261ecSmrg      lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
29905b261ecSmrg      if (lfd < 0)
30005b261ecSmrg         sleep(2);
30105b261ecSmrg      else
30205b261ecSmrg         break;
30305b261ecSmrg    } while (i < 3);
30405b261ecSmrg  }
30505b261ecSmrg  if (lfd < 0)
30605b261ecSmrg    FatalError("Could not create lock file in %s\n", tmp);
30705b261ecSmrg  (void) sprintf(pid_str, "%10ld\n", (long)getpid());
30805b261ecSmrg  (void) write(lfd, pid_str, 11);
30905b261ecSmrg  (void) chmod(tmp, 0444);
31005b261ecSmrg  (void) close(lfd);
31105b261ecSmrg
31205b261ecSmrg  /*
31305b261ecSmrg   * OK.  Now the tmp file exists.  Try three times to move it in place
31405b261ecSmrg   * for the lock.
31505b261ecSmrg   */
31605b261ecSmrg  i = 0;
31705b261ecSmrg  haslock = 0;
31805b261ecSmrg  while ((!haslock) && (i++ < 3)) {
31905b261ecSmrg    haslock = (link(tmp,LockFile) == 0);
32005b261ecSmrg    if (haslock) {
32105b261ecSmrg      /*
32205b261ecSmrg       * We're done.
32305b261ecSmrg       */
32405b261ecSmrg      break;
32505b261ecSmrg    }
32605b261ecSmrg    else {
32705b261ecSmrg      /*
32805b261ecSmrg       * Read the pid from the existing file
32905b261ecSmrg       */
33005b261ecSmrg      lfd = open(LockFile, O_RDONLY);
33105b261ecSmrg      if (lfd < 0) {
33205b261ecSmrg        unlink(tmp);
33305b261ecSmrg        FatalError("Can't read lock file %s\n", LockFile);
33405b261ecSmrg      }
33505b261ecSmrg      pid_str[0] = '\0';
33605b261ecSmrg      if (read(lfd, pid_str, 11) != 11) {
33705b261ecSmrg        /*
33805b261ecSmrg         * Bogus lock file.
33905b261ecSmrg         */
34005b261ecSmrg        unlink(LockFile);
34105b261ecSmrg        close(lfd);
34205b261ecSmrg        continue;
34305b261ecSmrg      }
34405b261ecSmrg      pid_str[11] = '\0';
34505b261ecSmrg      sscanf(pid_str, "%d", &l_pid);
34605b261ecSmrg      close(lfd);
34705b261ecSmrg
34805b261ecSmrg      /*
34905b261ecSmrg       * Now try to kill the PID to see if it exists.
35005b261ecSmrg       */
35105b261ecSmrg      errno = 0;
35205b261ecSmrg      t = kill(l_pid, 0);
35305b261ecSmrg      if ((t< 0) && (errno == ESRCH)) {
35405b261ecSmrg        /*
35505b261ecSmrg         * Stale lock file.
35605b261ecSmrg         */
35705b261ecSmrg        unlink(LockFile);
35805b261ecSmrg        continue;
35905b261ecSmrg      }
36005b261ecSmrg      else if (((t < 0) && (errno == EPERM)) || (t == 0)) {
36105b261ecSmrg        /*
36205b261ecSmrg         * Process is still active.
36305b261ecSmrg         */
36405b261ecSmrg        unlink(tmp);
36505b261ecSmrg	FatalError("Server is already active for display %s\n%s %s\n%s\n",
36605b261ecSmrg		   port, "\tIf this server is no longer running, remove",
36705b261ecSmrg		   LockFile, "\tand start again.");
36805b261ecSmrg      }
36905b261ecSmrg    }
37005b261ecSmrg  }
37105b261ecSmrg  unlink(tmp);
37205b261ecSmrg  if (!haslock)
37305b261ecSmrg    FatalError("Could not create server lock file: %s\n", LockFile);
37405b261ecSmrg  StillLocking = FALSE;
37505b261ecSmrg}
37605b261ecSmrg
37705b261ecSmrg/*
37805b261ecSmrg * UnlockServer --
37905b261ecSmrg *      Remove the server lock file.
38005b261ecSmrg */
38105b261ecSmrgvoid
38205b261ecSmrgUnlockServer(void)
38305b261ecSmrg{
38405b261ecSmrg  if (nolock) return;
38505b261ecSmrg
38605b261ecSmrg  if (!StillLocking){
38705b261ecSmrg
38805b261ecSmrg  (void) unlink(LockFile);
38905b261ecSmrg  }
39005b261ecSmrg}
39105b261ecSmrg
39205b261ecSmrg/* Force connections to close on SIGHUP from init */
39305b261ecSmrg
3944202a189Smrgvoid
39505b261ecSmrgAutoResetServer (int sig)
39605b261ecSmrg{
39705b261ecSmrg    int olderrno = errno;
39805b261ecSmrg
39905b261ecSmrg    dispatchException |= DE_RESET;
40005b261ecSmrg    isItTimeToYield = TRUE;
40105b261ecSmrg    errno = olderrno;
40205b261ecSmrg}
40305b261ecSmrg
40405b261ecSmrg/* Force connections to close and then exit on SIGTERM, SIGINT */
40505b261ecSmrg
4064202a189Smrgvoid
40705b261ecSmrgGiveUp(int sig)
40805b261ecSmrg{
40905b261ecSmrg    int olderrno = errno;
41005b261ecSmrg
41105b261ecSmrg    dispatchException |= DE_TERMINATE;
41205b261ecSmrg    isItTimeToYield = TRUE;
41305b261ecSmrg    errno = olderrno;
41405b261ecSmrg}
41505b261ecSmrg
4164202a189Smrg#if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__)
4174202a189SmrgCARD32
41805b261ecSmrgGetTimeInMillis (void)
41905b261ecSmrg{
42005b261ecSmrg  return GetTickCount ();
42105b261ecSmrg}
42205b261ecSmrg#else
4234202a189SmrgCARD32
42405b261ecSmrgGetTimeInMillis(void)
42505b261ecSmrg{
42605b261ecSmrg    struct timeval tv;
42705b261ecSmrg
42805b261ecSmrg#ifdef MONOTONIC_CLOCK
42905b261ecSmrg    struct timespec tp;
4301b684552Smrg    static clockid_t clockid;
4311b684552Smrg    if (!clockid) {
4321b684552Smrg#ifdef CLOCK_MONOTONIC_COARSE
4331b684552Smrg        if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
4341b684552Smrg            (tp.tv_nsec / 1000) <= 1000 &&
4351b684552Smrg            clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
4361b684552Smrg            clockid = CLOCK_MONOTONIC_COARSE;
4371b684552Smrg        else
4381b684552Smrg#endif
4391b684552Smrg        if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
4401b684552Smrg            clockid = CLOCK_MONOTONIC;
4411b684552Smrg        else
4421b684552Smrg            clockid = ~0L;
4431b684552Smrg    }
4441b684552Smrg    if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
44505b261ecSmrg        return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
44605b261ecSmrg#endif
44705b261ecSmrg
44805b261ecSmrg    X_GETTIMEOFDAY(&tv);
44905b261ecSmrg    return(tv.tv_sec * 1000) + (tv.tv_usec / 1000);
45005b261ecSmrg}
45105b261ecSmrg#endif
45205b261ecSmrg
4534202a189Smrgvoid
45405b261ecSmrgAdjustWaitForDelay (pointer waitTime, unsigned long newdelay)
45505b261ecSmrg{
45605b261ecSmrg    static struct timeval   delay_val;
45705b261ecSmrg    struct timeval	    **wt = (struct timeval **) waitTime;
45805b261ecSmrg    unsigned long	    olddelay;
45905b261ecSmrg
46005b261ecSmrg    if (*wt == NULL)
46105b261ecSmrg    {
46205b261ecSmrg	delay_val.tv_sec = newdelay / 1000;
46305b261ecSmrg	delay_val.tv_usec = 1000 * (newdelay % 1000);
46405b261ecSmrg	*wt = &delay_val;
46505b261ecSmrg    }
46605b261ecSmrg    else
46705b261ecSmrg    {
46805b261ecSmrg	olddelay = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000;
46905b261ecSmrg	if (newdelay < olddelay)
47005b261ecSmrg	{
47105b261ecSmrg	    (*wt)->tv_sec = newdelay / 1000;
47205b261ecSmrg	    (*wt)->tv_usec = 1000 * (newdelay % 1000);
47305b261ecSmrg	}
47405b261ecSmrg    }
47505b261ecSmrg}
47605b261ecSmrg
47705b261ecSmrgvoid UseMsg(void)
47805b261ecSmrg{
47905b261ecSmrg    ErrorF("use: X [:<display>] [option]\n");
4804202a189Smrg    ErrorF("-a #                   default pointer acceleration (factor)\n");
48105b261ecSmrg    ErrorF("-ac                    disable access control restrictions\n");
48205b261ecSmrg    ErrorF("-audit int             set audit trail level\n");
48305b261ecSmrg    ErrorF("-auth file             select authorization file\n");
48405b261ecSmrg    ErrorF("-br                    create root window with black background\n");
48505b261ecSmrg    ErrorF("+bs                    enable any backing store support\n");
48605b261ecSmrg    ErrorF("-bs                    disable any backing store support\n");
48705b261ecSmrg    ErrorF("-c                     turns off key-click\n");
48805b261ecSmrg    ErrorF("c #                    key-click volume (0-100)\n");
48905b261ecSmrg    ErrorF("-cc int                default color visual class\n");
4904202a189Smrg    ErrorF("-nocursor              disable the cursor\n");
49105b261ecSmrg    ErrorF("-core                  generate core dump on fatal error\n");
49205b261ecSmrg    ErrorF("-dpi int               screen resolution in dots per inch\n");
49305b261ecSmrg#ifdef DPMSExtension
49405b261ecSmrg    ErrorF("-dpms                  disables VESA DPMS monitor control\n");
49505b261ecSmrg#endif
49605b261ecSmrg    ErrorF("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n");
49705b261ecSmrg    ErrorF("-f #                   bell base (0-100)\n");
49805b261ecSmrg    ErrorF("-fc string             cursor font\n");
49905b261ecSmrg    ErrorF("-fn string             default font name\n");
50005b261ecSmrg    ErrorF("-fp string             default font path\n");
50105b261ecSmrg    ErrorF("-help                  prints message with these options\n");
50205b261ecSmrg    ErrorF("-I                     ignore all remaining arguments\n");
50305b261ecSmrg#ifdef RLIMIT_DATA
50405b261ecSmrg    ErrorF("-ld int                limit data space to N Kb\n");
50505b261ecSmrg#endif
50605b261ecSmrg#ifdef RLIMIT_NOFILE
50705b261ecSmrg    ErrorF("-lf int                limit number of open files to N\n");
50805b261ecSmrg#endif
50905b261ecSmrg#ifdef RLIMIT_STACK
51005b261ecSmrg    ErrorF("-ls int                limit stack space to N Kb\n");
51105b261ecSmrg#endif
51205b261ecSmrg    ErrorF("-nolock                disable the locking mechanism\n");
51305b261ecSmrg#ifndef NOLOGOHACK
51405b261ecSmrg    ErrorF("-logo                  enable logo in screen saver\n");
51505b261ecSmrg    ErrorF("nologo                 disable logo in screen saver\n");
51605b261ecSmrg#endif
51705b261ecSmrg    ErrorF("-nolisten string       don't listen on protocol\n");
51805b261ecSmrg    ErrorF("-noreset               don't reset after last client exists\n");
51905b261ecSmrg    ErrorF("-reset                 reset after last client exists\n");
52005b261ecSmrg    ErrorF("-p #                   screen-saver pattern duration (minutes)\n");
52105b261ecSmrg    ErrorF("-pn                    accept failure to listen on all ports\n");
52205b261ecSmrg    ErrorF("-nopn                  reject failure to listen on all ports\n");
52305b261ecSmrg    ErrorF("-r                     turns off auto-repeat\n");
52405b261ecSmrg    ErrorF("r                      turns on auto-repeat \n");
52505b261ecSmrg    ErrorF("-render [default|mono|gray|color] set render color alloc policy\n");
5264642e01fSmrg    ErrorF("-retro                 start with classic stipple and cursor\n");
527daf23d7fSsnj    ErrorF("-noretro               start with black background and no cursor\n");
52805b261ecSmrg    ErrorF("-s #                   screen-saver timeout (minutes)\n");
5294202a189Smrg    ErrorF("-t #                   default pointer threshold (pixels/t)\n");
53005b261ecSmrg    ErrorF("-terminate             terminate at server reset\n");
53105b261ecSmrg    ErrorF("-to #                  connection time out\n");
53205b261ecSmrg    ErrorF("-tst                   disable testing extensions\n");
53305b261ecSmrg    ErrorF("ttyxx                  server started from init on /dev/ttyxx\n");
53405b261ecSmrg    ErrorF("v                      video blanking for screen-saver\n");
53505b261ecSmrg    ErrorF("-v                     screen-saver without video blanking\n");
53605b261ecSmrg    ErrorF("-wm                    WhenMapped default backing-store\n");
53705b261ecSmrg    ErrorF("-wr                    create root window with white background\n");
53805b261ecSmrg    ErrorF("-maxbigreqsize         set maximal bigrequest size \n");
53905b261ecSmrg#ifdef PANORAMIX
54005b261ecSmrg    ErrorF("+xinerama              Enable XINERAMA extension\n");
54105b261ecSmrg    ErrorF("-xinerama              Disable XINERAMA extension\n");
54205b261ecSmrg#endif
54305b261ecSmrg    ErrorF("-dumbSched             Disable smart scheduling, enable old behavior\n");
54405b261ecSmrg    ErrorF("-schedInterval int     Set scheduler interval in msec\n");
54505b261ecSmrg    ErrorF("+extension name        Enable extension\n");
54605b261ecSmrg    ErrorF("-extension name        Disable extension\n");
54705b261ecSmrg#ifdef XDMCP
54805b261ecSmrg    XdmcpUseMsg();
54905b261ecSmrg#endif
55005b261ecSmrg    XkbUseMsg();
55105b261ecSmrg    ddxUseMsg();
55205b261ecSmrg}
55305b261ecSmrg
55405b261ecSmrg/*  This function performs a rudimentary sanity check
55505b261ecSmrg *  on the display name passed in on the command-line,
55605b261ecSmrg *  since this string is used to generate filenames.
55705b261ecSmrg *  It is especially important that the display name
55805b261ecSmrg *  not contain a "/" and not start with a "-".
55905b261ecSmrg *                                            --kvajk
56005b261ecSmrg */
56105b261ecSmrgstatic int
56205b261ecSmrgVerifyDisplayName(const char *d)
56305b261ecSmrg{
5644202a189Smrg    if ( d == (char *)0 ) return 0;  /*  null  */
5654202a189Smrg    if ( *d == '\0' ) return 0;  /*  empty  */
5664202a189Smrg    if ( *d == '-' ) return 0;  /*  could be confused for an option  */
5674202a189Smrg    if ( *d == '.' ) return 0;  /*  must not equal "." or ".."  */
5684202a189Smrg    if ( strchr(d, '/') != (char *)0 ) return 0;  /*  very important!!!  */
5694202a189Smrg    return 1;
57005b261ecSmrg}
57105b261ecSmrg
57205b261ecSmrg/*
57305b261ecSmrg * This function parses the command line. Handles device-independent fields
57405b261ecSmrg * and allows ddx to handle additional fields.  It is not allowed to modify
57505b261ecSmrg * argc or any of the strings pointed to by argv.
57605b261ecSmrg */
57705b261ecSmrgvoid
57805b261ecSmrgProcessCommandLine(int argc, char *argv[])
57905b261ecSmrg{
58005b261ecSmrg    int i, skip;
58105b261ecSmrg
58205b261ecSmrg    defaultKeyboardControl.autoRepeat = TRUE;
58305b261ecSmrg
58405b261ecSmrg#ifdef NO_PART_NET
58505b261ecSmrg    PartialNetwork = FALSE;
58605b261ecSmrg#else
58705b261ecSmrg    PartialNetwork = TRUE;
58805b261ecSmrg#endif
58905b261ecSmrg
59005b261ecSmrg    for ( i = 1; i < argc; i++ )
59105b261ecSmrg    {
59205b261ecSmrg	/* call ddx first, so it can peek/override if it wants */
59305b261ecSmrg        if((skip = ddxProcessArgument(argc, argv, i)))
59405b261ecSmrg	{
59505b261ecSmrg	    i += (skip - 1);
59605b261ecSmrg	}
59705b261ecSmrg	else if(argv[i][0] ==  ':')
59805b261ecSmrg	{
59905b261ecSmrg	    /* initialize display */
60005b261ecSmrg	    display = argv[i];
60105b261ecSmrg	    display++;
60205b261ecSmrg            if( ! VerifyDisplayName( display ) ) {
60305b261ecSmrg                ErrorF("Bad display name: %s\n", display);
60405b261ecSmrg                UseMsg();
60505b261ecSmrg		FatalError("Bad display name, exiting: %s\n", display);
60605b261ecSmrg            }
60705b261ecSmrg	}
60805b261ecSmrg	else if ( strcmp( argv[i], "-a") == 0)
60905b261ecSmrg	{
61005b261ecSmrg	    if(++i < argc)
61105b261ecSmrg	        defaultPointerControl.num = atoi(argv[i]);
61205b261ecSmrg	    else
61305b261ecSmrg		UseMsg();
61405b261ecSmrg	}
61505b261ecSmrg	else if ( strcmp( argv[i], "-ac") == 0)
61605b261ecSmrg	{
61705b261ecSmrg	    defeatAccessControl = TRUE;
61805b261ecSmrg	}
61905b261ecSmrg	else if ( strcmp( argv[i], "-audit") == 0)
62005b261ecSmrg	{
62105b261ecSmrg	    if(++i < argc)
62205b261ecSmrg	        auditTrailLevel = atoi(argv[i]);
62305b261ecSmrg	    else
62405b261ecSmrg		UseMsg();
62505b261ecSmrg	}
62605b261ecSmrg	else if ( strcmp( argv[i], "-auth") == 0)
62705b261ecSmrg	{
62805b261ecSmrg	    if(++i < argc)
62905b261ecSmrg	        InitAuthorization (argv[i]);
63005b261ecSmrg	    else
63105b261ecSmrg		UseMsg();
63205b261ecSmrg	}
6334642e01fSmrg	else if ( strcmp( argv[i], "-br") == 0) ; /* default */
63405b261ecSmrg	else if ( strcmp( argv[i], "+bs") == 0)
63505b261ecSmrg	    enableBackingStore = TRUE;
63605b261ecSmrg	else if ( strcmp( argv[i], "-bs") == 0)
63705b261ecSmrg	    disableBackingStore = TRUE;
63805b261ecSmrg	else if ( strcmp( argv[i], "c") == 0)
63905b261ecSmrg	{
64005b261ecSmrg	    if(++i < argc)
64105b261ecSmrg	        defaultKeyboardControl.click = atoi(argv[i]);
64205b261ecSmrg	    else
64305b261ecSmrg		UseMsg();
64405b261ecSmrg	}
64505b261ecSmrg	else if ( strcmp( argv[i], "-c") == 0)
64605b261ecSmrg	{
64705b261ecSmrg	    defaultKeyboardControl.click = 0;
64805b261ecSmrg	}
64905b261ecSmrg	else if ( strcmp( argv[i], "-cc") == 0)
65005b261ecSmrg	{
65105b261ecSmrg	    if(++i < argc)
65205b261ecSmrg	        defaultColorVisualClass = atoi(argv[i]);
65305b261ecSmrg	    else
65405b261ecSmrg		UseMsg();
65505b261ecSmrg	}
65605b261ecSmrg	else if ( strcmp( argv[i], "-core") == 0)
65705b261ecSmrg	{
65805b261ecSmrg#if !defined(WIN32) || !defined(__MINGW32__)
65905b261ecSmrg	    struct rlimit   core_limit;
66005b261ecSmrg	    getrlimit (RLIMIT_CORE, &core_limit);
66105b261ecSmrg	    core_limit.rlim_cur = core_limit.rlim_max;
66205b261ecSmrg	    setrlimit (RLIMIT_CORE, &core_limit);
66305b261ecSmrg#endif
6644202a189Smrg	    CoreDump = TRUE;
66505b261ecSmrg	}
6664202a189Smrg        else if ( strcmp( argv[i], "-nocursor") == 0)
6674202a189Smrg        {
6684202a189Smrg            EnableCursor = FALSE;
6694202a189Smrg        }
6704202a189Smrg        else if ( strcmp( argv[i], "-dpi") == 0)
67105b261ecSmrg	{
67205b261ecSmrg	    if(++i < argc)
67305b261ecSmrg	        monitorResolution = atoi(argv[i]);
67405b261ecSmrg	    else
67505b261ecSmrg		UseMsg();
67605b261ecSmrg	}
67705b261ecSmrg#ifdef DPMSExtension
67805b261ecSmrg	else if ( strcmp( argv[i], "dpms") == 0)
6794202a189Smrg	    /* ignored for compatibility */ ;
68005b261ecSmrg	else if ( strcmp( argv[i], "-dpms") == 0)
68105b261ecSmrg	    DPMSDisabledSwitch = TRUE;
68205b261ecSmrg#endif
68305b261ecSmrg	else if ( strcmp( argv[i], "-deferglyphs") == 0)
68405b261ecSmrg	{
68505b261ecSmrg	    if(++i >= argc || !ParseGlyphCachingMode(argv[i]))
68605b261ecSmrg		UseMsg();
68705b261ecSmrg	}
68805b261ecSmrg	else if ( strcmp( argv[i], "-f") == 0)
68905b261ecSmrg	{
69005b261ecSmrg	    if(++i < argc)
69105b261ecSmrg	        defaultKeyboardControl.bell = atoi(argv[i]);
69205b261ecSmrg	    else
69305b261ecSmrg		UseMsg();
69405b261ecSmrg	}
69505b261ecSmrg	else if ( strcmp( argv[i], "-fc") == 0)
69605b261ecSmrg	{
69705b261ecSmrg	    if(++i < argc)
69805b261ecSmrg	        defaultCursorFont = argv[i];
69905b261ecSmrg	    else
70005b261ecSmrg		UseMsg();
70105b261ecSmrg	}
70205b261ecSmrg	else if ( strcmp( argv[i], "-fn") == 0)
70305b261ecSmrg	{
70405b261ecSmrg	    if(++i < argc)
70505b261ecSmrg	        defaultTextFont = argv[i];
70605b261ecSmrg	    else
70705b261ecSmrg		UseMsg();
70805b261ecSmrg	}
70905b261ecSmrg	else if ( strcmp( argv[i], "-fp") == 0)
71005b261ecSmrg	{
71105b261ecSmrg	    if(++i < argc)
71205b261ecSmrg	    {
71305b261ecSmrg	        defaultFontPath = argv[i];
71405b261ecSmrg	    }
71505b261ecSmrg	    else
71605b261ecSmrg		UseMsg();
71705b261ecSmrg	}
71805b261ecSmrg	else if ( strcmp( argv[i], "-help") == 0)
71905b261ecSmrg	{
72005b261ecSmrg	    UseMsg();
72105b261ecSmrg	    exit(0);
72205b261ecSmrg	}
72305b261ecSmrg        else if ( (skip=XkbProcessArguments(argc,argv,i))!=0 ) {
72405b261ecSmrg	    if (skip>0)
72505b261ecSmrg		 i+= skip-1;
72605b261ecSmrg	    else UseMsg();
72705b261ecSmrg	}
72805b261ecSmrg#ifdef RLIMIT_DATA
72905b261ecSmrg	else if ( strcmp( argv[i], "-ld") == 0)
73005b261ecSmrg	{
73105b261ecSmrg	    if(++i < argc)
73205b261ecSmrg	    {
73305b261ecSmrg	        limitDataSpace = atoi(argv[i]);
73405b261ecSmrg		if (limitDataSpace > 0)
73505b261ecSmrg		    limitDataSpace *= 1024;
73605b261ecSmrg	    }
73705b261ecSmrg	    else
73805b261ecSmrg		UseMsg();
73905b261ecSmrg	}
74005b261ecSmrg#endif
74105b261ecSmrg#ifdef RLIMIT_NOFILE
74205b261ecSmrg	else if ( strcmp( argv[i], "-lf") == 0)
74305b261ecSmrg	{
74405b261ecSmrg	    if(++i < argc)
74505b261ecSmrg	        limitNoFile = atoi(argv[i]);
74605b261ecSmrg	    else
74705b261ecSmrg		UseMsg();
74805b261ecSmrg	}
74905b261ecSmrg#endif
75005b261ecSmrg#ifdef RLIMIT_STACK
75105b261ecSmrg	else if ( strcmp( argv[i], "-ls") == 0)
75205b261ecSmrg	{
75305b261ecSmrg	    if(++i < argc)
75405b261ecSmrg	    {
75505b261ecSmrg	        limitStackSpace = atoi(argv[i]);
75605b261ecSmrg		if (limitStackSpace > 0)
75705b261ecSmrg		    limitStackSpace *= 1024;
75805b261ecSmrg	    }
75905b261ecSmrg	    else
76005b261ecSmrg		UseMsg();
76105b261ecSmrg	}
76205b261ecSmrg#endif
76305b261ecSmrg	else if ( strcmp ( argv[i], "-nolock") == 0)
76405b261ecSmrg	{
76505b261ecSmrg#if !defined(WIN32) && !defined(__CYGWIN__)
76605b261ecSmrg	  if (getuid() != 0)
76705b261ecSmrg	    ErrorF("Warning: the -nolock option can only be used by root\n");
76805b261ecSmrg	  else
76905b261ecSmrg#endif
77005b261ecSmrg	    nolock = TRUE;
77105b261ecSmrg	}
77205b261ecSmrg#ifndef NOLOGOHACK
77305b261ecSmrg	else if ( strcmp( argv[i], "-logo") == 0)
77405b261ecSmrg	{
77505b261ecSmrg	    logoScreenSaver = 1;
77605b261ecSmrg	}
77705b261ecSmrg	else if ( strcmp( argv[i], "nologo") == 0)
77805b261ecSmrg	{
77905b261ecSmrg	    logoScreenSaver = 0;
78005b261ecSmrg	}
78105b261ecSmrg#endif
78205b261ecSmrg	else if ( strcmp( argv[i], "-nolisten") == 0)
78305b261ecSmrg	{
78405b261ecSmrg            if(++i < argc) {
78505b261ecSmrg		if (_XSERVTransNoListen(argv[i]))
78605b261ecSmrg		    FatalError ("Failed to disable listen for %s transport",
78705b261ecSmrg				argv[i]);
78805b261ecSmrg	   } else
78905b261ecSmrg		UseMsg();
79005b261ecSmrg	}
79105b261ecSmrg	else if ( strcmp( argv[i], "-noreset") == 0)
79205b261ecSmrg	{
79305b261ecSmrg	    dispatchExceptionAtReset = 0;
79405b261ecSmrg	}
79505b261ecSmrg	else if ( strcmp( argv[i], "-reset") == 0)
79605b261ecSmrg	{
79705b261ecSmrg	    dispatchExceptionAtReset = DE_RESET;
79805b261ecSmrg	}
79905b261ecSmrg	else if ( strcmp( argv[i], "-p") == 0)
80005b261ecSmrg	{
80105b261ecSmrg	    if(++i < argc)
80205b261ecSmrg	        defaultScreenSaverInterval = ((CARD32)atoi(argv[i])) *
80305b261ecSmrg					     MILLI_PER_MIN;
80405b261ecSmrg	    else
80505b261ecSmrg		UseMsg();
80605b261ecSmrg	}
8074642e01fSmrg	else if (strcmp(argv[i], "-pogo") == 0)
8084642e01fSmrg	{
8094642e01fSmrg	    dispatchException = DE_TERMINATE;
8104642e01fSmrg	}
81105b261ecSmrg	else if ( strcmp( argv[i], "-pn") == 0)
81205b261ecSmrg	    PartialNetwork = TRUE;
81305b261ecSmrg	else if ( strcmp( argv[i], "-nopn") == 0)
81405b261ecSmrg	    PartialNetwork = FALSE;
81505b261ecSmrg	else if ( strcmp( argv[i], "r") == 0)
81605b261ecSmrg	    defaultKeyboardControl.autoRepeat = TRUE;
81705b261ecSmrg	else if ( strcmp( argv[i], "-r") == 0)
81805b261ecSmrg	    defaultKeyboardControl.autoRepeat = FALSE;
8194642e01fSmrg	else if ( strcmp( argv[i], "-retro") == 0)
8204642e01fSmrg	    party_like_its_1989 = TRUE;
821daf23d7fSsnj	else if ( strcmp( argv[i], "-noretro") == 0)
822daf23d7fSsnj	    party_like_its_1989 = FALSE;
82305b261ecSmrg	else if ( strcmp( argv[i], "-s") == 0)
82405b261ecSmrg	{
82505b261ecSmrg	    if(++i < argc)
82605b261ecSmrg	        defaultScreenSaverTime = ((CARD32)atoi(argv[i])) *
82705b261ecSmrg					 MILLI_PER_MIN;
82805b261ecSmrg	    else
82905b261ecSmrg		UseMsg();
83005b261ecSmrg	}
83105b261ecSmrg	else if ( strcmp( argv[i], "-t") == 0)
83205b261ecSmrg	{
83305b261ecSmrg	    if(++i < argc)
83405b261ecSmrg	        defaultPointerControl.threshold = atoi(argv[i]);
83505b261ecSmrg	    else
83605b261ecSmrg		UseMsg();
83705b261ecSmrg	}
83805b261ecSmrg	else if ( strcmp( argv[i], "-terminate") == 0)
83905b261ecSmrg	{
84005b261ecSmrg	    dispatchExceptionAtReset = DE_TERMINATE;
84105b261ecSmrg	}
84205b261ecSmrg	else if ( strcmp( argv[i], "-to") == 0)
84305b261ecSmrg	{
84405b261ecSmrg	    if(++i < argc)
84505b261ecSmrg		TimeOutValue = ((CARD32)atoi(argv[i])) * MILLI_PER_SECOND;
84605b261ecSmrg	    else
84705b261ecSmrg		UseMsg();
84805b261ecSmrg	}
84905b261ecSmrg	else if ( strcmp( argv[i], "-tst") == 0)
85005b261ecSmrg	{
85105b261ecSmrg	    noTestExtensions = TRUE;
85205b261ecSmrg	}
85305b261ecSmrg	else if ( strcmp( argv[i], "v") == 0)
85405b261ecSmrg	    defaultScreenSaverBlanking = PreferBlanking;
85505b261ecSmrg	else if ( strcmp( argv[i], "-v") == 0)
85605b261ecSmrg	    defaultScreenSaverBlanking = DontPreferBlanking;
85705b261ecSmrg	else if ( strcmp( argv[i], "-wm") == 0)
85805b261ecSmrg	    defaultBackingStore = WhenMapped;
85905b261ecSmrg        else if ( strcmp( argv[i], "-wr") == 0)
86005b261ecSmrg            whiteRoot = TRUE;
86105b261ecSmrg        else if ( strcmp( argv[i], "-maxbigreqsize") == 0) {
86205b261ecSmrg             if(++i < argc) {
86305b261ecSmrg                 long reqSizeArg = atol(argv[i]);
86405b261ecSmrg
86505b261ecSmrg                 /* Request size > 128MB does not make much sense... */
86605b261ecSmrg                 if( reqSizeArg > 0L && reqSizeArg < 128L ) {
86705b261ecSmrg                     maxBigRequestSize = (reqSizeArg * 1048576L) - 1L;
86805b261ecSmrg                 }
86905b261ecSmrg                 else
87005b261ecSmrg                 {
87105b261ecSmrg                     UseMsg();
87205b261ecSmrg                 }
87305b261ecSmrg             }
87405b261ecSmrg             else
87505b261ecSmrg             {
87605b261ecSmrg                 UseMsg();
87705b261ecSmrg             }
87805b261ecSmrg         }
87905b261ecSmrg#ifdef PANORAMIX
88005b261ecSmrg	else if ( strcmp( argv[i], "+xinerama") == 0){
88105b261ecSmrg	    noPanoramiXExtension = FALSE;
88205b261ecSmrg	}
88305b261ecSmrg	else if ( strcmp( argv[i], "-xinerama") == 0){
88405b261ecSmrg	    noPanoramiXExtension = TRUE;
88505b261ecSmrg	}
88605b261ecSmrg	else if ( strcmp( argv[i], "-disablexineramaextension") == 0){
88705b261ecSmrg	    PanoramiXExtensionDisabledHack = TRUE;
88805b261ecSmrg	}
88905b261ecSmrg#endif
89005b261ecSmrg	else if ( strcmp( argv[i], "-I") == 0)
89105b261ecSmrg	{
89205b261ecSmrg	    /* ignore all remaining arguments */
89305b261ecSmrg	    break;
89405b261ecSmrg	}
89505b261ecSmrg	else if (strncmp (argv[i], "tty", 3) == 0)
89605b261ecSmrg	{
8974202a189Smrg            /* init supplies us with this useless information */
89805b261ecSmrg	}
89905b261ecSmrg#ifdef XDMCP
90005b261ecSmrg	else if ((skip = XdmcpOptions(argc, argv, i)) != i)
90105b261ecSmrg	{
90205b261ecSmrg	    i = skip - 1;
90305b261ecSmrg	}
90405b261ecSmrg#endif
90505b261ecSmrg	else if ( strcmp( argv[i], "-dumbSched") == 0)
90605b261ecSmrg	{
90705b261ecSmrg	    SmartScheduleDisable = TRUE;
90805b261ecSmrg	}
90905b261ecSmrg	else if ( strcmp( argv[i], "-schedInterval") == 0)
91005b261ecSmrg	{
91105b261ecSmrg	    if (++i < argc)
91205b261ecSmrg	    {
91305b261ecSmrg		SmartScheduleInterval = atoi(argv[i]);
91405b261ecSmrg		SmartScheduleSlice = SmartScheduleInterval;
91505b261ecSmrg	    }
91605b261ecSmrg	    else
91705b261ecSmrg		UseMsg();
91805b261ecSmrg	}
91905b261ecSmrg	else if ( strcmp( argv[i], "-schedMax") == 0)
92005b261ecSmrg	{
92105b261ecSmrg	    if (++i < argc)
92205b261ecSmrg	    {
92305b261ecSmrg		SmartScheduleMaxSlice = atoi(argv[i]);
92405b261ecSmrg	    }
92505b261ecSmrg	    else
92605b261ecSmrg		UseMsg();
92705b261ecSmrg	}
92805b261ecSmrg	else if ( strcmp( argv[i], "-render" ) == 0)
92905b261ecSmrg	{
93005b261ecSmrg	    if (++i < argc)
93105b261ecSmrg	    {
93205b261ecSmrg		int policy = PictureParseCmapPolicy (argv[i]);
93305b261ecSmrg
93405b261ecSmrg		if (policy != PictureCmapPolicyInvalid)
93505b261ecSmrg		    PictureCmapPolicy = policy;
93605b261ecSmrg		else
93705b261ecSmrg		    UseMsg ();
93805b261ecSmrg	    }
93905b261ecSmrg	    else
94005b261ecSmrg		UseMsg ();
94105b261ecSmrg	}
94205b261ecSmrg	else if ( strcmp( argv[i], "+extension") == 0)
94305b261ecSmrg	{
94405b261ecSmrg	    if (++i < argc)
94505b261ecSmrg	    {
94605b261ecSmrg		if (!EnableDisableExtension(argv[i], TRUE))
94705b261ecSmrg		    EnableDisableExtensionError(argv[i], TRUE);
94805b261ecSmrg	    }
94905b261ecSmrg	    else
95005b261ecSmrg		UseMsg();
95105b261ecSmrg	}
95205b261ecSmrg	else if ( strcmp( argv[i], "-extension") == 0)
95305b261ecSmrg	{
95405b261ecSmrg	    if (++i < argc)
95505b261ecSmrg	    {
95605b261ecSmrg		if (!EnableDisableExtension(argv[i], FALSE))
95705b261ecSmrg		    EnableDisableExtensionError(argv[i], FALSE);
95805b261ecSmrg	    }
95905b261ecSmrg	    else
96005b261ecSmrg		UseMsg();
96105b261ecSmrg	}
96205b261ecSmrg 	else
96305b261ecSmrg 	{
96405b261ecSmrg	    ErrorF("Unrecognized option: %s\n", argv[i]);
96505b261ecSmrg	    UseMsg();
96605b261ecSmrg	    FatalError("Unrecognized option: %s\n", argv[i]);
96705b261ecSmrg        }
96805b261ecSmrg    }
96905b261ecSmrg}
97005b261ecSmrg
97105b261ecSmrg/* Implement a simple-minded font authorization scheme.  The authorization
97205b261ecSmrg   name is "hp-hostname-1", the contents are simply the host name. */
97305b261ecSmrgint
97405b261ecSmrgset_font_authorizations(char **authorizations, int *authlen, pointer client)
97505b261ecSmrg{
97605b261ecSmrg#define AUTHORIZATION_NAME "hp-hostname-1"
97705b261ecSmrg#if defined(TCPCONN) || defined(STREAMSCONN)
97805b261ecSmrg    static char *result = NULL;
97905b261ecSmrg    static char *p = NULL;
98005b261ecSmrg
98105b261ecSmrg    if (p == NULL)
98205b261ecSmrg    {
98305b261ecSmrg	char hname[1024], *hnameptr;
98405b261ecSmrg	unsigned int len;
98505b261ecSmrg#if defined(IPv6) && defined(AF_INET6)
98605b261ecSmrg	struct addrinfo hints, *ai = NULL;
98705b261ecSmrg#else
98805b261ecSmrg	struct hostent *host;
98905b261ecSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
99005b261ecSmrg	_Xgethostbynameparams hparams;
99105b261ecSmrg#endif
99205b261ecSmrg#endif
99305b261ecSmrg
99405b261ecSmrg	gethostname(hname, 1024);
99505b261ecSmrg#if defined(IPv6) && defined(AF_INET6)
9964202a189Smrg	memset(&hints, 0, sizeof(hints));
99705b261ecSmrg	hints.ai_flags = AI_CANONNAME;
99805b261ecSmrg	if (getaddrinfo(hname, NULL, &hints, &ai) == 0) {
99905b261ecSmrg	    hnameptr = ai->ai_canonname;
100005b261ecSmrg	} else {
100105b261ecSmrg	    hnameptr = hname;
100205b261ecSmrg	}
100305b261ecSmrg#else
100405b261ecSmrg	host = _XGethostbyname(hname, hparams);
100505b261ecSmrg	if (host == NULL)
100605b261ecSmrg	    hnameptr = hname;
100705b261ecSmrg	else
100805b261ecSmrg	    hnameptr = host->h_name;
100905b261ecSmrg#endif
101005b261ecSmrg
101105b261ecSmrg	len = strlen(hnameptr) + 1;
10124202a189Smrg	result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4);
101305b261ecSmrg
101405b261ecSmrg	p = result;
101505b261ecSmrg        *p++ = sizeof(AUTHORIZATION_NAME) >> 8;
101605b261ecSmrg        *p++ = sizeof(AUTHORIZATION_NAME) & 0xff;
101705b261ecSmrg        *p++ = (len) >> 8;
101805b261ecSmrg        *p++ = (len & 0xff);
101905b261ecSmrg
102005b261ecSmrg	memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME));
102105b261ecSmrg	p += sizeof(AUTHORIZATION_NAME);
102205b261ecSmrg	memmove(p, hnameptr, len);
102305b261ecSmrg	p += len;
102405b261ecSmrg#if defined(IPv6) && defined(AF_INET6)
102505b261ecSmrg	if (ai) {
102605b261ecSmrg	    freeaddrinfo(ai);
102705b261ecSmrg	}
102805b261ecSmrg#endif
102905b261ecSmrg    }
103005b261ecSmrg    *authlen = p - result;
103105b261ecSmrg    *authorizations = result;
103205b261ecSmrg    return 1;
103305b261ecSmrg#else /* TCPCONN */
103405b261ecSmrg    return 0;
103505b261ecSmrg#endif /* TCPCONN */
103605b261ecSmrg}
103705b261ecSmrg
10384202a189Smrgvoid *
103905b261ecSmrgXalloc(unsigned long amount)
104005b261ecSmrg{
10414202a189Smrg    /*
10424202a189Smrg     * Xalloc used to return NULL when large amount of memory is requested. In
10434202a189Smrg     * order to catch the buggy callers this warning has been added, slated to
10444202a189Smrg     * removal by anyone who touches this code (or just looks at it) in 2011.
10454202a189Smrg     *
10464202a189Smrg     * -- Mikhail Gusarov
10474202a189Smrg     */
10484202a189Smrg    if ((long)amount <= 0)
10494202a189Smrg	ErrorF("Warning: Xalloc: "
10504202a189Smrg	       "requesting unpleasantly large amount of memory: %lu bytes.\n",
10514202a189Smrg               amount);
10524642e01fSmrg
10534202a189Smrg    return malloc(amount);
105405b261ecSmrg}
105505b261ecSmrg
10564202a189Smrgvoid *
105705b261ecSmrgXNFalloc(unsigned long amount)
105805b261ecSmrg{
10594202a189Smrg    void *ptr = malloc(amount);
106005b261ecSmrg    if (!ptr)
106105b261ecSmrg        FatalError("Out of memory");
10624642e01fSmrg    return ptr;
106305b261ecSmrg}
106405b261ecSmrg
10654202a189Smrgvoid *
106605b261ecSmrgXcalloc(unsigned long amount)
106705b261ecSmrg{
10684202a189Smrg    return calloc(1, amount);
106905b261ecSmrg}
107005b261ecSmrg
10714202a189Smrgvoid *
107205b261ecSmrgXNFcalloc(unsigned long amount)
107305b261ecSmrg{
10744202a189Smrg    void *ret = calloc(1, amount);
10754202a189Smrg    if (!ret)
10764202a189Smrg        FatalError("XNFcalloc: Out of memory");
107705b261ecSmrg    return ret;
107805b261ecSmrg}
107905b261ecSmrg
10804202a189Smrgvoid *
10814202a189SmrgXrealloc(void *ptr, unsigned long amount)
108205b261ecSmrg{
10834202a189Smrg    /*
10844202a189Smrg     * Xrealloc used to return NULL when large amount of memory is requested. In
10854202a189Smrg     * order to catch the buggy callers this warning has been added, slated to
10864202a189Smrg     * removal by anyone who touches this code (or just looks at it) in 2011.
10874202a189Smrg     *
10884202a189Smrg     * -- Mikhail Gusarov
10894202a189Smrg     */
109005b261ecSmrg    if ((long)amount <= 0)
10914202a189Smrg	ErrorF("Warning: Xrealloc: "
10924202a189Smrg	       "requesting unpleasantly large amount of memory: %lu bytes.\n",
10934202a189Smrg               amount);
10944642e01fSmrg
10954202a189Smrg    return realloc(ptr, amount);
109605b261ecSmrg}
10974202a189Smrg
10984202a189Smrgvoid *
10994202a189SmrgXNFrealloc(void *ptr, unsigned long amount)
110005b261ecSmrg{
11014202a189Smrg    void *ret = realloc(ptr, amount);
11024202a189Smrg    if (!ret)
11034202a189Smrg	FatalError("XNFrealloc: Out of memory");
11044202a189Smrg    return ret;
110505b261ecSmrg}
110605b261ecSmrg
11074202a189Smrgvoid
11084202a189SmrgXfree(void *ptr)
110905b261ecSmrg{
11104202a189Smrg    free(ptr);
111105b261ecSmrg}
111205b261ecSmrg
111305b261ecSmrg
111405b261ecSmrgchar *
111505b261ecSmrgXstrdup(const char *s)
111605b261ecSmrg{
111705b261ecSmrg    if (s == NULL)
111805b261ecSmrg	return NULL;
11194202a189Smrg    return strdup(s);
112005b261ecSmrg}
112105b261ecSmrg
11224202a189Smrgchar *
112305b261ecSmrgXNFstrdup(const char *s)
112405b261ecSmrg{
11254202a189Smrg    char *ret;
112605b261ecSmrg
112705b261ecSmrg    if (s == NULL)
112805b261ecSmrg	return NULL;
112905b261ecSmrg
11304202a189Smrg    ret = strdup(s);
11314202a189Smrg    if (!ret)
11324202a189Smrg	FatalError("XNFstrdup: Out of memory");
11334202a189Smrg    return ret;
113405b261ecSmrg}
113505b261ecSmrg
113605b261ecSmrg
113705b261ecSmrg#ifdef SIGVTALRM
113805b261ecSmrg#define SMART_SCHEDULE_POSSIBLE
113905b261ecSmrg#endif
114005b261ecSmrg
114105b261ecSmrg#ifdef SMART_SCHEDULE_POSSIBLE
114205b261ecSmrg#define SMART_SCHEDULE_SIGNAL		SIGALRM
114305b261ecSmrg#define SMART_SCHEDULE_TIMER		ITIMER_REAL
114405b261ecSmrg#endif
114505b261ecSmrg
11464642e01fSmrgvoid
114705b261ecSmrgSmartScheduleStopTimer (void)
114805b261ecSmrg{
114905b261ecSmrg#ifdef SMART_SCHEDULE_POSSIBLE
115005b261ecSmrg    struct itimerval	timer;
115105b261ecSmrg
11524642e01fSmrg    if (SmartScheduleDisable)
11534642e01fSmrg	return;
115405b261ecSmrg    timer.it_interval.tv_sec = 0;
115505b261ecSmrg    timer.it_interval.tv_usec = 0;
115605b261ecSmrg    timer.it_value.tv_sec = 0;
115705b261ecSmrg    timer.it_value.tv_usec = 0;
115805b261ecSmrg    (void) setitimer (ITIMER_REAL, &timer, 0);
115905b261ecSmrg#endif
116005b261ecSmrg}
116105b261ecSmrg
11624642e01fSmrgvoid
116305b261ecSmrgSmartScheduleStartTimer (void)
116405b261ecSmrg{
116505b261ecSmrg#ifdef SMART_SCHEDULE_POSSIBLE
116605b261ecSmrg    struct itimerval	timer;
116705b261ecSmrg
11684642e01fSmrg    if (SmartScheduleDisable)
11694642e01fSmrg	return;
117005b261ecSmrg    timer.it_interval.tv_sec = 0;
117105b261ecSmrg    timer.it_interval.tv_usec = SmartScheduleInterval * 1000;
117205b261ecSmrg    timer.it_value.tv_sec = 0;
117305b261ecSmrg    timer.it_value.tv_usec = SmartScheduleInterval * 1000;
11744642e01fSmrg    setitimer (ITIMER_REAL, &timer, 0);
117505b261ecSmrg#endif
117605b261ecSmrg}
117705b261ecSmrg
117805b261ecSmrg#ifdef SMART_SCHEDULE_POSSIBLE
117905b261ecSmrgstatic void
118005b261ecSmrgSmartScheduleTimer (int sig)
118105b261ecSmrg{
118205b261ecSmrg    SmartScheduleTime += SmartScheduleInterval;
118305b261ecSmrg}
118405b261ecSmrg#endif
118505b261ecSmrg
118605b261ecSmrgBool
118705b261ecSmrgSmartScheduleInit (void)
118805b261ecSmrg{
118905b261ecSmrg#ifdef SMART_SCHEDULE_POSSIBLE
119005b261ecSmrg    struct sigaction	act;
119105b261ecSmrg
119205b261ecSmrg    if (SmartScheduleDisable)
119305b261ecSmrg	return TRUE;
119405b261ecSmrg
11954202a189Smrg    memset((char *) &act, 0, sizeof(struct sigaction));
119605b261ecSmrg
119705b261ecSmrg    /* Set up the timer signal function */
119805b261ecSmrg    act.sa_handler = SmartScheduleTimer;
119905b261ecSmrg    sigemptyset (&act.sa_mask);
120005b261ecSmrg    sigaddset (&act.sa_mask, SMART_SCHEDULE_SIGNAL);
120105b261ecSmrg    if (sigaction (SMART_SCHEDULE_SIGNAL, &act, 0) < 0)
120205b261ecSmrg    {
120305b261ecSmrg	perror ("sigaction for smart scheduler");
120405b261ecSmrg	return FALSE;
120505b261ecSmrg    }
120605b261ecSmrg    return TRUE;
120705b261ecSmrg#else
120805b261ecSmrg    return FALSE;
120905b261ecSmrg#endif
121005b261ecSmrg}
121105b261ecSmrg
121205b261ecSmrg#ifdef SIG_BLOCK
121305b261ecSmrgstatic sigset_t	PreviousSignalMask;
121405b261ecSmrgstatic int	BlockedSignalCount;
121505b261ecSmrg#endif
121605b261ecSmrg
121705b261ecSmrgvoid
121805b261ecSmrgOsBlockSignals (void)
121905b261ecSmrg{
122005b261ecSmrg#ifdef SIG_BLOCK
122105b261ecSmrg    if (BlockedSignalCount++ == 0)
122205b261ecSmrg    {
122305b261ecSmrg	sigset_t    set;
122405b261ecSmrg
122505b261ecSmrg	sigemptyset (&set);
122605b261ecSmrg#ifdef SIGALRM
122705b261ecSmrg	sigaddset (&set, SIGALRM);
122805b261ecSmrg#endif
122905b261ecSmrg#ifdef SIGVTALRM
123005b261ecSmrg	sigaddset (&set, SIGVTALRM);
123105b261ecSmrg#endif
123205b261ecSmrg#ifdef SIGWINCH
123305b261ecSmrg	sigaddset (&set, SIGWINCH);
123405b261ecSmrg#endif
123505b261ecSmrg#ifdef SIGIO
123605b261ecSmrg	sigaddset (&set, SIGIO);
123705b261ecSmrg#endif
123805b261ecSmrg#ifdef SIGTSTP
123905b261ecSmrg	sigaddset (&set, SIGTSTP);
124005b261ecSmrg#endif
124105b261ecSmrg#ifdef SIGTTIN
124205b261ecSmrg	sigaddset (&set, SIGTTIN);
124305b261ecSmrg#endif
124405b261ecSmrg#ifdef SIGTTOU
124505b261ecSmrg	sigaddset (&set, SIGTTOU);
124605b261ecSmrg#endif
124705b261ecSmrg#ifdef SIGCHLD
124805b261ecSmrg	sigaddset (&set, SIGCHLD);
124905b261ecSmrg#endif
125005b261ecSmrg	sigprocmask (SIG_BLOCK, &set, &PreviousSignalMask);
125105b261ecSmrg    }
125205b261ecSmrg#endif
125305b261ecSmrg}
125405b261ecSmrg
125505b261ecSmrgvoid
125605b261ecSmrgOsReleaseSignals (void)
125705b261ecSmrg{
125805b261ecSmrg#ifdef SIG_BLOCK
125905b261ecSmrg    if (--BlockedSignalCount == 0)
126005b261ecSmrg    {
126105b261ecSmrg	sigprocmask (SIG_SETMASK, &PreviousSignalMask, 0);
126205b261ecSmrg    }
126305b261ecSmrg#endif
126405b261ecSmrg}
126505b261ecSmrg
12664202a189Smrg/*
12674202a189Smrg * Pending signals may interfere with core dumping. Provide a
12684202a189Smrg * mechanism to block signals when aborting.
12694202a189Smrg */
12704202a189Smrg
12714202a189Smrgvoid
12724202a189SmrgOsAbort (void)
12734202a189Smrg{
12744202a189Smrg#ifndef __APPLE__
12754202a189Smrg    OsBlockSignals();
12764202a189Smrg#endif
12774202a189Smrg    abort();
12784202a189Smrg}
12794202a189Smrg
128005b261ecSmrg#if !defined(WIN32)
128105b261ecSmrg/*
128205b261ecSmrg * "safer" versions of system(3), popen(3) and pclose(3) which give up
128305b261ecSmrg * all privs before running a command.
128405b261ecSmrg *
128505b261ecSmrg * This is based on the code in FreeBSD 2.2 libc.
128605b261ecSmrg *
128705b261ecSmrg * XXX It'd be good to redirect stderr so that it ends up in the log file
128805b261ecSmrg * as well.  As it is now, xkbcomp messages don't end up in the log file.
128905b261ecSmrg */
129005b261ecSmrg
129105b261ecSmrgint
129205b261ecSmrgSystem(char *command)
129305b261ecSmrg{
129405b261ecSmrg    int pid, p;
129505b261ecSmrg#ifdef SIGCHLD
129605b261ecSmrg    void (*csig)(int);
129705b261ecSmrg#endif
129805b261ecSmrg    int status;
129905b261ecSmrg
130005b261ecSmrg    if (!command)
13014202a189Smrg	return 1;
130205b261ecSmrg
130305b261ecSmrg#ifdef SIGCHLD
130405b261ecSmrg    csig = signal(SIGCHLD, SIG_DFL);
130505b261ecSmrg    if (csig == SIG_ERR) {
130605b261ecSmrg      perror("signal");
130705b261ecSmrg      return -1;
130805b261ecSmrg    }
130905b261ecSmrg#endif
131005b261ecSmrg
131105b261ecSmrg#ifdef DEBUG
131205b261ecSmrg    ErrorF("System: `%s'\n", command);
131305b261ecSmrg#endif
131405b261ecSmrg
131505b261ecSmrg    switch (pid = fork()) {
131605b261ecSmrg    case -1:	/* error */
131705b261ecSmrg	p = -1;
131805b261ecSmrg    case 0:	/* child */
131905b261ecSmrg	if (setgid(getgid()) == -1)
132005b261ecSmrg	    _exit(127);
132105b261ecSmrg	if (setuid(getuid()) == -1)
132205b261ecSmrg	    _exit(127);
132305b261ecSmrg	execl("/bin/sh", "sh", "-c", command, (char *)NULL);
132405b261ecSmrg	_exit(127);
132505b261ecSmrg    default:	/* parent */
132605b261ecSmrg	do {
132705b261ecSmrg	    p = waitpid(pid, &status, 0);
132805b261ecSmrg	} while (p == -1 && errno == EINTR);
132905b261ecSmrg
133005b261ecSmrg    }
133105b261ecSmrg
133205b261ecSmrg#ifdef SIGCHLD
133305b261ecSmrg    if (signal(SIGCHLD, csig) == SIG_ERR) {
133405b261ecSmrg      perror("signal");
133505b261ecSmrg      return -1;
133605b261ecSmrg    }
133705b261ecSmrg#endif
133805b261ecSmrg
133905b261ecSmrg    return p == -1 ? -1 : status;
134005b261ecSmrg}
134105b261ecSmrg
134205b261ecSmrgstatic struct pid {
134305b261ecSmrg    struct pid *next;
134405b261ecSmrg    FILE *fp;
134505b261ecSmrg    int pid;
134605b261ecSmrg} *pidlist;
134705b261ecSmrg
13484642e01fSmrgOsSigHandlerPtr old_alarm = NULL; /* XXX horrible awful hack */
134905b261ecSmrg
135005b261ecSmrgpointer
135105b261ecSmrgPopen(char *command, char *type)
135205b261ecSmrg{
135305b261ecSmrg    struct pid *cur;
135405b261ecSmrg    FILE *iop;
135505b261ecSmrg    int pdes[2], pid;
135605b261ecSmrg
135705b261ecSmrg    if (command == NULL || type == NULL)
135805b261ecSmrg	return NULL;
135905b261ecSmrg
136005b261ecSmrg    if ((*type != 'r' && *type != 'w') || type[1])
136105b261ecSmrg	return NULL;
136205b261ecSmrg
13634202a189Smrg    if ((cur = malloc(sizeof(struct pid))) == NULL)
136405b261ecSmrg	return NULL;
136505b261ecSmrg
136605b261ecSmrg    if (pipe(pdes) < 0) {
13674202a189Smrg	free(cur);
136805b261ecSmrg	return NULL;
136905b261ecSmrg    }
137005b261ecSmrg
137105b261ecSmrg    /* Ignore the smart scheduler while this is going on */
13724642e01fSmrg    old_alarm = OsSignal(SIGALRM, SIG_IGN);
137305b261ecSmrg    if (old_alarm == SIG_ERR) {
137405b261ecSmrg      perror("signal");
137505b261ecSmrg      return NULL;
137605b261ecSmrg    }
137705b261ecSmrg
137805b261ecSmrg    switch (pid = fork()) {
137905b261ecSmrg    case -1: 	/* error */
138005b261ecSmrg	close(pdes[0]);
138105b261ecSmrg	close(pdes[1]);
13824202a189Smrg	free(cur);
13834642e01fSmrg	if (OsSignal(SIGALRM, old_alarm) == SIG_ERR)
138405b261ecSmrg	  perror("signal");
138505b261ecSmrg	return NULL;
138605b261ecSmrg    case 0:	/* child */
138705b261ecSmrg	if (setgid(getgid()) == -1)
138805b261ecSmrg	    _exit(127);
138905b261ecSmrg	if (setuid(getuid()) == -1)
139005b261ecSmrg	    _exit(127);
139105b261ecSmrg	if (*type == 'r') {
139205b261ecSmrg	    if (pdes[1] != 1) {
139305b261ecSmrg		/* stdout */
139405b261ecSmrg		dup2(pdes[1], 1);
139505b261ecSmrg		close(pdes[1]);
139605b261ecSmrg	    }
139705b261ecSmrg	    close(pdes[0]);
139805b261ecSmrg	} else {
139905b261ecSmrg	    if (pdes[0] != 0) {
140005b261ecSmrg		/* stdin */
140105b261ecSmrg		dup2(pdes[0], 0);
140205b261ecSmrg		close(pdes[0]);
140305b261ecSmrg	    }
140405b261ecSmrg	    close(pdes[1]);
140505b261ecSmrg	}
140605b261ecSmrg	execl("/bin/sh", "sh", "-c", command, (char *)NULL);
140705b261ecSmrg	_exit(127);
140805b261ecSmrg    }
140905b261ecSmrg
141005b261ecSmrg    /* Avoid EINTR during stdio calls */
141105b261ecSmrg    OsBlockSignals ();
141205b261ecSmrg
141305b261ecSmrg    /* parent */
141405b261ecSmrg    if (*type == 'r') {
141505b261ecSmrg	iop = fdopen(pdes[0], type);
141605b261ecSmrg	close(pdes[1]);
141705b261ecSmrg    } else {
141805b261ecSmrg	iop = fdopen(pdes[1], type);
141905b261ecSmrg	close(pdes[0]);
142005b261ecSmrg    }
142105b261ecSmrg
142205b261ecSmrg    cur->fp = iop;
142305b261ecSmrg    cur->pid = pid;
142405b261ecSmrg    cur->next = pidlist;
142505b261ecSmrg    pidlist = cur;
142605b261ecSmrg
142705b261ecSmrg#ifdef DEBUG
142805b261ecSmrg    ErrorF("Popen: `%s', fp = %p\n", command, iop);
142905b261ecSmrg#endif
143005b261ecSmrg
143105b261ecSmrg    return iop;
143205b261ecSmrg}
143305b261ecSmrg
143405b261ecSmrg/* fopen that drops privileges */
143505b261ecSmrgpointer
143605b261ecSmrgFopen(char *file, char *type)
143705b261ecSmrg{
143805b261ecSmrg    FILE *iop;
143905b261ecSmrg#ifndef HAS_SAVED_IDS_AND_SETEUID
144005b261ecSmrg    struct pid *cur;
144105b261ecSmrg    int pdes[2], pid;
144205b261ecSmrg
144305b261ecSmrg    if (file == NULL || type == NULL)
144405b261ecSmrg	return NULL;
144505b261ecSmrg
144605b261ecSmrg    if ((*type != 'r' && *type != 'w') || type[1])
144705b261ecSmrg	return NULL;
144805b261ecSmrg
14494202a189Smrg    if ((cur = malloc(sizeof(struct pid))) == NULL)
145005b261ecSmrg	return NULL;
145105b261ecSmrg
145205b261ecSmrg    if (pipe(pdes) < 0) {
14534202a189Smrg	free(cur);
145405b261ecSmrg	return NULL;
145505b261ecSmrg    }
145605b261ecSmrg
145705b261ecSmrg    switch (pid = fork()) {
145805b261ecSmrg    case -1: 	/* error */
145905b261ecSmrg	close(pdes[0]);
146005b261ecSmrg	close(pdes[1]);
14614202a189Smrg	free(cur);
146205b261ecSmrg	return NULL;
146305b261ecSmrg    case 0:	/* child */
146405b261ecSmrg	if (setgid(getgid()) == -1)
146505b261ecSmrg	    _exit(127);
146605b261ecSmrg	if (setuid(getuid()) == -1)
146705b261ecSmrg	    _exit(127);
146805b261ecSmrg	if (*type == 'r') {
146905b261ecSmrg	    if (pdes[1] != 1) {
147005b261ecSmrg		/* stdout */
147105b261ecSmrg		dup2(pdes[1], 1);
147205b261ecSmrg		close(pdes[1]);
147305b261ecSmrg	    }
147405b261ecSmrg	    close(pdes[0]);
147505b261ecSmrg	} else {
147605b261ecSmrg	    if (pdes[0] != 0) {
147705b261ecSmrg		/* stdin */
147805b261ecSmrg		dup2(pdes[0], 0);
147905b261ecSmrg		close(pdes[0]);
148005b261ecSmrg	    }
148105b261ecSmrg	    close(pdes[1]);
148205b261ecSmrg	}
148305b261ecSmrg	execl("/bin/cat", "cat", file, (char *)NULL);
148405b261ecSmrg	_exit(127);
148505b261ecSmrg    }
148605b261ecSmrg
148705b261ecSmrg    /* Avoid EINTR during stdio calls */
148805b261ecSmrg    OsBlockSignals ();
148905b261ecSmrg
149005b261ecSmrg    /* parent */
149105b261ecSmrg    if (*type == 'r') {
149205b261ecSmrg	iop = fdopen(pdes[0], type);
149305b261ecSmrg	close(pdes[1]);
149405b261ecSmrg    } else {
149505b261ecSmrg	iop = fdopen(pdes[1], type);
149605b261ecSmrg	close(pdes[0]);
149705b261ecSmrg    }
149805b261ecSmrg
149905b261ecSmrg    cur->fp = iop;
150005b261ecSmrg    cur->pid = pid;
150105b261ecSmrg    cur->next = pidlist;
150205b261ecSmrg    pidlist = cur;
150305b261ecSmrg
150405b261ecSmrg#ifdef DEBUG
150505b261ecSmrg    ErrorF("Fopen(%s), fp = %p\n", file, iop);
150605b261ecSmrg#endif
150705b261ecSmrg
150805b261ecSmrg    return iop;
150905b261ecSmrg#else
151005b261ecSmrg    int ruid, euid;
151105b261ecSmrg
151205b261ecSmrg    ruid = getuid();
151305b261ecSmrg    euid = geteuid();
151405b261ecSmrg
151505b261ecSmrg    if (seteuid(ruid) == -1) {
151605b261ecSmrg	    return NULL;
151705b261ecSmrg    }
151805b261ecSmrg    iop = fopen(file, type);
151905b261ecSmrg
152005b261ecSmrg    if (seteuid(euid) == -1) {
152105b261ecSmrg	    fclose(iop);
152205b261ecSmrg	    return NULL;
152305b261ecSmrg    }
152405b261ecSmrg    return iop;
152505b261ecSmrg#endif /* HAS_SAVED_IDS_AND_SETEUID */
152605b261ecSmrg}
152705b261ecSmrg
152805b261ecSmrgint
152905b261ecSmrgPclose(pointer iop)
153005b261ecSmrg{
153105b261ecSmrg    struct pid *cur, *last;
153205b261ecSmrg    int pstat;
153305b261ecSmrg    int pid;
153405b261ecSmrg
153505b261ecSmrg#ifdef DEBUG
153605b261ecSmrg    ErrorF("Pclose: fp = %p\n", iop);
153705b261ecSmrg#endif
153805b261ecSmrg
153905b261ecSmrg    fclose(iop);
154005b261ecSmrg
154105b261ecSmrg    for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
154205b261ecSmrg	if (cur->fp == iop)
154305b261ecSmrg	    break;
154405b261ecSmrg    if (cur == NULL)
154505b261ecSmrg	return -1;
154605b261ecSmrg
154705b261ecSmrg    do {
154805b261ecSmrg	pid = waitpid(cur->pid, &pstat, 0);
154905b261ecSmrg    } while (pid == -1 && errno == EINTR);
155005b261ecSmrg
155105b261ecSmrg    if (last == NULL)
155205b261ecSmrg	pidlist = cur->next;
155305b261ecSmrg    else
155405b261ecSmrg	last->next = cur->next;
15554202a189Smrg    free(cur);
155605b261ecSmrg
155705b261ecSmrg    /* allow EINTR again */
155805b261ecSmrg    OsReleaseSignals ();
155905b261ecSmrg
15604642e01fSmrg    if (old_alarm && OsSignal(SIGALRM, old_alarm) == SIG_ERR) {
156105b261ecSmrg      perror("signal");
156205b261ecSmrg      return -1;
156305b261ecSmrg    }
156405b261ecSmrg
156505b261ecSmrg    return pid == -1 ? -1 : pstat;
156605b261ecSmrg}
156705b261ecSmrg
15684202a189Smrgint
156905b261ecSmrgFclose(pointer iop)
157005b261ecSmrg{
157105b261ecSmrg#ifdef HAS_SAVED_IDS_AND_SETEUID
157205b261ecSmrg    return fclose(iop);
157305b261ecSmrg#else
157405b261ecSmrg    return Pclose(iop);
157505b261ecSmrg#endif
157605b261ecSmrg}
157705b261ecSmrg
157805b261ecSmrg#endif /* !WIN32 */
157905b261ecSmrg
158005b261ecSmrg
158105b261ecSmrg/*
158205b261ecSmrg * CheckUserParameters: check for long command line arguments and long
158305b261ecSmrg * environment variables.  By default, these checks are only done when
158405b261ecSmrg * the server's euid != ruid.  In 3.3.x, these checks were done in an
158505b261ecSmrg * external wrapper utility.
158605b261ecSmrg */
158705b261ecSmrg
158805b261ecSmrg/* Consider LD* variables insecure? */
158905b261ecSmrg#ifndef REMOVE_ENV_LD
159005b261ecSmrg#define REMOVE_ENV_LD 1
159105b261ecSmrg#endif
159205b261ecSmrg
159305b261ecSmrg/* Remove long environment variables? */
159405b261ecSmrg#ifndef REMOVE_LONG_ENV
159505b261ecSmrg#define REMOVE_LONG_ENV 1
159605b261ecSmrg#endif
159705b261ecSmrg
159805b261ecSmrg/*
159905b261ecSmrg * Disallow stdout or stderr as pipes?  It's possible to block the X server
160005b261ecSmrg * when piping stdout+stderr to a pipe.
160105b261ecSmrg *
160205b261ecSmrg * Don't enable this because it looks like it's going to cause problems.
160305b261ecSmrg */
160405b261ecSmrg#ifndef NO_OUTPUT_PIPES
160505b261ecSmrg#define NO_OUTPUT_PIPES 0
160605b261ecSmrg#endif
160705b261ecSmrg
160805b261ecSmrg
160905b261ecSmrg/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
161005b261ecSmrg#ifndef CHECK_EUID
161105b261ecSmrg#ifndef WIN32
161205b261ecSmrg#define CHECK_EUID 1
161305b261ecSmrg#else
161405b261ecSmrg#define CHECK_EUID 0
161505b261ecSmrg#endif
161605b261ecSmrg#endif
161705b261ecSmrg
161805b261ecSmrg/*
161905b261ecSmrg * Maybe the locale can be faked to make isprint(3) report that everything
162005b261ecSmrg * is printable?  Avoid it by default.
162105b261ecSmrg */
162205b261ecSmrg#ifndef USE_ISPRINT
162305b261ecSmrg#define USE_ISPRINT 0
162405b261ecSmrg#endif
162505b261ecSmrg
162605b261ecSmrg#define MAX_ARG_LENGTH          128
162705b261ecSmrg#define MAX_ENV_LENGTH          256
162805b261ecSmrg#define MAX_ENV_PATH_LENGTH     2048	/* Limit for *PATH and TERMCAP */
162905b261ecSmrg
163005b261ecSmrg#if USE_ISPRINT
163105b261ecSmrg#include <ctype.h>
163205b261ecSmrg#define checkPrintable(c) isprint(c)
163305b261ecSmrg#else
163405b261ecSmrg#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
163505b261ecSmrg#endif
163605b261ecSmrg
163705b261ecSmrgenum BadCode {
163805b261ecSmrg    NotBad = 0,
163905b261ecSmrg    UnsafeArg,
164005b261ecSmrg    ArgTooLong,
164105b261ecSmrg    UnprintableArg,
164205b261ecSmrg    EnvTooLong,
164305b261ecSmrg    OutputIsPipe,
164405b261ecSmrg    InternalError
164505b261ecSmrg};
164605b261ecSmrg
164705b261ecSmrg#if defined(VENDORSUPPORT)
164805b261ecSmrg#define BUGADDRESS VENDORSUPPORT
164905b261ecSmrg#elif defined(BUILDERADDR)
165005b261ecSmrg#define BUGADDRESS BUILDERADDR
165105b261ecSmrg#else
165205b261ecSmrg#define BUGADDRESS "xorg@freedesktop.org"
165305b261ecSmrg#endif
165405b261ecSmrg
165505b261ecSmrgvoid
165605b261ecSmrgCheckUserParameters(int argc, char **argv, char **envp)
165705b261ecSmrg{
165805b261ecSmrg    enum BadCode bad = NotBad;
165905b261ecSmrg    int i = 0, j;
166005b261ecSmrg    char *a, *e = NULL;
166105b261ecSmrg
166205b261ecSmrg#if CHECK_EUID
166305b261ecSmrg    if (geteuid() == 0 && getuid() != geteuid())
166405b261ecSmrg#endif
166505b261ecSmrg    {
166605b261ecSmrg	/* Check each argv[] */
166705b261ecSmrg	for (i = 1; i < argc; i++) {
166805b261ecSmrg	    if (strcmp(argv[i], "-fp") == 0)
166905b261ecSmrg	    {
167005b261ecSmrg		i++; /* continue with next argument. skip the length check */
167105b261ecSmrg		if (i >= argc)
167205b261ecSmrg		    break;
167305b261ecSmrg	    } else
167405b261ecSmrg	    {
167505b261ecSmrg		if (strlen(argv[i]) > MAX_ARG_LENGTH) {
167605b261ecSmrg		    bad = ArgTooLong;
167705b261ecSmrg		    break;
167805b261ecSmrg		}
167905b261ecSmrg	    }
168005b261ecSmrg	    a = argv[i];
168105b261ecSmrg	    while (*a) {
168205b261ecSmrg		if (checkPrintable(*a) == 0) {
168305b261ecSmrg		    bad = UnprintableArg;
168405b261ecSmrg		    break;
168505b261ecSmrg		}
168605b261ecSmrg		a++;
168705b261ecSmrg	    }
168805b261ecSmrg	    if (bad)
168905b261ecSmrg		break;
169005b261ecSmrg	}
169105b261ecSmrg	if (!bad) {
169205b261ecSmrg	    /* Check each envp[] */
169305b261ecSmrg	    for (i = 0; envp[i]; i++) {
169405b261ecSmrg
169505b261ecSmrg		/* Check for bad environment variables and values */
169605b261ecSmrg#if REMOVE_ENV_LD
169705b261ecSmrg		while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
169805b261ecSmrg		    for (j = i; envp[j]; j++) {
169905b261ecSmrg			envp[j] = envp[j+1];
170005b261ecSmrg		    }
170105b261ecSmrg		}
170205b261ecSmrg#endif
170305b261ecSmrg		if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
170405b261ecSmrg#if REMOVE_LONG_ENV
170505b261ecSmrg		    for (j = i; envp[j]; j++) {
170605b261ecSmrg			envp[j] = envp[j+1];
170705b261ecSmrg		    }
170805b261ecSmrg		    i--;
170905b261ecSmrg#else
171005b261ecSmrg		    char *eq;
171105b261ecSmrg		    int len;
171205b261ecSmrg
171305b261ecSmrg		    eq = strchr(envp[i], '=');
171405b261ecSmrg		    if (!eq)
171505b261ecSmrg			continue;
171605b261ecSmrg		    len = eq - envp[i];
171705b261ecSmrg		    e = malloc(len + 1);
171805b261ecSmrg		    if (!e) {
171905b261ecSmrg			bad = InternalError;
172005b261ecSmrg			break;
172105b261ecSmrg		    }
172205b261ecSmrg		    strncpy(e, envp[i], len);
172305b261ecSmrg		    e[len] = 0;
172405b261ecSmrg		    if (len >= 4 &&
172505b261ecSmrg			(strcmp(e + len - 4, "PATH") == 0 ||
172605b261ecSmrg			 strcmp(e, "TERMCAP") == 0)) {
172705b261ecSmrg			if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
172805b261ecSmrg			    bad = EnvTooLong;
172905b261ecSmrg			    break;
173005b261ecSmrg			} else {
173105b261ecSmrg			    free(e);
173205b261ecSmrg			}
173305b261ecSmrg		    } else {
173405b261ecSmrg			bad = EnvTooLong;
173505b261ecSmrg			break;
173605b261ecSmrg		    }
173705b261ecSmrg#endif
173805b261ecSmrg		}
173905b261ecSmrg	    }
174005b261ecSmrg	}
174105b261ecSmrg#if NO_OUTPUT_PIPES
174205b261ecSmrg	if (!bad) {
174305b261ecSmrg	    struct stat buf;
174405b261ecSmrg
174505b261ecSmrg	    if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode))
174605b261ecSmrg		bad = OutputIsPipe;
174705b261ecSmrg	    if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode))
174805b261ecSmrg		bad = OutputIsPipe;
174905b261ecSmrg	}
175005b261ecSmrg#endif
175105b261ecSmrg    }
175205b261ecSmrg    switch (bad) {
175305b261ecSmrg    case NotBad:
175405b261ecSmrg	return;
175505b261ecSmrg    case UnsafeArg:
175605b261ecSmrg	ErrorF("Command line argument number %d is unsafe\n", i);
175705b261ecSmrg	break;
175805b261ecSmrg    case ArgTooLong:
175905b261ecSmrg	ErrorF("Command line argument number %d is too long\n", i);
176005b261ecSmrg	break;
176105b261ecSmrg    case UnprintableArg:
176205b261ecSmrg	ErrorF("Command line argument number %d contains unprintable"
176305b261ecSmrg		" characters\n", i);
176405b261ecSmrg	break;
176505b261ecSmrg    case EnvTooLong:
176605b261ecSmrg	ErrorF("Environment variable `%s' is too long\n", e);
176705b261ecSmrg	break;
176805b261ecSmrg    case OutputIsPipe:
176905b261ecSmrg	ErrorF("Stdout and/or stderr is a pipe\n");
177005b261ecSmrg	break;
177105b261ecSmrg    case InternalError:
177205b261ecSmrg	ErrorF("Internal Error\n");
177305b261ecSmrg	break;
177405b261ecSmrg    default:
177505b261ecSmrg	ErrorF("Unknown error\n");
177605b261ecSmrg	break;
177705b261ecSmrg    }
177805b261ecSmrg    FatalError("X server aborted because of unsafe environment\n");
177905b261ecSmrg}
178005b261ecSmrg
178105b261ecSmrg/*
178205b261ecSmrg * CheckUserAuthorization: check if the user is allowed to start the
178305b261ecSmrg * X server.  This usually means some sort of PAM checking, and it is
178405b261ecSmrg * usually only done for setuid servers (uid != euid).
178505b261ecSmrg */
178605b261ecSmrg
178705b261ecSmrg#ifdef USE_PAM
178805b261ecSmrg#include <security/pam_appl.h>
178905b261ecSmrg#include <security/pam_misc.h>
179005b261ecSmrg#include <pwd.h>
179105b261ecSmrg#endif /* USE_PAM */
179205b261ecSmrg
179305b261ecSmrgvoid
179405b261ecSmrgCheckUserAuthorization(void)
179505b261ecSmrg{
179605b261ecSmrg#ifdef USE_PAM
179705b261ecSmrg    static struct pam_conv conv = {
179805b261ecSmrg	misc_conv,
179905b261ecSmrg	NULL
180005b261ecSmrg    };
180105b261ecSmrg
180205b261ecSmrg    pam_handle_t *pamh = NULL;
180305b261ecSmrg    struct passwd *pw;
180405b261ecSmrg    int retval;
180505b261ecSmrg
180605b261ecSmrg    if (getuid() != geteuid()) {
180705b261ecSmrg	pw = getpwuid(getuid());
180805b261ecSmrg	if (pw == NULL)
180905b261ecSmrg	    FatalError("getpwuid() failed for uid %d\n", getuid());
181005b261ecSmrg
181105b261ecSmrg	retval = pam_start("xserver", pw->pw_name, &conv, &pamh);
181205b261ecSmrg	if (retval != PAM_SUCCESS)
181305b261ecSmrg	    FatalError("pam_start() failed.\n"
181405b261ecSmrg			"\tMissing or mangled PAM config file or module?\n");
181505b261ecSmrg
181605b261ecSmrg	retval = pam_authenticate(pamh, 0);
181705b261ecSmrg	if (retval != PAM_SUCCESS) {
181805b261ecSmrg	    pam_end(pamh, retval);
181905b261ecSmrg	    FatalError("PAM authentication failed, cannot start X server.\n"
182005b261ecSmrg			"\tPerhaps you do not have console ownership?\n");
182105b261ecSmrg	}
182205b261ecSmrg
182305b261ecSmrg	retval = pam_acct_mgmt(pamh, 0);
182405b261ecSmrg	if (retval != PAM_SUCCESS) {
182505b261ecSmrg	    pam_end(pamh, retval);
182605b261ecSmrg	    FatalError("PAM authentication failed, cannot start X server.\n"
182705b261ecSmrg			"\tPerhaps you do not have console ownership?\n");
182805b261ecSmrg	}
182905b261ecSmrg
183005b261ecSmrg	/* this is not a session, so do not do session management */
183105b261ecSmrg	pam_end(pamh, PAM_SUCCESS);
183205b261ecSmrg    }
183305b261ecSmrg#endif
183405b261ecSmrg}
183505b261ecSmrg
18364202a189Smrg/*
18374202a189Smrg * Tokenize a string into a NULL terminated array of strings. Always returns
18384202a189Smrg * an allocated array unless an error occurs.
18394202a189Smrg */
18404202a189Smrgchar**
18414202a189Smrgxstrtokenize(const char *str, const char *separators)
184205b261ecSmrg{
18434202a189Smrg    char **list, **nlist;
18444202a189Smrg    char *tok, *tmp;
18454202a189Smrg    unsigned num = 0, n;
184605b261ecSmrg
18474202a189Smrg    if (!str)
18484202a189Smrg        return NULL;
18494202a189Smrg    list = calloc(1, sizeof(*list));
18504202a189Smrg    if (!list)
18514202a189Smrg        return NULL;
18524202a189Smrg    tmp = strdup(str);
18534202a189Smrg    if (!tmp)
18544202a189Smrg        goto error;
18554202a189Smrg    for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) {
18564202a189Smrg        nlist = realloc(list, (num + 2) * sizeof(*list));
18574202a189Smrg        if (!nlist)
18584202a189Smrg            goto error;
18594202a189Smrg        list = nlist;
18604202a189Smrg        list[num] = strdup(tok);
18614202a189Smrg        if (!list[num])
18624202a189Smrg            goto error;
18634202a189Smrg        list[++num] = NULL;
18644202a189Smrg    }
18654202a189Smrg    free(tmp);
18664202a189Smrg    return list;
18674202a189Smrg
18684202a189Smrgerror:
18694202a189Smrg    free(tmp);
18704202a189Smrg    for (n = 0; n < num; n++)
18714202a189Smrg        free(list[n]);
18724202a189Smrg    free(list);
18734202a189Smrg    return NULL;
187405b261ecSmrg}
1875