utils.c revision 7e31ba66
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 1134202a189SmrgBool noTestExtensions; 114f7df2e56Smrg 11505b261ecSmrg#ifdef COMPOSITE 1164202a189SmrgBool noCompositeExtension = FALSE; 11705b261ecSmrg#endif 11805b261ecSmrg 11905b261ecSmrg#ifdef DAMAGE 1204202a189SmrgBool noDamageExtension = FALSE; 12105b261ecSmrg#endif 12205b261ecSmrg#ifdef DBE 1234202a189SmrgBool noDbeExtension = FALSE; 12405b261ecSmrg#endif 12505b261ecSmrg#ifdef DPMSExtension 1267e31ba66Smrg#include "dpmsproc.h" 1274202a189SmrgBool noDPMSExtension = FALSE; 12805b261ecSmrg#endif 12905b261ecSmrg#ifdef GLXEXT 1304202a189SmrgBool noGlxExtension = FALSE; 13105b261ecSmrg#endif 13205b261ecSmrg#ifdef SCREENSAVER 1334202a189SmrgBool noScreenSaverExtension = FALSE; 13405b261ecSmrg#endif 13505b261ecSmrg#ifdef MITSHM 1364202a189SmrgBool noMITShmExtension = FALSE; 13705b261ecSmrg#endif 13805b261ecSmrg#ifdef RANDR 1394202a189SmrgBool noRRExtension = FALSE; 14005b261ecSmrg#endif 1414202a189SmrgBool noRenderExtension = FALSE; 142f7df2e56Smrg 14305b261ecSmrg#ifdef XCSECURITY 1444202a189SmrgBool noSecurityExtension = FALSE; 14505b261ecSmrg#endif 14605b261ecSmrg#ifdef RES 1474202a189SmrgBool noResExtension = FALSE; 14805b261ecSmrg#endif 14905b261ecSmrg#ifdef XF86BIGFONT 1504202a189SmrgBool noXFree86BigfontExtension = FALSE; 15105b261ecSmrg#endif 15205b261ecSmrg#ifdef XFreeXDGA 1534202a189SmrgBool noXFree86DGAExtension = FALSE; 15405b261ecSmrg#endif 15505b261ecSmrg#ifdef XF86DRI 1564202a189SmrgBool noXFree86DRIExtension = FALSE; 15705b261ecSmrg#endif 15805b261ecSmrg#ifdef XF86VIDMODE 1594202a189SmrgBool noXFree86VidModeExtension = FALSE; 16005b261ecSmrg#endif 1614202a189SmrgBool noXFixesExtension = FALSE; 16205b261ecSmrg#ifdef PANORAMIX 16305b261ecSmrg/* Xinerama is disabled by default unless enabled via +xinerama */ 1644202a189SmrgBool noPanoramiXExtension = TRUE; 16505b261ecSmrg#endif 1664642e01fSmrg#ifdef XSELINUX 1674202a189SmrgBool noSELinuxExtension = FALSE; 1684202a189Smrgint selinuxEnforcingState = SELINUX_MODE_DEFAULT; 16905b261ecSmrg#endif 17005b261ecSmrg#ifdef XV 1714202a189SmrgBool noXvExtension = FALSE; 17205b261ecSmrg#endif 1734642e01fSmrg#ifdef DRI2 1744202a189SmrgBool noDRI2Extension = FALSE; 1754642e01fSmrg#endif 1764642e01fSmrg 1774202a189SmrgBool noGEExtension = FALSE; 17805b261ecSmrg 17905b261ecSmrg#define X_INCLUDE_NETDB_H 18005b261ecSmrg#include <X11/Xos_r.h> 18105b261ecSmrg 18205b261ecSmrg#include <errno.h> 18305b261ecSmrg 18405b261ecSmrgBool CoreDump; 18505b261ecSmrg 186f7df2e56SmrgBool enableIndirectGLX = FALSE; 187f7df2e56Smrg 18805b261ecSmrg#ifdef PANORAMIX 18905b261ecSmrgBool PanoramiXExtensionDisabledHack = FALSE; 19005b261ecSmrg#endif 19105b261ecSmrg 19205b261ecSmrgint auditTrailLevel = 1; 19305b261ecSmrg 194f7df2e56Smrgchar *SeatId = NULL; 195f7df2e56Smrg 196f7df2e56Smrgsig_atomic_t inSignalContext = FALSE; 197f7df2e56Smrg 19805b261ecSmrg#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED) 19905b261ecSmrg#define HAS_SAVED_IDS_AND_SETEUID 20005b261ecSmrg#endif 20105b261ecSmrg 2027e31ba66Smrg#ifdef MONOTONIC_CLOCK 2037e31ba66Smrgstatic clockid_t clockid; 2047e31ba66Smrg#endif 2057e31ba66Smrg 20605b261ecSmrgOsSigHandlerPtr 2074202a189SmrgOsSignal(int sig, OsSigHandlerPtr handler) 20805b261ecSmrg{ 209f7df2e56Smrg#if defined(WIN32) && !defined(__CYGWIN__) 210f7df2e56Smrg return signal(sig, handler); 211f7df2e56Smrg#else 21205b261ecSmrg struct sigaction act, oact; 21305b261ecSmrg 21405b261ecSmrg sigemptyset(&act.sa_mask); 21505b261ecSmrg if (handler != SIG_IGN) 216f7df2e56Smrg sigaddset(&act.sa_mask, sig); 21705b261ecSmrg act.sa_flags = 0; 21805b261ecSmrg act.sa_handler = handler; 21905b261ecSmrg if (sigaction(sig, &act, &oact)) 220f7df2e56Smrg perror("sigaction"); 22105b261ecSmrg return oact.sa_handler; 222f7df2e56Smrg#endif 22305b261ecSmrg} 2244642e01fSmrg 22505b261ecSmrg/* 22605b261ecSmrg * Explicit support for a server lock file like the ones used for UUCP. 22705b261ecSmrg * For architectures with virtual terminals that can run more than one 22805b261ecSmrg * server at a time. This keeps the servers from stomping on each other 22905b261ecSmrg * if the user forgets to give them different display numbers. 23005b261ecSmrg */ 23105b261ecSmrg#define LOCK_DIR "/tmp" 23205b261ecSmrg#define LOCK_TMP_PREFIX "/.tX" 23305b261ecSmrg#define LOCK_PREFIX "/.X" 23405b261ecSmrg#define LOCK_SUFFIX "-lock" 23505b261ecSmrg 236f7df2e56Smrg#if !defined(WIN32) || defined(__CYGWIN__) 237f7df2e56Smrg#define LOCK_SERVER 23805b261ecSmrg#endif 23905b261ecSmrg 240f7df2e56Smrg#ifndef LOCK_SERVER 241f7df2e56Smrgvoid 242f7df2e56SmrgLockServer(void) 243f7df2e56Smrg{} 244f7df2e56Smrg 245f7df2e56Smrgvoid 246f7df2e56SmrgUnlockServer(void) 247f7df2e56Smrg{} 248f7df2e56Smrg#else /* LOCK_SERVER */ 24905b261ecSmrgstatic Bool StillLocking = FALSE; 25005b261ecSmrgstatic char LockFile[PATH_MAX]; 25105b261ecSmrgstatic Bool nolock = FALSE; 25205b261ecSmrg 25305b261ecSmrg/* 25405b261ecSmrg * LockServer -- 25505b261ecSmrg * Check if the server lock file exists. If so, check if the PID 25605b261ecSmrg * contained inside is valid. If so, then die. Otherwise, create 25705b261ecSmrg * the lock file containing the PID. 25805b261ecSmrg */ 25905b261ecSmrgvoid 26005b261ecSmrgLockServer(void) 26105b261ecSmrg{ 262f7df2e56Smrg char tmp[PATH_MAX], pid_str[12]; 263f7df2e56Smrg int lfd, i, haslock, l_pid, t; 264f7df2e56Smrg const char *tmppath = LOCK_DIR; 265f7df2e56Smrg int len; 266f7df2e56Smrg char port[20]; 267f7df2e56Smrg 268f7df2e56Smrg if (nolock || NoListenAll) 269f7df2e56Smrg return; 270f7df2e56Smrg /* 271f7df2e56Smrg * Path names 272f7df2e56Smrg */ 273f7df2e56Smrg snprintf(port, sizeof(port), "%d", atoi(display)); 274f7df2e56Smrg len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) : 275f7df2e56Smrg strlen(LOCK_TMP_PREFIX); 276f7df2e56Smrg len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1; 277f7df2e56Smrg if (len > sizeof(LockFile)) 278f7df2e56Smrg FatalError("Display name `%s' is too long\n", port); 279f7df2e56Smrg (void) sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port); 280f7df2e56Smrg (void) sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port); 281f7df2e56Smrg 282f7df2e56Smrg /* 283f7df2e56Smrg * Create a temporary file containing our PID. Attempt three times 284f7df2e56Smrg * to create the file. 285f7df2e56Smrg */ 286f7df2e56Smrg StillLocking = TRUE; 28705b261ecSmrg i = 0; 28805b261ecSmrg do { 289f7df2e56Smrg i++; 290f7df2e56Smrg lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); 291f7df2e56Smrg if (lfd < 0) 292f7df2e56Smrg sleep(2); 293f7df2e56Smrg else 294f7df2e56Smrg break; 29505b261ecSmrg } while (i < 3); 296f7df2e56Smrg if (lfd < 0) { 29705b261ecSmrg unlink(tmp); 298f7df2e56Smrg i = 0; 299f7df2e56Smrg do { 300f7df2e56Smrg i++; 301f7df2e56Smrg lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); 302f7df2e56Smrg if (lfd < 0) 303f7df2e56Smrg sleep(2); 304f7df2e56Smrg else 305f7df2e56Smrg break; 306f7df2e56Smrg } while (i < 3); 30705b261ecSmrg } 308f7df2e56Smrg if (lfd < 0) 309f7df2e56Smrg FatalError("Could not create lock file in %s\n", tmp); 3107e31ba66Smrg snprintf(pid_str, sizeof(pid_str), "%10lu\n", (unsigned long) getpid()); 311f7df2e56Smrg if (write(lfd, pid_str, 11) != 11) 312f7df2e56Smrg FatalError("Could not write pid to lock file in %s\n", tmp); 313f7df2e56Smrg (void) fchmod(lfd, 0444); 314f7df2e56Smrg (void) close(lfd); 315f7df2e56Smrg 316f7df2e56Smrg /* 317f7df2e56Smrg * OK. Now the tmp file exists. Try three times to move it in place 318f7df2e56Smrg * for the lock. 319f7df2e56Smrg */ 320f7df2e56Smrg i = 0; 321f7df2e56Smrg haslock = 0; 322f7df2e56Smrg while ((!haslock) && (i++ < 3)) { 323f7df2e56Smrg haslock = (link(tmp, LockFile) == 0); 324f7df2e56Smrg if (haslock) { 325f7df2e56Smrg /* 326f7df2e56Smrg * We're done. 327f7df2e56Smrg */ 328f7df2e56Smrg break; 329f7df2e56Smrg } 330f7df2e56Smrg else { 331f7df2e56Smrg /* 332f7df2e56Smrg * Read the pid from the existing file 333f7df2e56Smrg */ 334f7df2e56Smrg lfd = open(LockFile, O_RDONLY | O_NOFOLLOW); 335f7df2e56Smrg if (lfd < 0) { 336f7df2e56Smrg unlink(tmp); 337f7df2e56Smrg FatalError("Can't read lock file %s\n", LockFile); 338f7df2e56Smrg } 339f7df2e56Smrg pid_str[0] = '\0'; 340f7df2e56Smrg if (read(lfd, pid_str, 11) != 11) { 341f7df2e56Smrg /* 342f7df2e56Smrg * Bogus lock file. 343f7df2e56Smrg */ 344f7df2e56Smrg unlink(LockFile); 345f7df2e56Smrg close(lfd); 346f7df2e56Smrg continue; 347f7df2e56Smrg } 348f7df2e56Smrg pid_str[11] = '\0'; 349f7df2e56Smrg sscanf(pid_str, "%d", &l_pid); 350f7df2e56Smrg close(lfd); 351f7df2e56Smrg 352f7df2e56Smrg /* 353f7df2e56Smrg * Now try to kill the PID to see if it exists. 354f7df2e56Smrg */ 355f7df2e56Smrg errno = 0; 356f7df2e56Smrg t = kill(l_pid, 0); 357f7df2e56Smrg if ((t < 0) && (errno == ESRCH)) { 358f7df2e56Smrg /* 359f7df2e56Smrg * Stale lock file. 360f7df2e56Smrg */ 361f7df2e56Smrg unlink(LockFile); 362f7df2e56Smrg continue; 363f7df2e56Smrg } 364f7df2e56Smrg else if (((t < 0) && (errno == EPERM)) || (t == 0)) { 365f7df2e56Smrg /* 366f7df2e56Smrg * Process is still active. 367f7df2e56Smrg */ 368f7df2e56Smrg unlink(tmp); 369f7df2e56Smrg FatalError 370f7df2e56Smrg ("Server is already active for display %s\n%s %s\n%s\n", 371f7df2e56Smrg port, "\tIf this server is no longer running, remove", 372f7df2e56Smrg LockFile, "\tand start again."); 373f7df2e56Smrg } 374f7df2e56Smrg } 375f7df2e56Smrg } 376f7df2e56Smrg unlink(tmp); 377f7df2e56Smrg if (!haslock) 378f7df2e56Smrg FatalError("Could not create server lock file: %s\n", LockFile); 379f7df2e56Smrg StillLocking = FALSE; 38005b261ecSmrg} 38105b261ecSmrg 38205b261ecSmrg/* 38305b261ecSmrg * UnlockServer -- 38405b261ecSmrg * Remove the server lock file. 38505b261ecSmrg */ 38605b261ecSmrgvoid 38705b261ecSmrgUnlockServer(void) 38805b261ecSmrg{ 389f7df2e56Smrg if (nolock || NoListenAll) 390f7df2e56Smrg return; 39105b261ecSmrg 392f7df2e56Smrg if (!StillLocking) { 39305b261ecSmrg 394f7df2e56Smrg (void) unlink(LockFile); 395f7df2e56Smrg } 39605b261ecSmrg} 397f7df2e56Smrg#endif /* LOCK_SERVER */ 39805b261ecSmrg 39905b261ecSmrg/* Force connections to close on SIGHUP from init */ 40005b261ecSmrg 4014202a189Smrgvoid 402f7df2e56SmrgAutoResetServer(int sig) 40305b261ecSmrg{ 40405b261ecSmrg int olderrno = errno; 40505b261ecSmrg 40605b261ecSmrg dispatchException |= DE_RESET; 40705b261ecSmrg isItTimeToYield = TRUE; 40805b261ecSmrg errno = olderrno; 40905b261ecSmrg} 41005b261ecSmrg 41105b261ecSmrg/* Force connections to close and then exit on SIGTERM, SIGINT */ 41205b261ecSmrg 4134202a189Smrgvoid 41405b261ecSmrgGiveUp(int sig) 41505b261ecSmrg{ 41605b261ecSmrg int olderrno = errno; 41705b261ecSmrg 41805b261ecSmrg dispatchException |= DE_TERMINATE; 41905b261ecSmrg isItTimeToYield = TRUE; 42005b261ecSmrg errno = olderrno; 42105b261ecSmrg} 42205b261ecSmrg 4237e31ba66Smrg#ifdef MONOTONIC_CLOCK 4247e31ba66Smrgvoid 4257e31ba66SmrgForceClockId(clockid_t forced_clockid) 4267e31ba66Smrg{ 4277e31ba66Smrg struct timespec tp; 4287e31ba66Smrg 4297e31ba66Smrg BUG_RETURN (clockid); 4307e31ba66Smrg 4317e31ba66Smrg clockid = forced_clockid; 4327e31ba66Smrg 4337e31ba66Smrg if (clock_gettime(clockid, &tp) != 0) { 4347e31ba66Smrg FatalError("Forced clock id failed to retrieve current time: %s\n", 4357e31ba66Smrg strerror(errno)); 4367e31ba66Smrg return; 4377e31ba66Smrg } 4387e31ba66Smrg} 4397e31ba66Smrg#endif 4407e31ba66Smrg 4414202a189Smrg#if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__) 4424202a189SmrgCARD32 443f7df2e56SmrgGetTimeInMillis(void) 444f7df2e56Smrg{ 445f7df2e56Smrg return GetTickCount(); 446f7df2e56Smrg} 447f7df2e56SmrgCARD64 448f7df2e56SmrgGetTimeInMicros(void) 44905b261ecSmrg{ 450f7df2e56Smrg return (CARD64) GetTickCount() * 1000; 45105b261ecSmrg} 45205b261ecSmrg#else 4534202a189SmrgCARD32 45405b261ecSmrgGetTimeInMillis(void) 45505b261ecSmrg{ 45605b261ecSmrg struct timeval tv; 45705b261ecSmrg 45805b261ecSmrg#ifdef MONOTONIC_CLOCK 45905b261ecSmrg struct timespec tp; 460f7df2e56Smrg 4611b684552Smrg if (!clockid) { 4621b684552Smrg#ifdef CLOCK_MONOTONIC_COARSE 4631b684552Smrg if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 && 4641b684552Smrg (tp.tv_nsec / 1000) <= 1000 && 4651b684552Smrg clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0) 4661b684552Smrg clockid = CLOCK_MONOTONIC_COARSE; 4671b684552Smrg else 4681b684552Smrg#endif 4691b684552Smrg if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) 4701b684552Smrg clockid = CLOCK_MONOTONIC; 4711b684552Smrg else 4721b684552Smrg clockid = ~0L; 4731b684552Smrg } 4741b684552Smrg if (clockid != ~0L && clock_gettime(clockid, &tp) == 0) 47505b261ecSmrg return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L); 47605b261ecSmrg#endif 47705b261ecSmrg 47805b261ecSmrg X_GETTIMEOFDAY(&tv); 479f7df2e56Smrg return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); 480f7df2e56Smrg} 481f7df2e56Smrg 482f7df2e56SmrgCARD64 483f7df2e56SmrgGetTimeInMicros(void) 484f7df2e56Smrg{ 485f7df2e56Smrg struct timeval tv; 486f7df2e56Smrg#ifdef MONOTONIC_CLOCK 487f7df2e56Smrg struct timespec tp; 488f7df2e56Smrg 489f7df2e56Smrg if (!clockid) { 490f7df2e56Smrg if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) 491f7df2e56Smrg clockid = CLOCK_MONOTONIC; 492f7df2e56Smrg else 493f7df2e56Smrg clockid = ~0L; 494f7df2e56Smrg } 495f7df2e56Smrg if (clockid != ~0L && clock_gettime(clockid, &tp) == 0) 496f7df2e56Smrg return (CARD64) tp.tv_sec * (CARD64)1000000 + tp.tv_nsec / 1000; 497f7df2e56Smrg#endif 498f7df2e56Smrg 499f7df2e56Smrg X_GETTIMEOFDAY(&tv); 5007e31ba66Smrg return (CARD64) tv.tv_sec * (CARD64)1000000 + (CARD64) tv.tv_usec; 50105b261ecSmrg} 50205b261ecSmrg#endif 50305b261ecSmrg 504f7df2e56Smrgvoid 505f7df2e56SmrgUseMsg(void) 50605b261ecSmrg{ 50705b261ecSmrg ErrorF("use: X [:<display>] [option]\n"); 5084202a189Smrg ErrorF("-a # default pointer acceleration (factor)\n"); 50905b261ecSmrg ErrorF("-ac disable access control restrictions\n"); 510f7df2e56Smrg ErrorF("-audit int set audit trail level\n"); 511f7df2e56Smrg ErrorF("-auth file select authorization file\n"); 51205b261ecSmrg ErrorF("-br create root window with black background\n"); 51305b261ecSmrg ErrorF("+bs enable any backing store support\n"); 51405b261ecSmrg ErrorF("-bs disable any backing store support\n"); 51505b261ecSmrg ErrorF("-c turns off key-click\n"); 51605b261ecSmrg ErrorF("c # key-click volume (0-100)\n"); 51705b261ecSmrg ErrorF("-cc int default color visual class\n"); 5184202a189Smrg ErrorF("-nocursor disable the cursor\n"); 51905b261ecSmrg ErrorF("-core generate core dump on fatal error\n"); 520f7df2e56Smrg ErrorF("-displayfd fd file descriptor to write display number to when ready to connect\n"); 52105b261ecSmrg ErrorF("-dpi int screen resolution in dots per inch\n"); 52205b261ecSmrg#ifdef DPMSExtension 52305b261ecSmrg ErrorF("-dpms disables VESA DPMS monitor control\n"); 52405b261ecSmrg#endif 525f7df2e56Smrg ErrorF 526f7df2e56Smrg ("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n"); 52705b261ecSmrg ErrorF("-f # bell base (0-100)\n"); 52805b261ecSmrg ErrorF("-fc string cursor font\n"); 52905b261ecSmrg ErrorF("-fn string default font name\n"); 53005b261ecSmrg ErrorF("-fp string default font path\n"); 53105b261ecSmrg ErrorF("-help prints message with these options\n"); 532f7df2e56Smrg ErrorF("+iglx Allow creating indirect GLX contexts\n"); 533f7df2e56Smrg ErrorF("-iglx Prohibit creating indirect GLX contexts (default)\n"); 53405b261ecSmrg ErrorF("-I ignore all remaining arguments\n"); 53505b261ecSmrg#ifdef RLIMIT_DATA 53605b261ecSmrg ErrorF("-ld int limit data space to N Kb\n"); 53705b261ecSmrg#endif 53805b261ecSmrg#ifdef RLIMIT_NOFILE 53905b261ecSmrg ErrorF("-lf int limit number of open files to N\n"); 54005b261ecSmrg#endif 54105b261ecSmrg#ifdef RLIMIT_STACK 54205b261ecSmrg ErrorF("-ls int limit stack space to N Kb\n"); 54305b261ecSmrg#endif 544f7df2e56Smrg#ifdef LOCK_SERVER 54505b261ecSmrg ErrorF("-nolock disable the locking mechanism\n"); 546f7df2e56Smrg#endif 547f7df2e56Smrg ErrorF("-maxclients n set maximum number of clients (power of two)\n"); 54805b261ecSmrg ErrorF("-nolisten string don't listen on protocol\n"); 549f7df2e56Smrg ErrorF("-listen string listen on protocol\n"); 55005b261ecSmrg ErrorF("-noreset don't reset after last client exists\n"); 55165b04b38Smrg ErrorF("-background [none] create root window with no background\n"); 55205b261ecSmrg ErrorF("-reset reset after last client exists\n"); 55305b261ecSmrg ErrorF("-p # screen-saver pattern duration (minutes)\n"); 55405b261ecSmrg ErrorF("-pn accept failure to listen on all ports\n"); 55505b261ecSmrg ErrorF("-nopn reject failure to listen on all ports\n"); 55605b261ecSmrg ErrorF("-r turns off auto-repeat\n"); 55705b261ecSmrg ErrorF("r turns on auto-repeat \n"); 55805b261ecSmrg ErrorF("-render [default|mono|gray|color] set render color alloc policy\n"); 5594642e01fSmrg ErrorF("-retro start with classic stipple and cursor\n"); 560daf23d7fSsnj ErrorF("-noretro start with black background and no cursor\n"); 56105b261ecSmrg ErrorF("-s # screen-saver timeout (minutes)\n"); 562f7df2e56Smrg ErrorF("-seat string seat to run on\n"); 5634202a189Smrg ErrorF("-t # default pointer threshold (pixels/t)\n"); 56405b261ecSmrg ErrorF("-terminate terminate at server reset\n"); 56505b261ecSmrg ErrorF("-to # connection time out\n"); 56605b261ecSmrg ErrorF("-tst disable testing extensions\n"); 56705b261ecSmrg ErrorF("ttyxx server started from init on /dev/ttyxx\n"); 56805b261ecSmrg ErrorF("v video blanking for screen-saver\n"); 56905b261ecSmrg ErrorF("-v screen-saver without video blanking\n"); 57005b261ecSmrg ErrorF("-wm WhenMapped default backing-store\n"); 57105b261ecSmrg ErrorF("-wr create root window with white background\n"); 57205b261ecSmrg ErrorF("-maxbigreqsize set maximal bigrequest size \n"); 57305b261ecSmrg#ifdef PANORAMIX 57405b261ecSmrg ErrorF("+xinerama Enable XINERAMA extension\n"); 57505b261ecSmrg ErrorF("-xinerama Disable XINERAMA extension\n"); 57605b261ecSmrg#endif 577f7df2e56Smrg ErrorF 5787e31ba66Smrg ("-dumbSched Disable smart scheduling and threaded input, enable old behavior\n"); 57905b261ecSmrg ErrorF("-schedInterval int Set scheduler interval in msec\n"); 58065b04b38Smrg ErrorF("-sigstop Enable SIGSTOP based startup\n"); 58105b261ecSmrg ErrorF("+extension name Enable extension\n"); 58205b261ecSmrg ErrorF("-extension name Disable extension\n"); 58305b261ecSmrg#ifdef XDMCP 58405b261ecSmrg XdmcpUseMsg(); 58505b261ecSmrg#endif 58605b261ecSmrg XkbUseMsg(); 58705b261ecSmrg ddxUseMsg(); 58805b261ecSmrg} 58905b261ecSmrg 59005b261ecSmrg/* This function performs a rudimentary sanity check 59105b261ecSmrg * on the display name passed in on the command-line, 59205b261ecSmrg * since this string is used to generate filenames. 59305b261ecSmrg * It is especially important that the display name 59405b261ecSmrg * not contain a "/" and not start with a "-". 59505b261ecSmrg * --kvajk 59605b261ecSmrg */ 597f7df2e56Smrgstatic int 59805b261ecSmrgVerifyDisplayName(const char *d) 59905b261ecSmrg{ 600f7df2e56Smrg int i; 601f7df2e56Smrg int period_found = FALSE; 602f7df2e56Smrg int after_period = 0; 603f7df2e56Smrg 604f7df2e56Smrg if (d == (char *) 0) 605f7df2e56Smrg return 0; /* null */ 606f7df2e56Smrg if (*d == '\0') 607f7df2e56Smrg return 0; /* empty */ 608f7df2e56Smrg if (*d == '-') 609f7df2e56Smrg return 0; /* could be confused for an option */ 610f7df2e56Smrg if (*d == '.') 611f7df2e56Smrg return 0; /* must not equal "." or ".." */ 612f7df2e56Smrg if (strchr(d, '/') != (char *) 0) 613f7df2e56Smrg return 0; /* very important!!! */ 614f7df2e56Smrg 615f7df2e56Smrg /* Since we run atoi() on the display later, only allow 616f7df2e56Smrg for digits, or exception of :0.0 and similar (two decimal points max) 617f7df2e56Smrg */ 618f7df2e56Smrg for (i = 0; i < strlen(d); i++) { 619f7df2e56Smrg if (!isdigit(d[i])) { 620f7df2e56Smrg if (d[i] != '.' || period_found) 621f7df2e56Smrg return 0; 622f7df2e56Smrg period_found = TRUE; 623f7df2e56Smrg } else if (period_found) 624f7df2e56Smrg after_period++; 625f7df2e56Smrg 626f7df2e56Smrg if (after_period > 2) 627f7df2e56Smrg return 0; 628f7df2e56Smrg } 629f7df2e56Smrg 630f7df2e56Smrg /* don't allow for :0. */ 631f7df2e56Smrg if (period_found && after_period == 0) 632f7df2e56Smrg return 0; 633f7df2e56Smrg 634f7df2e56Smrg if (atol(d) > INT_MAX) 635f7df2e56Smrg return 0; 636f7df2e56Smrg 6374202a189Smrg return 1; 63805b261ecSmrg} 63905b261ecSmrg 640f7df2e56Smrgstatic const char *defaultNoListenList[] = { 641f7df2e56Smrg#ifndef LISTEN_TCP 642f7df2e56Smrg "tcp", 643f7df2e56Smrg#endif 644f7df2e56Smrg#ifndef LISTEN_UNIX 645f7df2e56Smrg "unix", 646f7df2e56Smrg#endif 647f7df2e56Smrg#ifndef LISTEN_LOCAL 648f7df2e56Smrg "local", 649f7df2e56Smrg#endif 650f7df2e56Smrg NULL 651f7df2e56Smrg}; 652f7df2e56Smrg 65305b261ecSmrg/* 65405b261ecSmrg * This function parses the command line. Handles device-independent fields 65505b261ecSmrg * and allows ddx to handle additional fields. It is not allowed to modify 65605b261ecSmrg * argc or any of the strings pointed to by argv. 65705b261ecSmrg */ 65805b261ecSmrgvoid 65905b261ecSmrgProcessCommandLine(int argc, char *argv[]) 66005b261ecSmrg{ 66105b261ecSmrg int i, skip; 66205b261ecSmrg 66305b261ecSmrg defaultKeyboardControl.autoRepeat = TRUE; 66405b261ecSmrg 66505b261ecSmrg#ifdef NO_PART_NET 66605b261ecSmrg PartialNetwork = FALSE; 66705b261ecSmrg#else 66805b261ecSmrg PartialNetwork = TRUE; 66905b261ecSmrg#endif 67005b261ecSmrg 671f7df2e56Smrg for (i = 0; defaultNoListenList[i] != NULL; i++) { 672f7df2e56Smrg if (_XSERVTransNoListen(defaultNoListenList[i])) 673f7df2e56Smrg ErrorF("Failed to disable listen for %s transport", 674f7df2e56Smrg defaultNoListenList[i]); 675f7df2e56Smrg } 676f7df2e56Smrg 677f7df2e56Smrg for (i = 1; i < argc; i++) { 678f7df2e56Smrg /* call ddx first, so it can peek/override if it wants */ 679f7df2e56Smrg if ((skip = ddxProcessArgument(argc, argv, i))) { 680f7df2e56Smrg i += (skip - 1); 681f7df2e56Smrg } 682f7df2e56Smrg else if (argv[i][0] == ':') { 683f7df2e56Smrg /* initialize display */ 684f7df2e56Smrg display = argv[i]; 685f7df2e56Smrg explicit_display = TRUE; 686f7df2e56Smrg display++; 687f7df2e56Smrg if (!VerifyDisplayName(display)) { 68805b261ecSmrg ErrorF("Bad display name: %s\n", display); 68905b261ecSmrg UseMsg(); 690f7df2e56Smrg FatalError("Bad display name, exiting: %s\n", display); 69105b261ecSmrg } 692f7df2e56Smrg } 693f7df2e56Smrg else if (strcmp(argv[i], "-a") == 0) { 694f7df2e56Smrg if (++i < argc) 695f7df2e56Smrg defaultPointerControl.num = atoi(argv[i]); 696f7df2e56Smrg else 697f7df2e56Smrg UseMsg(); 698f7df2e56Smrg } 699f7df2e56Smrg else if (strcmp(argv[i], "-ac") == 0) { 700f7df2e56Smrg defeatAccessControl = TRUE; 701f7df2e56Smrg } 702f7df2e56Smrg else if (strcmp(argv[i], "-audit") == 0) { 703f7df2e56Smrg if (++i < argc) 704f7df2e56Smrg auditTrailLevel = atoi(argv[i]); 705f7df2e56Smrg else 706f7df2e56Smrg UseMsg(); 707f7df2e56Smrg } 708f7df2e56Smrg else if (strcmp(argv[i], "-auth") == 0) { 709f7df2e56Smrg if (++i < argc) 710f7df2e56Smrg InitAuthorization(argv[i]); 711f7df2e56Smrg else 712f7df2e56Smrg UseMsg(); 713f7df2e56Smrg } 714f7df2e56Smrg else if (strcmp(argv[i], "-br") == 0); /* default */ 715f7df2e56Smrg else if (strcmp(argv[i], "+bs") == 0) 716f7df2e56Smrg enableBackingStore = TRUE; 717f7df2e56Smrg else if (strcmp(argv[i], "-bs") == 0) 718f7df2e56Smrg disableBackingStore = TRUE; 719f7df2e56Smrg else if (strcmp(argv[i], "c") == 0) { 720f7df2e56Smrg if (++i < argc) 721f7df2e56Smrg defaultKeyboardControl.click = atoi(argv[i]); 722f7df2e56Smrg else 723f7df2e56Smrg UseMsg(); 724f7df2e56Smrg } 725f7df2e56Smrg else if (strcmp(argv[i], "-c") == 0) { 726f7df2e56Smrg defaultKeyboardControl.click = 0; 727f7df2e56Smrg } 728f7df2e56Smrg else if (strcmp(argv[i], "-cc") == 0) { 729f7df2e56Smrg if (++i < argc) 730f7df2e56Smrg defaultColorVisualClass = atoi(argv[i]); 731f7df2e56Smrg else 732f7df2e56Smrg UseMsg(); 733f7df2e56Smrg } 734f7df2e56Smrg else if (strcmp(argv[i], "-core") == 0) { 73505b261ecSmrg#if !defined(WIN32) || !defined(__MINGW32__) 736f7df2e56Smrg struct rlimit core_limit; 737f7df2e56Smrg 738f7df2e56Smrg if (getrlimit(RLIMIT_CORE, &core_limit) != -1) { 739f7df2e56Smrg core_limit.rlim_cur = core_limit.rlim_max; 740f7df2e56Smrg setrlimit(RLIMIT_CORE, &core_limit); 741f7df2e56Smrg } 74205b261ecSmrg#endif 743f7df2e56Smrg CoreDump = TRUE; 744f7df2e56Smrg } 745f7df2e56Smrg else if (strcmp(argv[i], "-nocursor") == 0) { 7464202a189Smrg EnableCursor = FALSE; 7474202a189Smrg } 748f7df2e56Smrg else if (strcmp(argv[i], "-dpi") == 0) { 749f7df2e56Smrg if (++i < argc) 750f7df2e56Smrg monitorResolution = atoi(argv[i]); 751f7df2e56Smrg else 752f7df2e56Smrg UseMsg(); 753f7df2e56Smrg } 754f7df2e56Smrg else if (strcmp(argv[i], "-displayfd") == 0) { 755f7df2e56Smrg if (++i < argc) { 756f7df2e56Smrg displayfd = atoi(argv[i]); 757f7df2e56Smrg#ifdef LOCK_SERVER 758f7df2e56Smrg nolock = TRUE; 759f7df2e56Smrg#endif 760f7df2e56Smrg } 761f7df2e56Smrg else 762f7df2e56Smrg UseMsg(); 763f7df2e56Smrg } 76405b261ecSmrg#ifdef DPMSExtension 765f7df2e56Smrg else if (strcmp(argv[i], "dpms") == 0) 766f7df2e56Smrg /* ignored for compatibility */ ; 767f7df2e56Smrg else if (strcmp(argv[i], "-dpms") == 0) 768f7df2e56Smrg DPMSDisabledSwitch = TRUE; 76905b261ecSmrg#endif 770f7df2e56Smrg else if (strcmp(argv[i], "-deferglyphs") == 0) { 7717e31ba66Smrg if (++i >= argc || !xfont2_parse_glyph_caching_mode(argv[i])) 772f7df2e56Smrg UseMsg(); 773f7df2e56Smrg } 774f7df2e56Smrg else if (strcmp(argv[i], "-f") == 0) { 775f7df2e56Smrg if (++i < argc) 776f7df2e56Smrg defaultKeyboardControl.bell = atoi(argv[i]); 777f7df2e56Smrg else 778f7df2e56Smrg UseMsg(); 779f7df2e56Smrg } 780f7df2e56Smrg else if (strcmp(argv[i], "-fc") == 0) { 781f7df2e56Smrg if (++i < argc) 782f7df2e56Smrg defaultCursorFont = argv[i]; 783f7df2e56Smrg else 784f7df2e56Smrg UseMsg(); 785f7df2e56Smrg } 786f7df2e56Smrg else if (strcmp(argv[i], "-fn") == 0) { 787f7df2e56Smrg if (++i < argc) 788f7df2e56Smrg defaultTextFont = argv[i]; 789f7df2e56Smrg else 790f7df2e56Smrg UseMsg(); 791f7df2e56Smrg } 792f7df2e56Smrg else if (strcmp(argv[i], "-fp") == 0) { 793f7df2e56Smrg if (++i < argc) { 794f7df2e56Smrg defaultFontPath = argv[i]; 795f7df2e56Smrg } 796f7df2e56Smrg else 797f7df2e56Smrg UseMsg(); 798f7df2e56Smrg } 799f7df2e56Smrg else if (strcmp(argv[i], "-help") == 0) { 800f7df2e56Smrg UseMsg(); 801f7df2e56Smrg exit(0); 802f7df2e56Smrg } 803f7df2e56Smrg else if (strcmp(argv[i], "+iglx") == 0) 804f7df2e56Smrg enableIndirectGLX = TRUE; 805f7df2e56Smrg else if (strcmp(argv[i], "-iglx") == 0) 806f7df2e56Smrg enableIndirectGLX = FALSE; 807f7df2e56Smrg else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) { 808f7df2e56Smrg if (skip > 0) 809f7df2e56Smrg i += skip - 1; 810f7df2e56Smrg else 811f7df2e56Smrg UseMsg(); 812f7df2e56Smrg } 81305b261ecSmrg#ifdef RLIMIT_DATA 814f7df2e56Smrg else if (strcmp(argv[i], "-ld") == 0) { 815f7df2e56Smrg if (++i < argc) { 816f7df2e56Smrg limitDataSpace = atoi(argv[i]); 817f7df2e56Smrg if (limitDataSpace > 0) 818f7df2e56Smrg limitDataSpace *= 1024; 819f7df2e56Smrg } 820f7df2e56Smrg else 821f7df2e56Smrg UseMsg(); 822f7df2e56Smrg } 82305b261ecSmrg#endif 82405b261ecSmrg#ifdef RLIMIT_NOFILE 825f7df2e56Smrg else if (strcmp(argv[i], "-lf") == 0) { 826f7df2e56Smrg if (++i < argc) 827f7df2e56Smrg limitNoFile = atoi(argv[i]); 828f7df2e56Smrg else 829f7df2e56Smrg UseMsg(); 830f7df2e56Smrg } 83105b261ecSmrg#endif 83205b261ecSmrg#ifdef RLIMIT_STACK 833f7df2e56Smrg else if (strcmp(argv[i], "-ls") == 0) { 834f7df2e56Smrg if (++i < argc) { 835f7df2e56Smrg limitStackSpace = atoi(argv[i]); 836f7df2e56Smrg if (limitStackSpace > 0) 837f7df2e56Smrg limitStackSpace *= 1024; 838f7df2e56Smrg } 839f7df2e56Smrg else 840f7df2e56Smrg UseMsg(); 841f7df2e56Smrg } 84205b261ecSmrg#endif 843f7df2e56Smrg#ifdef LOCK_SERVER 844f7df2e56Smrg else if (strcmp(argv[i], "-nolock") == 0) { 84505b261ecSmrg#if !defined(WIN32) && !defined(__CYGWIN__) 846f7df2e56Smrg if (getuid() != 0) 847f7df2e56Smrg ErrorF 848f7df2e56Smrg ("Warning: the -nolock option can only be used by root\n"); 849f7df2e56Smrg else 85005b261ecSmrg#endif 851f7df2e56Smrg nolock = TRUE; 852f7df2e56Smrg } 853f7df2e56Smrg#endif 854f7df2e56Smrg else if ( strcmp( argv[i], "-maxclients") == 0) 85505b261ecSmrg { 856f7df2e56Smrg if (++i < argc) { 857f7df2e56Smrg LimitClients = atoi(argv[i]); 858f7df2e56Smrg if (LimitClients != 64 && 859f7df2e56Smrg LimitClients != 128 && 860f7df2e56Smrg LimitClients != 256 && 8617e31ba66Smrg LimitClients != 512 && 8627e31ba66Smrg LimitClients != 1024 && 8637e31ba66Smrg LimitClients != 2048) { 8647e31ba66Smrg FatalError("maxclients must be one of 64, 128, 256, 512, 1024 or 2048\n"); 865f7df2e56Smrg } 866f7df2e56Smrg } else 86705b261ecSmrg UseMsg(); 86805b261ecSmrg } 869f7df2e56Smrg else if (strcmp(argv[i], "-nolisten") == 0) { 870f7df2e56Smrg if (++i < argc) { 871f7df2e56Smrg if (_XSERVTransNoListen(argv[i])) 872f7df2e56Smrg ErrorF("Failed to disable listen for %s transport", 873f7df2e56Smrg argv[i]); 874f7df2e56Smrg } 875f7df2e56Smrg else 876f7df2e56Smrg UseMsg(); 877f7df2e56Smrg } 878f7df2e56Smrg else if (strcmp(argv[i], "-listen") == 0) { 879f7df2e56Smrg if (++i < argc) { 880f7df2e56Smrg if (_XSERVTransListen(argv[i])) 881f7df2e56Smrg ErrorF("Failed to enable listen for %s transport", 882f7df2e56Smrg argv[i]); 883f7df2e56Smrg } 884f7df2e56Smrg else 885f7df2e56Smrg UseMsg(); 886f7df2e56Smrg } 887f7df2e56Smrg else if (strcmp(argv[i], "-noreset") == 0) { 888f7df2e56Smrg dispatchExceptionAtReset = 0; 889f7df2e56Smrg } 890f7df2e56Smrg else if (strcmp(argv[i], "-reset") == 0) { 891f7df2e56Smrg dispatchExceptionAtReset = DE_RESET; 892f7df2e56Smrg } 893f7df2e56Smrg else if (strcmp(argv[i], "-p") == 0) { 894f7df2e56Smrg if (++i < argc) 895f7df2e56Smrg defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) * 896f7df2e56Smrg MILLI_PER_MIN; 897f7df2e56Smrg else 898f7df2e56Smrg UseMsg(); 899f7df2e56Smrg } 900f7df2e56Smrg else if (strcmp(argv[i], "-pogo") == 0) { 901f7df2e56Smrg dispatchException = DE_TERMINATE; 902f7df2e56Smrg } 903f7df2e56Smrg else if (strcmp(argv[i], "-pn") == 0) 904f7df2e56Smrg PartialNetwork = TRUE; 905f7df2e56Smrg else if (strcmp(argv[i], "-nopn") == 0) 906f7df2e56Smrg PartialNetwork = FALSE; 907f7df2e56Smrg else if (strcmp(argv[i], "r") == 0) 908f7df2e56Smrg defaultKeyboardControl.autoRepeat = TRUE; 909f7df2e56Smrg else if (strcmp(argv[i], "-r") == 0) 910f7df2e56Smrg defaultKeyboardControl.autoRepeat = FALSE; 911f7df2e56Smrg else if (strcmp(argv[i], "-retro") == 0) 912f7df2e56Smrg party_like_its_1989 = TRUE; 913f7df2e56Smrg else if (strcmp(argv[i], "-noretro") == 0) 914daf23d7fSsnj party_like_its_1989 = FALSE; 915f7df2e56Smrg else if (strcmp(argv[i], "-s") == 0) { 916f7df2e56Smrg if (++i < argc) 917f7df2e56Smrg defaultScreenSaverTime = ((CARD32) atoi(argv[i])) * 918f7df2e56Smrg MILLI_PER_MIN; 919f7df2e56Smrg else 920f7df2e56Smrg UseMsg(); 921f7df2e56Smrg } 922f7df2e56Smrg else if (strcmp(argv[i], "-seat") == 0) { 923f7df2e56Smrg if (++i < argc) 924f7df2e56Smrg SeatId = argv[i]; 925f7df2e56Smrg else 926f7df2e56Smrg UseMsg(); 927f7df2e56Smrg } 928f7df2e56Smrg else if (strcmp(argv[i], "-t") == 0) { 929f7df2e56Smrg if (++i < argc) 930f7df2e56Smrg defaultPointerControl.threshold = atoi(argv[i]); 931f7df2e56Smrg else 932f7df2e56Smrg UseMsg(); 933f7df2e56Smrg } 934f7df2e56Smrg else if (strcmp(argv[i], "-terminate") == 0) { 935f7df2e56Smrg dispatchExceptionAtReset = DE_TERMINATE; 936f7df2e56Smrg } 937f7df2e56Smrg else if (strcmp(argv[i], "-to") == 0) { 938f7df2e56Smrg if (++i < argc) 939f7df2e56Smrg TimeOutValue = ((CARD32) atoi(argv[i])) * MILLI_PER_SECOND; 940f7df2e56Smrg else 941f7df2e56Smrg UseMsg(); 942f7df2e56Smrg } 943f7df2e56Smrg else if (strcmp(argv[i], "-tst") == 0) { 944f7df2e56Smrg noTestExtensions = TRUE; 945f7df2e56Smrg } 946f7df2e56Smrg else if (strcmp(argv[i], "v") == 0) 947f7df2e56Smrg defaultScreenSaverBlanking = PreferBlanking; 948f7df2e56Smrg else if (strcmp(argv[i], "-v") == 0) 949f7df2e56Smrg defaultScreenSaverBlanking = DontPreferBlanking; 950f7df2e56Smrg else if (strcmp(argv[i], "-wm") == 0) 951f7df2e56Smrg defaultBackingStore = WhenMapped; 952f7df2e56Smrg else if (strcmp(argv[i], "-wr") == 0) 95305b261ecSmrg whiteRoot = TRUE; 954f7df2e56Smrg else if (strcmp(argv[i], "-background") == 0) { 955f7df2e56Smrg if (++i < argc) { 956f7df2e56Smrg if (!strcmp(argv[i], "none")) 95765b04b38Smrg bgNoneRoot = TRUE; 95865b04b38Smrg else 95965b04b38Smrg UseMsg(); 96065b04b38Smrg } 96165b04b38Smrg } 962f7df2e56Smrg else if (strcmp(argv[i], "-maxbigreqsize") == 0) { 963f7df2e56Smrg if (++i < argc) { 964f7df2e56Smrg long reqSizeArg = atol(argv[i]); 965f7df2e56Smrg 966f7df2e56Smrg /* Request size > 128MB does not make much sense... */ 967f7df2e56Smrg if (reqSizeArg > 0L && reqSizeArg < 128L) { 968f7df2e56Smrg maxBigRequestSize = (reqSizeArg * 1048576L) - 1L; 969f7df2e56Smrg } 970f7df2e56Smrg else { 971f7df2e56Smrg UseMsg(); 972f7df2e56Smrg } 973f7df2e56Smrg } 974f7df2e56Smrg else { 975f7df2e56Smrg UseMsg(); 976f7df2e56Smrg } 977f7df2e56Smrg } 978f7df2e56Smrg#ifdef PANORAMIX 979f7df2e56Smrg else if (strcmp(argv[i], "+xinerama") == 0) { 980f7df2e56Smrg noPanoramiXExtension = FALSE; 981f7df2e56Smrg } 982f7df2e56Smrg else if (strcmp(argv[i], "-xinerama") == 0) { 983f7df2e56Smrg noPanoramiXExtension = TRUE; 984f7df2e56Smrg } 985f7df2e56Smrg else if (strcmp(argv[i], "-disablexineramaextension") == 0) { 986f7df2e56Smrg PanoramiXExtensionDisabledHack = TRUE; 987f7df2e56Smrg } 988f7df2e56Smrg#endif 989f7df2e56Smrg else if (strcmp(argv[i], "-I") == 0) { 990f7df2e56Smrg /* ignore all remaining arguments */ 991f7df2e56Smrg break; 992f7df2e56Smrg } 993f7df2e56Smrg else if (strncmp(argv[i], "tty", 3) == 0) { 994f7df2e56Smrg /* init supplies us with this useless information */ 995f7df2e56Smrg } 996f7df2e56Smrg#ifdef XDMCP 997f7df2e56Smrg else if ((skip = XdmcpOptions(argc, argv, i)) != i) { 998f7df2e56Smrg i = skip - 1; 999f7df2e56Smrg } 1000f7df2e56Smrg#endif 1001f7df2e56Smrg else if (strcmp(argv[i], "-dumbSched") == 0) { 10027e31ba66Smrg InputThreadEnable = FALSE; 10037e31ba66Smrg#ifdef HAVE_SETITIMER 10047e31ba66Smrg SmartScheduleSignalEnable = FALSE; 10057e31ba66Smrg#endif 1006f7df2e56Smrg } 1007f7df2e56Smrg else if (strcmp(argv[i], "-schedInterval") == 0) { 1008f7df2e56Smrg if (++i < argc) { 1009f7df2e56Smrg SmartScheduleInterval = atoi(argv[i]); 1010f7df2e56Smrg SmartScheduleSlice = SmartScheduleInterval; 1011f7df2e56Smrg } 1012f7df2e56Smrg else 1013f7df2e56Smrg UseMsg(); 1014f7df2e56Smrg } 1015f7df2e56Smrg else if (strcmp(argv[i], "-schedMax") == 0) { 1016f7df2e56Smrg if (++i < argc) { 1017f7df2e56Smrg SmartScheduleMaxSlice = atoi(argv[i]); 1018f7df2e56Smrg } 1019f7df2e56Smrg else 1020f7df2e56Smrg UseMsg(); 1021f7df2e56Smrg } 1022f7df2e56Smrg else if (strcmp(argv[i], "-render") == 0) { 1023f7df2e56Smrg if (++i < argc) { 1024f7df2e56Smrg int policy = PictureParseCmapPolicy(argv[i]); 1025f7df2e56Smrg 1026f7df2e56Smrg if (policy != PictureCmapPolicyInvalid) 1027f7df2e56Smrg PictureCmapPolicy = policy; 1028f7df2e56Smrg else 1029f7df2e56Smrg UseMsg(); 1030f7df2e56Smrg } 1031f7df2e56Smrg else 1032f7df2e56Smrg UseMsg(); 1033f7df2e56Smrg } 1034f7df2e56Smrg else if (strcmp(argv[i], "-sigstop") == 0) { 1035f7df2e56Smrg RunFromSigStopParent = TRUE; 1036f7df2e56Smrg } 1037f7df2e56Smrg else if (strcmp(argv[i], "+extension") == 0) { 1038f7df2e56Smrg if (++i < argc) { 1039f7df2e56Smrg if (!EnableDisableExtension(argv[i], TRUE)) 1040f7df2e56Smrg EnableDisableExtensionError(argv[i], TRUE); 1041f7df2e56Smrg } 1042f7df2e56Smrg else 1043f7df2e56Smrg UseMsg(); 1044f7df2e56Smrg } 1045f7df2e56Smrg else if (strcmp(argv[i], "-extension") == 0) { 1046f7df2e56Smrg if (++i < argc) { 1047f7df2e56Smrg if (!EnableDisableExtension(argv[i], FALSE)) 1048f7df2e56Smrg EnableDisableExtensionError(argv[i], FALSE); 1049f7df2e56Smrg } 1050f7df2e56Smrg else 1051f7df2e56Smrg UseMsg(); 1052f7df2e56Smrg } 1053f7df2e56Smrg else { 1054f7df2e56Smrg ErrorF("Unrecognized option: %s\n", argv[i]); 1055f7df2e56Smrg UseMsg(); 1056f7df2e56Smrg FatalError("Unrecognized option: %s\n", argv[i]); 105705b261ecSmrg } 105805b261ecSmrg } 105905b261ecSmrg} 106005b261ecSmrg 106105b261ecSmrg/* Implement a simple-minded font authorization scheme. The authorization 106205b261ecSmrg name is "hp-hostname-1", the contents are simply the host name. */ 106305b261ecSmrgint 1064f7df2e56Smrgset_font_authorizations(char **authorizations, int *authlen, void *client) 106505b261ecSmrg{ 106605b261ecSmrg#define AUTHORIZATION_NAME "hp-hostname-1" 10677e31ba66Smrg#if defined(TCPCONN) 106805b261ecSmrg static char *result = NULL; 106905b261ecSmrg static char *p = NULL; 107005b261ecSmrg 1071f7df2e56Smrg if (p == NULL) { 1072f7df2e56Smrg char hname[1024], *hnameptr; 1073f7df2e56Smrg unsigned int len; 1074f7df2e56Smrg 107505b261ecSmrg#if defined(IPv6) && defined(AF_INET6) 1076f7df2e56Smrg struct addrinfo hints, *ai = NULL; 107705b261ecSmrg#else 1078f7df2e56Smrg struct hostent *host; 1079f7df2e56Smrg 108005b261ecSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 1081f7df2e56Smrg _Xgethostbynameparams hparams; 108205b261ecSmrg#endif 108305b261ecSmrg#endif 108405b261ecSmrg 1085f7df2e56Smrg gethostname(hname, 1024); 108605b261ecSmrg#if defined(IPv6) && defined(AF_INET6) 1087f7df2e56Smrg memset(&hints, 0, sizeof(hints)); 1088f7df2e56Smrg hints.ai_flags = AI_CANONNAME; 1089f7df2e56Smrg if (getaddrinfo(hname, NULL, &hints, &ai) == 0) { 1090f7df2e56Smrg hnameptr = ai->ai_canonname; 1091f7df2e56Smrg } 1092f7df2e56Smrg else { 1093f7df2e56Smrg hnameptr = hname; 1094f7df2e56Smrg } 109505b261ecSmrg#else 1096f7df2e56Smrg host = _XGethostbyname(hname, hparams); 1097f7df2e56Smrg if (host == NULL) 1098f7df2e56Smrg hnameptr = hname; 1099f7df2e56Smrg else 1100f7df2e56Smrg hnameptr = host->h_name; 110105b261ecSmrg#endif 110205b261ecSmrg 1103f7df2e56Smrg len = strlen(hnameptr) + 1; 1104f7df2e56Smrg result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4); 110505b261ecSmrg 1106f7df2e56Smrg p = result; 110705b261ecSmrg *p++ = sizeof(AUTHORIZATION_NAME) >> 8; 110805b261ecSmrg *p++ = sizeof(AUTHORIZATION_NAME) & 0xff; 110905b261ecSmrg *p++ = (len) >> 8; 111005b261ecSmrg *p++ = (len & 0xff); 111105b261ecSmrg 1112f7df2e56Smrg memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME)); 1113f7df2e56Smrg p += sizeof(AUTHORIZATION_NAME); 1114f7df2e56Smrg memmove(p, hnameptr, len); 1115f7df2e56Smrg p += len; 111605b261ecSmrg#if defined(IPv6) && defined(AF_INET6) 1117f7df2e56Smrg if (ai) { 1118f7df2e56Smrg freeaddrinfo(ai); 1119f7df2e56Smrg } 112005b261ecSmrg#endif 112105b261ecSmrg } 112205b261ecSmrg *authlen = p - result; 112305b261ecSmrg *authorizations = result; 112405b261ecSmrg return 1; 1125f7df2e56Smrg#else /* TCPCONN */ 112605b261ecSmrg return 0; 1127f7df2e56Smrg#endif /* TCPCONN */ 112805b261ecSmrg} 112905b261ecSmrg 11304202a189Smrgvoid * 113105b261ecSmrgXNFalloc(unsigned long amount) 113205b261ecSmrg{ 11334202a189Smrg void *ptr = malloc(amount); 1134f7df2e56Smrg 113505b261ecSmrg if (!ptr) 113605b261ecSmrg FatalError("Out of memory"); 11374642e01fSmrg return ptr; 113805b261ecSmrg} 113905b261ecSmrg 1140f7df2e56Smrg/* The original XNFcalloc was used with the xnfcalloc macro which multiplied 1141f7df2e56Smrg * the arguments at the call site without allowing calloc to check for overflow. 1142f7df2e56Smrg * XNFcallocarray was added to fix that without breaking ABI. 1143f7df2e56Smrg */ 11444202a189Smrgvoid * 1145f7df2e56SmrgXNFcalloc(unsigned long amount) 114605b261ecSmrg{ 1147f7df2e56Smrg return XNFcallocarray(1, amount); 114805b261ecSmrg} 114905b261ecSmrg 11504202a189Smrgvoid * 1151f7df2e56SmrgXNFcallocarray(size_t nmemb, size_t size) 115205b261ecSmrg{ 1153f7df2e56Smrg void *ret = calloc(nmemb, size); 1154f7df2e56Smrg 11554202a189Smrg if (!ret) 11564202a189Smrg FatalError("XNFcalloc: Out of memory"); 115705b261ecSmrg return ret; 115805b261ecSmrg} 115905b261ecSmrg 11604202a189Smrgvoid * 11614202a189SmrgXNFrealloc(void *ptr, unsigned long amount) 116205b261ecSmrg{ 11634202a189Smrg void *ret = realloc(ptr, amount); 1164f7df2e56Smrg 11654202a189Smrg if (!ret) 1166f7df2e56Smrg FatalError("XNFrealloc: Out of memory"); 11674202a189Smrg return ret; 116805b261ecSmrg} 116905b261ecSmrg 1170f7df2e56Smrgvoid * 1171f7df2e56SmrgXNFreallocarray(void *ptr, size_t nmemb, size_t size) 117205b261ecSmrg{ 1173f7df2e56Smrg void *ret = reallocarray(ptr, nmemb, size); 117405b261ecSmrg 1175f7df2e56Smrg if (!ret) 1176f7df2e56Smrg FatalError("XNFreallocarray: Out of memory"); 1177f7df2e56Smrg return ret; 1178f7df2e56Smrg} 117905b261ecSmrg 118005b261ecSmrgchar * 118105b261ecSmrgXstrdup(const char *s) 118205b261ecSmrg{ 118305b261ecSmrg if (s == NULL) 1184f7df2e56Smrg return NULL; 11854202a189Smrg return strdup(s); 118605b261ecSmrg} 118705b261ecSmrg 11884202a189Smrgchar * 118905b261ecSmrgXNFstrdup(const char *s) 119005b261ecSmrg{ 11914202a189Smrg char *ret; 119205b261ecSmrg 119305b261ecSmrg if (s == NULL) 1194f7df2e56Smrg return NULL; 119505b261ecSmrg 11964202a189Smrg ret = strdup(s); 11974202a189Smrg if (!ret) 1198f7df2e56Smrg FatalError("XNFstrdup: Out of memory"); 11994202a189Smrg return ret; 120005b261ecSmrg} 120105b261ecSmrg 12024642e01fSmrgvoid 1203f7df2e56SmrgSmartScheduleStopTimer(void) 120405b261ecSmrg{ 12057e31ba66Smrg#ifdef HAVE_SETITIMER 1206f7df2e56Smrg struct itimerval timer; 1207f7df2e56Smrg 12087e31ba66Smrg if (!SmartScheduleSignalEnable) 1209f7df2e56Smrg return; 121005b261ecSmrg timer.it_interval.tv_sec = 0; 121105b261ecSmrg timer.it_interval.tv_usec = 0; 121205b261ecSmrg timer.it_value.tv_sec = 0; 121305b261ecSmrg timer.it_value.tv_usec = 0; 1214f7df2e56Smrg (void) setitimer(ITIMER_REAL, &timer, 0); 1215f7df2e56Smrg#endif 121605b261ecSmrg} 121705b261ecSmrg 12184642e01fSmrgvoid 1219f7df2e56SmrgSmartScheduleStartTimer(void) 122005b261ecSmrg{ 12217e31ba66Smrg#ifdef HAVE_SETITIMER 1222f7df2e56Smrg struct itimerval timer; 1223f7df2e56Smrg 12247e31ba66Smrg if (!SmartScheduleSignalEnable) 1225f7df2e56Smrg return; 122605b261ecSmrg timer.it_interval.tv_sec = 0; 122705b261ecSmrg timer.it_interval.tv_usec = SmartScheduleInterval * 1000; 122805b261ecSmrg timer.it_value.tv_sec = 0; 122905b261ecSmrg timer.it_value.tv_usec = SmartScheduleInterval * 1000; 1230f7df2e56Smrg setitimer(ITIMER_REAL, &timer, 0); 1231f7df2e56Smrg#endif 123205b261ecSmrg} 123305b261ecSmrg 12347e31ba66Smrg#ifdef HAVE_SETITIMER 123505b261ecSmrgstatic void 1236f7df2e56SmrgSmartScheduleTimer(int sig) 123705b261ecSmrg{ 123805b261ecSmrg SmartScheduleTime += SmartScheduleInterval; 123905b261ecSmrg} 124005b261ecSmrg 1241f7df2e56Smrgstatic int 1242f7df2e56SmrgSmartScheduleEnable(void) 124305b261ecSmrg{ 1244f7df2e56Smrg int ret = 0; 1245f7df2e56Smrg struct sigaction act; 124605b261ecSmrg 12477e31ba66Smrg if (!SmartScheduleSignalEnable) 1248f7df2e56Smrg return 0; 124965b04b38Smrg 12504202a189Smrg memset((char *) &act, 0, sizeof(struct sigaction)); 125105b261ecSmrg 125205b261ecSmrg /* Set up the timer signal function */ 1253f7df2e56Smrg act.sa_flags = SA_RESTART; 125405b261ecSmrg act.sa_handler = SmartScheduleTimer; 1255f7df2e56Smrg sigemptyset(&act.sa_mask); 1256f7df2e56Smrg sigaddset(&act.sa_mask, SIGALRM); 1257f7df2e56Smrg ret = sigaction(SIGALRM, &act, 0); 1258f7df2e56Smrg return ret; 1259f7df2e56Smrg} 1260f7df2e56Smrg 1261f7df2e56Smrgstatic int 1262f7df2e56SmrgSmartSchedulePause(void) 1263f7df2e56Smrg{ 1264f7df2e56Smrg int ret = 0; 1265f7df2e56Smrg struct sigaction act; 1266f7df2e56Smrg 12677e31ba66Smrg if (!SmartScheduleSignalEnable) 1268f7df2e56Smrg return 0; 1269f7df2e56Smrg 1270f7df2e56Smrg memset((char *) &act, 0, sizeof(struct sigaction)); 1271f7df2e56Smrg 1272f7df2e56Smrg act.sa_handler = SIG_IGN; 1273f7df2e56Smrg sigemptyset(&act.sa_mask); 1274f7df2e56Smrg ret = sigaction(SIGALRM, &act, 0); 1275f7df2e56Smrg return ret; 1276f7df2e56Smrg} 12777e31ba66Smrg#endif 1278f7df2e56Smrg 1279f7df2e56Smrgvoid 1280f7df2e56SmrgSmartScheduleInit(void) 1281f7df2e56Smrg{ 12827e31ba66Smrg#ifdef HAVE_SETITIMER 1283f7df2e56Smrg if (SmartScheduleEnable() < 0) { 1284f7df2e56Smrg perror("sigaction for smart scheduler"); 12857e31ba66Smrg SmartScheduleSignalEnable = FALSE; 128605b261ecSmrg } 12877e31ba66Smrg#endif 128805b261ecSmrg} 128905b261ecSmrg 129005b261ecSmrg#ifdef SIG_BLOCK 1291f7df2e56Smrgstatic sigset_t PreviousSignalMask; 1292f7df2e56Smrgstatic int BlockedSignalCount; 129305b261ecSmrg#endif 129405b261ecSmrg 129505b261ecSmrgvoid 1296f7df2e56SmrgOsBlockSignals(void) 129705b261ecSmrg{ 129805b261ecSmrg#ifdef SIG_BLOCK 1299f7df2e56Smrg if (BlockedSignalCount++ == 0) { 1300f7df2e56Smrg sigset_t set; 1301f7df2e56Smrg 1302f7df2e56Smrg sigemptyset(&set); 1303f7df2e56Smrg sigaddset(&set, SIGALRM); 1304f7df2e56Smrg sigaddset(&set, SIGVTALRM); 130505b261ecSmrg#ifdef SIGWINCH 1306f7df2e56Smrg sigaddset(&set, SIGWINCH); 1307f7df2e56Smrg#endif 1308f7df2e56Smrg sigaddset(&set, SIGTSTP); 1309f7df2e56Smrg sigaddset(&set, SIGTTIN); 1310f7df2e56Smrg sigaddset(&set, SIGTTOU); 1311f7df2e56Smrg sigaddset(&set, SIGCHLD); 13127e31ba66Smrg xthread_sigmask(SIG_BLOCK, &set, &PreviousSignalMask); 131305b261ecSmrg } 131405b261ecSmrg#endif 131505b261ecSmrg} 131605b261ecSmrg 131705b261ecSmrgvoid 1318f7df2e56SmrgOsReleaseSignals(void) 131905b261ecSmrg{ 132005b261ecSmrg#ifdef SIG_BLOCK 1321f7df2e56Smrg if (--BlockedSignalCount == 0) { 13227e31ba66Smrg xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0); 132305b261ecSmrg } 132405b261ecSmrg#endif 132505b261ecSmrg} 132605b261ecSmrg 1327f7df2e56Smrgvoid 1328f7df2e56SmrgOsResetSignals(void) 1329f7df2e56Smrg{ 1330f7df2e56Smrg#ifdef SIG_BLOCK 1331f7df2e56Smrg while (BlockedSignalCount > 0) 1332f7df2e56Smrg OsReleaseSignals(); 13337e31ba66Smrg input_force_unlock(); 1334f7df2e56Smrg#endif 1335f7df2e56Smrg} 1336f7df2e56Smrg 13374202a189Smrg/* 13384202a189Smrg * Pending signals may interfere with core dumping. Provide a 13394202a189Smrg * mechanism to block signals when aborting. 13404202a189Smrg */ 13414202a189Smrg 13424202a189Smrgvoid 1343f7df2e56SmrgOsAbort(void) 13444202a189Smrg{ 13454202a189Smrg#ifndef __APPLE__ 13464202a189Smrg OsBlockSignals(); 13477e31ba66Smrg#endif 13487e31ba66Smrg#if !defined(WIN32) || defined(__CYGWIN__) 13497e31ba66Smrg /* abort() raises SIGABRT, so we have to stop handling that to prevent 13507e31ba66Smrg * recursion 13517e31ba66Smrg */ 13527e31ba66Smrg OsSignal(SIGABRT, SIG_DFL); 13534202a189Smrg#endif 13544202a189Smrg abort(); 13554202a189Smrg} 13564202a189Smrg 135705b261ecSmrg#if !defined(WIN32) 135805b261ecSmrg/* 135905b261ecSmrg * "safer" versions of system(3), popen(3) and pclose(3) which give up 136005b261ecSmrg * all privs before running a command. 136105b261ecSmrg * 136205b261ecSmrg * This is based on the code in FreeBSD 2.2 libc. 136305b261ecSmrg * 136405b261ecSmrg * XXX It'd be good to redirect stderr so that it ends up in the log file 136505b261ecSmrg * as well. As it is now, xkbcomp messages don't end up in the log file. 136605b261ecSmrg */ 136705b261ecSmrg 136805b261ecSmrgint 1369f7df2e56SmrgSystem(const char *command) 137005b261ecSmrg{ 137105b261ecSmrg int pid, p; 1372f7df2e56Smrg void (*csig) (int); 137305b261ecSmrg int status; 137405b261ecSmrg 137505b261ecSmrg if (!command) 1376f7df2e56Smrg return 1; 137705b261ecSmrg 13787e31ba66Smrg csig = OsSignal(SIGCHLD, SIG_DFL); 137905b261ecSmrg if (csig == SIG_ERR) { 1380f7df2e56Smrg perror("signal"); 1381f7df2e56Smrg return -1; 138205b261ecSmrg } 138365b04b38Smrg DebugF("System: `%s'\n", command); 138405b261ecSmrg 138505b261ecSmrg switch (pid = fork()) { 1386f7df2e56Smrg case -1: /* error */ 1387f7df2e56Smrg p = -1; 1388f7df2e56Smrg break; 1389f7df2e56Smrg case 0: /* child */ 1390f7df2e56Smrg if (setgid(getgid()) == -1) 1391f7df2e56Smrg _exit(127); 1392f7df2e56Smrg if (setuid(getuid()) == -1) 1393f7df2e56Smrg _exit(127); 1394f7df2e56Smrg execl("/bin/sh", "sh", "-c", command, (char *) NULL); 1395f7df2e56Smrg _exit(127); 1396f7df2e56Smrg default: /* parent */ 1397f7df2e56Smrg do { 1398f7df2e56Smrg p = waitpid(pid, &status, 0); 1399f7df2e56Smrg } while (p == -1 && errno == EINTR); 1400f7df2e56Smrg 140105b261ecSmrg } 140205b261ecSmrg 14037e31ba66Smrg if (OsSignal(SIGCHLD, csig) == SIG_ERR) { 1404f7df2e56Smrg perror("signal"); 1405f7df2e56Smrg return -1; 140605b261ecSmrg } 140705b261ecSmrg 140805b261ecSmrg return p == -1 ? -1 : status; 140905b261ecSmrg} 141005b261ecSmrg 141105b261ecSmrgstatic struct pid { 141205b261ecSmrg struct pid *next; 141305b261ecSmrg FILE *fp; 141405b261ecSmrg int pid; 141505b261ecSmrg} *pidlist; 141605b261ecSmrg 1417f7df2e56Smrgvoid * 1418f7df2e56SmrgPopen(const char *command, const char *type) 141905b261ecSmrg{ 142005b261ecSmrg struct pid *cur; 142105b261ecSmrg FILE *iop; 142205b261ecSmrg int pdes[2], pid; 142305b261ecSmrg 142405b261ecSmrg if (command == NULL || type == NULL) 1425f7df2e56Smrg return NULL; 142605b261ecSmrg 142705b261ecSmrg if ((*type != 'r' && *type != 'w') || type[1]) 1428f7df2e56Smrg return NULL; 142905b261ecSmrg 14304202a189Smrg if ((cur = malloc(sizeof(struct pid))) == NULL) 1431f7df2e56Smrg return NULL; 143205b261ecSmrg 143305b261ecSmrg if (pipe(pdes) < 0) { 1434f7df2e56Smrg free(cur); 1435f7df2e56Smrg return NULL; 143605b261ecSmrg } 143705b261ecSmrg 143805b261ecSmrg /* Ignore the smart scheduler while this is going on */ 14397e31ba66Smrg#ifdef HAVE_SETITIMER 1440f7df2e56Smrg if (SmartSchedulePause() < 0) { 1441f7df2e56Smrg close(pdes[0]); 1442f7df2e56Smrg close(pdes[1]); 1443f7df2e56Smrg free(cur); 1444f7df2e56Smrg perror("signal"); 1445f7df2e56Smrg return NULL; 144605b261ecSmrg } 14477e31ba66Smrg#endif 144805b261ecSmrg 144905b261ecSmrg switch (pid = fork()) { 1450f7df2e56Smrg case -1: /* error */ 1451f7df2e56Smrg close(pdes[0]); 1452f7df2e56Smrg close(pdes[1]); 1453f7df2e56Smrg free(cur); 14547e31ba66Smrg#ifdef HAVE_SETITIMER 1455f7df2e56Smrg if (SmartScheduleEnable() < 0) 1456f7df2e56Smrg perror("signal"); 14577e31ba66Smrg#endif 1458f7df2e56Smrg return NULL; 1459f7df2e56Smrg case 0: /* child */ 1460f7df2e56Smrg if (setgid(getgid()) == -1) 1461f7df2e56Smrg _exit(127); 1462f7df2e56Smrg if (setuid(getuid()) == -1) 1463f7df2e56Smrg _exit(127); 1464f7df2e56Smrg if (*type == 'r') { 1465f7df2e56Smrg if (pdes[1] != 1) { 1466f7df2e56Smrg /* stdout */ 1467f7df2e56Smrg dup2(pdes[1], 1); 1468f7df2e56Smrg close(pdes[1]); 1469f7df2e56Smrg } 1470f7df2e56Smrg close(pdes[0]); 1471f7df2e56Smrg } 1472f7df2e56Smrg else { 1473f7df2e56Smrg if (pdes[0] != 0) { 1474f7df2e56Smrg /* stdin */ 1475f7df2e56Smrg dup2(pdes[0], 0); 1476f7df2e56Smrg close(pdes[0]); 1477f7df2e56Smrg } 1478f7df2e56Smrg close(pdes[1]); 1479f7df2e56Smrg } 1480f7df2e56Smrg execl("/bin/sh", "sh", "-c", command, (char *) NULL); 1481f7df2e56Smrg _exit(127); 148205b261ecSmrg } 148305b261ecSmrg 148405b261ecSmrg /* Avoid EINTR during stdio calls */ 1485f7df2e56Smrg OsBlockSignals(); 1486f7df2e56Smrg 148705b261ecSmrg /* parent */ 148805b261ecSmrg if (*type == 'r') { 1489f7df2e56Smrg iop = fdopen(pdes[0], type); 1490f7df2e56Smrg close(pdes[1]); 1491f7df2e56Smrg } 1492f7df2e56Smrg else { 1493f7df2e56Smrg iop = fdopen(pdes[1], type); 1494f7df2e56Smrg close(pdes[0]); 149505b261ecSmrg } 149605b261ecSmrg 149705b261ecSmrg cur->fp = iop; 149805b261ecSmrg cur->pid = pid; 149905b261ecSmrg cur->next = pidlist; 150005b261ecSmrg pidlist = cur; 150105b261ecSmrg 150265b04b38Smrg DebugF("Popen: `%s', fp = %p\n", command, iop); 150305b261ecSmrg 150405b261ecSmrg return iop; 150505b261ecSmrg} 150605b261ecSmrg 150705b261ecSmrg/* fopen that drops privileges */ 1508f7df2e56Smrgvoid * 1509f7df2e56SmrgFopen(const char *file, const char *type) 151005b261ecSmrg{ 151105b261ecSmrg FILE *iop; 1512f7df2e56Smrg 151305b261ecSmrg#ifndef HAS_SAVED_IDS_AND_SETEUID 151405b261ecSmrg struct pid *cur; 151505b261ecSmrg int pdes[2], pid; 151605b261ecSmrg 151705b261ecSmrg if (file == NULL || type == NULL) 1518f7df2e56Smrg return NULL; 151905b261ecSmrg 152005b261ecSmrg if ((*type != 'r' && *type != 'w') || type[1]) 1521f7df2e56Smrg return NULL; 152205b261ecSmrg 15234202a189Smrg if ((cur = malloc(sizeof(struct pid))) == NULL) 1524f7df2e56Smrg return NULL; 152505b261ecSmrg 152605b261ecSmrg if (pipe(pdes) < 0) { 1527f7df2e56Smrg free(cur); 1528f7df2e56Smrg return NULL; 152905b261ecSmrg } 153005b261ecSmrg 153105b261ecSmrg switch (pid = fork()) { 1532f7df2e56Smrg case -1: /* error */ 1533f7df2e56Smrg close(pdes[0]); 1534f7df2e56Smrg close(pdes[1]); 1535f7df2e56Smrg free(cur); 1536f7df2e56Smrg return NULL; 1537f7df2e56Smrg case 0: /* child */ 1538f7df2e56Smrg if (setgid(getgid()) == -1) 1539f7df2e56Smrg _exit(127); 1540f7df2e56Smrg if (setuid(getuid()) == -1) 1541f7df2e56Smrg _exit(127); 1542f7df2e56Smrg if (*type == 'r') { 1543f7df2e56Smrg if (pdes[1] != 1) { 1544f7df2e56Smrg /* stdout */ 1545f7df2e56Smrg dup2(pdes[1], 1); 1546f7df2e56Smrg close(pdes[1]); 1547f7df2e56Smrg } 1548f7df2e56Smrg close(pdes[0]); 1549f7df2e56Smrg } 1550f7df2e56Smrg else { 1551f7df2e56Smrg if (pdes[0] != 0) { 1552f7df2e56Smrg /* stdin */ 1553f7df2e56Smrg dup2(pdes[0], 0); 1554f7df2e56Smrg close(pdes[0]); 1555f7df2e56Smrg } 1556f7df2e56Smrg close(pdes[1]); 1557f7df2e56Smrg } 1558f7df2e56Smrg execl("/bin/cat", "cat", file, (char *) NULL); 1559f7df2e56Smrg _exit(127); 156005b261ecSmrg } 156105b261ecSmrg 156205b261ecSmrg /* Avoid EINTR during stdio calls */ 1563f7df2e56Smrg OsBlockSignals(); 1564f7df2e56Smrg 156505b261ecSmrg /* parent */ 156605b261ecSmrg if (*type == 'r') { 1567f7df2e56Smrg iop = fdopen(pdes[0], type); 1568f7df2e56Smrg close(pdes[1]); 1569f7df2e56Smrg } 1570f7df2e56Smrg else { 1571f7df2e56Smrg iop = fdopen(pdes[1], type); 1572f7df2e56Smrg close(pdes[0]); 157305b261ecSmrg } 157405b261ecSmrg 157505b261ecSmrg cur->fp = iop; 157605b261ecSmrg cur->pid = pid; 157705b261ecSmrg cur->next = pidlist; 157805b261ecSmrg pidlist = cur; 157905b261ecSmrg 158065b04b38Smrg DebugF("Fopen(%s), fp = %p\n", file, iop); 158105b261ecSmrg 158205b261ecSmrg return iop; 158305b261ecSmrg#else 158405b261ecSmrg int ruid, euid; 158505b261ecSmrg 158605b261ecSmrg ruid = getuid(); 158705b261ecSmrg euid = geteuid(); 1588f7df2e56Smrg 158905b261ecSmrg if (seteuid(ruid) == -1) { 1590f7df2e56Smrg return NULL; 159105b261ecSmrg } 159205b261ecSmrg iop = fopen(file, type); 159305b261ecSmrg 159405b261ecSmrg if (seteuid(euid) == -1) { 1595f7df2e56Smrg fclose(iop); 1596f7df2e56Smrg return NULL; 159705b261ecSmrg } 159805b261ecSmrg return iop; 1599f7df2e56Smrg#endif /* HAS_SAVED_IDS_AND_SETEUID */ 160005b261ecSmrg} 160105b261ecSmrg 160205b261ecSmrgint 1603f7df2e56SmrgPclose(void *iop) 160405b261ecSmrg{ 160505b261ecSmrg struct pid *cur, *last; 160605b261ecSmrg int pstat; 160705b261ecSmrg int pid; 160805b261ecSmrg 160965b04b38Smrg DebugF("Pclose: fp = %p\n", iop); 161005b261ecSmrg fclose(iop); 161105b261ecSmrg 161205b261ecSmrg for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) 1613f7df2e56Smrg if (cur->fp == iop) 1614f7df2e56Smrg break; 161505b261ecSmrg if (cur == NULL) 1616f7df2e56Smrg return -1; 161705b261ecSmrg 161805b261ecSmrg do { 1619f7df2e56Smrg pid = waitpid(cur->pid, &pstat, 0); 162005b261ecSmrg } while (pid == -1 && errno == EINTR); 162105b261ecSmrg 162205b261ecSmrg if (last == NULL) 1623f7df2e56Smrg pidlist = cur->next; 162405b261ecSmrg else 1625f7df2e56Smrg last->next = cur->next; 16264202a189Smrg free(cur); 162705b261ecSmrg 162805b261ecSmrg /* allow EINTR again */ 1629f7df2e56Smrg OsReleaseSignals(); 1630f7df2e56Smrg 16317e31ba66Smrg#ifdef HAVE_SETITIMER 1632f7df2e56Smrg if (SmartScheduleEnable() < 0) { 1633f7df2e56Smrg perror("signal"); 1634f7df2e56Smrg return -1; 163505b261ecSmrg } 16367e31ba66Smrg#endif 163705b261ecSmrg 163805b261ecSmrg return pid == -1 ? -1 : pstat; 163905b261ecSmrg} 164005b261ecSmrg 16414202a189Smrgint 1642f7df2e56SmrgFclose(void *iop) 164305b261ecSmrg{ 164405b261ecSmrg#ifdef HAS_SAVED_IDS_AND_SETEUID 164505b261ecSmrg return fclose(iop); 164605b261ecSmrg#else 164705b261ecSmrg return Pclose(iop); 164805b261ecSmrg#endif 164905b261ecSmrg} 165005b261ecSmrg 1651f7df2e56Smrg#endif /* !WIN32 */ 1652f7df2e56Smrg 1653f7df2e56Smrg#ifdef WIN32 1654f7df2e56Smrg 1655f7df2e56Smrg#include <X11/Xwindows.h> 1656f7df2e56Smrg 1657f7df2e56Smrgconst char * 1658f7df2e56SmrgWin32TempDir(void) 1659f7df2e56Smrg{ 1660f7df2e56Smrg static char buffer[PATH_MAX]; 1661f7df2e56Smrg 1662f7df2e56Smrg if (GetTempPath(sizeof(buffer), buffer)) { 1663f7df2e56Smrg int len; 1664f7df2e56Smrg 1665f7df2e56Smrg buffer[sizeof(buffer) - 1] = 0; 1666f7df2e56Smrg len = strlen(buffer); 1667f7df2e56Smrg if (len > 0) 1668f7df2e56Smrg if (buffer[len - 1] == '\\') 1669f7df2e56Smrg buffer[len - 1] = 0; 1670f7df2e56Smrg return buffer; 1671f7df2e56Smrg } 1672f7df2e56Smrg if (getenv("TEMP") != NULL) 1673f7df2e56Smrg return getenv("TEMP"); 1674f7df2e56Smrg else if (getenv("TMP") != NULL) 1675f7df2e56Smrg return getenv("TMP"); 1676f7df2e56Smrg else 1677f7df2e56Smrg return "/tmp"; 1678f7df2e56Smrg} 1679f7df2e56Smrg 1680f7df2e56Smrgint 1681f7df2e56SmrgSystem(const char *cmdline) 1682f7df2e56Smrg{ 1683f7df2e56Smrg STARTUPINFO si; 1684f7df2e56Smrg PROCESS_INFORMATION pi; 1685f7df2e56Smrg DWORD dwExitCode; 1686f7df2e56Smrg char *cmd = strdup(cmdline); 1687f7df2e56Smrg 1688f7df2e56Smrg ZeroMemory(&si, sizeof(si)); 1689f7df2e56Smrg si.cb = sizeof(si); 1690f7df2e56Smrg ZeroMemory(&pi, sizeof(pi)); 1691f7df2e56Smrg 1692f7df2e56Smrg if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { 1693f7df2e56Smrg LPVOID buffer; 1694f7df2e56Smrg 1695f7df2e56Smrg if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 1696f7df2e56Smrg FORMAT_MESSAGE_FROM_SYSTEM | 1697f7df2e56Smrg FORMAT_MESSAGE_IGNORE_INSERTS, 1698f7df2e56Smrg NULL, 1699f7df2e56Smrg GetLastError(), 1700f7df2e56Smrg MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 1701f7df2e56Smrg (LPTSTR) &buffer, 0, NULL)) { 1702f7df2e56Smrg ErrorF("[xkb] Starting '%s' failed!\n", cmdline); 1703f7df2e56Smrg } 1704f7df2e56Smrg else { 1705f7df2e56Smrg ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer); 1706f7df2e56Smrg LocalFree(buffer); 1707f7df2e56Smrg } 1708f7df2e56Smrg 1709f7df2e56Smrg free(cmd); 1710f7df2e56Smrg return -1; 1711f7df2e56Smrg } 1712f7df2e56Smrg /* Wait until child process exits. */ 1713f7df2e56Smrg WaitForSingleObject(pi.hProcess, INFINITE); 1714f7df2e56Smrg 1715f7df2e56Smrg GetExitCodeProcess(pi.hProcess, &dwExitCode); 171605b261ecSmrg 1717f7df2e56Smrg /* Close process and thread handles. */ 1718f7df2e56Smrg CloseHandle(pi.hProcess); 1719f7df2e56Smrg CloseHandle(pi.hThread); 1720f7df2e56Smrg free(cmd); 1721f7df2e56Smrg 1722f7df2e56Smrg return dwExitCode; 1723f7df2e56Smrg} 1724f7df2e56Smrg#endif 172505b261ecSmrg 17267e31ba66SmrgBool 17277e31ba66SmrgPrivsElevated(void) 17287e31ba66Smrg{ 17297e31ba66Smrg static Bool privsTested = FALSE; 17307e31ba66Smrg static Bool privsElevated = TRUE; 17317e31ba66Smrg 17327e31ba66Smrg if (!privsTested) { 17337e31ba66Smrg#if defined(WIN32) 17347e31ba66Smrg privsElevated = FALSE; 17357e31ba66Smrg#else 17367e31ba66Smrg if ((getuid() != geteuid()) || (getgid() != getegid())) { 17377e31ba66Smrg privsElevated = TRUE; 17387e31ba66Smrg } 17397e31ba66Smrg else { 17407e31ba66Smrg#if defined(HAVE_ISSETUGID) 17417e31ba66Smrg privsElevated = issetugid(); 17427e31ba66Smrg#elif defined(HAVE_GETRESUID) 17437e31ba66Smrg uid_t ruid, euid, suid; 17447e31ba66Smrg gid_t rgid, egid, sgid; 17457e31ba66Smrg 17467e31ba66Smrg if ((getresuid(&ruid, &euid, &suid) == 0) && 17477e31ba66Smrg (getresgid(&rgid, &egid, &sgid) == 0)) { 17487e31ba66Smrg privsElevated = (euid != suid) || (egid != sgid); 17497e31ba66Smrg } 17507e31ba66Smrg else { 17517e31ba66Smrg printf("Failed getresuid or getresgid"); 17527e31ba66Smrg /* Something went wrong, make defensive assumption */ 17537e31ba66Smrg privsElevated = TRUE; 17547e31ba66Smrg } 17557e31ba66Smrg#else 17567e31ba66Smrg if (getuid() == 0) { 17577e31ba66Smrg /* running as root: uid==euid==0 */ 17587e31ba66Smrg privsElevated = FALSE; 17597e31ba66Smrg } 17607e31ba66Smrg else { 17617e31ba66Smrg /* 17627e31ba66Smrg * If there are saved ID's the process might still be privileged 17637e31ba66Smrg * even though the above test succeeded. If issetugid() and 17647e31ba66Smrg * getresgid() aren't available, test this by trying to set 17657e31ba66Smrg * euid to 0. 17667e31ba66Smrg */ 17677e31ba66Smrg unsigned int oldeuid; 17687e31ba66Smrg 17697e31ba66Smrg oldeuid = geteuid(); 17707e31ba66Smrg 17717e31ba66Smrg if (seteuid(0) != 0) { 17727e31ba66Smrg privsElevated = FALSE; 17737e31ba66Smrg } 17747e31ba66Smrg else { 17757e31ba66Smrg if (seteuid(oldeuid) != 0) { 17767e31ba66Smrg FatalError("Failed to drop privileges. Exiting\n"); 17777e31ba66Smrg } 17787e31ba66Smrg privsElevated = TRUE; 17797e31ba66Smrg } 17807e31ba66Smrg } 17817e31ba66Smrg#endif 17827e31ba66Smrg } 17837e31ba66Smrg#endif 17847e31ba66Smrg privsTested = TRUE; 17857e31ba66Smrg } 17867e31ba66Smrg return privsElevated; 17877e31ba66Smrg} 17887e31ba66Smrg 178905b261ecSmrg/* 179005b261ecSmrg * CheckUserParameters: check for long command line arguments and long 179105b261ecSmrg * environment variables. By default, these checks are only done when 179205b261ecSmrg * the server's euid != ruid. In 3.3.x, these checks were done in an 179305b261ecSmrg * external wrapper utility. 179405b261ecSmrg */ 179505b261ecSmrg 179605b261ecSmrg/* Consider LD* variables insecure? */ 179705b261ecSmrg#ifndef REMOVE_ENV_LD 179805b261ecSmrg#define REMOVE_ENV_LD 1 179905b261ecSmrg#endif 180005b261ecSmrg 180105b261ecSmrg/* Remove long environment variables? */ 180205b261ecSmrg#ifndef REMOVE_LONG_ENV 180305b261ecSmrg#define REMOVE_LONG_ENV 1 180405b261ecSmrg#endif 180505b261ecSmrg 180605b261ecSmrg/* 180705b261ecSmrg * Disallow stdout or stderr as pipes? It's possible to block the X server 180805b261ecSmrg * when piping stdout+stderr to a pipe. 180905b261ecSmrg * 181005b261ecSmrg * Don't enable this because it looks like it's going to cause problems. 181105b261ecSmrg */ 181205b261ecSmrg#ifndef NO_OUTPUT_PIPES 181305b261ecSmrg#define NO_OUTPUT_PIPES 0 181405b261ecSmrg#endif 181505b261ecSmrg 181605b261ecSmrg/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */ 181705b261ecSmrg#ifndef CHECK_EUID 181805b261ecSmrg#ifndef WIN32 181905b261ecSmrg#define CHECK_EUID 1 182005b261ecSmrg#else 182105b261ecSmrg#define CHECK_EUID 0 182205b261ecSmrg#endif 182305b261ecSmrg#endif 182405b261ecSmrg 182505b261ecSmrg/* 182605b261ecSmrg * Maybe the locale can be faked to make isprint(3) report that everything 182705b261ecSmrg * is printable? Avoid it by default. 182805b261ecSmrg */ 182905b261ecSmrg#ifndef USE_ISPRINT 183005b261ecSmrg#define USE_ISPRINT 0 183105b261ecSmrg#endif 183205b261ecSmrg 183305b261ecSmrg#define MAX_ARG_LENGTH 128 183405b261ecSmrg#define MAX_ENV_LENGTH 256 1835f7df2e56Smrg#define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */ 183605b261ecSmrg 183705b261ecSmrg#if USE_ISPRINT 183805b261ecSmrg#include <ctype.h> 183905b261ecSmrg#define checkPrintable(c) isprint(c) 184005b261ecSmrg#else 184105b261ecSmrg#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f) 184205b261ecSmrg#endif 184305b261ecSmrg 184405b261ecSmrgenum BadCode { 184505b261ecSmrg NotBad = 0, 184605b261ecSmrg UnsafeArg, 184705b261ecSmrg ArgTooLong, 184805b261ecSmrg UnprintableArg, 184905b261ecSmrg EnvTooLong, 185005b261ecSmrg OutputIsPipe, 185105b261ecSmrg InternalError 185205b261ecSmrg}; 185305b261ecSmrg 185405b261ecSmrg#if defined(VENDORSUPPORT) 185505b261ecSmrg#define BUGADDRESS VENDORSUPPORT 185605b261ecSmrg#elif defined(BUILDERADDR) 185705b261ecSmrg#define BUGADDRESS BUILDERADDR 185805b261ecSmrg#else 185905b261ecSmrg#define BUGADDRESS "xorg@freedesktop.org" 186005b261ecSmrg#endif 186105b261ecSmrg 186205b261ecSmrgvoid 186305b261ecSmrgCheckUserParameters(int argc, char **argv, char **envp) 186405b261ecSmrg{ 186505b261ecSmrg enum BadCode bad = NotBad; 186605b261ecSmrg int i = 0, j; 186705b261ecSmrg char *a, *e = NULL; 186805b261ecSmrg 186905b261ecSmrg#if CHECK_EUID 18707e31ba66Smrg if (PrivsElevated()) 187105b261ecSmrg#endif 187205b261ecSmrg { 1873f7df2e56Smrg /* Check each argv[] */ 1874f7df2e56Smrg for (i = 1; i < argc; i++) { 1875f7df2e56Smrg if (strcmp(argv[i], "-fp") == 0) { 1876f7df2e56Smrg i++; /* continue with next argument. skip the length check */ 1877f7df2e56Smrg if (i >= argc) 1878f7df2e56Smrg break; 1879f7df2e56Smrg } 1880f7df2e56Smrg else { 1881f7df2e56Smrg if (strlen(argv[i]) > MAX_ARG_LENGTH) { 1882f7df2e56Smrg bad = ArgTooLong; 1883f7df2e56Smrg break; 1884f7df2e56Smrg } 1885f7df2e56Smrg } 1886f7df2e56Smrg a = argv[i]; 1887f7df2e56Smrg while (*a) { 1888f7df2e56Smrg if (checkPrintable(*a) == 0) { 1889f7df2e56Smrg bad = UnprintableArg; 1890f7df2e56Smrg break; 1891f7df2e56Smrg } 1892f7df2e56Smrg a++; 1893f7df2e56Smrg } 1894f7df2e56Smrg if (bad) 1895f7df2e56Smrg break; 1896f7df2e56Smrg } 1897f7df2e56Smrg if (!bad) { 1898f7df2e56Smrg /* Check each envp[] */ 1899f7df2e56Smrg for (i = 0; envp[i]; i++) { 190005b261ecSmrg 1901f7df2e56Smrg /* Check for bad environment variables and values */ 190205b261ecSmrg#if REMOVE_ENV_LD 1903f7df2e56Smrg while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) { 1904f7df2e56Smrg for (j = i; envp[j]; j++) { 1905f7df2e56Smrg envp[j] = envp[j + 1]; 1906f7df2e56Smrg } 1907f7df2e56Smrg } 1908f7df2e56Smrg#endif 1909f7df2e56Smrg if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) { 191005b261ecSmrg#if REMOVE_LONG_ENV 1911f7df2e56Smrg for (j = i; envp[j]; j++) { 1912f7df2e56Smrg envp[j] = envp[j + 1]; 1913f7df2e56Smrg } 1914f7df2e56Smrg i--; 191505b261ecSmrg#else 1916f7df2e56Smrg char *eq; 1917f7df2e56Smrg int len; 1918f7df2e56Smrg 1919f7df2e56Smrg eq = strchr(envp[i], '='); 1920f7df2e56Smrg if (!eq) 1921f7df2e56Smrg continue; 1922f7df2e56Smrg len = eq - envp[i]; 1923f7df2e56Smrg e = strndup(envp[i], len); 1924f7df2e56Smrg if (!e) { 1925f7df2e56Smrg bad = InternalError; 1926f7df2e56Smrg break; 1927f7df2e56Smrg } 1928f7df2e56Smrg if (len >= 4 && 1929f7df2e56Smrg (strcmp(e + len - 4, "PATH") == 0 || 1930f7df2e56Smrg strcmp(e, "TERMCAP") == 0)) { 1931f7df2e56Smrg if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) { 1932f7df2e56Smrg bad = EnvTooLong; 1933f7df2e56Smrg break; 1934f7df2e56Smrg } 1935f7df2e56Smrg else { 1936f7df2e56Smrg free(e); 1937f7df2e56Smrg } 1938f7df2e56Smrg } 1939f7df2e56Smrg else { 1940f7df2e56Smrg bad = EnvTooLong; 1941f7df2e56Smrg break; 1942f7df2e56Smrg } 1943f7df2e56Smrg#endif 1944f7df2e56Smrg } 1945f7df2e56Smrg } 1946f7df2e56Smrg } 194705b261ecSmrg#if NO_OUTPUT_PIPES 1948f7df2e56Smrg if (!bad) { 1949f7df2e56Smrg struct stat buf; 195005b261ecSmrg 1951f7df2e56Smrg if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1952f7df2e56Smrg bad = OutputIsPipe; 1953f7df2e56Smrg if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1954f7df2e56Smrg bad = OutputIsPipe; 1955f7df2e56Smrg } 195605b261ecSmrg#endif 195705b261ecSmrg } 195805b261ecSmrg switch (bad) { 195905b261ecSmrg case NotBad: 1960f7df2e56Smrg return; 196105b261ecSmrg case UnsafeArg: 1962f7df2e56Smrg ErrorF("Command line argument number %d is unsafe\n", i); 1963f7df2e56Smrg break; 196405b261ecSmrg case ArgTooLong: 1965f7df2e56Smrg ErrorF("Command line argument number %d is too long\n", i); 1966f7df2e56Smrg break; 196705b261ecSmrg case UnprintableArg: 1968f7df2e56Smrg ErrorF("Command line argument number %d contains unprintable" 1969f7df2e56Smrg " characters\n", i); 1970f7df2e56Smrg break; 197105b261ecSmrg case EnvTooLong: 1972f7df2e56Smrg ErrorF("Environment variable `%s' is too long\n", e); 1973f7df2e56Smrg break; 197405b261ecSmrg case OutputIsPipe: 1975f7df2e56Smrg ErrorF("Stdout and/or stderr is a pipe\n"); 1976f7df2e56Smrg break; 197705b261ecSmrg case InternalError: 1978f7df2e56Smrg ErrorF("Internal Error\n"); 1979f7df2e56Smrg break; 198005b261ecSmrg default: 1981f7df2e56Smrg ErrorF("Unknown error\n"); 1982f7df2e56Smrg break; 198305b261ecSmrg } 198405b261ecSmrg FatalError("X server aborted because of unsafe environment\n"); 198505b261ecSmrg} 198605b261ecSmrg 198705b261ecSmrg/* 198805b261ecSmrg * CheckUserAuthorization: check if the user is allowed to start the 198905b261ecSmrg * X server. This usually means some sort of PAM checking, and it is 199005b261ecSmrg * usually only done for setuid servers (uid != euid). 199105b261ecSmrg */ 199205b261ecSmrg 199305b261ecSmrg#ifdef USE_PAM 199405b261ecSmrg#include <security/pam_appl.h> 199505b261ecSmrg#include <security/pam_misc.h> 199605b261ecSmrg#include <pwd.h> 1997f7df2e56Smrg#endif /* USE_PAM */ 199805b261ecSmrg 199905b261ecSmrgvoid 200005b261ecSmrgCheckUserAuthorization(void) 200105b261ecSmrg{ 200205b261ecSmrg#ifdef USE_PAM 200305b261ecSmrg static struct pam_conv conv = { 2004f7df2e56Smrg misc_conv, 2005f7df2e56Smrg NULL 200605b261ecSmrg }; 200705b261ecSmrg 200805b261ecSmrg pam_handle_t *pamh = NULL; 200905b261ecSmrg struct passwd *pw; 201005b261ecSmrg int retval; 201105b261ecSmrg 201205b261ecSmrg if (getuid() != geteuid()) { 2013f7df2e56Smrg pw = getpwuid(getuid()); 2014f7df2e56Smrg if (pw == NULL) 2015f7df2e56Smrg FatalError("getpwuid() failed for uid %d\n", getuid()); 2016f7df2e56Smrg 2017f7df2e56Smrg retval = pam_start("xserver", pw->pw_name, &conv, &pamh); 2018f7df2e56Smrg if (retval != PAM_SUCCESS) 2019f7df2e56Smrg FatalError("pam_start() failed.\n" 2020f7df2e56Smrg "\tMissing or mangled PAM config file or module?\n"); 2021f7df2e56Smrg 2022f7df2e56Smrg retval = pam_authenticate(pamh, 0); 2023f7df2e56Smrg if (retval != PAM_SUCCESS) { 2024f7df2e56Smrg pam_end(pamh, retval); 2025f7df2e56Smrg FatalError("PAM authentication failed, cannot start X server.\n" 2026f7df2e56Smrg "\tPerhaps you do not have console ownership?\n"); 2027f7df2e56Smrg } 202805b261ecSmrg 2029f7df2e56Smrg retval = pam_acct_mgmt(pamh, 0); 2030f7df2e56Smrg if (retval != PAM_SUCCESS) { 2031f7df2e56Smrg pam_end(pamh, retval); 2032f7df2e56Smrg FatalError("PAM authentication failed, cannot start X server.\n" 2033f7df2e56Smrg "\tPerhaps you do not have console ownership?\n"); 2034f7df2e56Smrg } 203505b261ecSmrg 2036f7df2e56Smrg /* this is not a session, so do not do session management */ 2037f7df2e56Smrg pam_end(pamh, PAM_SUCCESS); 203805b261ecSmrg } 203905b261ecSmrg#endif 204005b261ecSmrg} 204105b261ecSmrg 20424202a189Smrg/* 20434202a189Smrg * Tokenize a string into a NULL terminated array of strings. Always returns 20444202a189Smrg * an allocated array unless an error occurs. 20454202a189Smrg */ 2046f7df2e56Smrgchar ** 20474202a189Smrgxstrtokenize(const char *str, const char *separators) 204805b261ecSmrg{ 20494202a189Smrg char **list, **nlist; 20504202a189Smrg char *tok, *tmp; 20514202a189Smrg unsigned num = 0, n; 205205b261ecSmrg 20534202a189Smrg if (!str) 20544202a189Smrg return NULL; 20554202a189Smrg list = calloc(1, sizeof(*list)); 20564202a189Smrg if (!list) 20574202a189Smrg return NULL; 20584202a189Smrg tmp = strdup(str); 20594202a189Smrg if (!tmp) 20604202a189Smrg goto error; 20614202a189Smrg for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) { 2062f7df2e56Smrg nlist = reallocarray(list, num + 2, sizeof(*list)); 20634202a189Smrg if (!nlist) 20644202a189Smrg goto error; 20654202a189Smrg list = nlist; 20664202a189Smrg list[num] = strdup(tok); 20674202a189Smrg if (!list[num]) 20684202a189Smrg goto error; 20694202a189Smrg list[++num] = NULL; 20704202a189Smrg } 20714202a189Smrg free(tmp); 20724202a189Smrg return list; 20734202a189Smrg 2074f7df2e56Smrg error: 20754202a189Smrg free(tmp); 20764202a189Smrg for (n = 0; n < num; n++) 20774202a189Smrg free(list[n]); 20784202a189Smrg free(list); 20794202a189Smrg return NULL; 208005b261ecSmrg} 2081f7df2e56Smrg 2082f7df2e56Smrg/* Format a signed number into a string in a signal safe manner. The string 2083f7df2e56Smrg * should be at least 21 characters in order to handle all int64_t values. 2084f7df2e56Smrg */ 2085f7df2e56Smrgvoid 2086f7df2e56SmrgFormatInt64(int64_t num, char *string) 2087f7df2e56Smrg{ 2088f7df2e56Smrg if (num < 0) { 2089f7df2e56Smrg string[0] = '-'; 2090f7df2e56Smrg num *= -1; 2091f7df2e56Smrg string++; 2092f7df2e56Smrg } 2093f7df2e56Smrg FormatUInt64(num, string); 2094f7df2e56Smrg} 2095f7df2e56Smrg 2096f7df2e56Smrg/* Format a number into a string in a signal safe manner. The string should be 2097f7df2e56Smrg * at least 21 characters in order to handle all uint64_t values. */ 2098f7df2e56Smrgvoid 2099f7df2e56SmrgFormatUInt64(uint64_t num, char *string) 2100f7df2e56Smrg{ 2101f7df2e56Smrg uint64_t divisor; 2102f7df2e56Smrg int len; 2103f7df2e56Smrg int i; 2104f7df2e56Smrg 2105f7df2e56Smrg for (len = 1, divisor = 10; 2106f7df2e56Smrg len < 20 && num / divisor; 2107f7df2e56Smrg len++, divisor *= 10); 2108f7df2e56Smrg 2109f7df2e56Smrg for (i = len, divisor = 1; i > 0; i--, divisor *= 10) 2110f7df2e56Smrg string[i - 1] = '0' + ((num / divisor) % 10); 2111f7df2e56Smrg 2112f7df2e56Smrg string[len] = '\0'; 2113f7df2e56Smrg} 2114f7df2e56Smrg 2115f7df2e56Smrg/** 2116f7df2e56Smrg * Format a double number as %.2f. 2117f7df2e56Smrg */ 2118f7df2e56Smrgvoid 2119f7df2e56SmrgFormatDouble(double dbl, char *string) 2120f7df2e56Smrg{ 2121f7df2e56Smrg int slen = 0; 2122f7df2e56Smrg uint64_t frac; 2123f7df2e56Smrg 2124f7df2e56Smrg frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5; 2125f7df2e56Smrg frac %= 100; 2126f7df2e56Smrg 2127f7df2e56Smrg /* write decimal part to string */ 2128f7df2e56Smrg if (dbl < 0 && dbl > -1) 2129f7df2e56Smrg string[slen++] = '-'; 2130f7df2e56Smrg FormatInt64((int64_t)dbl, &string[slen]); 2131f7df2e56Smrg 2132f7df2e56Smrg while(string[slen] != '\0') 2133f7df2e56Smrg slen++; 2134f7df2e56Smrg 2135f7df2e56Smrg /* append fractional part, but only if we have enough characters. We 2136f7df2e56Smrg * expect string to be 21 chars (incl trailing \0) */ 2137f7df2e56Smrg if (slen <= 17) { 2138f7df2e56Smrg string[slen++] = '.'; 2139f7df2e56Smrg if (frac < 10) 2140f7df2e56Smrg string[slen++] = '0'; 2141f7df2e56Smrg 2142f7df2e56Smrg FormatUInt64(frac, &string[slen]); 2143f7df2e56Smrg } 2144f7df2e56Smrg} 2145f7df2e56Smrg 2146f7df2e56Smrg 2147f7df2e56Smrg/* Format a number into a hexadecimal string in a signal safe manner. The string 2148f7df2e56Smrg * should be at least 17 characters in order to handle all uint64_t values. */ 2149f7df2e56Smrgvoid 2150f7df2e56SmrgFormatUInt64Hex(uint64_t num, char *string) 2151f7df2e56Smrg{ 2152f7df2e56Smrg uint64_t divisor; 2153f7df2e56Smrg int len; 2154f7df2e56Smrg int i; 2155f7df2e56Smrg 2156f7df2e56Smrg for (len = 1, divisor = 0x10; 2157f7df2e56Smrg len < 16 && num / divisor; 2158f7df2e56Smrg len++, divisor *= 0x10); 2159f7df2e56Smrg 2160f7df2e56Smrg for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) { 2161f7df2e56Smrg int val = (num / divisor) % 0x10; 2162f7df2e56Smrg 2163f7df2e56Smrg if (val < 10) 2164f7df2e56Smrg string[i - 1] = '0' + val; 2165f7df2e56Smrg else 2166f7df2e56Smrg string[i - 1] = 'a' + val - 10; 2167f7df2e56Smrg } 2168f7df2e56Smrg 2169f7df2e56Smrg string[len] = '\0'; 2170f7df2e56Smrg} 2171f7df2e56Smrg 2172f7df2e56Smrg#if !defined(WIN32) || defined(__CYGWIN__) 2173f7df2e56Smrg/* Move a file descriptor out of the way of our select mask; this 2174f7df2e56Smrg * is useful for file descriptors which will never appear in the 2175f7df2e56Smrg * select mask to avoid reducing the number of clients that can 2176f7df2e56Smrg * connect to the server 2177f7df2e56Smrg */ 2178f7df2e56Smrgint 2179f7df2e56Smrgos_move_fd(int fd) 2180f7df2e56Smrg{ 2181f7df2e56Smrg int newfd; 2182f7df2e56Smrg 2183f7df2e56Smrg#ifdef F_DUPFD_CLOEXEC 2184f7df2e56Smrg newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS); 2185f7df2e56Smrg#else 2186f7df2e56Smrg newfd = fcntl(fd, F_DUPFD, MAXCLIENTS); 2187f7df2e56Smrg#endif 2188f7df2e56Smrg if (newfd < 0) 2189f7df2e56Smrg return fd; 2190f7df2e56Smrg#ifndef F_DUPFD_CLOEXEC 2191f7df2e56Smrg fcntl(newfd, F_SETFD, FD_CLOEXEC); 2192f7df2e56Smrg#endif 2193f7df2e56Smrg close(fd); 2194f7df2e56Smrg return newfd; 2195f7df2e56Smrg} 2196f7df2e56Smrg#endif 2197