utils.c revision 5a112b11
105b261ecSmrg/* 205b261ecSmrg 305b261ecSmrgCopyright 1987, 1998 The Open Group 405b261ecSmrg 505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its 605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that 705b261ecSmrgthe above copyright notice appear in all copies and that both that 805b261ecSmrgcopyright notice and this permission notice appear in supporting 905b261ecSmrgdocumentation. 1005b261ecSmrg 1105b261ecSmrgThe above copyright notice and this permission notice shall be included 1205b261ecSmrgin all copies or substantial portions of the Software. 1305b261ecSmrg 1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1505b261ecSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1605b261ecSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 1705b261ecSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 1805b261ecSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1905b261ecSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2005b261ecSmrgOTHER DEALINGS IN THE SOFTWARE. 2105b261ecSmrg 2205b261ecSmrgExcept as contained in this notice, the name of The Open Group shall 2305b261ecSmrgnot be used in advertising or otherwise to promote the sale, use or 2405b261ecSmrgother dealings in this Software without prior written authorization 2505b261ecSmrgfrom The Open Group. 2605b261ecSmrg 2705b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, 2805b261ecSmrgCopyright 1994 Quarterdeck Office Systems. 2905b261ecSmrg 3005b261ecSmrg All Rights Reserved 3105b261ecSmrg 3205b261ecSmrgPermission to use, copy, modify, and distribute this software and its 3305b261ecSmrgdocumentation for any purpose and without fee is hereby granted, 3405b261ecSmrgprovided that the above copyright notice appear in all copies and that 3505b261ecSmrgboth that copyright notice and this permission notice appear in 3605b261ecSmrgsupporting documentation, and that the names of Digital and 3705b261ecSmrgQuarterdeck not be used in advertising or publicity pertaining to 3805b261ecSmrgdistribution of the software without specific, written prior 3905b261ecSmrgpermission. 4005b261ecSmrg 4105b261ecSmrgDIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 4205b261ecSmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 4305b261ecSmrgFITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT 4405b261ecSmrgOR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 4505b261ecSmrgOF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 4605b261ecSmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE 4705b261ecSmrgOR PERFORMANCE OF THIS SOFTWARE. 4805b261ecSmrg 4905b261ecSmrg*/ 5005b261ecSmrg 5105b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 5205b261ecSmrg#include <dix-config.h> 5305b261ecSmrg#endif 5405b261ecSmrg 5505b261ecSmrg#ifdef __CYGWIN__ 5605b261ecSmrg#include <stdlib.h> 5705b261ecSmrg#include <signal.h> 584202a189Smrg/* 594202a189Smrg Sigh... We really need a prototype for this to know it is stdcall, 604202a189Smrg but #include-ing <windows.h> here is not a good idea... 614202a189Smrg*/ 624202a189Smrg__stdcall unsigned long GetTickCount(void); 6305b261ecSmrg#endif 6405b261ecSmrg 6505b261ecSmrg#if defined(WIN32) && !defined(__CYGWIN__) 6605b261ecSmrg#include <X11/Xwinsock.h> 6705b261ecSmrg#endif 6805b261ecSmrg#include <X11/Xos.h> 6905b261ecSmrg#include <stdio.h> 7005b261ecSmrg#include <time.h> 7105b261ecSmrg#if !defined(WIN32) || !defined(__MINGW32__) 7205b261ecSmrg#include <sys/time.h> 7305b261ecSmrg#include <sys/resource.h> 7405b261ecSmrg#endif 7505b261ecSmrg#include "misc.h" 7605b261ecSmrg#include <X11/X.h> 7705b261ecSmrg#define XSERV_t 7805b261ecSmrg#define TRANS_SERVER 7905b261ecSmrg#define TRANS_REOPEN 8005b261ecSmrg#include <X11/Xtrans/Xtrans.h> 8105b261ecSmrg#include "input.h" 8205b261ecSmrg#include "dixfont.h" 837e31ba66Smrg#include <X11/fonts/libxfont2.h> 8405b261ecSmrg#include "osdep.h" 8505b261ecSmrg#include "extension.h" 8605b261ecSmrg#include <signal.h> 8705b261ecSmrg#ifndef WIN32 8805b261ecSmrg#include <sys/wait.h> 8905b261ecSmrg#endif 90f7df2e56Smrg#if !defined(SYSV) && !defined(WIN32) 9105b261ecSmrg#include <sys/resource.h> 9205b261ecSmrg#endif 9305b261ecSmrg#include <sys/stat.h> 94f7df2e56Smrg#include <ctype.h> /* for isspace */ 9505b261ecSmrg#include <stdarg.h> 9605b261ecSmrg 97f7df2e56Smrg#include <stdlib.h> /* for malloc() */ 9805b261ecSmrg 997e31ba66Smrg#if defined(TCPCONN) 100f7df2e56Smrg#ifndef WIN32 101f7df2e56Smrg#include <netdb.h> 102f7df2e56Smrg#endif 10305b261ecSmrg#endif 10405b261ecSmrg 10505b261ecSmrg#include "opaque.h" 10605b261ecSmrg 10705b261ecSmrg#include "dixstruct.h" 10805b261ecSmrg 1094202a189Smrg#include "xkbsrv.h" 11005b261ecSmrg 11105b261ecSmrg#include "picture.h" 11205b261ecSmrg 1135a112b11Smrg#include "miinitext.h" 1145a112b11Smrg 1155a112b11Smrg#include "present.h" 1165a112b11Smrg 1174202a189SmrgBool noTestExtensions; 118f7df2e56Smrg 11905b261ecSmrg#ifdef COMPOSITE 1204202a189SmrgBool noCompositeExtension = FALSE; 12105b261ecSmrg#endif 12205b261ecSmrg 12305b261ecSmrg#ifdef DAMAGE 1244202a189SmrgBool noDamageExtension = FALSE; 12505b261ecSmrg#endif 12605b261ecSmrg#ifdef DBE 1274202a189SmrgBool noDbeExtension = FALSE; 12805b261ecSmrg#endif 12905b261ecSmrg#ifdef DPMSExtension 1307e31ba66Smrg#include "dpmsproc.h" 1314202a189SmrgBool noDPMSExtension = FALSE; 13205b261ecSmrg#endif 13305b261ecSmrg#ifdef GLXEXT 1344202a189SmrgBool noGlxExtension = FALSE; 13505b261ecSmrg#endif 13605b261ecSmrg#ifdef SCREENSAVER 1374202a189SmrgBool noScreenSaverExtension = FALSE; 13805b261ecSmrg#endif 13905b261ecSmrg#ifdef MITSHM 1404202a189SmrgBool noMITShmExtension = FALSE; 14105b261ecSmrg#endif 14205b261ecSmrg#ifdef RANDR 1434202a189SmrgBool noRRExtension = FALSE; 14405b261ecSmrg#endif 1454202a189SmrgBool noRenderExtension = FALSE; 146f7df2e56Smrg 14705b261ecSmrg#ifdef XCSECURITY 1484202a189SmrgBool noSecurityExtension = FALSE; 14905b261ecSmrg#endif 15005b261ecSmrg#ifdef RES 1514202a189SmrgBool noResExtension = FALSE; 15205b261ecSmrg#endif 15305b261ecSmrg#ifdef XF86BIGFONT 1544202a189SmrgBool noXFree86BigfontExtension = FALSE; 15505b261ecSmrg#endif 15605b261ecSmrg#ifdef XFreeXDGA 1574202a189SmrgBool noXFree86DGAExtension = FALSE; 15805b261ecSmrg#endif 15905b261ecSmrg#ifdef XF86DRI 1604202a189SmrgBool noXFree86DRIExtension = FALSE; 16105b261ecSmrg#endif 16205b261ecSmrg#ifdef XF86VIDMODE 1634202a189SmrgBool noXFree86VidModeExtension = FALSE; 16405b261ecSmrg#endif 1654202a189SmrgBool noXFixesExtension = FALSE; 16605b261ecSmrg#ifdef PANORAMIX 16705b261ecSmrg/* Xinerama is disabled by default unless enabled via +xinerama */ 1684202a189SmrgBool noPanoramiXExtension = TRUE; 16905b261ecSmrg#endif 1704642e01fSmrg#ifdef XSELINUX 1714202a189SmrgBool noSELinuxExtension = FALSE; 1724202a189Smrgint selinuxEnforcingState = SELINUX_MODE_DEFAULT; 17305b261ecSmrg#endif 17405b261ecSmrg#ifdef XV 1754202a189SmrgBool noXvExtension = FALSE; 17605b261ecSmrg#endif 1774642e01fSmrg#ifdef DRI2 1784202a189SmrgBool noDRI2Extension = FALSE; 1794642e01fSmrg#endif 1804642e01fSmrg 1814202a189SmrgBool noGEExtension = FALSE; 18205b261ecSmrg 18305b261ecSmrg#define X_INCLUDE_NETDB_H 18405b261ecSmrg#include <X11/Xos_r.h> 18505b261ecSmrg 18605b261ecSmrg#include <errno.h> 18705b261ecSmrg 18805b261ecSmrgBool CoreDump; 18905b261ecSmrg 190f7df2e56SmrgBool enableIndirectGLX = FALSE; 191f7df2e56Smrg 19205b261ecSmrg#ifdef PANORAMIX 19305b261ecSmrgBool PanoramiXExtensionDisabledHack = FALSE; 19405b261ecSmrg#endif 19505b261ecSmrg 19605b261ecSmrgint auditTrailLevel = 1; 19705b261ecSmrg 198f7df2e56Smrgchar *SeatId = NULL; 199f7df2e56Smrg 200f7df2e56Smrgsig_atomic_t inSignalContext = FALSE; 201f7df2e56Smrg 20205b261ecSmrg#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED) 20305b261ecSmrg#define HAS_SAVED_IDS_AND_SETEUID 20405b261ecSmrg#endif 20505b261ecSmrg 2067e31ba66Smrg#ifdef MONOTONIC_CLOCK 2077e31ba66Smrgstatic clockid_t clockid; 2087e31ba66Smrg#endif 2097e31ba66Smrg 21005b261ecSmrgOsSigHandlerPtr 2114202a189SmrgOsSignal(int sig, OsSigHandlerPtr handler) 21205b261ecSmrg{ 213f7df2e56Smrg#if defined(WIN32) && !defined(__CYGWIN__) 214f7df2e56Smrg return signal(sig, handler); 215f7df2e56Smrg#else 21605b261ecSmrg struct sigaction act, oact; 21705b261ecSmrg 21805b261ecSmrg sigemptyset(&act.sa_mask); 21905b261ecSmrg if (handler != SIG_IGN) 220f7df2e56Smrg sigaddset(&act.sa_mask, sig); 22105b261ecSmrg act.sa_flags = 0; 22205b261ecSmrg act.sa_handler = handler; 22305b261ecSmrg if (sigaction(sig, &act, &oact)) 224f7df2e56Smrg perror("sigaction"); 22505b261ecSmrg return oact.sa_handler; 226f7df2e56Smrg#endif 22705b261ecSmrg} 2284642e01fSmrg 22905b261ecSmrg/* 23005b261ecSmrg * Explicit support for a server lock file like the ones used for UUCP. 23105b261ecSmrg * For architectures with virtual terminals that can run more than one 23205b261ecSmrg * server at a time. This keeps the servers from stomping on each other 23305b261ecSmrg * if the user forgets to give them different display numbers. 23405b261ecSmrg */ 23505b261ecSmrg#define LOCK_DIR "/tmp" 23605b261ecSmrg#define LOCK_TMP_PREFIX "/.tX" 23705b261ecSmrg#define LOCK_PREFIX "/.X" 23805b261ecSmrg#define LOCK_SUFFIX "-lock" 23905b261ecSmrg 240f7df2e56Smrg#if !defined(WIN32) || defined(__CYGWIN__) 241f7df2e56Smrg#define LOCK_SERVER 24205b261ecSmrg#endif 24305b261ecSmrg 244f7df2e56Smrg#ifndef LOCK_SERVER 245f7df2e56Smrgvoid 246f7df2e56SmrgLockServer(void) 247f7df2e56Smrg{} 248f7df2e56Smrg 249f7df2e56Smrgvoid 250f7df2e56SmrgUnlockServer(void) 251f7df2e56Smrg{} 252f7df2e56Smrg#else /* LOCK_SERVER */ 25305b261ecSmrgstatic Bool StillLocking = FALSE; 25405b261ecSmrgstatic char LockFile[PATH_MAX]; 25505b261ecSmrgstatic Bool nolock = FALSE; 25605b261ecSmrg 25705b261ecSmrg/* 25805b261ecSmrg * LockServer -- 25905b261ecSmrg * Check if the server lock file exists. If so, check if the PID 26005b261ecSmrg * contained inside is valid. If so, then die. Otherwise, create 26105b261ecSmrg * the lock file containing the PID. 26205b261ecSmrg */ 26305b261ecSmrgvoid 26405b261ecSmrgLockServer(void) 26505b261ecSmrg{ 266f7df2e56Smrg char tmp[PATH_MAX], pid_str[12]; 267f7df2e56Smrg int lfd, i, haslock, l_pid, t; 268f7df2e56Smrg const char *tmppath = LOCK_DIR; 269f7df2e56Smrg int len; 270f7df2e56Smrg char port[20]; 271f7df2e56Smrg 272f7df2e56Smrg if (nolock || NoListenAll) 273f7df2e56Smrg return; 274f7df2e56Smrg /* 275f7df2e56Smrg * Path names 276f7df2e56Smrg */ 277f7df2e56Smrg snprintf(port, sizeof(port), "%d", atoi(display)); 278f7df2e56Smrg len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) : 279f7df2e56Smrg strlen(LOCK_TMP_PREFIX); 280f7df2e56Smrg len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1; 281f7df2e56Smrg if (len > sizeof(LockFile)) 282f7df2e56Smrg FatalError("Display name `%s' is too long\n", port); 283f7df2e56Smrg (void) sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port); 284f7df2e56Smrg (void) sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port); 285f7df2e56Smrg 286f7df2e56Smrg /* 287f7df2e56Smrg * Create a temporary file containing our PID. Attempt three times 288f7df2e56Smrg * to create the file. 289f7df2e56Smrg */ 290f7df2e56Smrg StillLocking = TRUE; 29105b261ecSmrg i = 0; 29205b261ecSmrg do { 293f7df2e56Smrg i++; 294f7df2e56Smrg lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); 295f7df2e56Smrg if (lfd < 0) 296f7df2e56Smrg sleep(2); 297f7df2e56Smrg else 298f7df2e56Smrg break; 29905b261ecSmrg } while (i < 3); 300f7df2e56Smrg if (lfd < 0) { 30105b261ecSmrg unlink(tmp); 302f7df2e56Smrg i = 0; 303f7df2e56Smrg do { 304f7df2e56Smrg i++; 305f7df2e56Smrg lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); 306f7df2e56Smrg if (lfd < 0) 307f7df2e56Smrg sleep(2); 308f7df2e56Smrg else 309f7df2e56Smrg break; 310f7df2e56Smrg } while (i < 3); 31105b261ecSmrg } 312f7df2e56Smrg if (lfd < 0) 313f7df2e56Smrg FatalError("Could not create lock file in %s\n", tmp); 3147e31ba66Smrg snprintf(pid_str, sizeof(pid_str), "%10lu\n", (unsigned long) getpid()); 315f7df2e56Smrg if (write(lfd, pid_str, 11) != 11) 316f7df2e56Smrg FatalError("Could not write pid to lock file in %s\n", tmp); 317f7df2e56Smrg (void) fchmod(lfd, 0444); 318f7df2e56Smrg (void) close(lfd); 319f7df2e56Smrg 320f7df2e56Smrg /* 321f7df2e56Smrg * OK. Now the tmp file exists. Try three times to move it in place 322f7df2e56Smrg * for the lock. 323f7df2e56Smrg */ 324f7df2e56Smrg i = 0; 325f7df2e56Smrg haslock = 0; 326f7df2e56Smrg while ((!haslock) && (i++ < 3)) { 327f7df2e56Smrg haslock = (link(tmp, LockFile) == 0); 328f7df2e56Smrg if (haslock) { 329f7df2e56Smrg /* 330f7df2e56Smrg * We're done. 331f7df2e56Smrg */ 332f7df2e56Smrg break; 333f7df2e56Smrg } 3345a112b11Smrg else if (errno == EEXIST) { 335f7df2e56Smrg /* 336f7df2e56Smrg * Read the pid from the existing file 337f7df2e56Smrg */ 338f7df2e56Smrg lfd = open(LockFile, O_RDONLY | O_NOFOLLOW); 339f7df2e56Smrg if (lfd < 0) { 340f7df2e56Smrg unlink(tmp); 341f7df2e56Smrg FatalError("Can't read lock file %s\n", LockFile); 342f7df2e56Smrg } 343f7df2e56Smrg pid_str[0] = '\0'; 344f7df2e56Smrg if (read(lfd, pid_str, 11) != 11) { 345f7df2e56Smrg /* 346f7df2e56Smrg * Bogus lock file. 347f7df2e56Smrg */ 348f7df2e56Smrg unlink(LockFile); 349f7df2e56Smrg close(lfd); 350f7df2e56Smrg continue; 351f7df2e56Smrg } 352f7df2e56Smrg pid_str[11] = '\0'; 353f7df2e56Smrg sscanf(pid_str, "%d", &l_pid); 354f7df2e56Smrg close(lfd); 355f7df2e56Smrg 356f7df2e56Smrg /* 357f7df2e56Smrg * Now try to kill the PID to see if it exists. 358f7df2e56Smrg */ 359f7df2e56Smrg errno = 0; 360f7df2e56Smrg t = kill(l_pid, 0); 361f7df2e56Smrg if ((t < 0) && (errno == ESRCH)) { 362f7df2e56Smrg /* 363f7df2e56Smrg * Stale lock file. 364f7df2e56Smrg */ 365f7df2e56Smrg unlink(LockFile); 366f7df2e56Smrg continue; 367f7df2e56Smrg } 368f7df2e56Smrg else if (((t < 0) && (errno == EPERM)) || (t == 0)) { 369f7df2e56Smrg /* 370f7df2e56Smrg * Process is still active. 371f7df2e56Smrg */ 372f7df2e56Smrg unlink(tmp); 373f7df2e56Smrg FatalError 374f7df2e56Smrg ("Server is already active for display %s\n%s %s\n%s\n", 375f7df2e56Smrg port, "\tIf this server is no longer running, remove", 376f7df2e56Smrg LockFile, "\tand start again."); 377f7df2e56Smrg } 378f7df2e56Smrg } 3795a112b11Smrg else { 3805a112b11Smrg unlink(tmp); 3815a112b11Smrg FatalError 3825a112b11Smrg ("Linking lock file (%s) in place failed: %s\n", 3835a112b11Smrg LockFile, strerror(errno)); 3845a112b11Smrg } 385f7df2e56Smrg } 386f7df2e56Smrg unlink(tmp); 387f7df2e56Smrg if (!haslock) 388f7df2e56Smrg FatalError("Could not create server lock file: %s\n", LockFile); 389f7df2e56Smrg StillLocking = FALSE; 39005b261ecSmrg} 39105b261ecSmrg 39205b261ecSmrg/* 39305b261ecSmrg * UnlockServer -- 39405b261ecSmrg * Remove the server lock file. 39505b261ecSmrg */ 39605b261ecSmrgvoid 39705b261ecSmrgUnlockServer(void) 39805b261ecSmrg{ 399f7df2e56Smrg if (nolock || NoListenAll) 400f7df2e56Smrg return; 40105b261ecSmrg 402f7df2e56Smrg if (!StillLocking) { 40305b261ecSmrg 404f7df2e56Smrg (void) unlink(LockFile); 405f7df2e56Smrg } 40605b261ecSmrg} 407f7df2e56Smrg#endif /* LOCK_SERVER */ 40805b261ecSmrg 40905b261ecSmrg/* Force connections to close on SIGHUP from init */ 41005b261ecSmrg 4114202a189Smrgvoid 412f7df2e56SmrgAutoResetServer(int sig) 41305b261ecSmrg{ 41405b261ecSmrg int olderrno = errno; 41505b261ecSmrg 41605b261ecSmrg dispatchException |= DE_RESET; 41705b261ecSmrg isItTimeToYield = TRUE; 41805b261ecSmrg errno = olderrno; 41905b261ecSmrg} 42005b261ecSmrg 42105b261ecSmrg/* Force connections to close and then exit on SIGTERM, SIGINT */ 42205b261ecSmrg 4234202a189Smrgvoid 42405b261ecSmrgGiveUp(int sig) 42505b261ecSmrg{ 42605b261ecSmrg int olderrno = errno; 42705b261ecSmrg 42805b261ecSmrg dispatchException |= DE_TERMINATE; 42905b261ecSmrg isItTimeToYield = TRUE; 43005b261ecSmrg errno = olderrno; 43105b261ecSmrg} 43205b261ecSmrg 4337e31ba66Smrg#ifdef MONOTONIC_CLOCK 4347e31ba66Smrgvoid 4357e31ba66SmrgForceClockId(clockid_t forced_clockid) 4367e31ba66Smrg{ 4377e31ba66Smrg struct timespec tp; 4387e31ba66Smrg 4397e31ba66Smrg BUG_RETURN (clockid); 4407e31ba66Smrg 4417e31ba66Smrg clockid = forced_clockid; 4427e31ba66Smrg 4437e31ba66Smrg if (clock_gettime(clockid, &tp) != 0) { 4447e31ba66Smrg FatalError("Forced clock id failed to retrieve current time: %s\n", 4457e31ba66Smrg strerror(errno)); 4467e31ba66Smrg return; 4477e31ba66Smrg } 4487e31ba66Smrg} 4497e31ba66Smrg#endif 4507e31ba66Smrg 4514202a189Smrg#if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__) 4524202a189SmrgCARD32 453f7df2e56SmrgGetTimeInMillis(void) 454f7df2e56Smrg{ 455f7df2e56Smrg return GetTickCount(); 456f7df2e56Smrg} 457f7df2e56SmrgCARD64 458f7df2e56SmrgGetTimeInMicros(void) 45905b261ecSmrg{ 460f7df2e56Smrg return (CARD64) GetTickCount() * 1000; 46105b261ecSmrg} 46205b261ecSmrg#else 4634202a189SmrgCARD32 46405b261ecSmrgGetTimeInMillis(void) 46505b261ecSmrg{ 46605b261ecSmrg struct timeval tv; 46705b261ecSmrg 46805b261ecSmrg#ifdef MONOTONIC_CLOCK 46905b261ecSmrg struct timespec tp; 470f7df2e56Smrg 4711b684552Smrg if (!clockid) { 4721b684552Smrg#ifdef CLOCK_MONOTONIC_COARSE 4731b684552Smrg if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 && 4741b684552Smrg (tp.tv_nsec / 1000) <= 1000 && 4751b684552Smrg clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0) 4761b684552Smrg clockid = CLOCK_MONOTONIC_COARSE; 4771b684552Smrg else 4781b684552Smrg#endif 4791b684552Smrg if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) 4801b684552Smrg clockid = CLOCK_MONOTONIC; 4811b684552Smrg else 4821b684552Smrg clockid = ~0L; 4831b684552Smrg } 4841b684552Smrg if (clockid != ~0L && clock_gettime(clockid, &tp) == 0) 48505b261ecSmrg return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L); 48605b261ecSmrg#endif 48705b261ecSmrg 48805b261ecSmrg X_GETTIMEOFDAY(&tv); 489f7df2e56Smrg return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); 490f7df2e56Smrg} 491f7df2e56Smrg 492f7df2e56SmrgCARD64 493f7df2e56SmrgGetTimeInMicros(void) 494f7df2e56Smrg{ 495f7df2e56Smrg struct timeval tv; 496f7df2e56Smrg#ifdef MONOTONIC_CLOCK 497f7df2e56Smrg struct timespec tp; 498bf8e669cSmrg static clockid_t uclockid; 499f7df2e56Smrg 500bf8e669cSmrg if (!uclockid) { 501f7df2e56Smrg if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) 502bf8e669cSmrg uclockid = CLOCK_MONOTONIC; 503f7df2e56Smrg else 504bf8e669cSmrg uclockid = ~0L; 505f7df2e56Smrg } 506bf8e669cSmrg if (uclockid != ~0L && clock_gettime(uclockid, &tp) == 0) 507f7df2e56Smrg return (CARD64) tp.tv_sec * (CARD64)1000000 + tp.tv_nsec / 1000; 508f7df2e56Smrg#endif 509f7df2e56Smrg 510f7df2e56Smrg X_GETTIMEOFDAY(&tv); 5117e31ba66Smrg return (CARD64) tv.tv_sec * (CARD64)1000000 + (CARD64) tv.tv_usec; 51205b261ecSmrg} 51305b261ecSmrg#endif 51405b261ecSmrg 515f7df2e56Smrgvoid 516f7df2e56SmrgUseMsg(void) 51705b261ecSmrg{ 51805b261ecSmrg ErrorF("use: X [:<display>] [option]\n"); 5194202a189Smrg ErrorF("-a # default pointer acceleration (factor)\n"); 52005b261ecSmrg ErrorF("-ac disable access control restrictions\n"); 521f7df2e56Smrg ErrorF("-audit int set audit trail level\n"); 522f7df2e56Smrg ErrorF("-auth file select authorization file\n"); 52305b261ecSmrg ErrorF("-br create root window with black background\n"); 52405b261ecSmrg ErrorF("+bs enable any backing store support\n"); 52505b261ecSmrg ErrorF("-bs disable any backing store support\n"); 52605b261ecSmrg ErrorF("-c turns off key-click\n"); 52705b261ecSmrg ErrorF("c # key-click volume (0-100)\n"); 52805b261ecSmrg ErrorF("-cc int default color visual class\n"); 5294202a189Smrg ErrorF("-nocursor disable the cursor\n"); 53005b261ecSmrg ErrorF("-core generate core dump on fatal error\n"); 531f7df2e56Smrg ErrorF("-displayfd fd file descriptor to write display number to when ready to connect\n"); 53205b261ecSmrg ErrorF("-dpi int screen resolution in dots per inch\n"); 53305b261ecSmrg#ifdef DPMSExtension 53405b261ecSmrg ErrorF("-dpms disables VESA DPMS monitor control\n"); 53505b261ecSmrg#endif 536f7df2e56Smrg ErrorF 537f7df2e56Smrg ("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n"); 53805b261ecSmrg ErrorF("-f # bell base (0-100)\n"); 5395a112b11Smrg ErrorF("-fakescreenfps # fake screen default fps (1-600)\n"); 54005b261ecSmrg ErrorF("-fp string default font path\n"); 54105b261ecSmrg ErrorF("-help prints message with these options\n"); 542f7df2e56Smrg ErrorF("+iglx Allow creating indirect GLX contexts\n"); 543f7df2e56Smrg ErrorF("-iglx Prohibit creating indirect GLX contexts (default)\n"); 54405b261ecSmrg ErrorF("-I ignore all remaining arguments\n"); 54505b261ecSmrg#ifdef RLIMIT_DATA 54605b261ecSmrg ErrorF("-ld int limit data space to N Kb\n"); 54705b261ecSmrg#endif 54805b261ecSmrg#ifdef RLIMIT_NOFILE 54905b261ecSmrg ErrorF("-lf int limit number of open files to N\n"); 55005b261ecSmrg#endif 55105b261ecSmrg#ifdef RLIMIT_STACK 55205b261ecSmrg ErrorF("-ls int limit stack space to N Kb\n"); 55305b261ecSmrg#endif 554f7df2e56Smrg#ifdef LOCK_SERVER 55505b261ecSmrg ErrorF("-nolock disable the locking mechanism\n"); 556f7df2e56Smrg#endif 557f7df2e56Smrg ErrorF("-maxclients n set maximum number of clients (power of two)\n"); 55805b261ecSmrg ErrorF("-nolisten string don't listen on protocol\n"); 559f7df2e56Smrg ErrorF("-listen string listen on protocol\n"); 56005b261ecSmrg ErrorF("-noreset don't reset after last client exists\n"); 56165b04b38Smrg ErrorF("-background [none] create root window with no background\n"); 56205b261ecSmrg ErrorF("-reset reset after last client exists\n"); 56305b261ecSmrg ErrorF("-p # screen-saver pattern duration (minutes)\n"); 56405b261ecSmrg ErrorF("-pn accept failure to listen on all ports\n"); 56505b261ecSmrg ErrorF("-nopn reject failure to listen on all ports\n"); 56605b261ecSmrg ErrorF("-r turns off auto-repeat\n"); 56705b261ecSmrg ErrorF("r turns on auto-repeat \n"); 56805b261ecSmrg ErrorF("-render [default|mono|gray|color] set render color alloc policy\n"); 5694642e01fSmrg ErrorF("-retro start with classic stipple and cursor\n"); 570daf23d7fSsnj ErrorF("-noretro start with black background and no cursor\n"); 57105b261ecSmrg ErrorF("-s # screen-saver timeout (minutes)\n"); 572f7df2e56Smrg ErrorF("-seat string seat to run on\n"); 5734202a189Smrg ErrorF("-t # default pointer threshold (pixels/t)\n"); 5745a112b11Smrg ErrorF("-terminate [delay] terminate at server reset (optional delay in sec)\n"); 57505b261ecSmrg ErrorF("-tst disable testing extensions\n"); 57605b261ecSmrg ErrorF("ttyxx server started from init on /dev/ttyxx\n"); 57705b261ecSmrg ErrorF("v video blanking for screen-saver\n"); 57805b261ecSmrg ErrorF("-v screen-saver without video blanking\n"); 57905b261ecSmrg ErrorF("-wr create root window with white background\n"); 58005b261ecSmrg ErrorF("-maxbigreqsize set maximal bigrequest size \n"); 58105b261ecSmrg#ifdef PANORAMIX 58205b261ecSmrg ErrorF("+xinerama Enable XINERAMA extension\n"); 58305b261ecSmrg ErrorF("-xinerama Disable XINERAMA extension\n"); 58405b261ecSmrg#endif 585f7df2e56Smrg ErrorF 5867e31ba66Smrg ("-dumbSched Disable smart scheduling and threaded input, enable old behavior\n"); 58705b261ecSmrg ErrorF("-schedInterval int Set scheduler interval in msec\n"); 58865b04b38Smrg ErrorF("-sigstop Enable SIGSTOP based startup\n"); 58905b261ecSmrg ErrorF("+extension name Enable extension\n"); 59005b261ecSmrg ErrorF("-extension name Disable extension\n"); 5915a112b11Smrg ListStaticExtensions(); 59205b261ecSmrg#ifdef XDMCP 59305b261ecSmrg XdmcpUseMsg(); 59405b261ecSmrg#endif 59505b261ecSmrg XkbUseMsg(); 59605b261ecSmrg ddxUseMsg(); 59705b261ecSmrg} 59805b261ecSmrg 59905b261ecSmrg/* This function performs a rudimentary sanity check 60005b261ecSmrg * on the display name passed in on the command-line, 60105b261ecSmrg * since this string is used to generate filenames. 60205b261ecSmrg * It is especially important that the display name 60305b261ecSmrg * not contain a "/" and not start with a "-". 60405b261ecSmrg * --kvajk 60505b261ecSmrg */ 606f7df2e56Smrgstatic int 60705b261ecSmrgVerifyDisplayName(const char *d) 60805b261ecSmrg{ 609f7df2e56Smrg int i; 610f7df2e56Smrg int period_found = FALSE; 611f7df2e56Smrg int after_period = 0; 612f7df2e56Smrg 613f7df2e56Smrg if (d == (char *) 0) 614f7df2e56Smrg return 0; /* null */ 615f7df2e56Smrg if (*d == '\0') 616f7df2e56Smrg return 0; /* empty */ 617f7df2e56Smrg if (*d == '-') 618f7df2e56Smrg return 0; /* could be confused for an option */ 619f7df2e56Smrg if (*d == '.') 620f7df2e56Smrg return 0; /* must not equal "." or ".." */ 621f7df2e56Smrg if (strchr(d, '/') != (char *) 0) 622f7df2e56Smrg return 0; /* very important!!! */ 623f7df2e56Smrg 624f7df2e56Smrg /* Since we run atoi() on the display later, only allow 625f7df2e56Smrg for digits, or exception of :0.0 and similar (two decimal points max) 626f7df2e56Smrg */ 627f7df2e56Smrg for (i = 0; i < strlen(d); i++) { 628f7df2e56Smrg if (!isdigit(d[i])) { 629f7df2e56Smrg if (d[i] != '.' || period_found) 630f7df2e56Smrg return 0; 631f7df2e56Smrg period_found = TRUE; 632f7df2e56Smrg } else if (period_found) 633f7df2e56Smrg after_period++; 634f7df2e56Smrg 635f7df2e56Smrg if (after_period > 2) 636f7df2e56Smrg return 0; 637f7df2e56Smrg } 638f7df2e56Smrg 639f7df2e56Smrg /* don't allow for :0. */ 640f7df2e56Smrg if (period_found && after_period == 0) 641f7df2e56Smrg return 0; 642f7df2e56Smrg 643f7df2e56Smrg if (atol(d) > INT_MAX) 644f7df2e56Smrg return 0; 645f7df2e56Smrg 6464202a189Smrg return 1; 64705b261ecSmrg} 64805b261ecSmrg 649f7df2e56Smrgstatic const char *defaultNoListenList[] = { 650f7df2e56Smrg#ifndef LISTEN_TCP 651f7df2e56Smrg "tcp", 652f7df2e56Smrg#endif 653f7df2e56Smrg#ifndef LISTEN_UNIX 654f7df2e56Smrg "unix", 655f7df2e56Smrg#endif 656f7df2e56Smrg#ifndef LISTEN_LOCAL 657f7df2e56Smrg "local", 658f7df2e56Smrg#endif 659f7df2e56Smrg NULL 660f7df2e56Smrg}; 661f7df2e56Smrg 66205b261ecSmrg/* 66305b261ecSmrg * This function parses the command line. Handles device-independent fields 66405b261ecSmrg * and allows ddx to handle additional fields. It is not allowed to modify 66505b261ecSmrg * argc or any of the strings pointed to by argv. 66605b261ecSmrg */ 66705b261ecSmrgvoid 66805b261ecSmrgProcessCommandLine(int argc, char *argv[]) 66905b261ecSmrg{ 67005b261ecSmrg int i, skip; 67105b261ecSmrg 67205b261ecSmrg defaultKeyboardControl.autoRepeat = TRUE; 67305b261ecSmrg 67405b261ecSmrg#ifdef NO_PART_NET 67505b261ecSmrg PartialNetwork = FALSE; 67605b261ecSmrg#else 67705b261ecSmrg PartialNetwork = TRUE; 67805b261ecSmrg#endif 67905b261ecSmrg 680f7df2e56Smrg for (i = 0; defaultNoListenList[i] != NULL; i++) { 681f7df2e56Smrg if (_XSERVTransNoListen(defaultNoListenList[i])) 682f7df2e56Smrg ErrorF("Failed to disable listen for %s transport", 683f7df2e56Smrg defaultNoListenList[i]); 684f7df2e56Smrg } 6855a112b11Smrg SeatId = getenv("XDG_SEAT"); 686f7df2e56Smrg 687f7df2e56Smrg for (i = 1; i < argc; i++) { 688f7df2e56Smrg /* call ddx first, so it can peek/override if it wants */ 689f7df2e56Smrg if ((skip = ddxProcessArgument(argc, argv, i))) { 690f7df2e56Smrg i += (skip - 1); 691f7df2e56Smrg } 692f7df2e56Smrg else if (argv[i][0] == ':') { 693f7df2e56Smrg /* initialize display */ 694f7df2e56Smrg display = argv[i]; 695f7df2e56Smrg explicit_display = TRUE; 696f7df2e56Smrg display++; 697f7df2e56Smrg if (!VerifyDisplayName(display)) { 69805b261ecSmrg ErrorF("Bad display name: %s\n", display); 69905b261ecSmrg UseMsg(); 700f7df2e56Smrg FatalError("Bad display name, exiting: %s\n", display); 70105b261ecSmrg } 702f7df2e56Smrg } 703f7df2e56Smrg else if (strcmp(argv[i], "-a") == 0) { 704f7df2e56Smrg if (++i < argc) 705f7df2e56Smrg defaultPointerControl.num = atoi(argv[i]); 706f7df2e56Smrg else 707f7df2e56Smrg UseMsg(); 708f7df2e56Smrg } 709f7df2e56Smrg else if (strcmp(argv[i], "-ac") == 0) { 710f7df2e56Smrg defeatAccessControl = TRUE; 711f7df2e56Smrg } 712f7df2e56Smrg else if (strcmp(argv[i], "-audit") == 0) { 713f7df2e56Smrg if (++i < argc) 714f7df2e56Smrg auditTrailLevel = atoi(argv[i]); 715f7df2e56Smrg else 716f7df2e56Smrg UseMsg(); 717f7df2e56Smrg } 718f7df2e56Smrg else if (strcmp(argv[i], "-auth") == 0) { 719f7df2e56Smrg if (++i < argc) 720f7df2e56Smrg InitAuthorization(argv[i]); 721f7df2e56Smrg else 722f7df2e56Smrg UseMsg(); 723f7df2e56Smrg } 724f7df2e56Smrg else if (strcmp(argv[i], "-br") == 0); /* default */ 725f7df2e56Smrg else if (strcmp(argv[i], "+bs") == 0) 726f7df2e56Smrg enableBackingStore = TRUE; 727f7df2e56Smrg else if (strcmp(argv[i], "-bs") == 0) 728f7df2e56Smrg disableBackingStore = TRUE; 729f7df2e56Smrg else if (strcmp(argv[i], "c") == 0) { 730f7df2e56Smrg if (++i < argc) 731f7df2e56Smrg defaultKeyboardControl.click = atoi(argv[i]); 732f7df2e56Smrg else 733f7df2e56Smrg UseMsg(); 734f7df2e56Smrg } 735f7df2e56Smrg else if (strcmp(argv[i], "-c") == 0) { 736f7df2e56Smrg defaultKeyboardControl.click = 0; 737f7df2e56Smrg } 738f7df2e56Smrg else if (strcmp(argv[i], "-cc") == 0) { 739f7df2e56Smrg if (++i < argc) 740f7df2e56Smrg defaultColorVisualClass = atoi(argv[i]); 741f7df2e56Smrg else 742f7df2e56Smrg UseMsg(); 743f7df2e56Smrg } 744f7df2e56Smrg else if (strcmp(argv[i], "-core") == 0) { 74505b261ecSmrg#if !defined(WIN32) || !defined(__MINGW32__) 746f7df2e56Smrg struct rlimit core_limit; 747f7df2e56Smrg 748f7df2e56Smrg if (getrlimit(RLIMIT_CORE, &core_limit) != -1) { 749f7df2e56Smrg core_limit.rlim_cur = core_limit.rlim_max; 750f7df2e56Smrg setrlimit(RLIMIT_CORE, &core_limit); 751f7df2e56Smrg } 75205b261ecSmrg#endif 753f7df2e56Smrg CoreDump = TRUE; 754f7df2e56Smrg } 755f7df2e56Smrg else if (strcmp(argv[i], "-nocursor") == 0) { 7564202a189Smrg EnableCursor = FALSE; 7574202a189Smrg } 758f7df2e56Smrg else if (strcmp(argv[i], "-dpi") == 0) { 759f7df2e56Smrg if (++i < argc) 760f7df2e56Smrg monitorResolution = atoi(argv[i]); 761f7df2e56Smrg else 762f7df2e56Smrg UseMsg(); 763f7df2e56Smrg } 764f7df2e56Smrg else if (strcmp(argv[i], "-displayfd") == 0) { 765f7df2e56Smrg if (++i < argc) { 766f7df2e56Smrg displayfd = atoi(argv[i]); 767f7df2e56Smrg#ifdef LOCK_SERVER 768f7df2e56Smrg nolock = TRUE; 769f7df2e56Smrg#endif 770f7df2e56Smrg } 771f7df2e56Smrg else 772f7df2e56Smrg UseMsg(); 773f7df2e56Smrg } 77405b261ecSmrg#ifdef DPMSExtension 775f7df2e56Smrg else if (strcmp(argv[i], "dpms") == 0) 776f7df2e56Smrg /* ignored for compatibility */ ; 777f7df2e56Smrg else if (strcmp(argv[i], "-dpms") == 0) 778f7df2e56Smrg DPMSDisabledSwitch = TRUE; 77905b261ecSmrg#endif 780f7df2e56Smrg else if (strcmp(argv[i], "-deferglyphs") == 0) { 7817e31ba66Smrg if (++i >= argc || !xfont2_parse_glyph_caching_mode(argv[i])) 782f7df2e56Smrg UseMsg(); 783f7df2e56Smrg } 784f7df2e56Smrg else if (strcmp(argv[i], "-f") == 0) { 785f7df2e56Smrg if (++i < argc) 786f7df2e56Smrg defaultKeyboardControl.bell = atoi(argv[i]); 787f7df2e56Smrg else 788f7df2e56Smrg UseMsg(); 789f7df2e56Smrg } 7905a112b11Smrg else if (strcmp(argv[i], "-fakescreenfps") == 0) { 7915a112b11Smrg if (++i < argc) { 7925a112b11Smrg FakeScreenFps = (uint32_t) atoi(argv[i]); 7935a112b11Smrg if (FakeScreenFps < 1 || FakeScreenFps > 600) 7945a112b11Smrg FatalError("fakescreenfps must be an integer in [1;600] range\n"); 7955a112b11Smrg } 796f7df2e56Smrg else 797f7df2e56Smrg UseMsg(); 798f7df2e56Smrg } 799f7df2e56Smrg else if (strcmp(argv[i], "-fp") == 0) { 800f7df2e56Smrg if (++i < argc) { 801f7df2e56Smrg defaultFontPath = argv[i]; 802f7df2e56Smrg } 803f7df2e56Smrg else 804f7df2e56Smrg UseMsg(); 805f7df2e56Smrg } 806f7df2e56Smrg else if (strcmp(argv[i], "-help") == 0) { 807f7df2e56Smrg UseMsg(); 808f7df2e56Smrg exit(0); 809f7df2e56Smrg } 810f7df2e56Smrg else if (strcmp(argv[i], "+iglx") == 0) 811f7df2e56Smrg enableIndirectGLX = TRUE; 812f7df2e56Smrg else if (strcmp(argv[i], "-iglx") == 0) 813f7df2e56Smrg enableIndirectGLX = FALSE; 814f7df2e56Smrg else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) { 815f7df2e56Smrg if (skip > 0) 816f7df2e56Smrg i += skip - 1; 817f7df2e56Smrg else 818f7df2e56Smrg UseMsg(); 819f7df2e56Smrg } 82005b261ecSmrg#ifdef RLIMIT_DATA 821f7df2e56Smrg else if (strcmp(argv[i], "-ld") == 0) { 822f7df2e56Smrg if (++i < argc) { 823f7df2e56Smrg limitDataSpace = atoi(argv[i]); 824f7df2e56Smrg if (limitDataSpace > 0) 825f7df2e56Smrg limitDataSpace *= 1024; 826f7df2e56Smrg } 827f7df2e56Smrg else 828f7df2e56Smrg UseMsg(); 829f7df2e56Smrg } 83005b261ecSmrg#endif 83105b261ecSmrg#ifdef RLIMIT_NOFILE 832f7df2e56Smrg else if (strcmp(argv[i], "-lf") == 0) { 833f7df2e56Smrg if (++i < argc) 834f7df2e56Smrg limitNoFile = atoi(argv[i]); 835f7df2e56Smrg else 836f7df2e56Smrg UseMsg(); 837f7df2e56Smrg } 83805b261ecSmrg#endif 83905b261ecSmrg#ifdef RLIMIT_STACK 840f7df2e56Smrg else if (strcmp(argv[i], "-ls") == 0) { 841f7df2e56Smrg if (++i < argc) { 842f7df2e56Smrg limitStackSpace = atoi(argv[i]); 843f7df2e56Smrg if (limitStackSpace > 0) 844f7df2e56Smrg limitStackSpace *= 1024; 845f7df2e56Smrg } 846f7df2e56Smrg else 847f7df2e56Smrg UseMsg(); 848f7df2e56Smrg } 84905b261ecSmrg#endif 850f7df2e56Smrg#ifdef LOCK_SERVER 851f7df2e56Smrg else if (strcmp(argv[i], "-nolock") == 0) { 85205b261ecSmrg#if !defined(WIN32) && !defined(__CYGWIN__) 853f7df2e56Smrg if (getuid() != 0) 854f7df2e56Smrg ErrorF 855f7df2e56Smrg ("Warning: the -nolock option can only be used by root\n"); 856f7df2e56Smrg else 85705b261ecSmrg#endif 858f7df2e56Smrg nolock = TRUE; 859f7df2e56Smrg } 860f7df2e56Smrg#endif 861f7df2e56Smrg else if ( strcmp( argv[i], "-maxclients") == 0) 86205b261ecSmrg { 863f7df2e56Smrg if (++i < argc) { 864f7df2e56Smrg LimitClients = atoi(argv[i]); 865f7df2e56Smrg if (LimitClients != 64 && 866f7df2e56Smrg LimitClients != 128 && 867f7df2e56Smrg LimitClients != 256 && 8687e31ba66Smrg LimitClients != 512 && 8697e31ba66Smrg LimitClients != 1024 && 8707e31ba66Smrg LimitClients != 2048) { 8717e31ba66Smrg FatalError("maxclients must be one of 64, 128, 256, 512, 1024 or 2048\n"); 872f7df2e56Smrg } 873f7df2e56Smrg } else 87405b261ecSmrg UseMsg(); 87505b261ecSmrg } 876f7df2e56Smrg else if (strcmp(argv[i], "-nolisten") == 0) { 877f7df2e56Smrg if (++i < argc) { 878f7df2e56Smrg if (_XSERVTransNoListen(argv[i])) 879f7df2e56Smrg ErrorF("Failed to disable listen for %s transport", 880f7df2e56Smrg argv[i]); 881f7df2e56Smrg } 882f7df2e56Smrg else 883f7df2e56Smrg UseMsg(); 884f7df2e56Smrg } 885f7df2e56Smrg else if (strcmp(argv[i], "-listen") == 0) { 886f7df2e56Smrg if (++i < argc) { 887f7df2e56Smrg if (_XSERVTransListen(argv[i])) 888f7df2e56Smrg ErrorF("Failed to enable listen for %s transport", 889f7df2e56Smrg argv[i]); 890f7df2e56Smrg } 891f7df2e56Smrg else 892f7df2e56Smrg UseMsg(); 893f7df2e56Smrg } 894f7df2e56Smrg else if (strcmp(argv[i], "-noreset") == 0) { 895f7df2e56Smrg dispatchExceptionAtReset = 0; 896f7df2e56Smrg } 897f7df2e56Smrg else if (strcmp(argv[i], "-reset") == 0) { 898f7df2e56Smrg dispatchExceptionAtReset = DE_RESET; 899f7df2e56Smrg } 900f7df2e56Smrg else if (strcmp(argv[i], "-p") == 0) { 901f7df2e56Smrg if (++i < argc) 902f7df2e56Smrg defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) * 903f7df2e56Smrg MILLI_PER_MIN; 904f7df2e56Smrg else 905f7df2e56Smrg UseMsg(); 906f7df2e56Smrg } 907f7df2e56Smrg else if (strcmp(argv[i], "-pogo") == 0) { 908f7df2e56Smrg dispatchException = DE_TERMINATE; 909f7df2e56Smrg } 910f7df2e56Smrg else if (strcmp(argv[i], "-pn") == 0) 911f7df2e56Smrg PartialNetwork = TRUE; 912f7df2e56Smrg else if (strcmp(argv[i], "-nopn") == 0) 913f7df2e56Smrg PartialNetwork = FALSE; 914f7df2e56Smrg else if (strcmp(argv[i], "r") == 0) 915f7df2e56Smrg defaultKeyboardControl.autoRepeat = TRUE; 916f7df2e56Smrg else if (strcmp(argv[i], "-r") == 0) 917f7df2e56Smrg defaultKeyboardControl.autoRepeat = FALSE; 918f7df2e56Smrg else if (strcmp(argv[i], "-retro") == 0) 919f7df2e56Smrg party_like_its_1989 = TRUE; 920f7df2e56Smrg else if (strcmp(argv[i], "-noretro") == 0) 921daf23d7fSsnj party_like_its_1989 = FALSE; 922f7df2e56Smrg else if (strcmp(argv[i], "-s") == 0) { 923f7df2e56Smrg if (++i < argc) 924f7df2e56Smrg defaultScreenSaverTime = ((CARD32) atoi(argv[i])) * 925f7df2e56Smrg MILLI_PER_MIN; 926f7df2e56Smrg else 927f7df2e56Smrg UseMsg(); 928f7df2e56Smrg } 929f7df2e56Smrg else if (strcmp(argv[i], "-seat") == 0) { 930f7df2e56Smrg if (++i < argc) 931f7df2e56Smrg SeatId = argv[i]; 932f7df2e56Smrg else 933f7df2e56Smrg UseMsg(); 934f7df2e56Smrg } 935f7df2e56Smrg else if (strcmp(argv[i], "-t") == 0) { 936f7df2e56Smrg if (++i < argc) 937f7df2e56Smrg defaultPointerControl.threshold = atoi(argv[i]); 938f7df2e56Smrg else 939f7df2e56Smrg UseMsg(); 940f7df2e56Smrg } 941f7df2e56Smrg else if (strcmp(argv[i], "-terminate") == 0) { 942f7df2e56Smrg dispatchExceptionAtReset = DE_TERMINATE; 9435a112b11Smrg terminateDelay = -1; 9445a112b11Smrg if ((i + 1 < argc) && (isdigit(*argv[i + 1]))) 9455a112b11Smrg terminateDelay = atoi(argv[++i]); 9465a112b11Smrg terminateDelay = max(0, terminateDelay); 947f7df2e56Smrg } 948f7df2e56Smrg else if (strcmp(argv[i], "-tst") == 0) { 949f7df2e56Smrg noTestExtensions = TRUE; 950f7df2e56Smrg } 951f7df2e56Smrg else if (strcmp(argv[i], "v") == 0) 952f7df2e56Smrg defaultScreenSaverBlanking = PreferBlanking; 953f7df2e56Smrg else if (strcmp(argv[i], "-v") == 0) 954f7df2e56Smrg defaultScreenSaverBlanking = DontPreferBlanking; 955f7df2e56Smrg else if (strcmp(argv[i], "-wr") == 0) 95605b261ecSmrg whiteRoot = TRUE; 957f7df2e56Smrg else if (strcmp(argv[i], "-background") == 0) { 958f7df2e56Smrg if (++i < argc) { 959f7df2e56Smrg if (!strcmp(argv[i], "none")) 96065b04b38Smrg bgNoneRoot = TRUE; 96165b04b38Smrg else 96265b04b38Smrg UseMsg(); 96365b04b38Smrg } 96465b04b38Smrg } 965f7df2e56Smrg else if (strcmp(argv[i], "-maxbigreqsize") == 0) { 966f7df2e56Smrg if (++i < argc) { 967f7df2e56Smrg long reqSizeArg = atol(argv[i]); 968f7df2e56Smrg 969f7df2e56Smrg /* Request size > 128MB does not make much sense... */ 970f7df2e56Smrg if (reqSizeArg > 0L && reqSizeArg < 128L) { 971f7df2e56Smrg maxBigRequestSize = (reqSizeArg * 1048576L) - 1L; 972f7df2e56Smrg } 973f7df2e56Smrg else { 974f7df2e56Smrg UseMsg(); 975f7df2e56Smrg } 976f7df2e56Smrg } 977f7df2e56Smrg else { 978f7df2e56Smrg UseMsg(); 979f7df2e56Smrg } 980f7df2e56Smrg } 981f7df2e56Smrg#ifdef PANORAMIX 982f7df2e56Smrg else if (strcmp(argv[i], "+xinerama") == 0) { 983f7df2e56Smrg noPanoramiXExtension = FALSE; 984f7df2e56Smrg } 985f7df2e56Smrg else if (strcmp(argv[i], "-xinerama") == 0) { 986f7df2e56Smrg noPanoramiXExtension = TRUE; 987f7df2e56Smrg } 988f7df2e56Smrg else if (strcmp(argv[i], "-disablexineramaextension") == 0) { 989f7df2e56Smrg PanoramiXExtensionDisabledHack = TRUE; 990f7df2e56Smrg } 991f7df2e56Smrg#endif 992f7df2e56Smrg else if (strcmp(argv[i], "-I") == 0) { 993f7df2e56Smrg /* ignore all remaining arguments */ 994f7df2e56Smrg break; 995f7df2e56Smrg } 996f7df2e56Smrg else if (strncmp(argv[i], "tty", 3) == 0) { 997f7df2e56Smrg /* init supplies us with this useless information */ 998f7df2e56Smrg } 999f7df2e56Smrg#ifdef XDMCP 1000f7df2e56Smrg else if ((skip = XdmcpOptions(argc, argv, i)) != i) { 1001f7df2e56Smrg i = skip - 1; 1002f7df2e56Smrg } 1003f7df2e56Smrg#endif 1004f7df2e56Smrg else if (strcmp(argv[i], "-dumbSched") == 0) { 10057e31ba66Smrg InputThreadEnable = FALSE; 10067e31ba66Smrg#ifdef HAVE_SETITIMER 10077e31ba66Smrg SmartScheduleSignalEnable = FALSE; 10087e31ba66Smrg#endif 1009f7df2e56Smrg } 1010f7df2e56Smrg else if (strcmp(argv[i], "-schedInterval") == 0) { 1011f7df2e56Smrg if (++i < argc) { 1012f7df2e56Smrg SmartScheduleInterval = atoi(argv[i]); 1013f7df2e56Smrg SmartScheduleSlice = SmartScheduleInterval; 1014f7df2e56Smrg } 1015f7df2e56Smrg else 1016f7df2e56Smrg UseMsg(); 1017f7df2e56Smrg } 1018f7df2e56Smrg else if (strcmp(argv[i], "-schedMax") == 0) { 1019f7df2e56Smrg if (++i < argc) { 1020f7df2e56Smrg SmartScheduleMaxSlice = atoi(argv[i]); 1021f7df2e56Smrg } 1022f7df2e56Smrg else 1023f7df2e56Smrg UseMsg(); 1024f7df2e56Smrg } 1025f7df2e56Smrg else if (strcmp(argv[i], "-render") == 0) { 1026f7df2e56Smrg if (++i < argc) { 1027f7df2e56Smrg int policy = PictureParseCmapPolicy(argv[i]); 1028f7df2e56Smrg 1029f7df2e56Smrg if (policy != PictureCmapPolicyInvalid) 1030f7df2e56Smrg PictureCmapPolicy = policy; 1031f7df2e56Smrg else 1032f7df2e56Smrg UseMsg(); 1033f7df2e56Smrg } 1034f7df2e56Smrg else 1035f7df2e56Smrg UseMsg(); 1036f7df2e56Smrg } 1037f7df2e56Smrg else if (strcmp(argv[i], "-sigstop") == 0) { 1038f7df2e56Smrg RunFromSigStopParent = TRUE; 1039f7df2e56Smrg } 1040f7df2e56Smrg else if (strcmp(argv[i], "+extension") == 0) { 1041f7df2e56Smrg if (++i < argc) { 1042f7df2e56Smrg if (!EnableDisableExtension(argv[i], TRUE)) 1043f7df2e56Smrg EnableDisableExtensionError(argv[i], TRUE); 1044f7df2e56Smrg } 1045f7df2e56Smrg else 1046f7df2e56Smrg UseMsg(); 1047f7df2e56Smrg } 1048f7df2e56Smrg else if (strcmp(argv[i], "-extension") == 0) { 1049f7df2e56Smrg if (++i < argc) { 1050f7df2e56Smrg if (!EnableDisableExtension(argv[i], FALSE)) 1051f7df2e56Smrg EnableDisableExtensionError(argv[i], FALSE); 1052f7df2e56Smrg } 1053f7df2e56Smrg else 1054f7df2e56Smrg UseMsg(); 1055f7df2e56Smrg } 1056f7df2e56Smrg else { 1057f7df2e56Smrg ErrorF("Unrecognized option: %s\n", argv[i]); 1058f7df2e56Smrg UseMsg(); 1059f7df2e56Smrg FatalError("Unrecognized option: %s\n", argv[i]); 106005b261ecSmrg } 106105b261ecSmrg } 106205b261ecSmrg} 106305b261ecSmrg 106405b261ecSmrg/* Implement a simple-minded font authorization scheme. The authorization 106505b261ecSmrg name is "hp-hostname-1", the contents are simply the host name. */ 106605b261ecSmrgint 1067f7df2e56Smrgset_font_authorizations(char **authorizations, int *authlen, void *client) 106805b261ecSmrg{ 106905b261ecSmrg#define AUTHORIZATION_NAME "hp-hostname-1" 10707e31ba66Smrg#if defined(TCPCONN) 107105b261ecSmrg static char *result = NULL; 107205b261ecSmrg static char *p = NULL; 107305b261ecSmrg 1074f7df2e56Smrg if (p == NULL) { 1075f7df2e56Smrg char hname[1024], *hnameptr; 1076f7df2e56Smrg unsigned int len; 1077f7df2e56Smrg 107805b261ecSmrg#if defined(IPv6) && defined(AF_INET6) 1079f7df2e56Smrg struct addrinfo hints, *ai = NULL; 108005b261ecSmrg#else 1081f7df2e56Smrg struct hostent *host; 1082f7df2e56Smrg 108305b261ecSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 1084f7df2e56Smrg _Xgethostbynameparams hparams; 108505b261ecSmrg#endif 108605b261ecSmrg#endif 108705b261ecSmrg 1088f7df2e56Smrg gethostname(hname, 1024); 108905b261ecSmrg#if defined(IPv6) && defined(AF_INET6) 1090f7df2e56Smrg memset(&hints, 0, sizeof(hints)); 1091f7df2e56Smrg hints.ai_flags = AI_CANONNAME; 1092f7df2e56Smrg if (getaddrinfo(hname, NULL, &hints, &ai) == 0) { 1093f7df2e56Smrg hnameptr = ai->ai_canonname; 1094f7df2e56Smrg } 1095f7df2e56Smrg else { 1096f7df2e56Smrg hnameptr = hname; 1097f7df2e56Smrg } 109805b261ecSmrg#else 1099f7df2e56Smrg host = _XGethostbyname(hname, hparams); 1100f7df2e56Smrg if (host == NULL) 1101f7df2e56Smrg hnameptr = hname; 1102f7df2e56Smrg else 1103f7df2e56Smrg hnameptr = host->h_name; 110405b261ecSmrg#endif 110505b261ecSmrg 1106f7df2e56Smrg len = strlen(hnameptr) + 1; 1107f7df2e56Smrg result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4); 110805b261ecSmrg 1109f7df2e56Smrg p = result; 111005b261ecSmrg *p++ = sizeof(AUTHORIZATION_NAME) >> 8; 111105b261ecSmrg *p++ = sizeof(AUTHORIZATION_NAME) & 0xff; 111205b261ecSmrg *p++ = (len) >> 8; 111305b261ecSmrg *p++ = (len & 0xff); 111405b261ecSmrg 1115f7df2e56Smrg memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME)); 1116f7df2e56Smrg p += sizeof(AUTHORIZATION_NAME); 1117f7df2e56Smrg memmove(p, hnameptr, len); 1118f7df2e56Smrg p += len; 111905b261ecSmrg#if defined(IPv6) && defined(AF_INET6) 1120f7df2e56Smrg if (ai) { 1121f7df2e56Smrg freeaddrinfo(ai); 1122f7df2e56Smrg } 112305b261ecSmrg#endif 112405b261ecSmrg } 112505b261ecSmrg *authlen = p - result; 112605b261ecSmrg *authorizations = result; 112705b261ecSmrg return 1; 1128f7df2e56Smrg#else /* TCPCONN */ 112905b261ecSmrg return 0; 1130f7df2e56Smrg#endif /* TCPCONN */ 113105b261ecSmrg} 113205b261ecSmrg 11334202a189Smrgvoid * 113405b261ecSmrgXNFalloc(unsigned long amount) 113505b261ecSmrg{ 11364202a189Smrg void *ptr = malloc(amount); 1137f7df2e56Smrg 113805b261ecSmrg if (!ptr) 113905b261ecSmrg FatalError("Out of memory"); 11404642e01fSmrg return ptr; 114105b261ecSmrg} 114205b261ecSmrg 1143f7df2e56Smrg/* The original XNFcalloc was used with the xnfcalloc macro which multiplied 1144f7df2e56Smrg * the arguments at the call site without allowing calloc to check for overflow. 1145f7df2e56Smrg * XNFcallocarray was added to fix that without breaking ABI. 1146f7df2e56Smrg */ 11474202a189Smrgvoid * 1148f7df2e56SmrgXNFcalloc(unsigned long amount) 114905b261ecSmrg{ 1150f7df2e56Smrg return XNFcallocarray(1, amount); 115105b261ecSmrg} 115205b261ecSmrg 11534202a189Smrgvoid * 1154f7df2e56SmrgXNFcallocarray(size_t nmemb, size_t size) 115505b261ecSmrg{ 1156f7df2e56Smrg void *ret = calloc(nmemb, size); 1157f7df2e56Smrg 11584202a189Smrg if (!ret) 11594202a189Smrg FatalError("XNFcalloc: Out of memory"); 116005b261ecSmrg return ret; 116105b261ecSmrg} 116205b261ecSmrg 11634202a189Smrgvoid * 11644202a189SmrgXNFrealloc(void *ptr, unsigned long amount) 116505b261ecSmrg{ 11664202a189Smrg void *ret = realloc(ptr, amount); 1167f7df2e56Smrg 11684202a189Smrg if (!ret) 1169f7df2e56Smrg FatalError("XNFrealloc: Out of memory"); 11704202a189Smrg return ret; 117105b261ecSmrg} 117205b261ecSmrg 1173f7df2e56Smrgvoid * 1174f7df2e56SmrgXNFreallocarray(void *ptr, size_t nmemb, size_t size) 117505b261ecSmrg{ 1176f7df2e56Smrg void *ret = reallocarray(ptr, nmemb, size); 117705b261ecSmrg 1178f7df2e56Smrg if (!ret) 1179f7df2e56Smrg FatalError("XNFreallocarray: Out of memory"); 1180f7df2e56Smrg return ret; 1181f7df2e56Smrg} 118205b261ecSmrg 118305b261ecSmrgchar * 118405b261ecSmrgXstrdup(const char *s) 118505b261ecSmrg{ 118605b261ecSmrg if (s == NULL) 1187f7df2e56Smrg return NULL; 11884202a189Smrg return strdup(s); 118905b261ecSmrg} 119005b261ecSmrg 11914202a189Smrgchar * 119205b261ecSmrgXNFstrdup(const char *s) 119305b261ecSmrg{ 11944202a189Smrg char *ret; 119505b261ecSmrg 119605b261ecSmrg if (s == NULL) 1197f7df2e56Smrg return NULL; 119805b261ecSmrg 11994202a189Smrg ret = strdup(s); 12004202a189Smrg if (!ret) 1201f7df2e56Smrg FatalError("XNFstrdup: Out of memory"); 12024202a189Smrg return ret; 120305b261ecSmrg} 120405b261ecSmrg 12054642e01fSmrgvoid 1206f7df2e56SmrgSmartScheduleStopTimer(void) 120705b261ecSmrg{ 12087e31ba66Smrg#ifdef HAVE_SETITIMER 1209f7df2e56Smrg struct itimerval timer; 1210f7df2e56Smrg 12117e31ba66Smrg if (!SmartScheduleSignalEnable) 1212f7df2e56Smrg return; 121305b261ecSmrg timer.it_interval.tv_sec = 0; 121405b261ecSmrg timer.it_interval.tv_usec = 0; 121505b261ecSmrg timer.it_value.tv_sec = 0; 121605b261ecSmrg timer.it_value.tv_usec = 0; 1217f7df2e56Smrg (void) setitimer(ITIMER_REAL, &timer, 0); 1218f7df2e56Smrg#endif 121905b261ecSmrg} 122005b261ecSmrg 12214642e01fSmrgvoid 1222f7df2e56SmrgSmartScheduleStartTimer(void) 122305b261ecSmrg{ 12247e31ba66Smrg#ifdef HAVE_SETITIMER 1225f7df2e56Smrg struct itimerval timer; 1226f7df2e56Smrg 12277e31ba66Smrg if (!SmartScheduleSignalEnable) 1228f7df2e56Smrg return; 122905b261ecSmrg timer.it_interval.tv_sec = 0; 123005b261ecSmrg timer.it_interval.tv_usec = SmartScheduleInterval * 1000; 123105b261ecSmrg timer.it_value.tv_sec = 0; 123205b261ecSmrg timer.it_value.tv_usec = SmartScheduleInterval * 1000; 1233f7df2e56Smrg setitimer(ITIMER_REAL, &timer, 0); 1234f7df2e56Smrg#endif 123505b261ecSmrg} 123605b261ecSmrg 12377e31ba66Smrg#ifdef HAVE_SETITIMER 123805b261ecSmrgstatic void 1239f7df2e56SmrgSmartScheduleTimer(int sig) 124005b261ecSmrg{ 124105b261ecSmrg SmartScheduleTime += SmartScheduleInterval; 124205b261ecSmrg} 124305b261ecSmrg 1244f7df2e56Smrgstatic int 1245f7df2e56SmrgSmartScheduleEnable(void) 124605b261ecSmrg{ 1247f7df2e56Smrg int ret = 0; 1248f7df2e56Smrg struct sigaction act; 124905b261ecSmrg 12507e31ba66Smrg if (!SmartScheduleSignalEnable) 1251f7df2e56Smrg return 0; 125265b04b38Smrg 12534202a189Smrg memset((char *) &act, 0, sizeof(struct sigaction)); 125405b261ecSmrg 125505b261ecSmrg /* Set up the timer signal function */ 1256f7df2e56Smrg act.sa_flags = SA_RESTART; 125705b261ecSmrg act.sa_handler = SmartScheduleTimer; 1258f7df2e56Smrg sigemptyset(&act.sa_mask); 1259f7df2e56Smrg sigaddset(&act.sa_mask, SIGALRM); 1260f7df2e56Smrg ret = sigaction(SIGALRM, &act, 0); 1261f7df2e56Smrg return ret; 1262f7df2e56Smrg} 1263f7df2e56Smrg 1264f7df2e56Smrgstatic int 1265f7df2e56SmrgSmartSchedulePause(void) 1266f7df2e56Smrg{ 1267f7df2e56Smrg int ret = 0; 1268f7df2e56Smrg struct sigaction act; 1269f7df2e56Smrg 12707e31ba66Smrg if (!SmartScheduleSignalEnable) 1271f7df2e56Smrg return 0; 1272f7df2e56Smrg 1273f7df2e56Smrg memset((char *) &act, 0, sizeof(struct sigaction)); 1274f7df2e56Smrg 1275f7df2e56Smrg act.sa_handler = SIG_IGN; 1276f7df2e56Smrg sigemptyset(&act.sa_mask); 1277f7df2e56Smrg ret = sigaction(SIGALRM, &act, 0); 1278f7df2e56Smrg return ret; 1279f7df2e56Smrg} 12807e31ba66Smrg#endif 1281f7df2e56Smrg 1282f7df2e56Smrgvoid 1283f7df2e56SmrgSmartScheduleInit(void) 1284f7df2e56Smrg{ 12857e31ba66Smrg#ifdef HAVE_SETITIMER 1286f7df2e56Smrg if (SmartScheduleEnable() < 0) { 1287f7df2e56Smrg perror("sigaction for smart scheduler"); 12887e31ba66Smrg SmartScheduleSignalEnable = FALSE; 128905b261ecSmrg } 12907e31ba66Smrg#endif 129105b261ecSmrg} 129205b261ecSmrg 12935a112b11Smrg#ifdef HAVE_SIGPROCMASK 1294f7df2e56Smrgstatic sigset_t PreviousSignalMask; 1295f7df2e56Smrgstatic int BlockedSignalCount; 129605b261ecSmrg#endif 129705b261ecSmrg 129805b261ecSmrgvoid 1299f7df2e56SmrgOsBlockSignals(void) 130005b261ecSmrg{ 13015a112b11Smrg#ifdef HAVE_SIGPROCMASK 1302f7df2e56Smrg if (BlockedSignalCount++ == 0) { 1303f7df2e56Smrg sigset_t set; 1304f7df2e56Smrg 1305f7df2e56Smrg sigemptyset(&set); 1306f7df2e56Smrg sigaddset(&set, SIGALRM); 1307f7df2e56Smrg sigaddset(&set, SIGVTALRM); 130805b261ecSmrg#ifdef SIGWINCH 1309f7df2e56Smrg sigaddset(&set, SIGWINCH); 1310f7df2e56Smrg#endif 1311f7df2e56Smrg sigaddset(&set, SIGTSTP); 1312f7df2e56Smrg sigaddset(&set, SIGTTIN); 1313f7df2e56Smrg sigaddset(&set, SIGTTOU); 1314f7df2e56Smrg sigaddset(&set, SIGCHLD); 13157e31ba66Smrg xthread_sigmask(SIG_BLOCK, &set, &PreviousSignalMask); 131605b261ecSmrg } 131705b261ecSmrg#endif 131805b261ecSmrg} 131905b261ecSmrg 132005b261ecSmrgvoid 1321f7df2e56SmrgOsReleaseSignals(void) 132205b261ecSmrg{ 13235a112b11Smrg#ifdef HAVE_SIGPROCMASK 1324f7df2e56Smrg if (--BlockedSignalCount == 0) { 13257e31ba66Smrg xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0); 132605b261ecSmrg } 132705b261ecSmrg#endif 132805b261ecSmrg} 132905b261ecSmrg 1330f7df2e56Smrgvoid 1331f7df2e56SmrgOsResetSignals(void) 1332f7df2e56Smrg{ 13335a112b11Smrg#ifdef HAVE_SIGPROCMASK 1334f7df2e56Smrg while (BlockedSignalCount > 0) 1335f7df2e56Smrg OsReleaseSignals(); 13367e31ba66Smrg input_force_unlock(); 1337f7df2e56Smrg#endif 1338f7df2e56Smrg} 1339f7df2e56Smrg 13404202a189Smrg/* 13414202a189Smrg * Pending signals may interfere with core dumping. Provide a 13424202a189Smrg * mechanism to block signals when aborting. 13434202a189Smrg */ 13444202a189Smrg 13454202a189Smrgvoid 1346f7df2e56SmrgOsAbort(void) 13474202a189Smrg{ 13484202a189Smrg#ifndef __APPLE__ 13494202a189Smrg OsBlockSignals(); 13507e31ba66Smrg#endif 13517e31ba66Smrg#if !defined(WIN32) || defined(__CYGWIN__) 13527e31ba66Smrg /* abort() raises SIGABRT, so we have to stop handling that to prevent 13537e31ba66Smrg * recursion 13547e31ba66Smrg */ 13557e31ba66Smrg OsSignal(SIGABRT, SIG_DFL); 13564202a189Smrg#endif 13574202a189Smrg abort(); 13584202a189Smrg} 13594202a189Smrg 136005b261ecSmrg#if !defined(WIN32) 136105b261ecSmrg/* 136205b261ecSmrg * "safer" versions of system(3), popen(3) and pclose(3) which give up 136305b261ecSmrg * all privs before running a command. 136405b261ecSmrg * 136505b261ecSmrg * This is based on the code in FreeBSD 2.2 libc. 136605b261ecSmrg * 136705b261ecSmrg * XXX It'd be good to redirect stderr so that it ends up in the log file 136805b261ecSmrg * as well. As it is now, xkbcomp messages don't end up in the log file. 136905b261ecSmrg */ 137005b261ecSmrg 137105b261ecSmrgint 1372f7df2e56SmrgSystem(const char *command) 137305b261ecSmrg{ 137405b261ecSmrg int pid, p; 1375f7df2e56Smrg void (*csig) (int); 137605b261ecSmrg int status; 137705b261ecSmrg 137805b261ecSmrg if (!command) 1379f7df2e56Smrg return 1; 138005b261ecSmrg 13817e31ba66Smrg csig = OsSignal(SIGCHLD, SIG_DFL); 138205b261ecSmrg if (csig == SIG_ERR) { 1383f7df2e56Smrg perror("signal"); 1384f7df2e56Smrg return -1; 138505b261ecSmrg } 138665b04b38Smrg DebugF("System: `%s'\n", command); 138705b261ecSmrg 138805b261ecSmrg switch (pid = fork()) { 1389f7df2e56Smrg case -1: /* error */ 1390f7df2e56Smrg p = -1; 1391f7df2e56Smrg break; 1392f7df2e56Smrg case 0: /* child */ 1393f7df2e56Smrg if (setgid(getgid()) == -1) 1394f7df2e56Smrg _exit(127); 1395f7df2e56Smrg if (setuid(getuid()) == -1) 1396f7df2e56Smrg _exit(127); 1397f7df2e56Smrg execl("/bin/sh", "sh", "-c", command, (char *) NULL); 1398f7df2e56Smrg _exit(127); 1399f7df2e56Smrg default: /* parent */ 1400f7df2e56Smrg do { 1401f7df2e56Smrg p = waitpid(pid, &status, 0); 1402f7df2e56Smrg } while (p == -1 && errno == EINTR); 1403f7df2e56Smrg 140405b261ecSmrg } 140505b261ecSmrg 14067e31ba66Smrg if (OsSignal(SIGCHLD, csig) == SIG_ERR) { 1407f7df2e56Smrg perror("signal"); 1408f7df2e56Smrg return -1; 140905b261ecSmrg } 141005b261ecSmrg 141105b261ecSmrg return p == -1 ? -1 : status; 141205b261ecSmrg} 141305b261ecSmrg 141405b261ecSmrgstatic struct pid { 141505b261ecSmrg struct pid *next; 141605b261ecSmrg FILE *fp; 141705b261ecSmrg int pid; 141805b261ecSmrg} *pidlist; 141905b261ecSmrg 1420f7df2e56Smrgvoid * 1421f7df2e56SmrgPopen(const char *command, const char *type) 142205b261ecSmrg{ 142305b261ecSmrg struct pid *cur; 142405b261ecSmrg FILE *iop; 142505b261ecSmrg int pdes[2], pid; 142605b261ecSmrg 142705b261ecSmrg if (command == NULL || type == NULL) 1428f7df2e56Smrg return NULL; 142905b261ecSmrg 143005b261ecSmrg if ((*type != 'r' && *type != 'w') || type[1]) 1431f7df2e56Smrg return NULL; 143205b261ecSmrg 14334202a189Smrg if ((cur = malloc(sizeof(struct pid))) == NULL) 1434f7df2e56Smrg return NULL; 143505b261ecSmrg 143605b261ecSmrg if (pipe(pdes) < 0) { 1437f7df2e56Smrg free(cur); 1438f7df2e56Smrg return NULL; 143905b261ecSmrg } 144005b261ecSmrg 144105b261ecSmrg /* Ignore the smart scheduler while this is going on */ 14427e31ba66Smrg#ifdef HAVE_SETITIMER 1443f7df2e56Smrg if (SmartSchedulePause() < 0) { 1444f7df2e56Smrg close(pdes[0]); 1445f7df2e56Smrg close(pdes[1]); 1446f7df2e56Smrg free(cur); 1447f7df2e56Smrg perror("signal"); 1448f7df2e56Smrg return NULL; 144905b261ecSmrg } 14507e31ba66Smrg#endif 145105b261ecSmrg 145205b261ecSmrg switch (pid = fork()) { 1453f7df2e56Smrg case -1: /* error */ 1454f7df2e56Smrg close(pdes[0]); 1455f7df2e56Smrg close(pdes[1]); 1456f7df2e56Smrg free(cur); 14577e31ba66Smrg#ifdef HAVE_SETITIMER 1458f7df2e56Smrg if (SmartScheduleEnable() < 0) 1459f7df2e56Smrg perror("signal"); 14607e31ba66Smrg#endif 1461f7df2e56Smrg return NULL; 1462f7df2e56Smrg case 0: /* child */ 1463f7df2e56Smrg if (setgid(getgid()) == -1) 1464f7df2e56Smrg _exit(127); 1465f7df2e56Smrg if (setuid(getuid()) == -1) 1466f7df2e56Smrg _exit(127); 1467f7df2e56Smrg if (*type == 'r') { 1468f7df2e56Smrg if (pdes[1] != 1) { 1469f7df2e56Smrg /* stdout */ 1470f7df2e56Smrg dup2(pdes[1], 1); 1471f7df2e56Smrg close(pdes[1]); 1472f7df2e56Smrg } 1473f7df2e56Smrg close(pdes[0]); 1474f7df2e56Smrg } 1475f7df2e56Smrg else { 1476f7df2e56Smrg if (pdes[0] != 0) { 1477f7df2e56Smrg /* stdin */ 1478f7df2e56Smrg dup2(pdes[0], 0); 1479f7df2e56Smrg close(pdes[0]); 1480f7df2e56Smrg } 1481f7df2e56Smrg close(pdes[1]); 1482f7df2e56Smrg } 1483f7df2e56Smrg execl("/bin/sh", "sh", "-c", command, (char *) NULL); 1484f7df2e56Smrg _exit(127); 148505b261ecSmrg } 148605b261ecSmrg 148705b261ecSmrg /* Avoid EINTR during stdio calls */ 1488f7df2e56Smrg OsBlockSignals(); 1489f7df2e56Smrg 149005b261ecSmrg /* parent */ 149105b261ecSmrg if (*type == 'r') { 1492f7df2e56Smrg iop = fdopen(pdes[0], type); 1493f7df2e56Smrg close(pdes[1]); 1494f7df2e56Smrg } 1495f7df2e56Smrg else { 1496f7df2e56Smrg iop = fdopen(pdes[1], type); 1497f7df2e56Smrg close(pdes[0]); 149805b261ecSmrg } 149905b261ecSmrg 150005b261ecSmrg cur->fp = iop; 150105b261ecSmrg cur->pid = pid; 150205b261ecSmrg cur->next = pidlist; 150305b261ecSmrg pidlist = cur; 150405b261ecSmrg 150565b04b38Smrg DebugF("Popen: `%s', fp = %p\n", command, iop); 150605b261ecSmrg 150705b261ecSmrg return iop; 150805b261ecSmrg} 150905b261ecSmrg 151005b261ecSmrg/* fopen that drops privileges */ 1511f7df2e56Smrgvoid * 1512f7df2e56SmrgFopen(const char *file, const char *type) 151305b261ecSmrg{ 151405b261ecSmrg FILE *iop; 1515f7df2e56Smrg 151605b261ecSmrg#ifndef HAS_SAVED_IDS_AND_SETEUID 151705b261ecSmrg struct pid *cur; 151805b261ecSmrg int pdes[2], pid; 151905b261ecSmrg 152005b261ecSmrg if (file == NULL || type == NULL) 1521f7df2e56Smrg return NULL; 152205b261ecSmrg 152305b261ecSmrg if ((*type != 'r' && *type != 'w') || type[1]) 1524f7df2e56Smrg return NULL; 152505b261ecSmrg 15264202a189Smrg if ((cur = malloc(sizeof(struct pid))) == NULL) 1527f7df2e56Smrg return NULL; 152805b261ecSmrg 152905b261ecSmrg if (pipe(pdes) < 0) { 1530f7df2e56Smrg free(cur); 1531f7df2e56Smrg return NULL; 153205b261ecSmrg } 153305b261ecSmrg 153405b261ecSmrg switch (pid = fork()) { 1535f7df2e56Smrg case -1: /* error */ 1536f7df2e56Smrg close(pdes[0]); 1537f7df2e56Smrg close(pdes[1]); 1538f7df2e56Smrg free(cur); 1539f7df2e56Smrg return NULL; 1540f7df2e56Smrg case 0: /* child */ 1541f7df2e56Smrg if (setgid(getgid()) == -1) 1542f7df2e56Smrg _exit(127); 1543f7df2e56Smrg if (setuid(getuid()) == -1) 1544f7df2e56Smrg _exit(127); 1545f7df2e56Smrg if (*type == 'r') { 1546f7df2e56Smrg if (pdes[1] != 1) { 1547f7df2e56Smrg /* stdout */ 1548f7df2e56Smrg dup2(pdes[1], 1); 1549f7df2e56Smrg close(pdes[1]); 1550f7df2e56Smrg } 1551f7df2e56Smrg close(pdes[0]); 1552f7df2e56Smrg } 1553f7df2e56Smrg else { 1554f7df2e56Smrg if (pdes[0] != 0) { 1555f7df2e56Smrg /* stdin */ 1556f7df2e56Smrg dup2(pdes[0], 0); 1557f7df2e56Smrg close(pdes[0]); 1558f7df2e56Smrg } 1559f7df2e56Smrg close(pdes[1]); 1560f7df2e56Smrg } 1561f7df2e56Smrg execl("/bin/cat", "cat", file, (char *) NULL); 1562f7df2e56Smrg _exit(127); 156305b261ecSmrg } 156405b261ecSmrg 156505b261ecSmrg /* Avoid EINTR during stdio calls */ 1566f7df2e56Smrg OsBlockSignals(); 1567f7df2e56Smrg 156805b261ecSmrg /* parent */ 156905b261ecSmrg if (*type == 'r') { 1570f7df2e56Smrg iop = fdopen(pdes[0], type); 1571f7df2e56Smrg close(pdes[1]); 1572f7df2e56Smrg } 1573f7df2e56Smrg else { 1574f7df2e56Smrg iop = fdopen(pdes[1], type); 1575f7df2e56Smrg close(pdes[0]); 157605b261ecSmrg } 157705b261ecSmrg 157805b261ecSmrg cur->fp = iop; 157905b261ecSmrg cur->pid = pid; 158005b261ecSmrg cur->next = pidlist; 158105b261ecSmrg pidlist = cur; 158205b261ecSmrg 158365b04b38Smrg DebugF("Fopen(%s), fp = %p\n", file, iop); 158405b261ecSmrg 158505b261ecSmrg return iop; 158605b261ecSmrg#else 158705b261ecSmrg int ruid, euid; 158805b261ecSmrg 158905b261ecSmrg ruid = getuid(); 159005b261ecSmrg euid = geteuid(); 1591f7df2e56Smrg 159205b261ecSmrg if (seteuid(ruid) == -1) { 1593f7df2e56Smrg return NULL; 159405b261ecSmrg } 159505b261ecSmrg iop = fopen(file, type); 159605b261ecSmrg 159705b261ecSmrg if (seteuid(euid) == -1) { 1598f7df2e56Smrg fclose(iop); 1599f7df2e56Smrg return NULL; 160005b261ecSmrg } 160105b261ecSmrg return iop; 1602f7df2e56Smrg#endif /* HAS_SAVED_IDS_AND_SETEUID */ 160305b261ecSmrg} 160405b261ecSmrg 160505b261ecSmrgint 1606f7df2e56SmrgPclose(void *iop) 160705b261ecSmrg{ 160805b261ecSmrg struct pid *cur, *last; 160905b261ecSmrg int pstat; 161005b261ecSmrg int pid; 161105b261ecSmrg 161265b04b38Smrg DebugF("Pclose: fp = %p\n", iop); 161305b261ecSmrg fclose(iop); 161405b261ecSmrg 161505b261ecSmrg for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) 1616f7df2e56Smrg if (cur->fp == iop) 1617f7df2e56Smrg break; 161805b261ecSmrg if (cur == NULL) 1619f7df2e56Smrg return -1; 162005b261ecSmrg 162105b261ecSmrg do { 1622f7df2e56Smrg pid = waitpid(cur->pid, &pstat, 0); 162305b261ecSmrg } while (pid == -1 && errno == EINTR); 162405b261ecSmrg 162505b261ecSmrg if (last == NULL) 1626f7df2e56Smrg pidlist = cur->next; 162705b261ecSmrg else 1628f7df2e56Smrg last->next = cur->next; 16294202a189Smrg free(cur); 163005b261ecSmrg 163105b261ecSmrg /* allow EINTR again */ 1632f7df2e56Smrg OsReleaseSignals(); 1633f7df2e56Smrg 16347e31ba66Smrg#ifdef HAVE_SETITIMER 1635f7df2e56Smrg if (SmartScheduleEnable() < 0) { 1636f7df2e56Smrg perror("signal"); 1637f7df2e56Smrg return -1; 163805b261ecSmrg } 16397e31ba66Smrg#endif 164005b261ecSmrg 164105b261ecSmrg return pid == -1 ? -1 : pstat; 164205b261ecSmrg} 164305b261ecSmrg 16444202a189Smrgint 1645f7df2e56SmrgFclose(void *iop) 164605b261ecSmrg{ 164705b261ecSmrg#ifdef HAS_SAVED_IDS_AND_SETEUID 164805b261ecSmrg return fclose(iop); 164905b261ecSmrg#else 165005b261ecSmrg return Pclose(iop); 165105b261ecSmrg#endif 165205b261ecSmrg} 165305b261ecSmrg 1654f7df2e56Smrg#endif /* !WIN32 */ 1655f7df2e56Smrg 1656f7df2e56Smrg#ifdef WIN32 1657f7df2e56Smrg 1658f7df2e56Smrg#include <X11/Xwindows.h> 1659f7df2e56Smrg 1660f7df2e56Smrgconst char * 1661f7df2e56SmrgWin32TempDir(void) 1662f7df2e56Smrg{ 1663f7df2e56Smrg static char buffer[PATH_MAX]; 1664f7df2e56Smrg 1665f7df2e56Smrg if (GetTempPath(sizeof(buffer), buffer)) { 1666f7df2e56Smrg int len; 1667f7df2e56Smrg 1668f7df2e56Smrg buffer[sizeof(buffer) - 1] = 0; 1669f7df2e56Smrg len = strlen(buffer); 1670f7df2e56Smrg if (len > 0) 1671f7df2e56Smrg if (buffer[len - 1] == '\\') 1672f7df2e56Smrg buffer[len - 1] = 0; 1673f7df2e56Smrg return buffer; 1674f7df2e56Smrg } 1675f7df2e56Smrg if (getenv("TEMP") != NULL) 1676f7df2e56Smrg return getenv("TEMP"); 1677f7df2e56Smrg else if (getenv("TMP") != NULL) 1678f7df2e56Smrg return getenv("TMP"); 1679f7df2e56Smrg else 1680f7df2e56Smrg return "/tmp"; 1681f7df2e56Smrg} 1682f7df2e56Smrg 1683f7df2e56Smrgint 1684f7df2e56SmrgSystem(const char *cmdline) 1685f7df2e56Smrg{ 1686f7df2e56Smrg STARTUPINFO si; 1687f7df2e56Smrg PROCESS_INFORMATION pi; 1688f7df2e56Smrg DWORD dwExitCode; 1689f7df2e56Smrg char *cmd = strdup(cmdline); 1690f7df2e56Smrg 1691f7df2e56Smrg ZeroMemory(&si, sizeof(si)); 1692f7df2e56Smrg si.cb = sizeof(si); 1693f7df2e56Smrg ZeroMemory(&pi, sizeof(pi)); 1694f7df2e56Smrg 1695f7df2e56Smrg if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { 1696f7df2e56Smrg LPVOID buffer; 1697f7df2e56Smrg 1698f7df2e56Smrg if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 1699f7df2e56Smrg FORMAT_MESSAGE_FROM_SYSTEM | 1700f7df2e56Smrg FORMAT_MESSAGE_IGNORE_INSERTS, 1701f7df2e56Smrg NULL, 1702f7df2e56Smrg GetLastError(), 1703f7df2e56Smrg MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 1704f7df2e56Smrg (LPTSTR) &buffer, 0, NULL)) { 1705f7df2e56Smrg ErrorF("[xkb] Starting '%s' failed!\n", cmdline); 1706f7df2e56Smrg } 1707f7df2e56Smrg else { 1708f7df2e56Smrg ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer); 1709f7df2e56Smrg LocalFree(buffer); 1710f7df2e56Smrg } 1711f7df2e56Smrg 1712f7df2e56Smrg free(cmd); 1713f7df2e56Smrg return -1; 1714f7df2e56Smrg } 1715f7df2e56Smrg /* Wait until child process exits. */ 1716f7df2e56Smrg WaitForSingleObject(pi.hProcess, INFINITE); 1717f7df2e56Smrg 1718f7df2e56Smrg GetExitCodeProcess(pi.hProcess, &dwExitCode); 171905b261ecSmrg 1720f7df2e56Smrg /* Close process and thread handles. */ 1721f7df2e56Smrg CloseHandle(pi.hProcess); 1722f7df2e56Smrg CloseHandle(pi.hThread); 1723f7df2e56Smrg free(cmd); 1724f7df2e56Smrg 1725f7df2e56Smrg return dwExitCode; 1726f7df2e56Smrg} 1727f7df2e56Smrg#endif 172805b261ecSmrg 17297e31ba66SmrgBool 17307e31ba66SmrgPrivsElevated(void) 17317e31ba66Smrg{ 17327e31ba66Smrg static Bool privsTested = FALSE; 17337e31ba66Smrg static Bool privsElevated = TRUE; 17347e31ba66Smrg 17357e31ba66Smrg if (!privsTested) { 17367e31ba66Smrg#if defined(WIN32) 17377e31ba66Smrg privsElevated = FALSE; 17387e31ba66Smrg#else 17397e31ba66Smrg if ((getuid() != geteuid()) || (getgid() != getegid())) { 17407e31ba66Smrg privsElevated = TRUE; 17417e31ba66Smrg } 17427e31ba66Smrg else { 17437e31ba66Smrg#if defined(HAVE_ISSETUGID) 17447e31ba66Smrg privsElevated = issetugid(); 17457e31ba66Smrg#elif defined(HAVE_GETRESUID) 17467e31ba66Smrg uid_t ruid, euid, suid; 17477e31ba66Smrg gid_t rgid, egid, sgid; 17487e31ba66Smrg 17497e31ba66Smrg if ((getresuid(&ruid, &euid, &suid) == 0) && 17507e31ba66Smrg (getresgid(&rgid, &egid, &sgid) == 0)) { 17517e31ba66Smrg privsElevated = (euid != suid) || (egid != sgid); 17527e31ba66Smrg } 17537e31ba66Smrg else { 17547e31ba66Smrg printf("Failed getresuid or getresgid"); 17557e31ba66Smrg /* Something went wrong, make defensive assumption */ 17567e31ba66Smrg privsElevated = TRUE; 17577e31ba66Smrg } 17587e31ba66Smrg#else 17597e31ba66Smrg if (getuid() == 0) { 17607e31ba66Smrg /* running as root: uid==euid==0 */ 17617e31ba66Smrg privsElevated = FALSE; 17627e31ba66Smrg } 17637e31ba66Smrg else { 17647e31ba66Smrg /* 17657e31ba66Smrg * If there are saved ID's the process might still be privileged 17667e31ba66Smrg * even though the above test succeeded. If issetugid() and 17677e31ba66Smrg * getresgid() aren't available, test this by trying to set 17687e31ba66Smrg * euid to 0. 17697e31ba66Smrg */ 17707e31ba66Smrg unsigned int oldeuid; 17717e31ba66Smrg 17727e31ba66Smrg oldeuid = geteuid(); 17737e31ba66Smrg 17747e31ba66Smrg if (seteuid(0) != 0) { 17757e31ba66Smrg privsElevated = FALSE; 17767e31ba66Smrg } 17777e31ba66Smrg else { 17787e31ba66Smrg if (seteuid(oldeuid) != 0) { 17797e31ba66Smrg FatalError("Failed to drop privileges. Exiting\n"); 17807e31ba66Smrg } 17817e31ba66Smrg privsElevated = TRUE; 17827e31ba66Smrg } 17837e31ba66Smrg } 17847e31ba66Smrg#endif 17857e31ba66Smrg } 17867e31ba66Smrg#endif 17877e31ba66Smrg privsTested = TRUE; 17887e31ba66Smrg } 17897e31ba66Smrg return privsElevated; 17907e31ba66Smrg} 17917e31ba66Smrg 179205b261ecSmrg/* 179305b261ecSmrg * CheckUserParameters: check for long command line arguments and long 179405b261ecSmrg * environment variables. By default, these checks are only done when 179505b261ecSmrg * the server's euid != ruid. In 3.3.x, these checks were done in an 179605b261ecSmrg * external wrapper utility. 179705b261ecSmrg */ 179805b261ecSmrg 179905b261ecSmrg/* Consider LD* variables insecure? */ 180005b261ecSmrg#ifndef REMOVE_ENV_LD 180105b261ecSmrg#define REMOVE_ENV_LD 1 180205b261ecSmrg#endif 180305b261ecSmrg 180405b261ecSmrg/* Remove long environment variables? */ 180505b261ecSmrg#ifndef REMOVE_LONG_ENV 180605b261ecSmrg#define REMOVE_LONG_ENV 1 180705b261ecSmrg#endif 180805b261ecSmrg 180905b261ecSmrg/* 181005b261ecSmrg * Disallow stdout or stderr as pipes? It's possible to block the X server 181105b261ecSmrg * when piping stdout+stderr to a pipe. 181205b261ecSmrg * 181305b261ecSmrg * Don't enable this because it looks like it's going to cause problems. 181405b261ecSmrg */ 181505b261ecSmrg#ifndef NO_OUTPUT_PIPES 181605b261ecSmrg#define NO_OUTPUT_PIPES 0 181705b261ecSmrg#endif 181805b261ecSmrg 181905b261ecSmrg/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */ 182005b261ecSmrg#ifndef CHECK_EUID 182105b261ecSmrg#ifndef WIN32 182205b261ecSmrg#define CHECK_EUID 1 182305b261ecSmrg#else 182405b261ecSmrg#define CHECK_EUID 0 182505b261ecSmrg#endif 182605b261ecSmrg#endif 182705b261ecSmrg 182805b261ecSmrg/* 182905b261ecSmrg * Maybe the locale can be faked to make isprint(3) report that everything 183005b261ecSmrg * is printable? Avoid it by default. 183105b261ecSmrg */ 183205b261ecSmrg#ifndef USE_ISPRINT 183305b261ecSmrg#define USE_ISPRINT 0 183405b261ecSmrg#endif 183505b261ecSmrg 183605b261ecSmrg#define MAX_ARG_LENGTH 128 183705b261ecSmrg#define MAX_ENV_LENGTH 256 1838f7df2e56Smrg#define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */ 183905b261ecSmrg 184005b261ecSmrg#if USE_ISPRINT 184105b261ecSmrg#include <ctype.h> 184205b261ecSmrg#define checkPrintable(c) isprint(c) 184305b261ecSmrg#else 184405b261ecSmrg#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f) 184505b261ecSmrg#endif 184605b261ecSmrg 184705b261ecSmrgenum BadCode { 184805b261ecSmrg NotBad = 0, 184905b261ecSmrg UnsafeArg, 185005b261ecSmrg ArgTooLong, 185105b261ecSmrg UnprintableArg, 185205b261ecSmrg EnvTooLong, 185305b261ecSmrg OutputIsPipe, 185405b261ecSmrg InternalError 185505b261ecSmrg}; 185605b261ecSmrg 185705b261ecSmrg#if defined(VENDORSUPPORT) 185805b261ecSmrg#define BUGADDRESS VENDORSUPPORT 185905b261ecSmrg#elif defined(BUILDERADDR) 186005b261ecSmrg#define BUGADDRESS BUILDERADDR 186105b261ecSmrg#else 186205b261ecSmrg#define BUGADDRESS "xorg@freedesktop.org" 186305b261ecSmrg#endif 186405b261ecSmrg 186505b261ecSmrgvoid 186605b261ecSmrgCheckUserParameters(int argc, char **argv, char **envp) 186705b261ecSmrg{ 186805b261ecSmrg enum BadCode bad = NotBad; 186905b261ecSmrg int i = 0, j; 187005b261ecSmrg char *a, *e = NULL; 187105b261ecSmrg 187205b261ecSmrg#if CHECK_EUID 18737e31ba66Smrg if (PrivsElevated()) 187405b261ecSmrg#endif 187505b261ecSmrg { 1876f7df2e56Smrg /* Check each argv[] */ 1877f7df2e56Smrg for (i = 1; i < argc; i++) { 1878f7df2e56Smrg if (strcmp(argv[i], "-fp") == 0) { 1879f7df2e56Smrg i++; /* continue with next argument. skip the length check */ 1880f7df2e56Smrg if (i >= argc) 1881f7df2e56Smrg break; 1882f7df2e56Smrg } 1883f7df2e56Smrg else { 1884f7df2e56Smrg if (strlen(argv[i]) > MAX_ARG_LENGTH) { 1885f7df2e56Smrg bad = ArgTooLong; 1886f7df2e56Smrg break; 1887f7df2e56Smrg } 1888f7df2e56Smrg } 1889f7df2e56Smrg a = argv[i]; 1890f7df2e56Smrg while (*a) { 1891f7df2e56Smrg if (checkPrintable(*a) == 0) { 1892f7df2e56Smrg bad = UnprintableArg; 1893f7df2e56Smrg break; 1894f7df2e56Smrg } 1895f7df2e56Smrg a++; 1896f7df2e56Smrg } 1897f7df2e56Smrg if (bad) 1898f7df2e56Smrg break; 1899f7df2e56Smrg } 1900f7df2e56Smrg if (!bad) { 1901f7df2e56Smrg /* Check each envp[] */ 1902f7df2e56Smrg for (i = 0; envp[i]; i++) { 190305b261ecSmrg 1904f7df2e56Smrg /* Check for bad environment variables and values */ 190505b261ecSmrg#if REMOVE_ENV_LD 1906f7df2e56Smrg while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) { 1907f7df2e56Smrg for (j = i; envp[j]; j++) { 1908f7df2e56Smrg envp[j] = envp[j + 1]; 1909f7df2e56Smrg } 1910f7df2e56Smrg } 1911f7df2e56Smrg#endif 1912f7df2e56Smrg if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) { 191305b261ecSmrg#if REMOVE_LONG_ENV 1914f7df2e56Smrg for (j = i; envp[j]; j++) { 1915f7df2e56Smrg envp[j] = envp[j + 1]; 1916f7df2e56Smrg } 1917f7df2e56Smrg i--; 191805b261ecSmrg#else 1919f7df2e56Smrg char *eq; 1920f7df2e56Smrg int len; 1921f7df2e56Smrg 1922f7df2e56Smrg eq = strchr(envp[i], '='); 1923f7df2e56Smrg if (!eq) 1924f7df2e56Smrg continue; 1925f7df2e56Smrg len = eq - envp[i]; 1926f7df2e56Smrg e = strndup(envp[i], len); 1927f7df2e56Smrg if (!e) { 1928f7df2e56Smrg bad = InternalError; 1929f7df2e56Smrg break; 1930f7df2e56Smrg } 1931f7df2e56Smrg if (len >= 4 && 1932f7df2e56Smrg (strcmp(e + len - 4, "PATH") == 0 || 1933f7df2e56Smrg strcmp(e, "TERMCAP") == 0)) { 1934f7df2e56Smrg if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) { 1935f7df2e56Smrg bad = EnvTooLong; 1936f7df2e56Smrg break; 1937f7df2e56Smrg } 1938f7df2e56Smrg else { 1939f7df2e56Smrg free(e); 1940f7df2e56Smrg } 1941f7df2e56Smrg } 1942f7df2e56Smrg else { 1943f7df2e56Smrg bad = EnvTooLong; 1944f7df2e56Smrg break; 1945f7df2e56Smrg } 1946f7df2e56Smrg#endif 1947f7df2e56Smrg } 1948f7df2e56Smrg } 1949f7df2e56Smrg } 195005b261ecSmrg#if NO_OUTPUT_PIPES 1951f7df2e56Smrg if (!bad) { 1952f7df2e56Smrg struct stat buf; 195305b261ecSmrg 1954f7df2e56Smrg if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1955f7df2e56Smrg bad = OutputIsPipe; 1956f7df2e56Smrg if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1957f7df2e56Smrg bad = OutputIsPipe; 1958f7df2e56Smrg } 195905b261ecSmrg#endif 196005b261ecSmrg } 196105b261ecSmrg switch (bad) { 196205b261ecSmrg case NotBad: 1963f7df2e56Smrg return; 196405b261ecSmrg case UnsafeArg: 1965f7df2e56Smrg ErrorF("Command line argument number %d is unsafe\n", i); 1966f7df2e56Smrg break; 196705b261ecSmrg case ArgTooLong: 1968f7df2e56Smrg ErrorF("Command line argument number %d is too long\n", i); 1969f7df2e56Smrg break; 197005b261ecSmrg case UnprintableArg: 1971f7df2e56Smrg ErrorF("Command line argument number %d contains unprintable" 1972f7df2e56Smrg " characters\n", i); 1973f7df2e56Smrg break; 197405b261ecSmrg case EnvTooLong: 1975f7df2e56Smrg ErrorF("Environment variable `%s' is too long\n", e); 1976f7df2e56Smrg break; 197705b261ecSmrg case OutputIsPipe: 1978f7df2e56Smrg ErrorF("Stdout and/or stderr is a pipe\n"); 1979f7df2e56Smrg break; 198005b261ecSmrg case InternalError: 1981f7df2e56Smrg ErrorF("Internal Error\n"); 1982f7df2e56Smrg break; 198305b261ecSmrg default: 1984f7df2e56Smrg ErrorF("Unknown error\n"); 1985f7df2e56Smrg break; 198605b261ecSmrg } 198705b261ecSmrg FatalError("X server aborted because of unsafe environment\n"); 198805b261ecSmrg} 198905b261ecSmrg 199005b261ecSmrg/* 199105b261ecSmrg * CheckUserAuthorization: check if the user is allowed to start the 199205b261ecSmrg * X server. This usually means some sort of PAM checking, and it is 199305b261ecSmrg * usually only done for setuid servers (uid != euid). 199405b261ecSmrg */ 199505b261ecSmrg 199605b261ecSmrg#ifdef USE_PAM 199705b261ecSmrg#include <security/pam_appl.h> 199805b261ecSmrg#include <security/pam_misc.h> 199905b261ecSmrg#include <pwd.h> 2000f7df2e56Smrg#endif /* USE_PAM */ 200105b261ecSmrg 200205b261ecSmrgvoid 200305b261ecSmrgCheckUserAuthorization(void) 200405b261ecSmrg{ 200505b261ecSmrg#ifdef USE_PAM 200605b261ecSmrg static struct pam_conv conv = { 2007f7df2e56Smrg misc_conv, 2008f7df2e56Smrg NULL 200905b261ecSmrg }; 201005b261ecSmrg 201105b261ecSmrg pam_handle_t *pamh = NULL; 201205b261ecSmrg struct passwd *pw; 201305b261ecSmrg int retval; 201405b261ecSmrg 201505b261ecSmrg if (getuid() != geteuid()) { 2016f7df2e56Smrg pw = getpwuid(getuid()); 2017f7df2e56Smrg if (pw == NULL) 2018f7df2e56Smrg FatalError("getpwuid() failed for uid %d\n", getuid()); 2019f7df2e56Smrg 2020f7df2e56Smrg retval = pam_start("xserver", pw->pw_name, &conv, &pamh); 2021f7df2e56Smrg if (retval != PAM_SUCCESS) 2022f7df2e56Smrg FatalError("pam_start() failed.\n" 2023f7df2e56Smrg "\tMissing or mangled PAM config file or module?\n"); 2024f7df2e56Smrg 2025f7df2e56Smrg retval = pam_authenticate(pamh, 0); 2026f7df2e56Smrg if (retval != PAM_SUCCESS) { 2027f7df2e56Smrg pam_end(pamh, retval); 2028f7df2e56Smrg FatalError("PAM authentication failed, cannot start X server.\n" 2029f7df2e56Smrg "\tPerhaps you do not have console ownership?\n"); 2030f7df2e56Smrg } 203105b261ecSmrg 2032f7df2e56Smrg retval = pam_acct_mgmt(pamh, 0); 2033f7df2e56Smrg if (retval != PAM_SUCCESS) { 2034f7df2e56Smrg pam_end(pamh, retval); 2035f7df2e56Smrg FatalError("PAM authentication failed, cannot start X server.\n" 2036f7df2e56Smrg "\tPerhaps you do not have console ownership?\n"); 2037f7df2e56Smrg } 203805b261ecSmrg 2039f7df2e56Smrg /* this is not a session, so do not do session management */ 2040f7df2e56Smrg pam_end(pamh, PAM_SUCCESS); 204105b261ecSmrg } 204205b261ecSmrg#endif 204305b261ecSmrg} 204405b261ecSmrg 20454202a189Smrg/* 20464202a189Smrg * Tokenize a string into a NULL terminated array of strings. Always returns 20474202a189Smrg * an allocated array unless an error occurs. 20484202a189Smrg */ 2049f7df2e56Smrgchar ** 20504202a189Smrgxstrtokenize(const char *str, const char *separators) 205105b261ecSmrg{ 20524202a189Smrg char **list, **nlist; 20534202a189Smrg char *tok, *tmp; 20544202a189Smrg unsigned num = 0, n; 205505b261ecSmrg 20564202a189Smrg if (!str) 20574202a189Smrg return NULL; 20584202a189Smrg list = calloc(1, sizeof(*list)); 20594202a189Smrg if (!list) 20604202a189Smrg return NULL; 20614202a189Smrg tmp = strdup(str); 20624202a189Smrg if (!tmp) 20634202a189Smrg goto error; 20644202a189Smrg for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) { 2065f7df2e56Smrg nlist = reallocarray(list, num + 2, sizeof(*list)); 20664202a189Smrg if (!nlist) 20674202a189Smrg goto error; 20684202a189Smrg list = nlist; 20694202a189Smrg list[num] = strdup(tok); 20704202a189Smrg if (!list[num]) 20714202a189Smrg goto error; 20724202a189Smrg list[++num] = NULL; 20734202a189Smrg } 20744202a189Smrg free(tmp); 20754202a189Smrg return list; 20764202a189Smrg 2077f7df2e56Smrg error: 20784202a189Smrg free(tmp); 20794202a189Smrg for (n = 0; n < num; n++) 20804202a189Smrg free(list[n]); 20814202a189Smrg free(list); 20824202a189Smrg return NULL; 208305b261ecSmrg} 2084f7df2e56Smrg 2085f7df2e56Smrg/* Format a signed number into a string in a signal safe manner. The string 2086f7df2e56Smrg * should be at least 21 characters in order to handle all int64_t values. 2087f7df2e56Smrg */ 2088f7df2e56Smrgvoid 2089f7df2e56SmrgFormatInt64(int64_t num, char *string) 2090f7df2e56Smrg{ 2091f7df2e56Smrg if (num < 0) { 2092f7df2e56Smrg string[0] = '-'; 2093f7df2e56Smrg num *= -1; 2094f7df2e56Smrg string++; 2095f7df2e56Smrg } 2096f7df2e56Smrg FormatUInt64(num, string); 2097f7df2e56Smrg} 2098f7df2e56Smrg 2099f7df2e56Smrg/* Format a number into a string in a signal safe manner. The string should be 2100f7df2e56Smrg * at least 21 characters in order to handle all uint64_t values. */ 2101f7df2e56Smrgvoid 2102f7df2e56SmrgFormatUInt64(uint64_t num, char *string) 2103f7df2e56Smrg{ 2104f7df2e56Smrg uint64_t divisor; 2105f7df2e56Smrg int len; 2106f7df2e56Smrg int i; 2107f7df2e56Smrg 2108f7df2e56Smrg for (len = 1, divisor = 10; 2109f7df2e56Smrg len < 20 && num / divisor; 2110f7df2e56Smrg len++, divisor *= 10); 2111f7df2e56Smrg 2112f7df2e56Smrg for (i = len, divisor = 1; i > 0; i--, divisor *= 10) 2113f7df2e56Smrg string[i - 1] = '0' + ((num / divisor) % 10); 2114f7df2e56Smrg 2115f7df2e56Smrg string[len] = '\0'; 2116f7df2e56Smrg} 2117f7df2e56Smrg 2118f7df2e56Smrg/** 2119f7df2e56Smrg * Format a double number as %.2f. 2120f7df2e56Smrg */ 2121f7df2e56Smrgvoid 2122f7df2e56SmrgFormatDouble(double dbl, char *string) 2123f7df2e56Smrg{ 2124f7df2e56Smrg int slen = 0; 2125f7df2e56Smrg uint64_t frac; 2126f7df2e56Smrg 2127f7df2e56Smrg frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5; 2128f7df2e56Smrg frac %= 100; 2129f7df2e56Smrg 2130f7df2e56Smrg /* write decimal part to string */ 2131f7df2e56Smrg if (dbl < 0 && dbl > -1) 2132f7df2e56Smrg string[slen++] = '-'; 2133f7df2e56Smrg FormatInt64((int64_t)dbl, &string[slen]); 2134f7df2e56Smrg 2135f7df2e56Smrg while(string[slen] != '\0') 2136f7df2e56Smrg slen++; 2137f7df2e56Smrg 2138f7df2e56Smrg /* append fractional part, but only if we have enough characters. We 2139f7df2e56Smrg * expect string to be 21 chars (incl trailing \0) */ 2140f7df2e56Smrg if (slen <= 17) { 2141f7df2e56Smrg string[slen++] = '.'; 2142f7df2e56Smrg if (frac < 10) 2143f7df2e56Smrg string[slen++] = '0'; 2144f7df2e56Smrg 2145f7df2e56Smrg FormatUInt64(frac, &string[slen]); 2146f7df2e56Smrg } 2147f7df2e56Smrg} 2148f7df2e56Smrg 2149f7df2e56Smrg 2150f7df2e56Smrg/* Format a number into a hexadecimal string in a signal safe manner. The string 2151f7df2e56Smrg * should be at least 17 characters in order to handle all uint64_t values. */ 2152f7df2e56Smrgvoid 2153f7df2e56SmrgFormatUInt64Hex(uint64_t num, char *string) 2154f7df2e56Smrg{ 2155f7df2e56Smrg uint64_t divisor; 2156f7df2e56Smrg int len; 2157f7df2e56Smrg int i; 2158f7df2e56Smrg 2159f7df2e56Smrg for (len = 1, divisor = 0x10; 2160f7df2e56Smrg len < 16 && num / divisor; 2161f7df2e56Smrg len++, divisor *= 0x10); 2162f7df2e56Smrg 2163f7df2e56Smrg for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) { 2164f7df2e56Smrg int val = (num / divisor) % 0x10; 2165f7df2e56Smrg 2166f7df2e56Smrg if (val < 10) 2167f7df2e56Smrg string[i - 1] = '0' + val; 2168f7df2e56Smrg else 2169f7df2e56Smrg string[i - 1] = 'a' + val - 10; 2170f7df2e56Smrg } 2171f7df2e56Smrg 2172f7df2e56Smrg string[len] = '\0'; 2173f7df2e56Smrg} 2174f7df2e56Smrg 2175f7df2e56Smrg#if !defined(WIN32) || defined(__CYGWIN__) 2176f7df2e56Smrg/* Move a file descriptor out of the way of our select mask; this 2177f7df2e56Smrg * is useful for file descriptors which will never appear in the 2178f7df2e56Smrg * select mask to avoid reducing the number of clients that can 2179f7df2e56Smrg * connect to the server 2180f7df2e56Smrg */ 2181f7df2e56Smrgint 2182f7df2e56Smrgos_move_fd(int fd) 2183f7df2e56Smrg{ 2184f7df2e56Smrg int newfd; 2185f7df2e56Smrg 2186f7df2e56Smrg#ifdef F_DUPFD_CLOEXEC 2187f7df2e56Smrg newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS); 2188f7df2e56Smrg#else 2189f7df2e56Smrg newfd = fcntl(fd, F_DUPFD, MAXCLIENTS); 2190f7df2e56Smrg#endif 2191f7df2e56Smrg if (newfd < 0) 2192f7df2e56Smrg return fd; 2193f7df2e56Smrg#ifndef F_DUPFD_CLOEXEC 2194f7df2e56Smrg fcntl(newfd, F_SETFD, FD_CLOEXEC); 2195f7df2e56Smrg#endif 2196f7df2e56Smrg close(fd); 2197f7df2e56Smrg return newfd; 2198f7df2e56Smrg} 2199f7df2e56Smrg#endif 2200