3 Copyright 1987, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
27 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
28 Copyright 1994 Quarterdeck Office Systems.
32 Permission to use, copy, modify, and distribute this software and its
33 documentation for any purpose and without fee is hereby granted,
34 provided that the above copyright notice appear in all copies and that
35 both that copyright notice and this permission notice appear in
36 supporting documentation, and that the names of Digital and
37 Quarterdeck not be used in advertising or publicity pertaining to
38 distribution of the software without specific, written prior
41 DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
42 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
43 FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
44 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
45 OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
46 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
47 OR PERFORMANCE OF THIS SOFTWARE.
51 #ifdef HAVE_DIX_CONFIG_H
52 #include <dix-config.h>
59 Sigh... We really need a prototype for this to know it is stdcall,
60 but #include-ing <windows.h> here is not a good idea...
62 __stdcall
unsigned long GetTickCount(void);
65 #if defined(WIN32) && !defined(__CYGWIN__)
66 #include <X11/Xwinsock.h>
71 #if !defined(WIN32) || !defined(__MINGW32__)
73 #include <sys/resource.h>
74 # define SMART_SCHEDULE_POSSIBLE
81 #include <X11/Xtrans/Xtrans.h>
85 #include "extension.h"
86 #ifdef X_POSIX_C_SOURCE
87 #define _POSIX_C_SOURCE X_POSIX_C_SOURCE
89 #undef _POSIX_C_SOURCE
91 #if defined(_POSIX_SOURCE)
100 #include <sys/wait.h>
102 #if !defined(SYSV) && !defined(WIN32)
103 #include <sys/resource.h>
105 #include <sys/stat.h>
106 #include <ctype.h> /* for isspace */
109 #include <stdlib.h> /* for malloc() */
111 #if defined(TCPCONN) || defined(STREAMSCONN)
119 #include "dixstruct.h"
125 Bool noTestExtensions
;
128 Bool noCompositeExtension
= FALSE
;
132 Bool noDamageExtension
= FALSE
;
135 Bool noDbeExtension
= FALSE
;
138 Bool noDPMSExtension
= FALSE
;
141 Bool noGlxExtension
= FALSE
;
144 Bool noScreenSaverExtension
= FALSE
;
147 Bool noMITShmExtension
= FALSE
;
150 Bool noRRExtension
= FALSE
;
152 Bool noRenderExtension
= FALSE
;
155 Bool noSecurityExtension
= FALSE
;
158 Bool noResExtension
= FALSE
;
161 Bool noXFree86BigfontExtension
= FALSE
;
164 Bool noXFree86DGAExtension
= FALSE
;
167 Bool noXFree86DRIExtension
= FALSE
;
170 Bool noXFree86VidModeExtension
= FALSE
;
172 Bool noXFixesExtension
= FALSE
;
174 /* Xinerama is disabled by default unless enabled via +xinerama */
175 Bool noPanoramiXExtension
= TRUE
;
178 Bool noSELinuxExtension
= FALSE
;
179 int selinuxEnforcingState
= SELINUX_MODE_DEFAULT
;
182 Bool noXvExtension
= FALSE
;
185 Bool noDRI2Extension
= FALSE
;
188 Bool noGEExtension
= FALSE
;
190 #define X_INCLUDE_NETDB_H
191 #include <X11/Xos_r.h>
198 Bool PanoramiXExtensionDisabledHack
= FALSE
;
201 int auditTrailLevel
= 1;
205 sig_atomic_t inSignalContext
= FALSE
;
207 #if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
208 #define HAS_SAVED_IDS_AND_SETEUID
212 OsSignal(int sig
, OsSigHandlerPtr handler
)
214 #if defined(WIN32) && !defined(__CYGWIN__)
215 return signal(sig
, handler
);
217 struct sigaction act
, oact
;
219 sigemptyset(&act
.sa_mask
);
220 if (handler
!= SIG_IGN
)
221 sigaddset(&act
.sa_mask
, sig
);
223 act
.sa_handler
= handler
;
224 if (sigaction(sig
, &act
, &oact
))
226 return oact
.sa_handler
;
231 * Explicit support for a server lock file like the ones used for UUCP.
232 * For architectures with virtual terminals that can run more than one
233 * server at a time. This keeps the servers from stomping on each other
234 * if the user forgets to give them different display numbers.
236 #define LOCK_DIR "/tmp"
237 #define LOCK_TMP_PREFIX "/.tX"
238 #define LOCK_PREFIX "/.X"
239 #define LOCK_SUFFIX "-lock"
241 #if !defined(WIN32) || defined(__CYGWIN__)
253 #else /* LOCK_SERVER */
254 static Bool StillLocking
= FALSE
;
255 static char LockFile
[PATH_MAX
];
256 static Bool nolock
= FALSE
;
260 * Check if the server lock file exists. If so, check if the PID
261 * contained inside is valid. If so, then die. Otherwise, create
262 * the lock file containing the PID.
267 char tmp
[PATH_MAX
], pid_str
[12];
268 int lfd
, i
, haslock
, l_pid
, t
;
269 const char *tmppath
= LOCK_DIR
;
278 snprintf(port
, sizeof(port
), "%d", atoi(display
));
279 len
= strlen(LOCK_PREFIX
) > strlen(LOCK_TMP_PREFIX
) ? strlen(LOCK_PREFIX
) :
280 strlen(LOCK_TMP_PREFIX
);
281 len
+= strlen(tmppath
) + strlen(port
) + strlen(LOCK_SUFFIX
) + 1;
282 if (len
> sizeof(LockFile
))
283 FatalError("Display name `%s' is too long\n", port
);
284 (void) sprintf(tmp
, "%s" LOCK_TMP_PREFIX
"%s" LOCK_SUFFIX
, tmppath
, port
);
285 (void) sprintf(LockFile
, "%s" LOCK_PREFIX
"%s" LOCK_SUFFIX
, tmppath
, port
);
288 * Create a temporary file containing our PID. Attempt three times
289 * to create the file.
295 lfd
= open(tmp
, O_CREAT
| O_EXCL
| O_WRONLY
, 0644);
306 lfd
= open(tmp
, O_CREAT
| O_EXCL
| O_WRONLY
, 0644);
314 FatalError("Could not create lock file in %s\n", tmp
);
315 snprintf(pid_str
, sizeof(pid_str
), "%10ld\n", (long) getpid());
316 (void) write(lfd
, pid_str
, 11);
317 (void) fchmod(lfd
, 0444);
321 * OK. Now the tmp file exists. Try three times to move it in place
326 while ((!haslock
) && (i
++ < 3)) {
327 haslock
= (link(tmp
, LockFile
) == 0);
336 * Read the pid from the existing file
338 lfd
= open(LockFile
, O_RDONLY
| O_NOFOLLOW
);
341 FatalError("Can't read lock file %s\n", LockFile
);
344 if (read(lfd
, pid_str
, 11) != 11) {
353 sscanf(pid_str
, "%d", &l_pid
);
357 * Now try to kill the PID to see if it exists.
361 if ((t
< 0) && (errno
== ESRCH
)) {
368 else if (((t
< 0) && (errno
== EPERM
)) || (t
== 0)) {
370 * Process is still active.
374 ("Server is already active for display %s\n%s %s\n%s\n",
375 port
, "\tIf this server is no longer running, remove",
376 LockFile
, "\tand start again.");
382 FatalError("Could not create server lock file: %s\n", LockFile
);
383 StillLocking
= FALSE
;
388 * Remove the server lock file.
398 (void) unlink(LockFile
);
401 #endif /* LOCK_SERVER */
403 /* Force connections to close on SIGHUP from init */
406 AutoResetServer(int sig
)
408 int olderrno
= errno
;
410 dispatchException
|= DE_RESET
;
411 isItTimeToYield
= TRUE
;
415 /* Force connections to close and then exit on SIGTERM, SIGINT */
420 int olderrno
= errno
;
422 dispatchException
|= DE_TERMINATE
;
423 isItTimeToYield
= TRUE
;
427 #if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__)
429 GetTimeInMillis(void)
431 return GetTickCount();
434 GetTimeInMicros(void)
436 return (CARD64
) GetTickCount() * 1000;
440 GetTimeInMillis(void)
444 #ifdef MONOTONIC_CLOCK
446 static clockid_t clockid
;
449 #ifdef CLOCK_MONOTONIC_COARSE
450 if (clock_getres(CLOCK_MONOTONIC_COARSE
, &tp
) == 0 &&
451 (tp
.tv_nsec
/ 1000) <= 1000 &&
452 clock_gettime(CLOCK_MONOTONIC_COARSE
, &tp
) == 0)
453 clockid
= CLOCK_MONOTONIC_COARSE
;
456 if (clock_gettime(CLOCK_MONOTONIC
, &tp
) == 0)
457 clockid
= CLOCK_MONOTONIC
;
461 if (clockid
!= ~0L && clock_gettime(clockid
, &tp
) == 0)
462 return (tp
.tv_sec
* 1000) + (tp
.tv_nsec
/ 1000000L);
466 return (tv
.tv_sec
* 1000) + (tv
.tv_usec
/ 1000);
470 GetTimeInMicros(void)
473 #ifdef MONOTONIC_CLOCK
475 static clockid_t clockid
;
478 if (clock_gettime(CLOCK_MONOTONIC
, &tp
) == 0)
479 clockid
= CLOCK_MONOTONIC
;
483 if (clockid
!= ~0L && clock_gettime(clockid
, &tp
) == 0)
484 return (CARD64
) tp
.tv_sec
* (CARD64
)1000000 + tp
.tv_nsec
/ 1000;
488 return (CARD64
) tv
.tv_sec
* (CARD64
)1000000000 + (CARD64
) tv
.tv_usec
* 1000;
493 AdjustWaitForDelay(pointer waitTime
, unsigned long newdelay
)
495 static struct timeval delay_val
;
496 struct timeval
**wt
= (struct timeval
**) waitTime
;
497 unsigned long olddelay
;
500 delay_val
.tv_sec
= newdelay
/ 1000;
501 delay_val
.tv_usec
= 1000 * (newdelay
% 1000);
505 olddelay
= (*wt
)->tv_sec
* 1000 + (*wt
)->tv_usec
/ 1000;
506 if (newdelay
< olddelay
) {
507 (*wt
)->tv_sec
= newdelay
/ 1000;
508 (*wt
)->tv_usec
= 1000 * (newdelay
% 1000);
516 ErrorF("use: X [:<display>] [option]\n");
517 ErrorF("-a # default pointer acceleration (factor)\n");
518 ErrorF("-ac disable access control restrictions\n");
519 ErrorF("-audit int set audit trail level\n");
520 ErrorF("-auth file select authorization file\n");
521 ErrorF("-br create root window with black background\n");
522 ErrorF("+bs enable any backing store support\n");
523 ErrorF("-bs disable any backing store support\n");
524 ErrorF("-c turns off key-click\n");
525 ErrorF("c # key-click volume (0-100)\n");
526 ErrorF("-cc int default color visual class\n");
527 ErrorF("-nocursor disable the cursor\n");
528 ErrorF("-core generate core dump on fatal error\n");
529 ErrorF("-dpi int screen resolution in dots per inch\n");
531 ErrorF("-dpms disables VESA DPMS monitor control\n");
534 ("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n");
535 ErrorF("-f # bell base (0-100)\n");
536 ErrorF("-fc string cursor font\n");
537 ErrorF("-fn string default font name\n");
538 ErrorF("-fp string default font path\n");
539 ErrorF("-help prints message with these options\n");
540 ErrorF("-I ignore all remaining arguments\n");
542 ErrorF("-ld int limit data space to N Kb\n");
545 ErrorF("-lf int limit number of open files to N\n");
548 ErrorF("-ls int limit stack space to N Kb\n");
551 ErrorF("-nolock disable the locking mechanism\n");
553 ErrorF("-nolisten string don't listen on protocol\n");
554 ErrorF("-noreset don't reset after last client exists\n");
555 ErrorF("-background [none] create root window with no background\n");
556 ErrorF("-reset reset after last client exists\n");
557 ErrorF("-p # screen-saver pattern duration (minutes)\n");
558 ErrorF("-pn accept failure to listen on all ports\n");
559 ErrorF("-nopn reject failure to listen on all ports\n");
560 ErrorF("-r turns off auto-repeat\n");
561 ErrorF("r turns on auto-repeat \n");
562 ErrorF("-render [default|mono|gray|color] set render color alloc policy\n");
563 ErrorF("-retro start with classic stipple and cursor\n");
564 ErrorF("-s # screen-saver timeout (minutes)\n");
565 ErrorF("-seat string seat to run on\n");
566 ErrorF("-t # default pointer threshold (pixels/t)\n");
567 ErrorF("-terminate terminate at server reset\n");
568 ErrorF("-to # connection time out\n");
569 ErrorF("-tst disable testing extensions\n");
570 ErrorF("ttyxx server started from init on /dev/ttyxx\n");
571 ErrorF("v video blanking for screen-saver\n");
572 ErrorF("-v screen-saver without video blanking\n");
573 ErrorF("-wm WhenMapped default backing-store\n");
574 ErrorF("-wr create root window with white background\n");
575 ErrorF("-maxbigreqsize set maximal bigrequest size \n");
577 ErrorF("+xinerama Enable XINERAMA extension\n");
578 ErrorF("-xinerama Disable XINERAMA extension\n");
581 ("-dumbSched Disable smart scheduling, enable old behavior\n");
582 ErrorF("-schedInterval int Set scheduler interval in msec\n");
583 ErrorF("-sigstop Enable SIGSTOP based startup\n");
584 ErrorF("+extension name Enable extension\n");
585 ErrorF("-extension name Disable extension\n");
593 /* This function performs a rudimentary sanity check
594 * on the display name passed in on the command-line,
595 * since this string is used to generate filenames.
596 * It is especially important that the display name
597 * not contain a "/" and not start with a "-".
601 VerifyDisplayName(const char *d
)
604 int period_found
= FALSE
;
605 int after_period
= 0;
610 return 0; /* empty */
612 return 0; /* could be confused for an option */
614 return 0; /* must not equal "." or ".." */
615 if (strchr(d
, '/') != (char *) 0)
616 return 0; /* very important!!! */
618 /* Since we run atoi() on the display later, only allow
619 for digits, or exception of :0.0 and similar (two decimal points max)
621 for (i
= 0; i
< strlen(d
); i
++) {
622 if (!isdigit(d
[i
])) {
623 if (d
[i
] != '.' || period_found
)
626 } else if (period_found
)
629 if (after_period
> 2)
633 /* don't allow for :0. */
634 if (period_found
&& after_period
== 0)
637 if (atol(d
) > INT_MAX
)
644 * This function parses the command line. Handles device-independent fields
645 * and allows ddx to handle additional fields. It is not allowed to modify
646 * argc or any of the strings pointed to by argv.
649 ProcessCommandLine(int argc
, char *argv
[])
653 defaultKeyboardControl
.autoRepeat
= TRUE
;
656 PartialNetwork
= FALSE
;
658 PartialNetwork
= TRUE
;
661 for (i
= 1; i
< argc
; i
++) {
662 /* call ddx first, so it can peek/override if it wants */
663 if ((skip
= ddxProcessArgument(argc
, argv
, i
))) {
666 else if (argv
[i
][0] == ':') {
667 /* initialize display */
670 if (!VerifyDisplayName(display
)) {
671 ErrorF("Bad display name: %s\n", display
);
673 FatalError("Bad display name, exiting: %s\n", display
);
676 else if (strcmp(argv
[i
], "-a") == 0) {
678 defaultPointerControl
.num
= atoi(argv
[i
]);
682 else if (strcmp(argv
[i
], "-ac") == 0) {
683 defeatAccessControl
= TRUE
;
685 else if (strcmp(argv
[i
], "-audit") == 0) {
687 auditTrailLevel
= atoi(argv
[i
]);
691 else if (strcmp(argv
[i
], "-auth") == 0) {
693 InitAuthorization(argv
[i
]);
697 else if (strcmp(argv
[i
], "-br") == 0); /* default */
698 else if (strcmp(argv
[i
], "+bs") == 0)
699 enableBackingStore
= TRUE
;
700 else if (strcmp(argv
[i
], "-bs") == 0)
701 disableBackingStore
= TRUE
;
702 else if (strcmp(argv
[i
], "c") == 0) {
704 defaultKeyboardControl
.click
= atoi(argv
[i
]);
708 else if (strcmp(argv
[i
], "-c") == 0) {
709 defaultKeyboardControl
.click
= 0;
711 else if (strcmp(argv
[i
], "-cc") == 0) {
713 defaultColorVisualClass
= atoi(argv
[i
]);
717 else if (strcmp(argv
[i
], "-core") == 0) {
718 #if !defined(WIN32) || !defined(__MINGW32__)
719 struct rlimit core_limit
;
721 getrlimit(RLIMIT_CORE
, &core_limit
);
722 core_limit
.rlim_cur
= core_limit
.rlim_max
;
723 setrlimit(RLIMIT_CORE
, &core_limit
);
727 else if (strcmp(argv
[i
], "-nocursor") == 0) {
728 EnableCursor
= FALSE
;
730 else if (strcmp(argv
[i
], "-dpi") == 0) {
732 monitorResolution
= atoi(argv
[i
]);
736 else if (strcmp(argv
[i
], "-displayfd") == 0) {
738 displayfd
= atoi(argv
[i
]);
748 else if (strcmp(argv
[i
], "dpms") == 0)
749 /* ignored for compatibility */ ;
750 else if (strcmp(argv
[i
], "-dpms") == 0)
751 DPMSDisabledSwitch
= TRUE
;
753 else if (strcmp(argv
[i
], "-deferglyphs") == 0) {
754 if (++i
>= argc
|| !ParseGlyphCachingMode(argv
[i
]))
757 else if (strcmp(argv
[i
], "-f") == 0) {
759 defaultKeyboardControl
.bell
= atoi(argv
[i
]);
763 else if (strcmp(argv
[i
], "-fc") == 0) {
765 defaultCursorFont
= argv
[i
];
769 else if (strcmp(argv
[i
], "-fn") == 0) {
771 defaultTextFont
= argv
[i
];
775 else if (strcmp(argv
[i
], "-fp") == 0) {
777 defaultFontPath
= argv
[i
];
782 else if (strcmp(argv
[i
], "-help") == 0) {
786 else if ((skip
= XkbProcessArguments(argc
, argv
, i
)) != 0) {
793 else if (strcmp(argv
[i
], "-ld") == 0) {
795 limitDataSpace
= atoi(argv
[i
]);
796 if (limitDataSpace
> 0)
797 limitDataSpace
*= 1024;
804 else if (strcmp(argv
[i
], "-lf") == 0) {
806 limitNoFile
= atoi(argv
[i
]);
812 else if (strcmp(argv
[i
], "-ls") == 0) {
814 limitStackSpace
= atoi(argv
[i
]);
815 if (limitStackSpace
> 0)
816 limitStackSpace
*= 1024;
823 else if (strcmp(argv
[i
], "-nolock") == 0) {
824 #if !defined(WIN32) && !defined(__CYGWIN__)
827 ("Warning: the -nolock option can only be used by root\n");
833 else if (strcmp(argv
[i
], "-nolisten") == 0) {
835 if (_XSERVTransNoListen(argv
[i
]))
836 ErrorF("Failed to disable listen for %s transport",
842 else if (strcmp(argv
[i
], "-noreset") == 0) {
843 dispatchExceptionAtReset
= 0;
845 else if (strcmp(argv
[i
], "-reset") == 0) {
846 dispatchExceptionAtReset
= DE_RESET
;
848 else if (strcmp(argv
[i
], "-p") == 0) {
850 defaultScreenSaverInterval
= ((CARD32
) atoi(argv
[i
])) *
855 else if (strcmp(argv
[i
], "-pogo") == 0) {
856 dispatchException
= DE_TERMINATE
;
858 else if (strcmp(argv
[i
], "-pn") == 0)
859 PartialNetwork
= TRUE
;
860 else if (strcmp(argv
[i
], "-nopn") == 0)
861 PartialNetwork
= FALSE
;
862 else if (strcmp(argv
[i
], "r") == 0)
863 defaultKeyboardControl
.autoRepeat
= TRUE
;
864 else if (strcmp(argv
[i
], "-r") == 0)
865 defaultKeyboardControl
.autoRepeat
= FALSE
;
866 else if (strcmp(argv
[i
], "-retro") == 0)
867 party_like_its_1989
= TRUE
;
868 else if (strcmp(argv
[i
], "-s") == 0) {
870 defaultScreenSaverTime
= ((CARD32
) atoi(argv
[i
])) *
875 else if (strcmp(argv
[i
], "-seat") == 0) {
881 else if (strcmp(argv
[i
], "-t") == 0) {
883 defaultPointerControl
.threshold
= atoi(argv
[i
]);
887 else if (strcmp(argv
[i
], "-terminate") == 0) {
888 dispatchExceptionAtReset
= DE_TERMINATE
;
890 else if (strcmp(argv
[i
], "-to") == 0) {
892 TimeOutValue
= ((CARD32
) atoi(argv
[i
])) * MILLI_PER_SECOND
;
896 else if (strcmp(argv
[i
], "-tst") == 0) {
897 noTestExtensions
= TRUE
;
899 else if (strcmp(argv
[i
], "v") == 0)
900 defaultScreenSaverBlanking
= PreferBlanking
;
901 else if (strcmp(argv
[i
], "-v") == 0)
902 defaultScreenSaverBlanking
= DontPreferBlanking
;
903 else if (strcmp(argv
[i
], "-wm") == 0)
904 defaultBackingStore
= WhenMapped
;
905 else if (strcmp(argv
[i
], "-wr") == 0)
907 else if (strcmp(argv
[i
], "-background") == 0) {
909 if (!strcmp(argv
[i
], "none"))
915 else if (strcmp(argv
[i
], "-maxbigreqsize") == 0) {
917 long reqSizeArg
= atol(argv
[i
]);
919 /* Request size > 128MB does not make much sense... */
920 if (reqSizeArg
> 0L && reqSizeArg
< 128L) {
921 maxBigRequestSize
= (reqSizeArg
* 1048576L) - 1L;
932 else if (strcmp(argv
[i
], "+xinerama") == 0) {
933 noPanoramiXExtension
= FALSE
;
935 else if (strcmp(argv
[i
], "-xinerama") == 0) {
936 noPanoramiXExtension
= TRUE
;
938 else if (strcmp(argv
[i
], "-disablexineramaextension") == 0) {
939 PanoramiXExtensionDisabledHack
= TRUE
;
942 else if (strcmp(argv
[i
], "-I") == 0) {
943 /* ignore all remaining arguments */
946 else if (strncmp(argv
[i
], "tty", 3) == 0) {
947 /* init supplies us with this useless information */
950 else if ((skip
= XdmcpOptions(argc
, argv
, i
)) != i
) {
954 #ifdef SMART_SCHEDULE_POSSIBLE
955 else if (strcmp(argv
[i
], "-dumbSched") == 0) {
956 SmartScheduleDisable
= TRUE
;
958 else if (strcmp(argv
[i
], "-schedInterval") == 0) {
960 SmartScheduleInterval
= atoi(argv
[i
]);
961 SmartScheduleSlice
= SmartScheduleInterval
;
966 else if (strcmp(argv
[i
], "-schedMax") == 0) {
968 SmartScheduleMaxSlice
= atoi(argv
[i
]);
974 else if (strcmp(argv
[i
], "-render") == 0) {
976 int policy
= PictureParseCmapPolicy(argv
[i
]);
978 if (policy
!= PictureCmapPolicyInvalid
)
979 PictureCmapPolicy
= policy
;
986 else if (strcmp(argv
[i
], "-sigstop") == 0) {
987 RunFromSigStopParent
= TRUE
;
989 else if (strcmp(argv
[i
], "+extension") == 0) {
991 if (!EnableDisableExtension(argv
[i
], TRUE
))
992 EnableDisableExtensionError(argv
[i
], TRUE
);
997 else if (strcmp(argv
[i
], "-extension") == 0) {
999 if (!EnableDisableExtension(argv
[i
], FALSE
))
1000 EnableDisableExtensionError(argv
[i
], FALSE
);
1006 ErrorF("Unrecognized option: %s\n", argv
[i
]);
1008 FatalError("Unrecognized option: %s\n", argv
[i
]);
1013 /* Implement a simple-minded font authorization scheme. The authorization
1014 name is "hp-hostname-1", the contents are simply the host name. */
1016 set_font_authorizations(char **authorizations
, int *authlen
, pointer client
)
1018 #define AUTHORIZATION_NAME "hp-hostname-1"
1019 #if defined(TCPCONN) || defined(STREAMSCONN)
1020 static char *result
= NULL
;
1021 static char *p
= NULL
;
1024 char hname
[1024], *hnameptr
;
1027 #if defined(IPv6) && defined(AF_INET6)
1028 struct addrinfo hints
, *ai
= NULL
;
1030 struct hostent
*host
;
1032 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1033 _Xgethostbynameparams hparams
;
1037 gethostname(hname
, 1024);
1038 #if defined(IPv6) && defined(AF_INET6)
1039 memset(&hints
, 0, sizeof(hints
));
1040 hints
.ai_flags
= AI_CANONNAME
;
1041 if (getaddrinfo(hname
, NULL
, &hints
, &ai
) == 0) {
1042 hnameptr
= ai
->ai_canonname
;
1048 host
= _XGethostbyname(hname
, hparams
);
1052 hnameptr
= host
->h_name
;
1055 len
= strlen(hnameptr
) + 1;
1056 result
= malloc(len
+ sizeof(AUTHORIZATION_NAME
) + 4);
1059 *p
++ = sizeof(AUTHORIZATION_NAME
) >> 8;
1060 *p
++ = sizeof(AUTHORIZATION_NAME
) & 0xff;
1062 *p
++ = (len
& 0xff);
1064 memmove(p
, AUTHORIZATION_NAME
, sizeof(AUTHORIZATION_NAME
));
1065 p
+= sizeof(AUTHORIZATION_NAME
);
1066 memmove(p
, hnameptr
, len
);
1068 #if defined(IPv6) && defined(AF_INET6)
1074 *authlen
= p
- result
;
1075 *authorizations
= result
;
1079 #endif /* TCPCONN */
1083 Xalloc(unsigned long amount
)
1086 * Xalloc used to return NULL when large amount of memory is requested. In
1087 * order to catch the buggy callers this warning has been added, slated to
1088 * removal by anyone who touches this code (or just looks at it) in 2011.
1090 * -- Mikhail Gusarov
1092 if ((long) amount
<= 0)
1093 ErrorF("Warning: Xalloc: "
1094 "requesting unpleasantly large amount of memory: %lu bytes.\n",
1097 return malloc(amount
);
1101 XNFalloc(unsigned long amount
)
1103 void *ptr
= malloc(amount
);
1106 FatalError("Out of memory");
1111 Xcalloc(unsigned long amount
)
1113 return calloc(1, amount
);
1117 XNFcalloc(unsigned long amount
)
1119 void *ret
= calloc(1, amount
);
1122 FatalError("XNFcalloc: Out of memory");
1127 Xrealloc(void *ptr
, unsigned long amount
)
1130 * Xrealloc used to return NULL when large amount of memory is requested. In
1131 * order to catch the buggy callers this warning has been added, slated to
1132 * removal by anyone who touches this code (or just looks at it) in 2011.
1134 * -- Mikhail Gusarov
1136 if ((long) amount
<= 0)
1137 ErrorF("Warning: Xrealloc: "
1138 "requesting unpleasantly large amount of memory: %lu bytes.\n",
1141 return realloc(ptr
, amount
);
1145 XNFrealloc(void *ptr
, unsigned long amount
)
1147 void *ret
= realloc(ptr
, amount
);
1150 FatalError("XNFrealloc: Out of memory");
1161 Xstrdup(const char *s
)
1169 XNFstrdup(const char *s
)
1178 FatalError("XNFstrdup: Out of memory");
1183 SmartScheduleStopTimer(void)
1185 #ifdef SMART_SCHEDULE_POSSIBLE
1186 struct itimerval timer
;
1188 if (SmartScheduleDisable
)
1190 timer
.it_interval
.tv_sec
= 0;
1191 timer
.it_interval
.tv_usec
= 0;
1192 timer
.it_value
.tv_sec
= 0;
1193 timer
.it_value
.tv_usec
= 0;
1194 (void) setitimer(ITIMER_REAL
, &timer
, 0);
1199 SmartScheduleStartTimer(void)
1201 #ifdef SMART_SCHEDULE_POSSIBLE
1202 struct itimerval timer
;
1204 if (SmartScheduleDisable
)
1206 timer
.it_interval
.tv_sec
= 0;
1207 timer
.it_interval
.tv_usec
= SmartScheduleInterval
* 1000;
1208 timer
.it_value
.tv_sec
= 0;
1209 timer
.it_value
.tv_usec
= SmartScheduleInterval
* 1000;
1210 setitimer(ITIMER_REAL
, &timer
, 0);
1215 SmartScheduleTimer(int sig
)
1217 SmartScheduleTime
+= SmartScheduleInterval
;
1221 SmartScheduleInit(void)
1223 #ifdef SMART_SCHEDULE_POSSIBLE
1224 struct sigaction act
;
1226 if (SmartScheduleDisable
)
1229 memset((char *) &act
, 0, sizeof(struct sigaction
));
1231 /* Set up the timer signal function */
1232 act
.sa_handler
= SmartScheduleTimer
;
1233 sigemptyset(&act
.sa_mask
);
1234 sigaddset(&act
.sa_mask
, SIGALRM
);
1235 if (sigaction(SIGALRM
, &act
, 0) < 0) {
1236 perror("sigaction for smart scheduler");
1237 SmartScheduleDisable
= TRUE
;
1243 static sigset_t PreviousSignalMask
;
1244 static int BlockedSignalCount
;
1248 OsBlockSignals(void)
1251 if (BlockedSignalCount
++ == 0) {
1258 sigaddset(&set
, SIGALRM
);
1259 sigaddset(&set
, SIGVTALRM
);
1261 sigaddset(&set
, SIGWINCH
);
1263 sigaddset(&set
, SIGTSTP
);
1264 sigaddset(&set
, SIGTTIN
);
1265 sigaddset(&set
, SIGTTOU
);
1266 sigaddset(&set
, SIGCHLD
);
1267 sigprocmask(SIG_BLOCK
, &set
, &PreviousSignalMask
);
1273 static sig_atomic_t sigio_blocked
;
1274 static sigset_t PreviousSigIOMask
;
1278 * returns zero if this call caused SIGIO to be blocked now, non-zero if it
1279 * was already blocked by a previous call to this function.
1286 if (sigio_blocked
++ == 0) {
1291 sigaddset(&set
, SIGIO
);
1292 sigprocmask(SIG_BLOCK
, &set
, &PreviousSigIOMask
);
1293 ret
= sigismember(&PreviousSigIOMask
, SIGIO
);
1302 OsReleaseSIGIO(void)
1306 if (--sigio_blocked
== 0) {
1307 sigprocmask(SIG_SETMASK
, &PreviousSigIOMask
, 0);
1308 } else if (sigio_blocked
< 0) {
1309 BUG_WARN(sigio_blocked
< 0);
1317 OsReleaseSignals(void)
1320 if (--BlockedSignalCount
== 0) {
1321 sigprocmask(SIG_SETMASK
, &PreviousSignalMask
, 0);
1328 OsResetSignals(void)
1331 while (BlockedSignalCount
> 0)
1334 while (sigio_blocked
> 0)
1341 * Pending signals may interfere with core dumping. Provide a
1342 * mechanism to block signals when aborting.
1356 * "safer" versions of system(3), popen(3) and pclose(3) which give up
1357 * all privs before running a command.
1359 * This is based on the code in FreeBSD 2.2 libc.
1361 * XXX It'd be good to redirect stderr so that it ends up in the log file
1362 * as well. As it is now, xkbcomp messages don't end up in the log file.
1366 System(const char *command
)
1375 csig
= signal(SIGCHLD
, SIG_DFL
);
1376 if (csig
== SIG_ERR
) {
1380 DebugF("System: `%s'\n", command
);
1382 switch (pid
= fork()) {
1383 case -1: /* error */
1386 if (setgid(getgid()) == -1)
1388 if (setuid(getuid()) == -1)
1390 execl("/bin/sh", "sh", "-c", command
, (char *) NULL
);
1392 default: /* parent */
1394 p
= waitpid(pid
, &status
, 0);
1395 } while (p
== -1 && errno
== EINTR
);
1399 if (signal(SIGCHLD
, csig
) == SIG_ERR
) {
1404 return p
== -1 ? -1 : status
;
1413 OsSigHandlerPtr old_alarm
= NULL
; /* XXX horrible awful hack */
1416 Popen(const char *command
, const char *type
)
1422 if (command
== NULL
|| type
== NULL
)
1425 if ((*type
!= 'r' && *type
!= 'w') || type
[1])
1428 if ((cur
= malloc(sizeof(struct pid
))) == NULL
)
1431 if (pipe(pdes
) < 0) {
1436 /* Ignore the smart scheduler while this is going on */
1437 old_alarm
= OsSignal(SIGALRM
, SIG_IGN
);
1438 if (old_alarm
== SIG_ERR
) {
1446 switch (pid
= fork()) {
1447 case -1: /* error */
1451 if (OsSignal(SIGALRM
, old_alarm
) == SIG_ERR
)
1455 if (setgid(getgid()) == -1)
1457 if (setuid(getuid()) == -1)
1475 execl("/bin/sh", "sh", "-c", command
, (char *) NULL
);
1479 /* Avoid EINTR during stdio calls */
1484 iop
= fdopen(pdes
[0], type
);
1488 iop
= fdopen(pdes
[1], type
);
1494 cur
->next
= pidlist
;
1497 DebugF("Popen: `%s', fp = %p\n", command
, iop
);
1502 /* fopen that drops privileges */
1504 Fopen(const char *file
, const char *type
)
1508 #ifndef HAS_SAVED_IDS_AND_SETEUID
1512 if (file
== NULL
|| type
== NULL
)
1515 if ((*type
!= 'r' && *type
!= 'w') || type
[1])
1518 if ((cur
= malloc(sizeof(struct pid
))) == NULL
)
1521 if (pipe(pdes
) < 0) {
1526 switch (pid
= fork()) {
1527 case -1: /* error */
1533 if (setgid(getgid()) == -1)
1535 if (setuid(getuid()) == -1)
1553 execl("/bin/cat", "cat", file
, (char *) NULL
);
1557 /* Avoid EINTR during stdio calls */
1562 iop
= fdopen(pdes
[0], type
);
1566 iop
= fdopen(pdes
[1], type
);
1572 cur
->next
= pidlist
;
1575 DebugF("Fopen(%s), fp = %p\n", file
, iop
);
1584 if (seteuid(ruid
) == -1) {
1587 iop
= fopen(file
, type
);
1589 if (seteuid(euid
) == -1) {
1594 #endif /* HAS_SAVED_IDS_AND_SETEUID */
1600 struct pid
*cur
, *last
;
1604 DebugF("Pclose: fp = %p\n", iop
);
1607 for (last
= NULL
, cur
= pidlist
; cur
; last
= cur
, cur
= cur
->next
)
1614 pid
= waitpid(cur
->pid
, &pstat
, 0);
1615 } while (pid
== -1 && errno
== EINTR
);
1618 pidlist
= cur
->next
;
1620 last
->next
= cur
->next
;
1623 /* allow EINTR again */
1626 if (old_alarm
&& OsSignal(SIGALRM
, old_alarm
) == SIG_ERR
) {
1631 return pid
== -1 ? -1 : pstat
;
1637 #ifdef HAS_SAVED_IDS_AND_SETEUID
1648 #include <X11/Xwindows.h>
1653 static char buffer
[PATH_MAX
];
1655 if (GetTempPath(sizeof(buffer
), buffer
)) {
1658 buffer
[sizeof(buffer
) - 1] = 0;
1659 len
= strlen(buffer
);
1661 if (buffer
[len
- 1] == '\\')
1662 buffer
[len
- 1] = 0;
1665 if (getenv("TEMP") != NULL
)
1666 return getenv("TEMP");
1667 else if (getenv("TMP") != NULL
)
1668 return getenv("TMP");
1674 System(const char *cmdline
)
1677 PROCESS_INFORMATION pi
;
1679 char *cmd
= strdup(cmdline
);
1681 ZeroMemory(&si
, sizeof(si
));
1683 ZeroMemory(&pi
, sizeof(pi
));
1685 if (!CreateProcess(NULL
, cmd
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
)) {
1688 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
1689 FORMAT_MESSAGE_FROM_SYSTEM
|
1690 FORMAT_MESSAGE_IGNORE_INSERTS
,
1693 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
1694 (LPTSTR
) &buffer
, 0, NULL
)) {
1695 ErrorF("[xkb] Starting '%s' failed!\n", cmdline
);
1698 ErrorF("[xkb] Starting '%s' failed: %s", cmdline
, (char *) buffer
);
1705 /* Wait until child process exits. */
1706 WaitForSingleObject(pi
.hProcess
, INFINITE
);
1708 GetExitCodeProcess(pi
.hProcess
, &dwExitCode
);
1710 /* Close process and thread handles. */
1711 CloseHandle(pi
.hProcess
);
1712 CloseHandle(pi
.hThread
);
1720 * CheckUserParameters: check for long command line arguments and long
1721 * environment variables. By default, these checks are only done when
1722 * the server's euid != ruid. In 3.3.x, these checks were done in an
1723 * external wrapper utility.
1726 /* Consider LD* variables insecure? */
1727 #ifndef REMOVE_ENV_LD
1728 #define REMOVE_ENV_LD 1
1731 /* Remove long environment variables? */
1732 #ifndef REMOVE_LONG_ENV
1733 #define REMOVE_LONG_ENV 1
1737 * Disallow stdout or stderr as pipes? It's possible to block the X server
1738 * when piping stdout+stderr to a pipe.
1740 * Don't enable this because it looks like it's going to cause problems.
1742 #ifndef NO_OUTPUT_PIPES
1743 #define NO_OUTPUT_PIPES 0
1746 /* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
1749 #define CHECK_EUID 1
1751 #define CHECK_EUID 0
1756 * Maybe the locale can be faked to make isprint(3) report that everything
1757 * is printable? Avoid it by default.
1760 #define USE_ISPRINT 0
1763 #define MAX_ARG_LENGTH 128
1764 #define MAX_ENV_LENGTH 256
1765 #define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */
1769 #define checkPrintable(c) isprint(c)
1771 #define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
1784 #if defined(VENDORSUPPORT)
1785 #define BUGADDRESS VENDORSUPPORT
1786 #elif defined(BUILDERADDR)
1787 #define BUGADDRESS BUILDERADDR
1789 #define BUGADDRESS "xorg@freedesktop.org"
1793 CheckUserParameters(int argc
, char **argv
, char **envp
)
1795 enum BadCode bad
= NotBad
;
1800 if (geteuid() == 0 && getuid() != geteuid())
1803 /* Check each argv[] */
1804 for (i
= 1; i
< argc
; i
++) {
1805 if (strcmp(argv
[i
], "-fp") == 0) {
1806 i
++; /* continue with next argument. skip the length check */
1811 if (strlen(argv
[i
]) > MAX_ARG_LENGTH
) {
1818 if (checkPrintable(*a
) == 0) {
1819 bad
= UnprintableArg
;
1828 /* Check each envp[] */
1829 for (i
= 0; envp
[i
]; i
++) {
1831 /* Check for bad environment variables and values */
1833 while (envp
[i
] && (strncmp(envp
[i
], "LD", 2) == 0)) {
1834 for (j
= i
; envp
[j
]; j
++) {
1835 envp
[j
] = envp
[j
+ 1];
1839 if (envp
[i
] && (strlen(envp
[i
]) > MAX_ENV_LENGTH
)) {
1841 for (j
= i
; envp
[j
]; j
++) {
1842 envp
[j
] = envp
[j
+ 1];
1849 eq
= strchr(envp
[i
], '=');
1853 e
= strndup(envp
[i
], len
);
1855 bad
= InternalError
;
1859 (strcmp(e
+ len
- 4, "PATH") == 0 ||
1860 strcmp(e
, "TERMCAP") == 0)) {
1861 if (strlen(envp
[i
]) > MAX_ENV_PATH_LENGTH
) {
1881 if (fstat(fileno(stdout
), &buf
) == 0 && S_ISFIFO(buf
.st_mode
))
1883 if (fstat(fileno(stderr
), &buf
) == 0 && S_ISFIFO(buf
.st_mode
))
1892 ErrorF("Command line argument number %d is unsafe\n", i
);
1895 ErrorF("Command line argument number %d is too long\n", i
);
1897 case UnprintableArg
:
1898 ErrorF("Command line argument number %d contains unprintable"
1899 " characters\n", i
);
1902 ErrorF("Environment variable `%s' is too long\n", e
);
1905 ErrorF("Stdout and/or stderr is a pipe\n");
1908 ErrorF("Internal Error\n");
1911 ErrorF("Unknown error\n");
1914 FatalError("X server aborted because of unsafe environment\n");
1918 * CheckUserAuthorization: check if the user is allowed to start the
1919 * X server. This usually means some sort of PAM checking, and it is
1920 * usually only done for setuid servers (uid != euid).
1924 #include <security/pam_appl.h>
1925 #include <security/pam_misc.h>
1927 #endif /* USE_PAM */
1930 CheckUserAuthorization(void)
1933 static struct pam_conv conv
= {
1938 pam_handle_t
*pamh
= NULL
;
1942 if (getuid() != geteuid()) {
1943 pw
= getpwuid(getuid());
1945 FatalError("getpwuid() failed for uid %d\n", getuid());
1947 retval
= pam_start("xserver", pw
->pw_name
, &conv
, &pamh
);
1948 if (retval
!= PAM_SUCCESS
)
1949 FatalError("pam_start() failed.\n"
1950 "\tMissing or mangled PAM config file or module?\n");
1952 retval
= pam_authenticate(pamh
, 0);
1953 if (retval
!= PAM_SUCCESS
) {
1954 pam_end(pamh
, retval
);
1955 FatalError("PAM authentication failed, cannot start X server.\n"
1956 "\tPerhaps you do not have console ownership?\n");
1959 retval
= pam_acct_mgmt(pamh
, 0);
1960 if (retval
!= PAM_SUCCESS
) {
1961 pam_end(pamh
, retval
);
1962 FatalError("PAM authentication failed, cannot start X server.\n"
1963 "\tPerhaps you do not have console ownership?\n");
1966 /* this is not a session, so do not do session management */
1967 pam_end(pamh
, PAM_SUCCESS
);
1973 * Tokenize a string into a NULL terminated array of strings. Always returns
1974 * an allocated array unless an error occurs.
1977 xstrtokenize(const char *str
, const char *separators
)
1979 char **list
, **nlist
;
1981 unsigned num
= 0, n
;
1985 list
= calloc(1, sizeof(*list
));
1991 for (tok
= strtok(tmp
, separators
); tok
; tok
= strtok(NULL
, separators
)) {
1992 nlist
= realloc(list
, (num
+ 2) * sizeof(*list
));
1996 list
[num
] = strdup(tok
);
2006 for (n
= 0; n
< num
; n
++)
2012 /* Format a signed number into a string in a signal safe manner. The string
2013 * should be at least 21 characters in order to handle all int64_t values.
2016 FormatInt64(int64_t num
, char *string
)
2023 FormatUInt64(num
, string
);
2026 /* Format a number into a string in a signal safe manner. The string should be
2027 * at least 21 characters in order to handle all uint64_t values. */
2029 FormatUInt64(uint64_t num
, char *string
)
2035 for (len
= 1, divisor
= 10;
2036 len
< 20 && num
/ divisor
;
2037 len
++, divisor
*= 10);
2039 for (i
= len
, divisor
= 1; i
> 0; i
--, divisor
*= 10)
2040 string
[i
- 1] = '0' + ((num
/ divisor
) % 10);
2046 * Format a double number as %.2f.
2049 FormatDouble(double dbl
, char *string
)
2054 frac
= (dbl
> 0 ? dbl
: -dbl
) * 100.0 + 0.5;
2057 /* write decimal part to string */
2058 if (dbl
< 0 && dbl
> -1)
2059 string
[slen
++] = '-';
2060 FormatInt64((int64_t)dbl
, &string
[slen
]);
2062 while(string
[slen
] != '\0')
2065 /* append fractional part, but only if we have enough characters. We
2066 * expect string to be 21 chars (incl trailing \0) */
2068 string
[slen
++] = '.';
2070 string
[slen
++] = '0';
2072 FormatUInt64(frac
, &string
[slen
]);
2077 /* Format a number into a hexadecimal string in a signal safe manner. The string
2078 * should be at least 17 characters in order to handle all uint64_t values. */
2080 FormatUInt64Hex(uint64_t num
, char *string
)
2086 for (len
= 1, divisor
= 0x10;
2087 len
< 16 && num
/ divisor
;
2088 len
++, divisor
*= 0x10);
2090 for (i
= len
, divisor
= 1; i
> 0; i
--, divisor
*= 0x10) {
2091 int val
= (num
/ divisor
) % 0x10;
2094 string
[i
- 1] = '0' + val
;
2096 string
[i
- 1] = 'a' + val
- 10;
2102 /* Move a file descriptor out of the way of our select mask; this
2103 * is useful for file descriptors which will never appear in the
2104 * select mask to avoid reducing the number of clients that can
2105 * connect to the server
2112 #ifdef F_DUPFD_CLOEXEC
2113 newfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, MAXCLIENTS
);
2115 newfd
= fcntl(fd
, F_DUPFD
, MAXCLIENTS
);
2119 #ifndef F_DUPFD_CLOEXEC
2120 fcntl(newfd
, F_SETFD
, FD_CLOEXEC
);