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