1603 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1603 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
| 
 | |
| Copyright 1987, 1998  The Open Group
 | |
| 
 | |
| Permission to use, copy, modify, distribute, and sell this software and its
 | |
| documentation for any purpose is hereby granted without fee, provided that
 | |
| the above copyright notice appear in all copies and that both that
 | |
| copyright notice and this permission notice appear in supporting
 | |
| documentation.
 | |
| 
 | |
| The above copyright notice and this permission notice shall be included
 | |
| in all copies or substantial portions of the Software.
 | |
| 
 | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 | |
| OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 | |
| IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | |
| OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | |
| ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | |
| OTHER DEALINGS IN THE SOFTWARE.
 | |
| 
 | |
| Except as contained in this notice, the name of The Open Group shall
 | |
| not be used in advertising or otherwise to promote the sale, use or
 | |
| other dealings in this Software without prior written authorization
 | |
| from The Open Group.
 | |
| 
 | |
| Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
 | |
| Copyright 1994 Quarterdeck Office Systems.
 | |
| 
 | |
|                         All Rights Reserved
 | |
| 
 | |
| Permission to use, copy, modify, and distribute this software and its
 | |
| documentation for any purpose and without fee is hereby granted,
 | |
| provided that the above copyright notice appear in all copies and that
 | |
| both that copyright notice and this permission notice appear in
 | |
| supporting documentation, and that the names of Digital and
 | |
| Quarterdeck not be used in advertising or publicity pertaining to
 | |
| distribution of the software without specific, written prior
 | |
| permission.
 | |
| 
 | |
| DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 | |
| SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | |
| FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
 | |
| OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 | |
| OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 | |
| OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
 | |
| OR PERFORMANCE OF THIS SOFTWARE.
 | |
| 
 | |
| */
 | |
| 
 | |
| #include <dix-config.h>
 | |
| 
 | |
| #ifdef __CYGWIN__
 | |
| #include <stdlib.h>
 | |
| #include <signal.h>
 | |
| /*
 | |
|    Sigh... We really need a prototype for this to know it is stdcall,
 | |
|    but #include-ing <windows.h> here is not a good idea...
 | |
| */
 | |
| __stdcall unsigned long GetTickCount(void);
 | |
| #endif
 | |
| 
 | |
| #if defined(WIN32) && !defined(__CYGWIN__)
 | |
| #include <X11/Xwinsock.h>
 | |
| #endif
 | |
| #include <X11/Xos.h>
 | |
| #include <stdio.h>
 | |
| #include <time.h>
 | |
| #if !defined(WIN32) || !defined(__MINGW32__)
 | |
| #include <sys/time.h>
 | |
| #include <sys/resource.h>
 | |
| #endif
 | |
| #include "misc.h"
 | |
| #include <X11/X.h>
 | |
| #define XSERV_t
 | |
| #define TRANS_SERVER
 | |
| #define TRANS_REOPEN
 | |
| #include <X11/Xtrans/Xtrans.h>
 | |
| 
 | |
| #include "os/audit.h"
 | |
| 
 | |
| #include "input.h"
 | |
| #include "dixfont.h"
 | |
| #include <X11/fonts/libxfont2.h>
 | |
| #include "osdep.h"
 | |
| #include "xdmcp.h"
 | |
| #include "extension.h"
 | |
| #include <signal.h>
 | |
| #ifndef WIN32
 | |
| #include <sys/wait.h>
 | |
| #endif
 | |
| #if !defined(WIN32)
 | |
| #include <sys/resource.h>
 | |
| #endif
 | |
| #include <sys/stat.h>
 | |
| #include <ctype.h>              /* for isspace */
 | |
| #include <stdarg.h>
 | |
| #include <stdlib.h>             /* for malloc() */
 | |
| 
 | |
| #if defined(TCPCONN)
 | |
| #ifndef WIN32
 | |
| #include <netdb.h>
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| #include "dix/dix_priv.h"
 | |
| #include "dix/input_priv.h"
 | |
| #include "os/auth.h"
 | |
| #include "os/cmdline.h"
 | |
| #include "os/ddx_priv.h"
 | |
| #include "os/osdep.h"
 | |
| #include "os/serverlock.h"
 | |
| 
 | |
| #include "dixstruct.h"
 | |
| #include "xkbsrv.h"
 | |
| #include "picture.h"
 | |
| #include "miinitext.h"
 | |
| #include "present.h"
 | |
| #include "dixstruct_priv.h"
 | |
| 
 | |
| Bool noTestExtensions;
 | |
| 
 | |
| #ifdef COMPOSITE
 | |
| Bool noCompositeExtension = FALSE;
 | |
| #endif
 | |
| 
 | |
| #ifdef DAMAGE
 | |
| Bool noDamageExtension = FALSE;
 | |
| #endif
 | |
| #ifdef DBE
 | |
| Bool noDbeExtension = FALSE;
 | |
| #endif
 | |
| #ifdef DPMSExtension
 | |
| #include "dpmsproc.h"
 | |
| Bool noDPMSExtension = FALSE;
 | |
| #endif
 | |
| #ifdef GLXEXT
 | |
| Bool noGlxExtension = FALSE;
 | |
| #endif
 | |
| #ifdef SCREENSAVER
 | |
| Bool noScreenSaverExtension = FALSE;
 | |
| #endif
 | |
| #ifdef MITSHM
 | |
| Bool noMITShmExtension = FALSE;
 | |
| #endif
 | |
| #ifdef RANDR
 | |
| Bool noRRExtension = FALSE;
 | |
| #endif
 | |
| Bool noRenderExtension = FALSE;
 | |
| Bool noShapeExtension = FALSE;
 | |
| 
 | |
| #ifdef XCSECURITY
 | |
| Bool noSecurityExtension = FALSE;
 | |
| #endif
 | |
| #ifdef RES
 | |
| Bool noResExtension = FALSE;
 | |
| #endif
 | |
| #ifdef XF86BIGFONT
 | |
| Bool noXFree86BigfontExtension = FALSE;
 | |
| #endif
 | |
| #ifdef XFreeXDGA
 | |
| Bool noXFree86DGAExtension = FALSE;
 | |
| #endif
 | |
| #ifdef XF86DRI
 | |
| Bool noXFree86DRIExtension = FALSE;
 | |
| #endif
 | |
| #ifdef XF86VIDMODE
 | |
| Bool noXFree86VidModeExtension = FALSE;
 | |
| #endif
 | |
| Bool noXFixesExtension = FALSE;
 | |
| #ifdef PANORAMIX
 | |
| /* Xinerama is disabled by default unless enabled via +xinerama */
 | |
| Bool noPanoramiXExtension = TRUE;
 | |
| #endif
 | |
| #ifdef DRI2
 | |
| Bool noDRI2Extension = FALSE;
 | |
| #endif
 | |
| 
 | |
| Bool noGEExtension = FALSE;
 | |
| 
 | |
| #define X_INCLUDE_NETDB_H
 | |
| #include <X11/Xos_r.h>
 | |
| 
 | |
| #include <errno.h>
 | |
| 
 | |
| Bool CoreDump;
 | |
| 
 | |
| Bool enableIndirectGLX = FALSE;
 | |
| 
 | |
| Bool AllowByteSwappedClients = FALSE;
 | |
| 
 | |
| #ifdef PANORAMIX
 | |
| Bool PanoramiXExtensionDisabledHack = FALSE;
 | |
| #endif
 | |
| 
 | |
| char *SeatId = NULL;
 | |
| 
 | |
| sig_atomic_t inSignalContext = FALSE;
 | |
| 
 | |
| #ifdef MONOTONIC_CLOCK
 | |
| static clockid_t clockid;
 | |
| #endif
 | |
| 
 | |
| OsSigHandlerPtr
 | |
| OsSignal(int sig, OsSigHandlerPtr handler)
 | |
| {
 | |
| #if defined(WIN32) && !defined(__CYGWIN__)
 | |
|     return signal(sig, handler);
 | |
| #else
 | |
|     struct sigaction act, oact;
 | |
| 
 | |
|     sigemptyset(&act.sa_mask);
 | |
|     if (handler != SIG_IGN)
 | |
|         sigaddset(&act.sa_mask, sig);
 | |
|     act.sa_flags = 0;
 | |
|     act.sa_handler = handler;
 | |
|     if (sigaction(sig, &act, &oact))
 | |
|         perror("sigaction");
 | |
|     return oact.sa_handler;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* Force connections to close on SIGHUP from init */
 | |
| 
 | |
| void
 | |
| AutoResetServer(int sig)
 | |
| {
 | |
|     int olderrno = errno;
 | |
| 
 | |
|     dispatchException |= DE_RESET;
 | |
|     isItTimeToYield = TRUE;
 | |
|     errno = olderrno;
 | |
| }
 | |
| 
 | |
| /* Force connections to close and then exit on SIGTERM, SIGINT */
 | |
| 
 | |
| void
 | |
| GiveUp(int sig)
 | |
| {
 | |
|     int olderrno = errno;
 | |
| 
 | |
|     dispatchException |= DE_TERMINATE;
 | |
|     isItTimeToYield = TRUE;
 | |
|     errno = olderrno;
 | |
| }
 | |
| 
 | |
| #ifdef MONOTONIC_CLOCK
 | |
| void
 | |
| ForceClockId(clockid_t forced_clockid)
 | |
| {
 | |
|     struct timespec tp;
 | |
| 
 | |
|     BUG_RETURN (clockid);
 | |
| 
 | |
|     clockid = forced_clockid;
 | |
| 
 | |
|     if (clock_gettime(clockid, &tp) != 0) {
 | |
|         FatalError("Forced clock id failed to retrieve current time: %s\n",
 | |
|                    strerror(errno));
 | |
|         return;
 | |
|     }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__)
 | |
| CARD32
 | |
| GetTimeInMillis(void)
 | |
| {
 | |
|     return GetTickCount();
 | |
| }
 | |
| CARD64
 | |
| GetTimeInMicros(void)
 | |
| {
 | |
|     return (CARD64) GetTickCount() * 1000;
 | |
| }
 | |
| #else
 | |
| CARD32
 | |
| GetTimeInMillis(void)
 | |
| {
 | |
|     struct timeval tv;
 | |
| 
 | |
| #ifdef MONOTONIC_CLOCK
 | |
|     struct timespec tp;
 | |
| 
 | |
|     if (!clockid) {
 | |
| #ifdef CLOCK_MONOTONIC_COARSE
 | |
|         if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
 | |
|             (tp.tv_nsec / 1000) <= 1000 &&
 | |
|             clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
 | |
|             clockid = CLOCK_MONOTONIC_COARSE;
 | |
|         else
 | |
| #endif
 | |
|         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
 | |
|             clockid = CLOCK_MONOTONIC;
 | |
|         else
 | |
|             clockid = ~0L;
 | |
|     }
 | |
|     if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
 | |
|         return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
 | |
| #endif
 | |
| 
 | |
|     X_GETTIMEOFDAY(&tv);
 | |
|     return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
 | |
| }
 | |
| 
 | |
| CARD64
 | |
| GetTimeInMicros(void)
 | |
| {
 | |
|     struct timeval tv;
 | |
| #ifdef MONOTONIC_CLOCK
 | |
|     struct timespec tp;
 | |
|     static clockid_t uclockid;
 | |
| 
 | |
|     if (!uclockid) {
 | |
|         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
 | |
|             uclockid = CLOCK_MONOTONIC;
 | |
|         else
 | |
|             uclockid = ~0L;
 | |
|     }
 | |
|     if (uclockid != ~0L && clock_gettime(uclockid, &tp) == 0)
 | |
|         return (CARD64) tp.tv_sec * (CARD64)1000000 + tp.tv_nsec / 1000;
 | |
| #endif
 | |
| 
 | |
|     X_GETTIMEOFDAY(&tv);
 | |
|     return (CARD64) tv.tv_sec * (CARD64)1000000 + (CARD64) tv.tv_usec;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| void
 | |
| UseMsg(void)
 | |
| {
 | |
|     ErrorF("use: X [:<display>] [option]\n");
 | |
|     ErrorF("-a #                   default pointer acceleration (factor)\n");
 | |
|     ErrorF("-ac                    disable access control restrictions\n");
 | |
|     ErrorF("-audit int             set audit trail level\n");
 | |
|     ErrorF("-auth file             select authorization file\n");
 | |
|     ErrorF("-br                    create root window with black background\n");
 | |
|     ErrorF("+bs                    enable any backing store support\n");
 | |
|     ErrorF("-bs                    disable any backing store support\n");
 | |
|     ErrorF("+byteswappedclients    Allow clients with endianess different to that of the server\n");
 | |
|     ErrorF("-byteswappedclients    Prohibit clients with endianess different to that of the server\n");
 | |
|     ErrorF("-c                     turns off key-click\n");
 | |
|     ErrorF("c #                    key-click volume (0-100)\n");
 | |
|     ErrorF("-cc int                default color visual class\n");
 | |
|     ErrorF("-nocursor              disable the cursor\n");
 | |
|     ErrorF("-core                  generate core dump on fatal error\n");
 | |
|     ErrorF("-displayfd fd          file descriptor to write display number to when ready to connect\n");
 | |
|     ErrorF("-dpi int               screen resolution in dots per inch\n");
 | |
| #ifdef DPMSExtension
 | |
|     ErrorF("-dpms                  disables VESA DPMS monitor control\n");
 | |
| #endif
 | |
|     ErrorF
 | |
|         ("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n");
 | |
|     ErrorF("-f #                   bell base (0-100)\n");
 | |
|     ErrorF("-fakescreenfps #       fake screen default fps (1-600)\n");
 | |
|     ErrorF("-fp string             default font path\n");
 | |
|     ErrorF("-help                  prints message with these options\n");
 | |
|     ErrorF("+iglx                  Allow creating indirect GLX contexts\n");
 | |
|     ErrorF("-iglx                  Prohibit creating indirect GLX contexts (default)\n");
 | |
|     ErrorF("-I                     ignore all remaining arguments\n");
 | |
| #ifdef RLIMIT_DATA
 | |
|     ErrorF("-ld int                limit data space to N Kb\n");
 | |
| #endif
 | |
| #ifdef RLIMIT_NOFILE
 | |
|     ErrorF("-lf int                limit number of open files to N\n");
 | |
| #endif
 | |
| #ifdef RLIMIT_STACK
 | |
|     ErrorF("-ls int                limit stack space to N Kb\n");
 | |
| #endif
 | |
|     LockServerUseMsg();
 | |
|     ErrorF("-maxclients n          set maximum number of clients (power of two)\n");
 | |
|     ErrorF("-nolisten string       don't listen on protocol\n");
 | |
|     ErrorF("-listen string         listen on protocol\n");
 | |
|     ErrorF("-noreset               don't reset after last client exists\n");
 | |
|     ErrorF("-background [none]     create root window with no background\n");
 | |
|     ErrorF("-reset                 reset after last client exists\n");
 | |
|     ErrorF("-p #                   screen-saver pattern duration (minutes)\n");
 | |
|     ErrorF("-pn                    accept failure to listen on all ports\n");
 | |
|     ErrorF("-nopn                  reject failure to listen on all ports\n");
 | |
|     ErrorF("-r                     turns off auto-repeat\n");
 | |
|     ErrorF("r                      turns on auto-repeat \n");
 | |
|     ErrorF("-render [default|mono|gray|color] set render color alloc policy\n");
 | |
|     ErrorF("-retro                 start with classic stipple and cursor\n");
 | |
|     ErrorF("-s #                   screen-saver timeout (minutes)\n");
 | |
|     ErrorF("-seat string           seat to run on\n");
 | |
|     ErrorF("-t #                   default pointer threshold (pixels/t)\n");
 | |
|     ErrorF("-terminate [delay]     terminate at server reset (optional delay in sec)\n");
 | |
|     ErrorF("-tst                   disable testing extensions\n");
 | |
|     ErrorF("ttyxx                  server started from init on /dev/ttyxx\n");
 | |
|     ErrorF("v                      video blanking for screen-saver\n");
 | |
|     ErrorF("-v                     screen-saver without video blanking\n");
 | |
|     ErrorF("-wr                    create root window with white background\n");
 | |
|     ErrorF("-maxbigreqsize         set maximal bigrequest size \n");
 | |
| #ifdef PANORAMIX
 | |
|     ErrorF("+xinerama              Enable XINERAMA extension\n");
 | |
|     ErrorF("-xinerama              Disable XINERAMA extension\n");
 | |
| #endif
 | |
|     ErrorF("-dumbSched             Disable smart scheduling and threaded input, enable old behavior\n");
 | |
|     ErrorF("-schedInterval int     Set scheduler interval in msec\n");
 | |
|     ErrorF("-sigstop               Enable SIGSTOP based startup\n");
 | |
|     ErrorF("+extension name        Enable extension\n");
 | |
|     ErrorF("-extension name        Disable extension\n");
 | |
|     ListStaticExtensions();
 | |
| #ifdef XDMCP
 | |
|     XdmcpUseMsg();
 | |
| #endif
 | |
|     XkbUseMsg();
 | |
|     ddxUseMsg();
 | |
| }
 | |
| 
 | |
| /*  This function performs a rudimentary sanity check
 | |
|  *  on the display name passed in on the command-line,
 | |
|  *  since this string is used to generate filenames.
 | |
|  *  It is especially important that the display name
 | |
|  *  not contain a "/" and not start with a "-".
 | |
|  *                                            --kvajk
 | |
|  */
 | |
| static int
 | |
| VerifyDisplayName(const char *d)
 | |
| {
 | |
|     int i;
 | |
|     int period_found = FALSE;
 | |
|     int after_period = 0;
 | |
| 
 | |
|     if (d == (char *) 0)
 | |
|         return 0;               /*  null  */
 | |
|     if (*d == '\0')
 | |
|         return 0;               /*  empty  */
 | |
|     if (*d == '-')
 | |
|         return 0;               /*  could be confused for an option  */
 | |
|     if (*d == '.')
 | |
|         return 0;               /*  must not equal "." or ".."  */
 | |
|     if (strchr(d, '/') != (char *) 0)
 | |
|         return 0;               /*  very important!!!  */
 | |
| 
 | |
|     /* Since we run atoi() on the display later, only allow
 | |
|        for digits, or exception of :0.0 and similar (two decimal points max)
 | |
|        */
 | |
|     for (i = 0; i < strlen(d); i++) {
 | |
|         if (!isdigit((unsigned char)d[i])) {
 | |
|             if (d[i] != '.' || period_found)
 | |
|                 return 0;
 | |
|             period_found = TRUE;
 | |
|         } else if (period_found)
 | |
|             after_period++;
 | |
| 
 | |
|         if (after_period > 2)
 | |
|             return 0;
 | |
|     }
 | |
| 
 | |
|     /* don't allow for :0. */
 | |
|     if (period_found && after_period == 0)
 | |
|         return 0;
 | |
| 
 | |
|     if (atol(d) > INT_MAX)
 | |
|         return 0;
 | |
| 
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| static const char *defaultNoListenList[] = {
 | |
| #ifndef LISTEN_TCP
 | |
|     "tcp",
 | |
| #endif
 | |
| #ifndef LISTEN_UNIX
 | |
|     "unix",
 | |
| #endif
 | |
| #ifndef LISTEN_LOCAL
 | |
|     "local",
 | |
| #endif
 | |
|     NULL
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * This function parses the command line. Handles device-independent fields
 | |
|  * and allows ddx to handle additional fields.  It is not allowed to modify
 | |
|  * argc or any of the strings pointed to by argv.
 | |
|  */
 | |
| void
 | |
| ProcessCommandLine(int argc, char *argv[])
 | |
| {
 | |
|     int i, skip;
 | |
| 
 | |
|     defaultKeyboardControl.autoRepeat = TRUE;
 | |
| 
 | |
| #ifdef NO_PART_NET
 | |
|     PartialNetwork = FALSE;
 | |
| #else
 | |
|     PartialNetwork = TRUE;
 | |
| #endif
 | |
| 
 | |
|     for (i = 0; defaultNoListenList[i] != NULL; i++) {
 | |
|         if (_XSERVTransNoListen(defaultNoListenList[i]))
 | |
|                     ErrorF("Failed to disable listen for %s transport",
 | |
|                            defaultNoListenList[i]);
 | |
|     }
 | |
|     SeatId = getenv("XDG_SEAT");
 | |
| 
 | |
|     for (i = 1; i < argc; i++) {
 | |
|         /* call ddx first, so it can peek/override if it wants */
 | |
|         if ((skip = ddxProcessArgument(argc, argv, i))) {
 | |
|             i += (skip - 1);
 | |
|         }
 | |
|         else if (argv[i][0] == ':') {
 | |
|             /* initialize display */
 | |
|             display = argv[i];
 | |
|             explicit_display = TRUE;
 | |
|             display++;
 | |
|             if (!VerifyDisplayName(display)) {
 | |
|                 ErrorF("Bad display name: %s\n", display);
 | |
|                 UseMsg();
 | |
|                 FatalError("Bad display name, exiting: %s\n", display);
 | |
|             }
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-a") == 0) {
 | |
|             if (++i < argc)
 | |
|                 defaultPointerControl.num = atoi(argv[i]);
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-ac") == 0) {
 | |
|             defeatAccessControl = TRUE;
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-audit") == 0) {
 | |
|             if (++i < argc)
 | |
|                 auditTrailLevel = atoi(argv[i]);
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-auth") == 0) {
 | |
|             if (++i < argc)
 | |
|                 InitAuthorization(argv[i]);
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-byteswappedclients") == 0) {
 | |
|             AllowByteSwappedClients = FALSE;
 | |
|         } else if (strcmp(argv[i], "+byteswappedclients") == 0) {
 | |
|             AllowByteSwappedClients = TRUE;
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-br") == 0);  /* default */
 | |
|         else if (strcmp(argv[i], "+bs") == 0)
 | |
|             enableBackingStore = TRUE;
 | |
|         else if (strcmp(argv[i], "-bs") == 0)
 | |
|             disableBackingStore = TRUE;
 | |
|         else if (strcmp(argv[i], "c") == 0) {
 | |
|             if (++i < argc)
 | |
|                 defaultKeyboardControl.click = atoi(argv[i]);
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-c") == 0) {
 | |
|             defaultKeyboardControl.click = 0;
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-cc") == 0) {
 | |
|             if (++i < argc)
 | |
|                 defaultColorVisualClass = atoi(argv[i]);
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-core") == 0) {
 | |
| #if !defined(WIN32) || !defined(__MINGW32__)
 | |
|             struct rlimit core_limit;
 | |
| 
 | |
|             getrlimit(RLIMIT_CORE, &core_limit);
 | |
|             core_limit.rlim_cur = core_limit.rlim_max;
 | |
|             setrlimit(RLIMIT_CORE, &core_limit);
 | |
| #endif
 | |
|             CoreDump = TRUE;
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-nocursor") == 0) {
 | |
|             EnableCursor = FALSE;
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-dpi") == 0) {
 | |
|             if (++i < argc)
 | |
|                 monitorResolution = atoi(argv[i]);
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-displayfd") == 0) {
 | |
|             if (++i < argc) {
 | |
|                 displayfd = atoi(argv[i]);
 | |
|                 DisableServerLock();
 | |
|             }
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
| #ifdef DPMSExtension
 | |
|         else if (strcmp(argv[i], "dpms") == 0)
 | |
|             /* ignored for compatibility */ ;
 | |
|         else if (strcmp(argv[i], "-dpms") == 0)
 | |
|             DPMSDisabledSwitch = TRUE;
 | |
| #endif
 | |
|         else if (strcmp(argv[i], "-deferglyphs") == 0) {
 | |
|             if (++i >= argc || !xfont2_parse_glyph_caching_mode(argv[i]))
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-f") == 0) {
 | |
|             if (++i < argc)
 | |
|                 defaultKeyboardControl.bell = atoi(argv[i]);
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-fakescreenfps") == 0) {
 | |
|             if (++i < argc) {
 | |
|                 FakeScreenFps = (uint32_t) atoi(argv[i]);
 | |
|                 if (FakeScreenFps < 1 || FakeScreenFps > 600)
 | |
|                     FatalError("fakescreenfps must be an integer in [1;600] range\n");
 | |
|             }
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-fp") == 0) {
 | |
|             if (++i < argc) {
 | |
|                 defaultFontPath = argv[i];
 | |
|             }
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-help") == 0) {
 | |
|             UseMsg();
 | |
|             exit(0);
 | |
|         }
 | |
|         else if (strcmp(argv[i], "+iglx") == 0)
 | |
|             enableIndirectGLX = TRUE;
 | |
|         else if (strcmp(argv[i], "-iglx") == 0)
 | |
|             enableIndirectGLX = FALSE;
 | |
|         else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) {
 | |
|             if (skip > 0)
 | |
|                 i += skip - 1;
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
| #ifdef RLIMIT_DATA
 | |
|         else if (strcmp(argv[i], "-ld") == 0) {
 | |
|             if (++i < argc) {
 | |
|                 limitDataSpace = atoi(argv[i]);
 | |
|                 if (limitDataSpace > 0)
 | |
|                     limitDataSpace *= 1024;
 | |
|             }
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
| #endif
 | |
| #ifdef RLIMIT_NOFILE
 | |
|         else if (strcmp(argv[i], "-lf") == 0) {
 | |
|             if (++i < argc)
 | |
|                 limitNoFile = atoi(argv[i]);
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
| #endif
 | |
| #ifdef RLIMIT_STACK
 | |
|         else if (strcmp(argv[i], "-ls") == 0) {
 | |
|             if (++i < argc) {
 | |
|                 limitStackSpace = atoi(argv[i]);
 | |
|                 if (limitStackSpace > 0)
 | |
|                     limitStackSpace *= 1024;
 | |
|             }
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
| #endif
 | |
| #ifdef LOCK_SERVER
 | |
|         else if (strcmp(argv[i], "-nolock") == 0) {
 | |
| #if !defined(WIN32) && !defined(__CYGWIN__)
 | |
|             if (getuid() != 0)
 | |
|                 ErrorF
 | |
|                     ("Warning: the -nolock option can only be used by root\n");
 | |
|             else
 | |
| #endif
 | |
|                 DisableServerLock();
 | |
|         }
 | |
| #endif
 | |
|         else if ( strcmp( argv[i], "-maxclients") == 0)
 | |
|         {
 | |
|             if (++i < argc) {
 | |
|                 LimitClients = atoi(argv[i]);
 | |
|                 if (LimitClients != 64 &&
 | |
|                     LimitClients != 128 &&
 | |
|                     LimitClients != 256 &&
 | |
|                     LimitClients != 512 &&
 | |
|                     LimitClients != 1024 &&
 | |
|                     LimitClients != 2048) {
 | |
|                     FatalError("maxclients must be one of 64, 128, 256, 512, 1024 or 2048\n");
 | |
|                 }
 | |
|             } else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-nolisten") == 0) {
 | |
|             if (++i < argc) {
 | |
|                 if (_XSERVTransNoListen(argv[i]))
 | |
|                     ErrorF("Failed to disable listen for %s transport",
 | |
|                            argv[i]);
 | |
|             }
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-listen") == 0) {
 | |
|             if (++i < argc) {
 | |
|                 if (_XSERVTransListen(argv[i]))
 | |
|                     ErrorF("Failed to enable listen for %s transport",
 | |
|                            argv[i]);
 | |
|             }
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-noreset") == 0) {
 | |
|             dispatchExceptionAtReset = 0;
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-reset") == 0) {
 | |
|             dispatchExceptionAtReset = DE_RESET;
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-p") == 0) {
 | |
|             if (++i < argc)
 | |
|                 defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) *
 | |
|                     MILLI_PER_MIN;
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-pogo") == 0) {
 | |
|             dispatchException = DE_TERMINATE;
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-pn") == 0)
 | |
|             PartialNetwork = TRUE;
 | |
|         else if (strcmp(argv[i], "-nopn") == 0)
 | |
|             PartialNetwork = FALSE;
 | |
|         else if (strcmp(argv[i], "r") == 0)
 | |
|             defaultKeyboardControl.autoRepeat = TRUE;
 | |
|         else if (strcmp(argv[i], "-r") == 0)
 | |
|             defaultKeyboardControl.autoRepeat = FALSE;
 | |
|         else if (strcmp(argv[i], "-retro") == 0)
 | |
|             party_like_its_1989 = TRUE;
 | |
|         else if (strcmp(argv[i], "-s") == 0) {
 | |
|             if (++i < argc)
 | |
|                 defaultScreenSaverTime = ((CARD32) atoi(argv[i])) *
 | |
|                     MILLI_PER_MIN;
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-seat") == 0) {
 | |
|             if (++i < argc)
 | |
|                 SeatId = argv[i];
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-t") == 0) {
 | |
|             if (++i < argc)
 | |
|                 defaultPointerControl.threshold = atoi(argv[i]);
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-terminate") == 0) {
 | |
|             dispatchExceptionAtReset = DE_TERMINATE;
 | |
|             terminateDelay = -1;
 | |
|             if ((i + 1 < argc) && (isdigit((unsigned char)*argv[i + 1])))
 | |
|                terminateDelay = atoi(argv[++i]);
 | |
|             terminateDelay = max(0, terminateDelay);
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-tst") == 0) {
 | |
|             noTestExtensions = TRUE;
 | |
|         }
 | |
|         else if (strcmp(argv[i], "v") == 0)
 | |
|             defaultScreenSaverBlanking = PreferBlanking;
 | |
|         else if (strcmp(argv[i], "-v") == 0)
 | |
|             defaultScreenSaverBlanking = DontPreferBlanking;
 | |
|         else if (strcmp(argv[i], "-wr") == 0)
 | |
|             whiteRoot = TRUE;
 | |
|         else if (strcmp(argv[i], "-background") == 0) {
 | |
|             if (++i < argc) {
 | |
|                 if (!strcmp(argv[i], "none"))
 | |
|                     bgNoneRoot = TRUE;
 | |
|                 else
 | |
|                     UseMsg();
 | |
|             }
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-maxbigreqsize") == 0) {
 | |
|             if (++i < argc) {
 | |
|                 long reqSizeArg = atol(argv[i]);
 | |
| 
 | |
|                 /* Request size > 128MB does not make much sense... */
 | |
|                 if (reqSizeArg > 0L && reqSizeArg < 128L) {
 | |
|                     maxBigRequestSize = (reqSizeArg * 1048576L) - 1L;
 | |
|                 }
 | |
|                 else {
 | |
|                     UseMsg();
 | |
|                 }
 | |
|             }
 | |
|             else {
 | |
|                 UseMsg();
 | |
|             }
 | |
|         }
 | |
| #ifdef PANORAMIX
 | |
|         else if (strcmp(argv[i], "+xinerama") == 0) {
 | |
|             noPanoramiXExtension = FALSE;
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-xinerama") == 0) {
 | |
|             noPanoramiXExtension = TRUE;
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-disablexineramaextension") == 0) {
 | |
|             PanoramiXExtensionDisabledHack = TRUE;
 | |
|         }
 | |
| #endif
 | |
|         else if (strcmp(argv[i], "-I") == 0) {
 | |
|             /* ignore all remaining arguments */
 | |
|             break;
 | |
|         }
 | |
|         else if (strncmp(argv[i], "tty", 3) == 0) {
 | |
|             /* init supplies us with this useless information */
 | |
|         }
 | |
| #ifdef XDMCP
 | |
|         else if ((skip = XdmcpOptions(argc, argv, i)) != i) {
 | |
|             i = skip - 1;
 | |
|         }
 | |
| #endif
 | |
|         else if (strcmp(argv[i], "-dumbSched") == 0) {
 | |
|             InputThreadEnable = FALSE;
 | |
| #ifdef HAVE_SETITIMER
 | |
|             SmartScheduleSignalEnable = FALSE;
 | |
| #endif
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-schedInterval") == 0) {
 | |
|             if (++i < argc) {
 | |
|                 SmartScheduleInterval = atoi(argv[i]);
 | |
|                 SmartScheduleSlice = SmartScheduleInterval;
 | |
|             }
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-schedMax") == 0) {
 | |
|             if (++i < argc) {
 | |
|                 SmartScheduleMaxSlice = atoi(argv[i]);
 | |
|             }
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-render") == 0) {
 | |
|             if (++i < argc) {
 | |
|                 int policy = PictureParseCmapPolicy(argv[i]);
 | |
| 
 | |
|                 if (policy != PictureCmapPolicyInvalid)
 | |
|                     PictureCmapPolicy = policy;
 | |
|                 else
 | |
|                     UseMsg();
 | |
|             }
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-sigstop") == 0) {
 | |
|             RunFromSigStopParent = TRUE;
 | |
|         }
 | |
|         else if (strcmp(argv[i], "+extension") == 0) {
 | |
|             if (++i < argc) {
 | |
|                 if (!EnableDisableExtension(argv[i], TRUE))
 | |
|                     EnableDisableExtensionError(argv[i], TRUE);
 | |
|             }
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else if (strcmp(argv[i], "-extension") == 0) {
 | |
|             if (++i < argc) {
 | |
|                 if (!EnableDisableExtension(argv[i], FALSE))
 | |
|                     EnableDisableExtensionError(argv[i], FALSE);
 | |
|             }
 | |
|             else
 | |
|                 UseMsg();
 | |
|         }
 | |
|         else {
 | |
|             ErrorF("Unrecognized option: %s\n", argv[i]);
 | |
|             UseMsg();
 | |
|             FatalError("Unrecognized option: %s\n", argv[i]);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Implement a simple-minded font authorization scheme.  The authorization
 | |
|    name is "hp-hostname-1", the contents are simply the host name. */
 | |
| int
 | |
| set_font_authorizations(char **authorizations, int *authlen, void *client)
 | |
| {
 | |
| #define AUTHORIZATION_NAME "hp-hostname-1"
 | |
| #if defined(TCPCONN)
 | |
|     static char *result = NULL;
 | |
|     static char *p = NULL;
 | |
| 
 | |
|     if (p == NULL) {
 | |
|         char hname[1024], *hnameptr;
 | |
|         unsigned int len;
 | |
| 
 | |
| #if defined(IPv6)
 | |
|         struct addrinfo hints, *ai = NULL;
 | |
| #else
 | |
|         struct hostent *host;
 | |
| 
 | |
| #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
 | |
|         _Xgethostbynameparams hparams;
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
|         gethostname(hname, 1024);
 | |
| #if defined(IPv6)
 | |
|         memset(&hints, 0, sizeof(hints));
 | |
|         hints.ai_flags = AI_CANONNAME;
 | |
|         if (getaddrinfo(hname, NULL, &hints, &ai) == 0) {
 | |
|             hnameptr = ai->ai_canonname;
 | |
|         }
 | |
|         else {
 | |
|             hnameptr = hname;
 | |
|         }
 | |
| #else
 | |
|         host = _XGethostbyname(hname, hparams);
 | |
|         if (host == NULL)
 | |
|             hnameptr = hname;
 | |
|         else
 | |
|             hnameptr = host->h_name;
 | |
| #endif
 | |
| 
 | |
|         len = strlen(hnameptr) + 1;
 | |
|         result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4);
 | |
| 
 | |
|         p = result;
 | |
|         *p++ = sizeof(AUTHORIZATION_NAME) >> 8;
 | |
|         *p++ = sizeof(AUTHORIZATION_NAME) & 0xff;
 | |
|         *p++ = (len) >> 8;
 | |
|         *p++ = (len & 0xff);
 | |
| 
 | |
|         memcpy(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME));
 | |
|         p += sizeof(AUTHORIZATION_NAME);
 | |
|         memcpy(p, hnameptr, len);
 | |
|         p += len;
 | |
| #if defined(IPv6)
 | |
|         if (ai) {
 | |
|             freeaddrinfo(ai);
 | |
|         }
 | |
| #endif
 | |
|     }
 | |
|     *authlen = p - result;
 | |
|     *authorizations = result;
 | |
|     return 1;
 | |
| #else                           /* TCPCONN */
 | |
|     return 0;
 | |
| #endif                          /* TCPCONN */
 | |
| }
 | |
| 
 | |
| void
 | |
| SmartScheduleStopTimer(void)
 | |
| {
 | |
| #ifdef HAVE_SETITIMER
 | |
|     struct itimerval timer;
 | |
| 
 | |
|     if (!SmartScheduleSignalEnable)
 | |
|         return;
 | |
|     timer.it_interval.tv_sec = 0;
 | |
|     timer.it_interval.tv_usec = 0;
 | |
|     timer.it_value.tv_sec = 0;
 | |
|     timer.it_value.tv_usec = 0;
 | |
|     (void) setitimer(ITIMER_REAL, &timer, 0);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void
 | |
| SmartScheduleStartTimer(void)
 | |
| {
 | |
| #ifdef HAVE_SETITIMER
 | |
|     struct itimerval timer;
 | |
| 
 | |
|     if (!SmartScheduleSignalEnable)
 | |
|         return;
 | |
|     timer.it_interval.tv_sec = 0;
 | |
|     timer.it_interval.tv_usec = SmartScheduleInterval * 1000;
 | |
|     timer.it_value.tv_sec = 0;
 | |
|     timer.it_value.tv_usec = SmartScheduleInterval * 1000;
 | |
|     setitimer(ITIMER_REAL, &timer, 0);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| #ifdef HAVE_SETITIMER
 | |
| static void
 | |
| SmartScheduleTimer(int sig)
 | |
| {
 | |
|     SmartScheduleTime += SmartScheduleInterval;
 | |
| }
 | |
| 
 | |
| static int
 | |
| SmartScheduleEnable(void)
 | |
| {
 | |
|     int ret = 0;
 | |
|     struct sigaction act;
 | |
| 
 | |
|     if (!SmartScheduleSignalEnable)
 | |
|         return 0;
 | |
| 
 | |
|     memset((char *) &act, 0, sizeof(struct sigaction));
 | |
| 
 | |
|     /* Set up the timer signal function */
 | |
|     act.sa_flags = SA_RESTART;
 | |
|     act.sa_handler = SmartScheduleTimer;
 | |
|     sigemptyset(&act.sa_mask);
 | |
|     sigaddset(&act.sa_mask, SIGALRM);
 | |
|     ret = sigaction(SIGALRM, &act, 0);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static int
 | |
| SmartSchedulePause(void)
 | |
| {
 | |
|     int ret = 0;
 | |
|     struct sigaction act;
 | |
| 
 | |
|     if (!SmartScheduleSignalEnable)
 | |
|         return 0;
 | |
| 
 | |
|     memset((char *) &act, 0, sizeof(struct sigaction));
 | |
| 
 | |
|     act.sa_handler = SIG_IGN;
 | |
|     sigemptyset(&act.sa_mask);
 | |
|     ret = sigaction(SIGALRM, &act, 0);
 | |
|     return ret;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| void
 | |
| SmartScheduleInit(void)
 | |
| {
 | |
| #ifdef HAVE_SETITIMER
 | |
|     if (SmartScheduleEnable() < 0) {
 | |
|         perror("sigaction for smart scheduler");
 | |
|         SmartScheduleSignalEnable = FALSE;
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| #ifdef HAVE_SIGPROCMASK
 | |
| static sigset_t PreviousSignalMask;
 | |
| static int BlockedSignalCount;
 | |
| #endif
 | |
| 
 | |
| void
 | |
| OsBlockSignals(void)
 | |
| {
 | |
| #ifdef HAVE_SIGPROCMASK
 | |
|     if (BlockedSignalCount++ == 0) {
 | |
|         sigset_t set;
 | |
| 
 | |
|         sigemptyset(&set);
 | |
|         sigaddset(&set, SIGALRM);
 | |
|         sigaddset(&set, SIGVTALRM);
 | |
| #ifdef SIGWINCH
 | |
|         sigaddset(&set, SIGWINCH);
 | |
| #endif
 | |
|         sigaddset(&set, SIGTSTP);
 | |
|         sigaddset(&set, SIGTTIN);
 | |
|         sigaddset(&set, SIGTTOU);
 | |
|         sigaddset(&set, SIGCHLD);
 | |
|         xthread_sigmask(SIG_BLOCK, &set, &PreviousSignalMask);
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void
 | |
| OsReleaseSignals(void)
 | |
| {
 | |
| #ifdef HAVE_SIGPROCMASK
 | |
|     if (--BlockedSignalCount == 0) {
 | |
|         xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0);
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void
 | |
| OsResetSignals(void)
 | |
| {
 | |
| #ifdef HAVE_SIGPROCMASK
 | |
|     while (BlockedSignalCount > 0)
 | |
|         OsReleaseSignals();
 | |
|     input_force_unlock();
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Pending signals may interfere with core dumping. Provide a
 | |
|  * mechanism to block signals when aborting.
 | |
|  */
 | |
| 
 | |
| void
 | |
| OsAbort(void)
 | |
| {
 | |
| #ifndef __APPLE__
 | |
|     OsBlockSignals();
 | |
| #endif
 | |
| #if !defined(WIN32) || defined(__CYGWIN__)
 | |
|     /* abort() raises SIGABRT, so we have to stop handling that to prevent
 | |
|      * recursion
 | |
|      */
 | |
|     OsSignal(SIGABRT, SIG_DFL);
 | |
| #endif
 | |
|     abort();
 | |
| }
 | |
| 
 | |
| #if !defined(WIN32)
 | |
| /*
 | |
|  * "safer" versions of system(3), popen(3) and pclose(3) which give up
 | |
|  * all privs before running a command.
 | |
|  *
 | |
|  * This is based on the code in FreeBSD 2.2 libc.
 | |
|  *
 | |
|  * XXX It'd be good to redirect stderr so that it ends up in the log file
 | |
|  * as well.  As it is now, xkbcomp messages don't end up in the log file.
 | |
|  */
 | |
| 
 | |
| static struct pid {
 | |
|     struct pid *next;
 | |
|     FILE *fp;
 | |
|     int pid;
 | |
| } *pidlist;
 | |
| 
 | |
| void *
 | |
| Popen(const char *command, const char *type)
 | |
| {
 | |
|     struct pid *cur;
 | |
|     FILE *iop;
 | |
|     int pdes[2], pid;
 | |
| 
 | |
|     if (command == NULL || type == NULL)
 | |
|         return NULL;
 | |
| 
 | |
|     if ((*type != 'r' && *type != 'w') || type[1])
 | |
|         return NULL;
 | |
| 
 | |
|     if ((cur = malloc(sizeof(struct pid))) == NULL)
 | |
|         return NULL;
 | |
| 
 | |
|     if (pipe(pdes) < 0) {
 | |
|         free(cur);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     /* Ignore the smart scheduler while this is going on */
 | |
| #ifdef HAVE_SETITIMER
 | |
|     if (SmartSchedulePause() < 0) {
 | |
|         close(pdes[0]);
 | |
|         close(pdes[1]);
 | |
|         free(cur);
 | |
|         perror("signal");
 | |
|         return NULL;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     switch (pid = fork()) {
 | |
|     case -1:                   /* error */
 | |
|         close(pdes[0]);
 | |
|         close(pdes[1]);
 | |
|         free(cur);
 | |
| #ifdef HAVE_SETITIMER
 | |
|         if (SmartScheduleEnable() < 0)
 | |
|             perror("signal");
 | |
| #endif
 | |
|         return NULL;
 | |
|     case 0:                    /* child */
 | |
|         if (setgid(getgid()) == -1)
 | |
|             _exit(127);
 | |
|         if (setuid(getuid()) == -1)
 | |
|             _exit(127);
 | |
|         if (*type == 'r') {
 | |
|             if (pdes[1] != 1) {
 | |
|                 /* stdout */
 | |
|                 dup2(pdes[1], 1);
 | |
|                 close(pdes[1]);
 | |
|             }
 | |
|             close(pdes[0]);
 | |
|         }
 | |
|         else {
 | |
|             if (pdes[0] != 0) {
 | |
|                 /* stdin */
 | |
|                 dup2(pdes[0], 0);
 | |
|                 close(pdes[0]);
 | |
|             }
 | |
|             close(pdes[1]);
 | |
|         }
 | |
|         execl("/bin/sh", "sh", "-c", command, (char *) NULL);
 | |
|         _exit(127);
 | |
|     }
 | |
| 
 | |
|     /* Avoid EINTR during stdio calls */
 | |
|     OsBlockSignals();
 | |
| 
 | |
|     /* parent */
 | |
|     if (*type == 'r') {
 | |
|         iop = fdopen(pdes[0], type);
 | |
|         close(pdes[1]);
 | |
|     }
 | |
|     else {
 | |
|         iop = fdopen(pdes[1], type);
 | |
|         close(pdes[0]);
 | |
|     }
 | |
| 
 | |
|     cur->fp = iop;
 | |
|     cur->pid = pid;
 | |
|     cur->next = pidlist;
 | |
|     pidlist = cur;
 | |
| 
 | |
|     DebugF("Popen: `%s', fp = %p\n", command, iop);
 | |
| 
 | |
|     return iop;
 | |
| }
 | |
| 
 | |
| /* fopen that drops privileges */
 | |
| void *
 | |
| Fopen(const char *file, const char *type)
 | |
| {
 | |
|     FILE *iop;
 | |
|     int ruid, euid;
 | |
| 
 | |
|     ruid = getuid();
 | |
|     euid = geteuid();
 | |
| 
 | |
|     if (seteuid(ruid) == -1) {
 | |
|         return NULL;
 | |
|     }
 | |
|     iop = fopen(file, type);
 | |
| 
 | |
|     if (seteuid(euid) == -1) {
 | |
|         fclose(iop);
 | |
|         return NULL;
 | |
|     }
 | |
|     return iop;
 | |
| }
 | |
| 
 | |
| int
 | |
| Pclose(void *iop)
 | |
| {
 | |
|     struct pid *cur, *last;
 | |
|     int pstat;
 | |
|     int pid;
 | |
| 
 | |
|     DebugF("Pclose: fp = %p\n", iop);
 | |
|     fclose(iop);
 | |
| 
 | |
|     for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
 | |
|         if (cur->fp == iop)
 | |
|             break;
 | |
|     if (cur == NULL)
 | |
|         return -1;
 | |
| 
 | |
|     do {
 | |
|         pid = waitpid(cur->pid, &pstat, 0);
 | |
|     } while (pid == -1 && errno == EINTR);
 | |
| 
 | |
|     if (last == NULL)
 | |
|         pidlist = cur->next;
 | |
|     else
 | |
|         last->next = cur->next;
 | |
|     free(cur);
 | |
| 
 | |
|     /* allow EINTR again */
 | |
|     OsReleaseSignals();
 | |
| 
 | |
| #ifdef HAVE_SETITIMER
 | |
|     if (SmartScheduleEnable() < 0) {
 | |
|         perror("signal");
 | |
|         return -1;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     return pid == -1 ? -1 : pstat;
 | |
| }
 | |
| 
 | |
| int
 | |
| Fclose(void *iop)
 | |
| {
 | |
|     return fclose(iop);
 | |
| }
 | |
| 
 | |
| #endif                          /* !WIN32 */
 | |
| 
 | |
| #ifdef WIN32
 | |
| 
 | |
| #include <X11/Xwindows.h>
 | |
| 
 | |
| const char *
 | |
| Win32TempDir(void)
 | |
| {
 | |
|     static char buffer[PATH_MAX];
 | |
| 
 | |
|     if (GetTempPath(sizeof(buffer), buffer)) {
 | |
|         int len;
 | |
| 
 | |
|         buffer[sizeof(buffer) - 1] = 0;
 | |
|         len = strlen(buffer);
 | |
|         if (len > 0)
 | |
|             if (buffer[len - 1] == '\\')
 | |
|                 buffer[len - 1] = 0;
 | |
|         return buffer;
 | |
|     }
 | |
|     if (getenv("TEMP") != NULL)
 | |
|         return getenv("TEMP");
 | |
|     else if (getenv("TMP") != NULL)
 | |
|         return getenv("TMP");
 | |
|     else
 | |
|         return "/tmp";
 | |
| }
 | |
| 
 | |
| int
 | |
| System(const char *cmdline)
 | |
| {
 | |
|     STARTUPINFO si = (STARTUPINFO) {
 | |
|         .cb = sizeof(si),
 | |
|     };
 | |
|     PROCESS_INFORMATION pi = (PROCESS_INFORMATION){0};
 | |
|     DWORD dwExitCode;
 | |
|     char *cmd = strdup(cmdline);
 | |
| 
 | |
|     if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
 | |
|         LPVOID buffer;
 | |
| 
 | |
|         if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
 | |
|                            FORMAT_MESSAGE_FROM_SYSTEM |
 | |
|                            FORMAT_MESSAGE_IGNORE_INSERTS,
 | |
|                            NULL,
 | |
|                            GetLastError(),
 | |
|                            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
 | |
|                            (LPTSTR) &buffer, 0, NULL)) {
 | |
|             ErrorF("[xkb] Starting '%s' failed!\n", cmdline);
 | |
|         }
 | |
|         else {
 | |
|             ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer);
 | |
|             LocalFree(buffer);
 | |
|         }
 | |
| 
 | |
|         free(cmd);
 | |
|         return -1;
 | |
|     }
 | |
|     /* Wait until child process exits. */
 | |
|     WaitForSingleObject(pi.hProcess, INFINITE);
 | |
| 
 | |
|     GetExitCodeProcess(pi.hProcess, &dwExitCode);
 | |
| 
 | |
|     /* Close process and thread handles. */
 | |
|     CloseHandle(pi.hProcess);
 | |
|     CloseHandle(pi.hThread);
 | |
|     free(cmd);
 | |
| 
 | |
|     return dwExitCode;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| Bool
 | |
| PrivsElevated(void)
 | |
| {
 | |
|     static Bool privsTested = FALSE;
 | |
|     static Bool privsElevated = TRUE;
 | |
| 
 | |
|     if (!privsTested) {
 | |
| #if defined(WIN32)
 | |
|         privsElevated = FALSE;
 | |
| #else
 | |
|         if ((getuid() != geteuid()) || (getgid() != getegid())) {
 | |
|             privsElevated = TRUE;
 | |
|         }
 | |
|         else {
 | |
| #if defined(HAVE_ISSETUGID)
 | |
|             privsElevated = issetugid();
 | |
| #elif defined(HAVE_GETRESUID)
 | |
|             uid_t ruid, euid, suid;
 | |
|             gid_t rgid, egid, sgid;
 | |
| 
 | |
|             if ((getresuid(&ruid, &euid, &suid) == 0) &&
 | |
|                 (getresgid(&rgid, &egid, &sgid) == 0)) {
 | |
|                 privsElevated = (euid != suid) || (egid != sgid);
 | |
|             }
 | |
|             else {
 | |
|                 printf("Failed getresuid or getresgid");
 | |
|                 /* Something went wrong, make defensive assumption */
 | |
|                 privsElevated = TRUE;
 | |
|             }
 | |
| #else
 | |
|             if (getuid() == 0) {
 | |
|                 /* running as root: uid==euid==0 */
 | |
|                 privsElevated = FALSE;
 | |
|             }
 | |
|             else {
 | |
|                 /*
 | |
|                  * If there are saved ID's the process might still be privileged
 | |
|                  * even though the above test succeeded. If issetugid() and
 | |
|                  * getresgid() aren't available, test this by trying to set
 | |
|                  * euid to 0.
 | |
|                  */
 | |
|                 unsigned int oldeuid;
 | |
| 
 | |
|                 oldeuid = geteuid();
 | |
| 
 | |
|                 if (seteuid(0) != 0) {
 | |
|                     privsElevated = FALSE;
 | |
|                 }
 | |
|                 else {
 | |
|                     if (seteuid(oldeuid) != 0) {
 | |
|                         FatalError("Failed to drop privileges.  Exiting\n");
 | |
|                     }
 | |
|                     privsElevated = TRUE;
 | |
|                 }
 | |
|             }
 | |
| #endif
 | |
|         }
 | |
| #endif
 | |
|         privsTested = TRUE;
 | |
|     }
 | |
|     return privsElevated;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * CheckUserParameters: check for long command line arguments and long
 | |
|  * environment variables.  By default, these checks are only done when
 | |
|  * the server's euid != ruid.  In 3.3.x, these checks were done in an
 | |
|  * external wrapper utility.
 | |
|  */
 | |
| 
 | |
| /* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
 | |
| #ifndef CHECK_EUID
 | |
| #ifndef WIN32
 | |
| #define CHECK_EUID 1
 | |
| #else
 | |
| #define CHECK_EUID 0
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| #define MAX_ARG_LENGTH          128
 | |
| #define MAX_ENV_LENGTH          256
 | |
| #define MAX_ENV_PATH_LENGTH     2048    /* Limit for *PATH and TERMCAP */
 | |
| 
 | |
| #define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
 | |
| 
 | |
| enum BadCode {
 | |
|     NotBad = 0,
 | |
|     UnsafeArg,
 | |
|     ArgTooLong,
 | |
|     UnprintableArg,
 | |
|     InternalError
 | |
| };
 | |
| 
 | |
| #if defined(BUILDERADDR)
 | |
| #define BUGADDRESS BUILDERADDR
 | |
| #else
 | |
| #define BUGADDRESS "xorg@freedesktop.org"
 | |
| #endif
 | |
| 
 | |
| void
 | |
| CheckUserParameters(int argc, char **argv, char **envp)
 | |
| {
 | |
|     enum BadCode bad = NotBad;
 | |
|     int i = 0, j;
 | |
|     char *a = NULL;
 | |
| 
 | |
| #if CHECK_EUID
 | |
|     if (PrivsElevated())
 | |
| #endif
 | |
|     {
 | |
|         /* Check each argv[] */
 | |
|         for (i = 1; i < argc; i++) {
 | |
|             if (strcmp(argv[i], "-fp") == 0) {
 | |
|                 i++;            /* continue with next argument. skip the length check */
 | |
|                 if (i >= argc)
 | |
|                     break;
 | |
|             }
 | |
|             else {
 | |
|                 if (strlen(argv[i]) > MAX_ARG_LENGTH) {
 | |
|                     bad = ArgTooLong;
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|             a = argv[i];
 | |
|             while (*a) {
 | |
|                 if (checkPrintable(*a) == 0) {
 | |
|                     bad = UnprintableArg;
 | |
|                     break;
 | |
|                 }
 | |
|                 a++;
 | |
|             }
 | |
|             if (bad)
 | |
|                 break;
 | |
|         }
 | |
|         if (!bad) {
 | |
|             /* Check each envp[] */
 | |
|             for (i = 0; envp[i]; i++) {
 | |
| 
 | |
|                 /* Check for bad environment variables and values */
 | |
|                 while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
 | |
|                     for (j = i; envp[j]; j++) {
 | |
|                         envp[j] = envp[j + 1];
 | |
|                     }
 | |
|                 }
 | |
|                 if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
 | |
|                     for (j = i; envp[j]; j++) {
 | |
|                         envp[j] = envp[j + 1];
 | |
|                     }
 | |
|                     i--;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     switch (bad) {
 | |
|     case NotBad:
 | |
|         return;
 | |
|     case UnsafeArg:
 | |
|         ErrorF("Command line argument number %d is unsafe\n", i);
 | |
|         break;
 | |
|     case ArgTooLong:
 | |
|         ErrorF("Command line argument number %d is too long\n", i);
 | |
|         break;
 | |
|     case UnprintableArg:
 | |
|         ErrorF("Command line argument number %d contains unprintable"
 | |
|                " characters\n", i);
 | |
|         break;
 | |
|     case InternalError:
 | |
|         ErrorF("Internal Error\n");
 | |
|         break;
 | |
|     default:
 | |
|         ErrorF("Unknown error\n");
 | |
|         break;
 | |
|     }
 | |
|     FatalError("X server aborted because of unsafe environment\n");
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * CheckUserAuthorization: check if the user is allowed to start the
 | |
|  * X server.  This usually means some sort of PAM checking, and it is
 | |
|  * usually only done for setuid servers (uid != euid).
 | |
|  */
 | |
| 
 | |
| #ifdef USE_PAM
 | |
| #include <security/pam_appl.h>
 | |
| #include <security/pam_misc.h>
 | |
| #include <pwd.h>
 | |
| #endif                          /* USE_PAM */
 | |
| 
 | |
| void
 | |
| CheckUserAuthorization(void)
 | |
| {
 | |
| #ifdef USE_PAM
 | |
|     static struct pam_conv conv = {
 | |
|         misc_conv,
 | |
|         NULL
 | |
|     };
 | |
| 
 | |
|     pam_handle_t *pamh = NULL;
 | |
|     struct passwd *pw;
 | |
|     int retval;
 | |
| 
 | |
|     if (getuid() != geteuid()) {
 | |
|         pw = getpwuid(getuid());
 | |
|         if (pw == NULL)
 | |
|             FatalError("getpwuid() failed for uid %d\n", getuid());
 | |
| 
 | |
|         retval = pam_start("xserver", pw->pw_name, &conv, &pamh);
 | |
|         if (retval != PAM_SUCCESS)
 | |
|             FatalError("pam_start() failed.\n"
 | |
|                        "\tMissing or mangled PAM config file or module?\n");
 | |
| 
 | |
|         retval = pam_authenticate(pamh, 0);
 | |
|         if (retval != PAM_SUCCESS) {
 | |
|             pam_end(pamh, retval);
 | |
|             FatalError("PAM authentication failed, cannot start X server.\n"
 | |
|                        "\tPerhaps you do not have console ownership?\n");
 | |
|         }
 | |
| 
 | |
|         retval = pam_acct_mgmt(pamh, 0);
 | |
|         if (retval != PAM_SUCCESS) {
 | |
|             pam_end(pamh, retval);
 | |
|             FatalError("PAM authentication failed, cannot start X server.\n"
 | |
|                        "\tPerhaps you do not have console ownership?\n");
 | |
|         }
 | |
| 
 | |
|         /* this is not a session, so do not do session management */
 | |
|         pam_end(pamh, PAM_SUCCESS);
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| #if !defined(WIN32) || defined(__CYGWIN__)
 | |
| /* Move a file descriptor out of the way of our select mask; this
 | |
|  * is useful for file descriptors which will never appear in the
 | |
|  * select mask to avoid reducing the number of clients that can
 | |
|  * connect to the server
 | |
|  */
 | |
| int
 | |
| os_move_fd(int fd)
 | |
| {
 | |
|     int newfd;
 | |
| 
 | |
| #ifdef F_DUPFD_CLOEXEC
 | |
|     newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS);
 | |
| #else
 | |
|     newfd = fcntl(fd, F_DUPFD, MAXCLIENTS);
 | |
| #endif
 | |
|     if (newfd < 0)
 | |
|         return fd;
 | |
| #ifndef F_DUPFD_CLOEXEC
 | |
|     fcntl(newfd, F_SETFD, FD_CLOEXEC);
 | |
| #endif
 | |
|     close(fd);
 | |
|     return newfd;
 | |
| }
 | |
| #endif
 |