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