utils.c revision 65b04b38
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    ErrorF("-nolisten string       don't listen on protocol\n");
51405b261ecSmrg    ErrorF("-noreset               don't reset after last client exists\n");
51565b04b38Smrg    ErrorF("-background [none]     create root window with no background\n");
51605b261ecSmrg    ErrorF("-reset                 reset after last client exists\n");
51705b261ecSmrg    ErrorF("-p #                   screen-saver pattern duration (minutes)\n");
51805b261ecSmrg    ErrorF("-pn                    accept failure to listen on all ports\n");
51905b261ecSmrg    ErrorF("-nopn                  reject failure to listen on all ports\n");
52005b261ecSmrg    ErrorF("-r                     turns off auto-repeat\n");
52105b261ecSmrg    ErrorF("r                      turns on auto-repeat \n");
52205b261ecSmrg    ErrorF("-render [default|mono|gray|color] set render color alloc policy\n");
5234642e01fSmrg    ErrorF("-retro                 start with classic stipple and cursor\n");
524daf23d7fSsnj    ErrorF("-noretro               start with black background and no cursor\n");
52505b261ecSmrg    ErrorF("-s #                   screen-saver timeout (minutes)\n");
5264202a189Smrg    ErrorF("-t #                   default pointer threshold (pixels/t)\n");
52705b261ecSmrg    ErrorF("-terminate             terminate at server reset\n");
52805b261ecSmrg    ErrorF("-to #                  connection time out\n");
52905b261ecSmrg    ErrorF("-tst                   disable testing extensions\n");
53005b261ecSmrg    ErrorF("ttyxx                  server started from init on /dev/ttyxx\n");
53105b261ecSmrg    ErrorF("v                      video blanking for screen-saver\n");
53205b261ecSmrg    ErrorF("-v                     screen-saver without video blanking\n");
53305b261ecSmrg    ErrorF("-wm                    WhenMapped default backing-store\n");
53405b261ecSmrg    ErrorF("-wr                    create root window with white background\n");
53505b261ecSmrg    ErrorF("-maxbigreqsize         set maximal bigrequest size \n");
53605b261ecSmrg#ifdef PANORAMIX
53705b261ecSmrg    ErrorF("+xinerama              Enable XINERAMA extension\n");
53805b261ecSmrg    ErrorF("-xinerama              Disable XINERAMA extension\n");
53905b261ecSmrg#endif
54005b261ecSmrg    ErrorF("-dumbSched             Disable smart scheduling, enable old behavior\n");
54105b261ecSmrg    ErrorF("-schedInterval int     Set scheduler interval in msec\n");
54265b04b38Smrg    ErrorF("-sigstop               Enable SIGSTOP based startup\n");
54305b261ecSmrg    ErrorF("+extension name        Enable extension\n");
54405b261ecSmrg    ErrorF("-extension name        Disable extension\n");
54505b261ecSmrg#ifdef XDMCP
54605b261ecSmrg    XdmcpUseMsg();
54705b261ecSmrg#endif
54805b261ecSmrg    XkbUseMsg();
54905b261ecSmrg    ddxUseMsg();
55005b261ecSmrg}
55105b261ecSmrg
55205b261ecSmrg/*  This function performs a rudimentary sanity check
55305b261ecSmrg *  on the display name passed in on the command-line,
55405b261ecSmrg *  since this string is used to generate filenames.
55505b261ecSmrg *  It is especially important that the display name
55605b261ecSmrg *  not contain a "/" and not start with a "-".
55705b261ecSmrg *                                            --kvajk
55805b261ecSmrg */
55905b261ecSmrgstatic int
56005b261ecSmrgVerifyDisplayName(const char *d)
56105b261ecSmrg{
5624202a189Smrg    if ( d == (char *)0 ) return 0;  /*  null  */
5634202a189Smrg    if ( *d == '\0' ) return 0;  /*  empty  */
5644202a189Smrg    if ( *d == '-' ) return 0;  /*  could be confused for an option  */
5654202a189Smrg    if ( *d == '.' ) return 0;  /*  must not equal "." or ".."  */
5664202a189Smrg    if ( strchr(d, '/') != (char *)0 ) return 0;  /*  very important!!!  */
5674202a189Smrg    return 1;
56805b261ecSmrg}
56905b261ecSmrg
57005b261ecSmrg/*
57105b261ecSmrg * This function parses the command line. Handles device-independent fields
57205b261ecSmrg * and allows ddx to handle additional fields.  It is not allowed to modify
57305b261ecSmrg * argc or any of the strings pointed to by argv.
57405b261ecSmrg */
57505b261ecSmrgvoid
57605b261ecSmrgProcessCommandLine(int argc, char *argv[])
57705b261ecSmrg{
57805b261ecSmrg    int i, skip;
57905b261ecSmrg
58005b261ecSmrg    defaultKeyboardControl.autoRepeat = TRUE;
58105b261ecSmrg
58205b261ecSmrg#ifdef NO_PART_NET
58305b261ecSmrg    PartialNetwork = FALSE;
58405b261ecSmrg#else
58505b261ecSmrg    PartialNetwork = TRUE;
58605b261ecSmrg#endif
58705b261ecSmrg
58805b261ecSmrg    for ( i = 1; i < argc; i++ )
58905b261ecSmrg    {
59005b261ecSmrg	/* call ddx first, so it can peek/override if it wants */
59105b261ecSmrg        if((skip = ddxProcessArgument(argc, argv, i)))
59205b261ecSmrg	{
59305b261ecSmrg	    i += (skip - 1);
59405b261ecSmrg	}
59505b261ecSmrg	else if(argv[i][0] ==  ':')
59605b261ecSmrg	{
59705b261ecSmrg	    /* initialize display */
59805b261ecSmrg	    display = argv[i];
59905b261ecSmrg	    display++;
60005b261ecSmrg            if( ! VerifyDisplayName( display ) ) {
60105b261ecSmrg                ErrorF("Bad display name: %s\n", display);
60205b261ecSmrg                UseMsg();
60305b261ecSmrg		FatalError("Bad display name, exiting: %s\n", display);
60405b261ecSmrg            }
60505b261ecSmrg	}
60605b261ecSmrg	else if ( strcmp( argv[i], "-a") == 0)
60705b261ecSmrg	{
60805b261ecSmrg	    if(++i < argc)
60905b261ecSmrg	        defaultPointerControl.num = atoi(argv[i]);
61005b261ecSmrg	    else
61105b261ecSmrg		UseMsg();
61205b261ecSmrg	}
61305b261ecSmrg	else if ( strcmp( argv[i], "-ac") == 0)
61405b261ecSmrg	{
61505b261ecSmrg	    defeatAccessControl = TRUE;
61605b261ecSmrg	}
61705b261ecSmrg	else if ( strcmp( argv[i], "-audit") == 0)
61805b261ecSmrg	{
61905b261ecSmrg	    if(++i < argc)
62005b261ecSmrg	        auditTrailLevel = atoi(argv[i]);
62105b261ecSmrg	    else
62205b261ecSmrg		UseMsg();
62305b261ecSmrg	}
62405b261ecSmrg	else if ( strcmp( argv[i], "-auth") == 0)
62505b261ecSmrg	{
62605b261ecSmrg	    if(++i < argc)
62705b261ecSmrg	        InitAuthorization (argv[i]);
62805b261ecSmrg	    else
62905b261ecSmrg		UseMsg();
63005b261ecSmrg	}
6314642e01fSmrg	else if ( strcmp( argv[i], "-br") == 0) ; /* default */
63205b261ecSmrg	else if ( strcmp( argv[i], "+bs") == 0)
63305b261ecSmrg	    enableBackingStore = TRUE;
63405b261ecSmrg	else if ( strcmp( argv[i], "-bs") == 0)
63505b261ecSmrg	    disableBackingStore = TRUE;
63605b261ecSmrg	else if ( strcmp( argv[i], "c") == 0)
63705b261ecSmrg	{
63805b261ecSmrg	    if(++i < argc)
63905b261ecSmrg	        defaultKeyboardControl.click = atoi(argv[i]);
64005b261ecSmrg	    else
64105b261ecSmrg		UseMsg();
64205b261ecSmrg	}
64305b261ecSmrg	else if ( strcmp( argv[i], "-c") == 0)
64405b261ecSmrg	{
64505b261ecSmrg	    defaultKeyboardControl.click = 0;
64605b261ecSmrg	}
64705b261ecSmrg	else if ( strcmp( argv[i], "-cc") == 0)
64805b261ecSmrg	{
64905b261ecSmrg	    if(++i < argc)
65005b261ecSmrg	        defaultColorVisualClass = atoi(argv[i]);
65105b261ecSmrg	    else
65205b261ecSmrg		UseMsg();
65305b261ecSmrg	}
65405b261ecSmrg	else if ( strcmp( argv[i], "-core") == 0)
65505b261ecSmrg	{
65605b261ecSmrg#if !defined(WIN32) || !defined(__MINGW32__)
65705b261ecSmrg	    struct rlimit   core_limit;
65805b261ecSmrg	    getrlimit (RLIMIT_CORE, &core_limit);
65905b261ecSmrg	    core_limit.rlim_cur = core_limit.rlim_max;
66005b261ecSmrg	    setrlimit (RLIMIT_CORE, &core_limit);
66105b261ecSmrg#endif
6624202a189Smrg	    CoreDump = TRUE;
66305b261ecSmrg	}
6644202a189Smrg        else if ( strcmp( argv[i], "-nocursor") == 0)
6654202a189Smrg        {
6664202a189Smrg            EnableCursor = FALSE;
6674202a189Smrg        }
6684202a189Smrg        else if ( strcmp( argv[i], "-dpi") == 0)
66905b261ecSmrg	{
67005b261ecSmrg	    if(++i < argc)
67105b261ecSmrg	        monitorResolution = atoi(argv[i]);
67205b261ecSmrg	    else
67305b261ecSmrg		UseMsg();
67405b261ecSmrg	}
67505b261ecSmrg#ifdef DPMSExtension
67605b261ecSmrg	else if ( strcmp( argv[i], "dpms") == 0)
6774202a189Smrg	    /* ignored for compatibility */ ;
67805b261ecSmrg	else if ( strcmp( argv[i], "-dpms") == 0)
67905b261ecSmrg	    DPMSDisabledSwitch = TRUE;
68005b261ecSmrg#endif
68105b261ecSmrg	else if ( strcmp( argv[i], "-deferglyphs") == 0)
68205b261ecSmrg	{
68305b261ecSmrg	    if(++i >= argc || !ParseGlyphCachingMode(argv[i]))
68405b261ecSmrg		UseMsg();
68505b261ecSmrg	}
68605b261ecSmrg	else if ( strcmp( argv[i], "-f") == 0)
68705b261ecSmrg	{
68805b261ecSmrg	    if(++i < argc)
68905b261ecSmrg	        defaultKeyboardControl.bell = atoi(argv[i]);
69005b261ecSmrg	    else
69105b261ecSmrg		UseMsg();
69205b261ecSmrg	}
69305b261ecSmrg	else if ( strcmp( argv[i], "-fc") == 0)
69405b261ecSmrg	{
69505b261ecSmrg	    if(++i < argc)
69605b261ecSmrg	        defaultCursorFont = argv[i];
69705b261ecSmrg	    else
69805b261ecSmrg		UseMsg();
69905b261ecSmrg	}
70005b261ecSmrg	else if ( strcmp( argv[i], "-fn") == 0)
70105b261ecSmrg	{
70205b261ecSmrg	    if(++i < argc)
70305b261ecSmrg	        defaultTextFont = argv[i];
70405b261ecSmrg	    else
70505b261ecSmrg		UseMsg();
70605b261ecSmrg	}
70705b261ecSmrg	else if ( strcmp( argv[i], "-fp") == 0)
70805b261ecSmrg	{
70905b261ecSmrg	    if(++i < argc)
71005b261ecSmrg	    {
71105b261ecSmrg	        defaultFontPath = argv[i];
71205b261ecSmrg	    }
71305b261ecSmrg	    else
71405b261ecSmrg		UseMsg();
71505b261ecSmrg	}
71605b261ecSmrg	else if ( strcmp( argv[i], "-help") == 0)
71705b261ecSmrg	{
71805b261ecSmrg	    UseMsg();
71905b261ecSmrg	    exit(0);
72005b261ecSmrg	}
72105b261ecSmrg        else if ( (skip=XkbProcessArguments(argc,argv,i))!=0 ) {
72205b261ecSmrg	    if (skip>0)
72305b261ecSmrg		 i+= skip-1;
72405b261ecSmrg	    else UseMsg();
72505b261ecSmrg	}
72605b261ecSmrg#ifdef RLIMIT_DATA
72705b261ecSmrg	else if ( strcmp( argv[i], "-ld") == 0)
72805b261ecSmrg	{
72905b261ecSmrg	    if(++i < argc)
73005b261ecSmrg	    {
73105b261ecSmrg	        limitDataSpace = atoi(argv[i]);
73205b261ecSmrg		if (limitDataSpace > 0)
73305b261ecSmrg		    limitDataSpace *= 1024;
73405b261ecSmrg	    }
73505b261ecSmrg	    else
73605b261ecSmrg		UseMsg();
73705b261ecSmrg	}
73805b261ecSmrg#endif
73905b261ecSmrg#ifdef RLIMIT_NOFILE
74005b261ecSmrg	else if ( strcmp( argv[i], "-lf") == 0)
74105b261ecSmrg	{
74205b261ecSmrg	    if(++i < argc)
74305b261ecSmrg	        limitNoFile = atoi(argv[i]);
74405b261ecSmrg	    else
74505b261ecSmrg		UseMsg();
74605b261ecSmrg	}
74705b261ecSmrg#endif
74805b261ecSmrg#ifdef RLIMIT_STACK
74905b261ecSmrg	else if ( strcmp( argv[i], "-ls") == 0)
75005b261ecSmrg	{
75105b261ecSmrg	    if(++i < argc)
75205b261ecSmrg	    {
75305b261ecSmrg	        limitStackSpace = atoi(argv[i]);
75405b261ecSmrg		if (limitStackSpace > 0)
75505b261ecSmrg		    limitStackSpace *= 1024;
75605b261ecSmrg	    }
75705b261ecSmrg	    else
75805b261ecSmrg		UseMsg();
75905b261ecSmrg	}
76005b261ecSmrg#endif
76105b261ecSmrg	else if ( strcmp ( argv[i], "-nolock") == 0)
76205b261ecSmrg	{
76305b261ecSmrg#if !defined(WIN32) && !defined(__CYGWIN__)
76405b261ecSmrg	  if (getuid() != 0)
76505b261ecSmrg	    ErrorF("Warning: the -nolock option can only be used by root\n");
76605b261ecSmrg	  else
76705b261ecSmrg#endif
76805b261ecSmrg	    nolock = TRUE;
76905b261ecSmrg	}
77005b261ecSmrg	else if ( strcmp( argv[i], "-nolisten") == 0)
77105b261ecSmrg	{
77205b261ecSmrg            if(++i < argc) {
77305b261ecSmrg		if (_XSERVTransNoListen(argv[i]))
77405b261ecSmrg		    FatalError ("Failed to disable listen for %s transport",
77505b261ecSmrg				argv[i]);
77605b261ecSmrg	   } else
77705b261ecSmrg		UseMsg();
77805b261ecSmrg	}
77905b261ecSmrg	else if ( strcmp( argv[i], "-noreset") == 0)
78005b261ecSmrg	{
78105b261ecSmrg	    dispatchExceptionAtReset = 0;
78205b261ecSmrg	}
78305b261ecSmrg	else if ( strcmp( argv[i], "-reset") == 0)
78405b261ecSmrg	{
78505b261ecSmrg	    dispatchExceptionAtReset = DE_RESET;
78605b261ecSmrg	}
78705b261ecSmrg	else if ( strcmp( argv[i], "-p") == 0)
78805b261ecSmrg	{
78905b261ecSmrg	    if(++i < argc)
79005b261ecSmrg	        defaultScreenSaverInterval = ((CARD32)atoi(argv[i])) *
79105b261ecSmrg					     MILLI_PER_MIN;
79205b261ecSmrg	    else
79305b261ecSmrg		UseMsg();
79405b261ecSmrg	}
7954642e01fSmrg	else if (strcmp(argv[i], "-pogo") == 0)
7964642e01fSmrg	{
7974642e01fSmrg	    dispatchException = DE_TERMINATE;
7984642e01fSmrg	}
79905b261ecSmrg	else if ( strcmp( argv[i], "-pn") == 0)
80005b261ecSmrg	    PartialNetwork = TRUE;
80105b261ecSmrg	else if ( strcmp( argv[i], "-nopn") == 0)
80205b261ecSmrg	    PartialNetwork = FALSE;
80305b261ecSmrg	else if ( strcmp( argv[i], "r") == 0)
80405b261ecSmrg	    defaultKeyboardControl.autoRepeat = TRUE;
80505b261ecSmrg	else if ( strcmp( argv[i], "-r") == 0)
80605b261ecSmrg	    defaultKeyboardControl.autoRepeat = FALSE;
8074642e01fSmrg	else if ( strcmp( argv[i], "-retro") == 0)
8084642e01fSmrg	    party_like_its_1989 = TRUE;
809daf23d7fSsnj	else if ( strcmp( argv[i], "-noretro") == 0)
810daf23d7fSsnj	    party_like_its_1989 = FALSE;
81105b261ecSmrg	else if ( strcmp( argv[i], "-s") == 0)
81205b261ecSmrg	{
81305b261ecSmrg	    if(++i < argc)
81405b261ecSmrg	        defaultScreenSaverTime = ((CARD32)atoi(argv[i])) *
81505b261ecSmrg					 MILLI_PER_MIN;
81605b261ecSmrg	    else
81705b261ecSmrg		UseMsg();
81805b261ecSmrg	}
81905b261ecSmrg	else if ( strcmp( argv[i], "-t") == 0)
82005b261ecSmrg	{
82105b261ecSmrg	    if(++i < argc)
82205b261ecSmrg	        defaultPointerControl.threshold = atoi(argv[i]);
82305b261ecSmrg	    else
82405b261ecSmrg		UseMsg();
82505b261ecSmrg	}
82605b261ecSmrg	else if ( strcmp( argv[i], "-terminate") == 0)
82705b261ecSmrg	{
82805b261ecSmrg	    dispatchExceptionAtReset = DE_TERMINATE;
82905b261ecSmrg	}
83005b261ecSmrg	else if ( strcmp( argv[i], "-to") == 0)
83105b261ecSmrg	{
83205b261ecSmrg	    if(++i < argc)
83305b261ecSmrg		TimeOutValue = ((CARD32)atoi(argv[i])) * MILLI_PER_SECOND;
83405b261ecSmrg	    else
83505b261ecSmrg		UseMsg();
83605b261ecSmrg	}
83705b261ecSmrg	else if ( strcmp( argv[i], "-tst") == 0)
83805b261ecSmrg	{
83905b261ecSmrg	    noTestExtensions = TRUE;
84005b261ecSmrg	}
84105b261ecSmrg	else if ( strcmp( argv[i], "v") == 0)
84205b261ecSmrg	    defaultScreenSaverBlanking = PreferBlanking;
84305b261ecSmrg	else if ( strcmp( argv[i], "-v") == 0)
84405b261ecSmrg	    defaultScreenSaverBlanking = DontPreferBlanking;
84505b261ecSmrg	else if ( strcmp( argv[i], "-wm") == 0)
84605b261ecSmrg	    defaultBackingStore = WhenMapped;
84705b261ecSmrg        else if ( strcmp( argv[i], "-wr") == 0)
84805b261ecSmrg            whiteRoot = TRUE;
84965b04b38Smrg        else if ( strcmp( argv[i], "-background") == 0) {
85065b04b38Smrg            if(++i < argc) {
85165b04b38Smrg                if (!strcmp ( argv[i], "none"))
85265b04b38Smrg                    bgNoneRoot = TRUE;
85365b04b38Smrg                else
85465b04b38Smrg                    UseMsg();
85565b04b38Smrg            }
85665b04b38Smrg        }
85705b261ecSmrg        else if ( strcmp( argv[i], "-maxbigreqsize") == 0) {
85805b261ecSmrg             if(++i < argc) {
85905b261ecSmrg                 long reqSizeArg = atol(argv[i]);
86005b261ecSmrg
86105b261ecSmrg                 /* Request size > 128MB does not make much sense... */
86205b261ecSmrg                 if( reqSizeArg > 0L && reqSizeArg < 128L ) {
86305b261ecSmrg                     maxBigRequestSize = (reqSizeArg * 1048576L) - 1L;
86405b261ecSmrg                 }
86505b261ecSmrg                 else
86605b261ecSmrg                 {
86705b261ecSmrg                     UseMsg();
86805b261ecSmrg                 }
86905b261ecSmrg             }
87005b261ecSmrg             else
87105b261ecSmrg             {
87205b261ecSmrg                 UseMsg();
87305b261ecSmrg             }
87405b261ecSmrg         }
87505b261ecSmrg#ifdef PANORAMIX
87605b261ecSmrg	else if ( strcmp( argv[i], "+xinerama") == 0){
87705b261ecSmrg	    noPanoramiXExtension = FALSE;
87805b261ecSmrg	}
87905b261ecSmrg	else if ( strcmp( argv[i], "-xinerama") == 0){
88005b261ecSmrg	    noPanoramiXExtension = TRUE;
88105b261ecSmrg	}
88205b261ecSmrg	else if ( strcmp( argv[i], "-disablexineramaextension") == 0){
88305b261ecSmrg	    PanoramiXExtensionDisabledHack = TRUE;
88405b261ecSmrg	}
88505b261ecSmrg#endif
88605b261ecSmrg	else if ( strcmp( argv[i], "-I") == 0)
88705b261ecSmrg	{
88805b261ecSmrg	    /* ignore all remaining arguments */
88905b261ecSmrg	    break;
89005b261ecSmrg	}
89105b261ecSmrg	else if (strncmp (argv[i], "tty", 3) == 0)
89205b261ecSmrg	{
8934202a189Smrg            /* init supplies us with this useless information */
89405b261ecSmrg	}
89505b261ecSmrg#ifdef XDMCP
89605b261ecSmrg	else if ((skip = XdmcpOptions(argc, argv, i)) != i)
89705b261ecSmrg	{
89805b261ecSmrg	    i = skip - 1;
89905b261ecSmrg	}
90005b261ecSmrg#endif
90105b261ecSmrg	else if ( strcmp( argv[i], "-dumbSched") == 0)
90205b261ecSmrg	{
90305b261ecSmrg	    SmartScheduleDisable = TRUE;
90405b261ecSmrg	}
90505b261ecSmrg	else if ( strcmp( argv[i], "-schedInterval") == 0)
90605b261ecSmrg	{
90705b261ecSmrg	    if (++i < argc)
90805b261ecSmrg	    {
90905b261ecSmrg		SmartScheduleInterval = atoi(argv[i]);
91005b261ecSmrg		SmartScheduleSlice = SmartScheduleInterval;
91105b261ecSmrg	    }
91205b261ecSmrg	    else
91305b261ecSmrg		UseMsg();
91405b261ecSmrg	}
91505b261ecSmrg	else if ( strcmp( argv[i], "-schedMax") == 0)
91605b261ecSmrg	{
91705b261ecSmrg	    if (++i < argc)
91805b261ecSmrg	    {
91905b261ecSmrg		SmartScheduleMaxSlice = atoi(argv[i]);
92005b261ecSmrg	    }
92105b261ecSmrg	    else
92205b261ecSmrg		UseMsg();
92305b261ecSmrg	}
92405b261ecSmrg	else if ( strcmp( argv[i], "-render" ) == 0)
92505b261ecSmrg	{
92605b261ecSmrg	    if (++i < argc)
92705b261ecSmrg	    {
92805b261ecSmrg		int policy = PictureParseCmapPolicy (argv[i]);
92905b261ecSmrg
93005b261ecSmrg		if (policy != PictureCmapPolicyInvalid)
93105b261ecSmrg		    PictureCmapPolicy = policy;
93205b261ecSmrg		else
93305b261ecSmrg		    UseMsg ();
93405b261ecSmrg	    }
93505b261ecSmrg	    else
93605b261ecSmrg		UseMsg ();
93705b261ecSmrg	}
93865b04b38Smrg	else if ( strcmp( argv[i], "-sigstop") == 0)
93965b04b38Smrg	{
94065b04b38Smrg	    RunFromSigStopParent = TRUE;
94165b04b38Smrg	}
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
11364642e01fSmrgvoid
113705b261ecSmrgSmartScheduleStopTimer (void)
113805b261ecSmrg{
113905b261ecSmrg    struct itimerval	timer;
114005b261ecSmrg
11414642e01fSmrg    if (SmartScheduleDisable)
11424642e01fSmrg	return;
114305b261ecSmrg    timer.it_interval.tv_sec = 0;
114405b261ecSmrg    timer.it_interval.tv_usec = 0;
114505b261ecSmrg    timer.it_value.tv_sec = 0;
114605b261ecSmrg    timer.it_value.tv_usec = 0;
114705b261ecSmrg    (void) setitimer (ITIMER_REAL, &timer, 0);
114805b261ecSmrg}
114905b261ecSmrg
11504642e01fSmrgvoid
115105b261ecSmrgSmartScheduleStartTimer (void)
115205b261ecSmrg{
115305b261ecSmrg    struct itimerval	timer;
115405b261ecSmrg
11554642e01fSmrg    if (SmartScheduleDisable)
11564642e01fSmrg	return;
115705b261ecSmrg    timer.it_interval.tv_sec = 0;
115805b261ecSmrg    timer.it_interval.tv_usec = SmartScheduleInterval * 1000;
115905b261ecSmrg    timer.it_value.tv_sec = 0;
116005b261ecSmrg    timer.it_value.tv_usec = SmartScheduleInterval * 1000;
11614642e01fSmrg    setitimer (ITIMER_REAL, &timer, 0);
116205b261ecSmrg}
116305b261ecSmrg
116405b261ecSmrgstatic void
116505b261ecSmrgSmartScheduleTimer (int sig)
116605b261ecSmrg{
116705b261ecSmrg    SmartScheduleTime += SmartScheduleInterval;
116805b261ecSmrg}
116905b261ecSmrg
117065b04b38Smrgvoid
117105b261ecSmrgSmartScheduleInit (void)
117205b261ecSmrg{
117305b261ecSmrg    struct sigaction	act;
117405b261ecSmrg
117505b261ecSmrg    if (SmartScheduleDisable)
117665b04b38Smrg	return;
117765b04b38Smrg
11784202a189Smrg    memset((char *) &act, 0, sizeof(struct sigaction));
117905b261ecSmrg
118005b261ecSmrg    /* Set up the timer signal function */
118105b261ecSmrg    act.sa_handler = SmartScheduleTimer;
118205b261ecSmrg    sigemptyset (&act.sa_mask);
118365b04b38Smrg    sigaddset (&act.sa_mask, SIGALRM);
118465b04b38Smrg    if (sigaction (SIGALRM, &act, 0) < 0)
118505b261ecSmrg    {
118605b261ecSmrg	perror ("sigaction for smart scheduler");
118765b04b38Smrg	SmartScheduleDisable = TRUE;
118805b261ecSmrg    }
118905b261ecSmrg}
119005b261ecSmrg
119105b261ecSmrg#ifdef SIG_BLOCK
119205b261ecSmrgstatic sigset_t	PreviousSignalMask;
119305b261ecSmrgstatic int	BlockedSignalCount;
119405b261ecSmrg#endif
119505b261ecSmrg
119605b261ecSmrgvoid
119705b261ecSmrgOsBlockSignals (void)
119805b261ecSmrg{
119905b261ecSmrg#ifdef SIG_BLOCK
120005b261ecSmrg    if (BlockedSignalCount++ == 0)
120105b261ecSmrg    {
120205b261ecSmrg	sigset_t    set;
120305b261ecSmrg
120405b261ecSmrg	sigemptyset (&set);
120505b261ecSmrg	sigaddset (&set, SIGALRM);
120605b261ecSmrg	sigaddset (&set, SIGVTALRM);
120705b261ecSmrg#ifdef SIGWINCH
120805b261ecSmrg	sigaddset (&set, SIGWINCH);
120905b261ecSmrg#endif
121005b261ecSmrg#ifdef SIGIO
121105b261ecSmrg	sigaddset (&set, SIGIO);
121205b261ecSmrg#endif
121305b261ecSmrg	sigaddset (&set, SIGTSTP);
121405b261ecSmrg	sigaddset (&set, SIGTTIN);
121505b261ecSmrg	sigaddset (&set, SIGTTOU);
121605b261ecSmrg	sigaddset (&set, SIGCHLD);
121705b261ecSmrg	sigprocmask (SIG_BLOCK, &set, &PreviousSignalMask);
121805b261ecSmrg    }
121905b261ecSmrg#endif
122005b261ecSmrg}
122105b261ecSmrg
122205b261ecSmrgvoid
122305b261ecSmrgOsReleaseSignals (void)
122405b261ecSmrg{
122505b261ecSmrg#ifdef SIG_BLOCK
122605b261ecSmrg    if (--BlockedSignalCount == 0)
122705b261ecSmrg    {
122805b261ecSmrg	sigprocmask (SIG_SETMASK, &PreviousSignalMask, 0);
122905b261ecSmrg    }
123005b261ecSmrg#endif
123105b261ecSmrg}
123205b261ecSmrg
12334202a189Smrg/*
12344202a189Smrg * Pending signals may interfere with core dumping. Provide a
12354202a189Smrg * mechanism to block signals when aborting.
12364202a189Smrg */
12374202a189Smrg
12384202a189Smrgvoid
12394202a189SmrgOsAbort (void)
12404202a189Smrg{
12414202a189Smrg#ifndef __APPLE__
12424202a189Smrg    OsBlockSignals();
12434202a189Smrg#endif
12444202a189Smrg    abort();
12454202a189Smrg}
12464202a189Smrg
124705b261ecSmrg#if !defined(WIN32)
124805b261ecSmrg/*
124905b261ecSmrg * "safer" versions of system(3), popen(3) and pclose(3) which give up
125005b261ecSmrg * all privs before running a command.
125105b261ecSmrg *
125205b261ecSmrg * This is based on the code in FreeBSD 2.2 libc.
125305b261ecSmrg *
125405b261ecSmrg * XXX It'd be good to redirect stderr so that it ends up in the log file
125505b261ecSmrg * as well.  As it is now, xkbcomp messages don't end up in the log file.
125605b261ecSmrg */
125705b261ecSmrg
125805b261ecSmrgint
125905b261ecSmrgSystem(char *command)
126005b261ecSmrg{
126105b261ecSmrg    int pid, p;
126205b261ecSmrg    void (*csig)(int);
126305b261ecSmrg    int status;
126405b261ecSmrg
126505b261ecSmrg    if (!command)
12664202a189Smrg	return 1;
126705b261ecSmrg
126805b261ecSmrg    csig = signal(SIGCHLD, SIG_DFL);
126905b261ecSmrg    if (csig == SIG_ERR) {
127005b261ecSmrg      perror("signal");
127105b261ecSmrg      return -1;
127205b261ecSmrg    }
127365b04b38Smrg    DebugF("System: `%s'\n", command);
127405b261ecSmrg
127505b261ecSmrg    switch (pid = fork()) {
127605b261ecSmrg    case -1:	/* error */
127705b261ecSmrg	p = -1;
127805b261ecSmrg    case 0:	/* child */
127905b261ecSmrg	if (setgid(getgid()) == -1)
128005b261ecSmrg	    _exit(127);
128105b261ecSmrg	if (setuid(getuid()) == -1)
128205b261ecSmrg	    _exit(127);
128305b261ecSmrg	execl("/bin/sh", "sh", "-c", command, (char *)NULL);
128405b261ecSmrg	_exit(127);
128505b261ecSmrg    default:	/* parent */
128605b261ecSmrg	do {
128705b261ecSmrg	    p = waitpid(pid, &status, 0);
128805b261ecSmrg	} while (p == -1 && errno == EINTR);
128905b261ecSmrg
129005b261ecSmrg    }
129105b261ecSmrg
129205b261ecSmrg    if (signal(SIGCHLD, csig) == SIG_ERR) {
129305b261ecSmrg      perror("signal");
129405b261ecSmrg      return -1;
129505b261ecSmrg    }
129605b261ecSmrg
129705b261ecSmrg    return p == -1 ? -1 : status;
129805b261ecSmrg}
129905b261ecSmrg
130005b261ecSmrgstatic struct pid {
130105b261ecSmrg    struct pid *next;
130205b261ecSmrg    FILE *fp;
130305b261ecSmrg    int pid;
130405b261ecSmrg} *pidlist;
130505b261ecSmrg
13064642e01fSmrgOsSigHandlerPtr old_alarm = NULL; /* XXX horrible awful hack */
130705b261ecSmrg
130805b261ecSmrgpointer
130905b261ecSmrgPopen(char *command, char *type)
131005b261ecSmrg{
131105b261ecSmrg    struct pid *cur;
131205b261ecSmrg    FILE *iop;
131305b261ecSmrg    int pdes[2], pid;
131405b261ecSmrg
131505b261ecSmrg    if (command == NULL || type == NULL)
131605b261ecSmrg	return NULL;
131705b261ecSmrg
131805b261ecSmrg    if ((*type != 'r' && *type != 'w') || type[1])
131905b261ecSmrg	return NULL;
132005b261ecSmrg
13214202a189Smrg    if ((cur = malloc(sizeof(struct pid))) == NULL)
132205b261ecSmrg	return NULL;
132305b261ecSmrg
132405b261ecSmrg    if (pipe(pdes) < 0) {
13254202a189Smrg	free(cur);
132605b261ecSmrg	return NULL;
132705b261ecSmrg    }
132805b261ecSmrg
132905b261ecSmrg    /* Ignore the smart scheduler while this is going on */
13304642e01fSmrg    old_alarm = OsSignal(SIGALRM, SIG_IGN);
133105b261ecSmrg    if (old_alarm == SIG_ERR) {
133265b04b38Smrg      close(pdes[0]);
133365b04b38Smrg      close(pdes[1]);
133465b04b38Smrg      free(cur);
133505b261ecSmrg      perror("signal");
133605b261ecSmrg      return NULL;
133705b261ecSmrg    }
133805b261ecSmrg
133905b261ecSmrg    switch (pid = fork()) {
134005b261ecSmrg    case -1: 	/* error */
134105b261ecSmrg	close(pdes[0]);
134205b261ecSmrg	close(pdes[1]);
13434202a189Smrg	free(cur);
13444642e01fSmrg	if (OsSignal(SIGALRM, old_alarm) == SIG_ERR)
134505b261ecSmrg	  perror("signal");
134605b261ecSmrg	return NULL;
134705b261ecSmrg    case 0:	/* child */
134805b261ecSmrg	if (setgid(getgid()) == -1)
134905b261ecSmrg	    _exit(127);
135005b261ecSmrg	if (setuid(getuid()) == -1)
135105b261ecSmrg	    _exit(127);
135205b261ecSmrg	if (*type == 'r') {
135305b261ecSmrg	    if (pdes[1] != 1) {
135405b261ecSmrg		/* stdout */
135505b261ecSmrg		dup2(pdes[1], 1);
135605b261ecSmrg		close(pdes[1]);
135705b261ecSmrg	    }
135805b261ecSmrg	    close(pdes[0]);
135905b261ecSmrg	} else {
136005b261ecSmrg	    if (pdes[0] != 0) {
136105b261ecSmrg		/* stdin */
136205b261ecSmrg		dup2(pdes[0], 0);
136305b261ecSmrg		close(pdes[0]);
136405b261ecSmrg	    }
136505b261ecSmrg	    close(pdes[1]);
136605b261ecSmrg	}
136705b261ecSmrg	execl("/bin/sh", "sh", "-c", command, (char *)NULL);
136805b261ecSmrg	_exit(127);
136905b261ecSmrg    }
137005b261ecSmrg
137105b261ecSmrg    /* Avoid EINTR during stdio calls */
137205b261ecSmrg    OsBlockSignals ();
137305b261ecSmrg
137405b261ecSmrg    /* parent */
137505b261ecSmrg    if (*type == 'r') {
137605b261ecSmrg	iop = fdopen(pdes[0], type);
137705b261ecSmrg	close(pdes[1]);
137805b261ecSmrg    } else {
137905b261ecSmrg	iop = fdopen(pdes[1], type);
138005b261ecSmrg	close(pdes[0]);
138105b261ecSmrg    }
138205b261ecSmrg
138305b261ecSmrg    cur->fp = iop;
138405b261ecSmrg    cur->pid = pid;
138505b261ecSmrg    cur->next = pidlist;
138605b261ecSmrg    pidlist = cur;
138705b261ecSmrg
138865b04b38Smrg    DebugF("Popen: `%s', fp = %p\n", command, iop);
138905b261ecSmrg
139005b261ecSmrg    return iop;
139105b261ecSmrg}
139205b261ecSmrg
139305b261ecSmrg/* fopen that drops privileges */
139405b261ecSmrgpointer
139505b261ecSmrgFopen(char *file, char *type)
139605b261ecSmrg{
139705b261ecSmrg    FILE *iop;
139805b261ecSmrg#ifndef HAS_SAVED_IDS_AND_SETEUID
139905b261ecSmrg    struct pid *cur;
140005b261ecSmrg    int pdes[2], pid;
140105b261ecSmrg
140205b261ecSmrg    if (file == NULL || type == NULL)
140305b261ecSmrg	return NULL;
140405b261ecSmrg
140505b261ecSmrg    if ((*type != 'r' && *type != 'w') || type[1])
140605b261ecSmrg	return NULL;
140705b261ecSmrg
14084202a189Smrg    if ((cur = malloc(sizeof(struct pid))) == NULL)
140905b261ecSmrg	return NULL;
141005b261ecSmrg
141105b261ecSmrg    if (pipe(pdes) < 0) {
14124202a189Smrg	free(cur);
141305b261ecSmrg	return NULL;
141405b261ecSmrg    }
141505b261ecSmrg
141605b261ecSmrg    switch (pid = fork()) {
141705b261ecSmrg    case -1: 	/* error */
141805b261ecSmrg	close(pdes[0]);
141905b261ecSmrg	close(pdes[1]);
14204202a189Smrg	free(cur);
142105b261ecSmrg	return NULL;
142205b261ecSmrg    case 0:	/* child */
142305b261ecSmrg	if (setgid(getgid()) == -1)
142405b261ecSmrg	    _exit(127);
142505b261ecSmrg	if (setuid(getuid()) == -1)
142605b261ecSmrg	    _exit(127);
142705b261ecSmrg	if (*type == 'r') {
142805b261ecSmrg	    if (pdes[1] != 1) {
142905b261ecSmrg		/* stdout */
143005b261ecSmrg		dup2(pdes[1], 1);
143105b261ecSmrg		close(pdes[1]);
143205b261ecSmrg	    }
143305b261ecSmrg	    close(pdes[0]);
143405b261ecSmrg	} else {
143505b261ecSmrg	    if (pdes[0] != 0) {
143605b261ecSmrg		/* stdin */
143705b261ecSmrg		dup2(pdes[0], 0);
143805b261ecSmrg		close(pdes[0]);
143905b261ecSmrg	    }
144005b261ecSmrg	    close(pdes[1]);
144105b261ecSmrg	}
144205b261ecSmrg	execl("/bin/cat", "cat", file, (char *)NULL);
144305b261ecSmrg	_exit(127);
144405b261ecSmrg    }
144505b261ecSmrg
144605b261ecSmrg    /* Avoid EINTR during stdio calls */
144705b261ecSmrg    OsBlockSignals ();
144805b261ecSmrg
144905b261ecSmrg    /* parent */
145005b261ecSmrg    if (*type == 'r') {
145105b261ecSmrg	iop = fdopen(pdes[0], type);
145205b261ecSmrg	close(pdes[1]);
145305b261ecSmrg    } else {
145405b261ecSmrg	iop = fdopen(pdes[1], type);
145505b261ecSmrg	close(pdes[0]);
145605b261ecSmrg    }
145705b261ecSmrg
145805b261ecSmrg    cur->fp = iop;
145905b261ecSmrg    cur->pid = pid;
146005b261ecSmrg    cur->next = pidlist;
146105b261ecSmrg    pidlist = cur;
146205b261ecSmrg
146365b04b38Smrg    DebugF("Fopen(%s), fp = %p\n", file, iop);
146405b261ecSmrg
146505b261ecSmrg    return iop;
146605b261ecSmrg#else
146705b261ecSmrg    int ruid, euid;
146805b261ecSmrg
146905b261ecSmrg    ruid = getuid();
147005b261ecSmrg    euid = geteuid();
147105b261ecSmrg
147205b261ecSmrg    if (seteuid(ruid) == -1) {
147305b261ecSmrg	    return NULL;
147405b261ecSmrg    }
147505b261ecSmrg    iop = fopen(file, type);
147605b261ecSmrg
147705b261ecSmrg    if (seteuid(euid) == -1) {
147805b261ecSmrg	    fclose(iop);
147905b261ecSmrg	    return NULL;
148005b261ecSmrg    }
148105b261ecSmrg    return iop;
148205b261ecSmrg#endif /* HAS_SAVED_IDS_AND_SETEUID */
148305b261ecSmrg}
148405b261ecSmrg
148505b261ecSmrgint
148605b261ecSmrgPclose(pointer iop)
148705b261ecSmrg{
148805b261ecSmrg    struct pid *cur, *last;
148905b261ecSmrg    int pstat;
149005b261ecSmrg    int pid;
149105b261ecSmrg
149265b04b38Smrg    DebugF("Pclose: fp = %p\n", iop);
149305b261ecSmrg    fclose(iop);
149405b261ecSmrg
149505b261ecSmrg    for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
149605b261ecSmrg	if (cur->fp == iop)
149705b261ecSmrg	    break;
149805b261ecSmrg    if (cur == NULL)
149905b261ecSmrg	return -1;
150005b261ecSmrg
150105b261ecSmrg    do {
150205b261ecSmrg	pid = waitpid(cur->pid, &pstat, 0);
150305b261ecSmrg    } while (pid == -1 && errno == EINTR);
150405b261ecSmrg
150505b261ecSmrg    if (last == NULL)
150605b261ecSmrg	pidlist = cur->next;
150705b261ecSmrg    else
150805b261ecSmrg	last->next = cur->next;
15094202a189Smrg    free(cur);
151005b261ecSmrg
151105b261ecSmrg    /* allow EINTR again */
151205b261ecSmrg    OsReleaseSignals ();
151305b261ecSmrg
15144642e01fSmrg    if (old_alarm && OsSignal(SIGALRM, old_alarm) == SIG_ERR) {
151505b261ecSmrg      perror("signal");
151605b261ecSmrg      return -1;
151705b261ecSmrg    }
151805b261ecSmrg
151905b261ecSmrg    return pid == -1 ? -1 : pstat;
152005b261ecSmrg}
152105b261ecSmrg
15224202a189Smrgint
152305b261ecSmrgFclose(pointer iop)
152405b261ecSmrg{
152505b261ecSmrg#ifdef HAS_SAVED_IDS_AND_SETEUID
152605b261ecSmrg    return fclose(iop);
152705b261ecSmrg#else
152805b261ecSmrg    return Pclose(iop);
152905b261ecSmrg#endif
153005b261ecSmrg}
153105b261ecSmrg
153205b261ecSmrg#endif /* !WIN32 */
153305b261ecSmrg
153405b261ecSmrg
153505b261ecSmrg/*
153605b261ecSmrg * CheckUserParameters: check for long command line arguments and long
153705b261ecSmrg * environment variables.  By default, these checks are only done when
153805b261ecSmrg * the server's euid != ruid.  In 3.3.x, these checks were done in an
153905b261ecSmrg * external wrapper utility.
154005b261ecSmrg */
154105b261ecSmrg
154205b261ecSmrg/* Consider LD* variables insecure? */
154305b261ecSmrg#ifndef REMOVE_ENV_LD
154405b261ecSmrg#define REMOVE_ENV_LD 1
154505b261ecSmrg#endif
154605b261ecSmrg
154705b261ecSmrg/* Remove long environment variables? */
154805b261ecSmrg#ifndef REMOVE_LONG_ENV
154905b261ecSmrg#define REMOVE_LONG_ENV 1
155005b261ecSmrg#endif
155105b261ecSmrg
155205b261ecSmrg/*
155305b261ecSmrg * Disallow stdout or stderr as pipes?  It's possible to block the X server
155405b261ecSmrg * when piping stdout+stderr to a pipe.
155505b261ecSmrg *
155605b261ecSmrg * Don't enable this because it looks like it's going to cause problems.
155705b261ecSmrg */
155805b261ecSmrg#ifndef NO_OUTPUT_PIPES
155905b261ecSmrg#define NO_OUTPUT_PIPES 0
156005b261ecSmrg#endif
156105b261ecSmrg
156205b261ecSmrg
156305b261ecSmrg/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
156405b261ecSmrg#ifndef CHECK_EUID
156505b261ecSmrg#ifndef WIN32
156605b261ecSmrg#define CHECK_EUID 1
156705b261ecSmrg#else
156805b261ecSmrg#define CHECK_EUID 0
156905b261ecSmrg#endif
157005b261ecSmrg#endif
157105b261ecSmrg
157205b261ecSmrg/*
157305b261ecSmrg * Maybe the locale can be faked to make isprint(3) report that everything
157405b261ecSmrg * is printable?  Avoid it by default.
157505b261ecSmrg */
157605b261ecSmrg#ifndef USE_ISPRINT
157705b261ecSmrg#define USE_ISPRINT 0
157805b261ecSmrg#endif
157905b261ecSmrg
158005b261ecSmrg#define MAX_ARG_LENGTH          128
158105b261ecSmrg#define MAX_ENV_LENGTH          256
158205b261ecSmrg#define MAX_ENV_PATH_LENGTH     2048	/* Limit for *PATH and TERMCAP */
158305b261ecSmrg
158405b261ecSmrg#if USE_ISPRINT
158505b261ecSmrg#include <ctype.h>
158605b261ecSmrg#define checkPrintable(c) isprint(c)
158705b261ecSmrg#else
158805b261ecSmrg#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
158905b261ecSmrg#endif
159005b261ecSmrg
159105b261ecSmrgenum BadCode {
159205b261ecSmrg    NotBad = 0,
159305b261ecSmrg    UnsafeArg,
159405b261ecSmrg    ArgTooLong,
159505b261ecSmrg    UnprintableArg,
159605b261ecSmrg    EnvTooLong,
159705b261ecSmrg    OutputIsPipe,
159805b261ecSmrg    InternalError
159905b261ecSmrg};
160005b261ecSmrg
160105b261ecSmrg#if defined(VENDORSUPPORT)
160205b261ecSmrg#define BUGADDRESS VENDORSUPPORT
160305b261ecSmrg#elif defined(BUILDERADDR)
160405b261ecSmrg#define BUGADDRESS BUILDERADDR
160505b261ecSmrg#else
160605b261ecSmrg#define BUGADDRESS "xorg@freedesktop.org"
160705b261ecSmrg#endif
160805b261ecSmrg
160905b261ecSmrgvoid
161005b261ecSmrgCheckUserParameters(int argc, char **argv, char **envp)
161105b261ecSmrg{
161205b261ecSmrg    enum BadCode bad = NotBad;
161305b261ecSmrg    int i = 0, j;
161405b261ecSmrg    char *a, *e = NULL;
161505b261ecSmrg
161605b261ecSmrg#if CHECK_EUID
161705b261ecSmrg    if (geteuid() == 0 && getuid() != geteuid())
161805b261ecSmrg#endif
161905b261ecSmrg    {
162005b261ecSmrg	/* Check each argv[] */
162105b261ecSmrg	for (i = 1; i < argc; i++) {
162205b261ecSmrg	    if (strcmp(argv[i], "-fp") == 0)
162305b261ecSmrg	    {
162405b261ecSmrg		i++; /* continue with next argument. skip the length check */
162505b261ecSmrg		if (i >= argc)
162605b261ecSmrg		    break;
162705b261ecSmrg	    } else
162805b261ecSmrg	    {
162905b261ecSmrg		if (strlen(argv[i]) > MAX_ARG_LENGTH) {
163005b261ecSmrg		    bad = ArgTooLong;
163105b261ecSmrg		    break;
163205b261ecSmrg		}
163305b261ecSmrg	    }
163405b261ecSmrg	    a = argv[i];
163505b261ecSmrg	    while (*a) {
163605b261ecSmrg		if (checkPrintable(*a) == 0) {
163705b261ecSmrg		    bad = UnprintableArg;
163805b261ecSmrg		    break;
163905b261ecSmrg		}
164005b261ecSmrg		a++;
164105b261ecSmrg	    }
164205b261ecSmrg	    if (bad)
164305b261ecSmrg		break;
164405b261ecSmrg	}
164505b261ecSmrg	if (!bad) {
164605b261ecSmrg	    /* Check each envp[] */
164705b261ecSmrg	    for (i = 0; envp[i]; i++) {
164805b261ecSmrg
164905b261ecSmrg		/* Check for bad environment variables and values */
165005b261ecSmrg#if REMOVE_ENV_LD
165105b261ecSmrg		while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
165205b261ecSmrg		    for (j = i; envp[j]; j++) {
165305b261ecSmrg			envp[j] = envp[j+1];
165405b261ecSmrg		    }
165505b261ecSmrg		}
165605b261ecSmrg#endif
165705b261ecSmrg		if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
165805b261ecSmrg#if REMOVE_LONG_ENV
165905b261ecSmrg		    for (j = i; envp[j]; j++) {
166005b261ecSmrg			envp[j] = envp[j+1];
166105b261ecSmrg		    }
166205b261ecSmrg		    i--;
166305b261ecSmrg#else
166405b261ecSmrg		    char *eq;
166505b261ecSmrg		    int len;
166605b261ecSmrg
166705b261ecSmrg		    eq = strchr(envp[i], '=');
166805b261ecSmrg		    if (!eq)
166905b261ecSmrg			continue;
167005b261ecSmrg		    len = eq - envp[i];
167105b261ecSmrg		    e = malloc(len + 1);
167205b261ecSmrg		    if (!e) {
167305b261ecSmrg			bad = InternalError;
167405b261ecSmrg			break;
167505b261ecSmrg		    }
167605b261ecSmrg		    strncpy(e, envp[i], len);
167705b261ecSmrg		    e[len] = 0;
167805b261ecSmrg		    if (len >= 4 &&
167905b261ecSmrg			(strcmp(e + len - 4, "PATH") == 0 ||
168005b261ecSmrg			 strcmp(e, "TERMCAP") == 0)) {
168105b261ecSmrg			if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
168205b261ecSmrg			    bad = EnvTooLong;
168305b261ecSmrg			    break;
168405b261ecSmrg			} else {
168505b261ecSmrg			    free(e);
168605b261ecSmrg			}
168705b261ecSmrg		    } else {
168805b261ecSmrg			bad = EnvTooLong;
168905b261ecSmrg			break;
169005b261ecSmrg		    }
169105b261ecSmrg#endif
169205b261ecSmrg		}
169305b261ecSmrg	    }
169405b261ecSmrg	}
169505b261ecSmrg#if NO_OUTPUT_PIPES
169605b261ecSmrg	if (!bad) {
169705b261ecSmrg	    struct stat buf;
169805b261ecSmrg
169905b261ecSmrg	    if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode))
170005b261ecSmrg		bad = OutputIsPipe;
170105b261ecSmrg	    if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode))
170205b261ecSmrg		bad = OutputIsPipe;
170305b261ecSmrg	}
170405b261ecSmrg#endif
170505b261ecSmrg    }
170605b261ecSmrg    switch (bad) {
170705b261ecSmrg    case NotBad:
170805b261ecSmrg	return;
170905b261ecSmrg    case UnsafeArg:
171005b261ecSmrg	ErrorF("Command line argument number %d is unsafe\n", i);
171105b261ecSmrg	break;
171205b261ecSmrg    case ArgTooLong:
171305b261ecSmrg	ErrorF("Command line argument number %d is too long\n", i);
171405b261ecSmrg	break;
171505b261ecSmrg    case UnprintableArg:
171605b261ecSmrg	ErrorF("Command line argument number %d contains unprintable"
171705b261ecSmrg		" characters\n", i);
171805b261ecSmrg	break;
171905b261ecSmrg    case EnvTooLong:
172005b261ecSmrg	ErrorF("Environment variable `%s' is too long\n", e);
172105b261ecSmrg	break;
172205b261ecSmrg    case OutputIsPipe:
172305b261ecSmrg	ErrorF("Stdout and/or stderr is a pipe\n");
172405b261ecSmrg	break;
172505b261ecSmrg    case InternalError:
172605b261ecSmrg	ErrorF("Internal Error\n");
172705b261ecSmrg	break;
172805b261ecSmrg    default:
172905b261ecSmrg	ErrorF("Unknown error\n");
173005b261ecSmrg	break;
173105b261ecSmrg    }
173205b261ecSmrg    FatalError("X server aborted because of unsafe environment\n");
173305b261ecSmrg}
173405b261ecSmrg
173505b261ecSmrg/*
173605b261ecSmrg * CheckUserAuthorization: check if the user is allowed to start the
173705b261ecSmrg * X server.  This usually means some sort of PAM checking, and it is
173805b261ecSmrg * usually only done for setuid servers (uid != euid).
173905b261ecSmrg */
174005b261ecSmrg
174105b261ecSmrg#ifdef USE_PAM
174205b261ecSmrg#include <security/pam_appl.h>
174305b261ecSmrg#include <security/pam_misc.h>
174405b261ecSmrg#include <pwd.h>
174505b261ecSmrg#endif /* USE_PAM */
174605b261ecSmrg
174705b261ecSmrgvoid
174805b261ecSmrgCheckUserAuthorization(void)
174905b261ecSmrg{
175005b261ecSmrg#ifdef USE_PAM
175105b261ecSmrg    static struct pam_conv conv = {
175205b261ecSmrg	misc_conv,
175305b261ecSmrg	NULL
175405b261ecSmrg    };
175505b261ecSmrg
175605b261ecSmrg    pam_handle_t *pamh = NULL;
175705b261ecSmrg    struct passwd *pw;
175805b261ecSmrg    int retval;
175905b261ecSmrg
176005b261ecSmrg    if (getuid() != geteuid()) {
176105b261ecSmrg	pw = getpwuid(getuid());
176205b261ecSmrg	if (pw == NULL)
176305b261ecSmrg	    FatalError("getpwuid() failed for uid %d\n", getuid());
176405b261ecSmrg
176505b261ecSmrg	retval = pam_start("xserver", pw->pw_name, &conv, &pamh);
176605b261ecSmrg	if (retval != PAM_SUCCESS)
176705b261ecSmrg	    FatalError("pam_start() failed.\n"
176805b261ecSmrg			"\tMissing or mangled PAM config file or module?\n");
176905b261ecSmrg
177005b261ecSmrg	retval = pam_authenticate(pamh, 0);
177105b261ecSmrg	if (retval != PAM_SUCCESS) {
177205b261ecSmrg	    pam_end(pamh, retval);
177305b261ecSmrg	    FatalError("PAM authentication failed, cannot start X server.\n"
177405b261ecSmrg			"\tPerhaps you do not have console ownership?\n");
177505b261ecSmrg	}
177605b261ecSmrg
177705b261ecSmrg	retval = pam_acct_mgmt(pamh, 0);
177805b261ecSmrg	if (retval != PAM_SUCCESS) {
177905b261ecSmrg	    pam_end(pamh, retval);
178005b261ecSmrg	    FatalError("PAM authentication failed, cannot start X server.\n"
178105b261ecSmrg			"\tPerhaps you do not have console ownership?\n");
178205b261ecSmrg	}
178305b261ecSmrg
178405b261ecSmrg	/* this is not a session, so do not do session management */
178505b261ecSmrg	pam_end(pamh, PAM_SUCCESS);
178605b261ecSmrg    }
178705b261ecSmrg#endif
178805b261ecSmrg}
178905b261ecSmrg
17904202a189Smrg/*
17914202a189Smrg * Tokenize a string into a NULL terminated array of strings. Always returns
17924202a189Smrg * an allocated array unless an error occurs.
17934202a189Smrg */
17944202a189Smrgchar**
17954202a189Smrgxstrtokenize(const char *str, const char *separators)
179605b261ecSmrg{
17974202a189Smrg    char **list, **nlist;
17984202a189Smrg    char *tok, *tmp;
17994202a189Smrg    unsigned num = 0, n;
180005b261ecSmrg
18014202a189Smrg    if (!str)
18024202a189Smrg        return NULL;
18034202a189Smrg    list = calloc(1, sizeof(*list));
18044202a189Smrg    if (!list)
18054202a189Smrg        return NULL;
18064202a189Smrg    tmp = strdup(str);
18074202a189Smrg    if (!tmp)
18084202a189Smrg        goto error;
18094202a189Smrg    for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) {
18104202a189Smrg        nlist = realloc(list, (num + 2) * sizeof(*list));
18114202a189Smrg        if (!nlist)
18124202a189Smrg            goto error;
18134202a189Smrg        list = nlist;
18144202a189Smrg        list[num] = strdup(tok);
18154202a189Smrg        if (!list[num])
18164202a189Smrg            goto error;
18174202a189Smrg        list[++num] = NULL;
18184202a189Smrg    }
18194202a189Smrg    free(tmp);
18204202a189Smrg    return list;
18214202a189Smrg
18224202a189Smrgerror:
18234202a189Smrg    free(tmp);
18244202a189Smrg    for (n = 0; n < num; n++)
18254202a189Smrg        free(list[n]);
18264202a189Smrg    free(list);
18274202a189Smrg    return NULL;
182805b261ecSmrg}
1829