Add patch that contain Mali fixes.
[deb_xorg-server.git] / os / utils.c
CommitLineData
a09e091a
JB
1/*
2
3Copyright 1987, 1998 The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
28Copyright 1994 Quarterdeck Office Systems.
29
30 All Rights Reserved
31
32Permission to use, copy, modify, and distribute this software and its
33documentation for any purpose and without fee is hereby granted,
34provided that the above copyright notice appear in all copies and that
35both that copyright notice and this permission notice appear in
36supporting documentation, and that the names of Digital and
37Quarterdeck not be used in advertising or publicity pertaining to
38distribution of the software without specific, written prior
39permission.
40
41DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
42SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
43FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
44OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
45OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
46OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
47OR PERFORMANCE OF THIS SOFTWARE.
48
49*/
50
51#ifdef HAVE_DIX_CONFIG_H
52#include <dix-config.h>
53#endif
54
55#ifdef __CYGWIN__
56#include <stdlib.h>
57#include <signal.h>
58/*
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...
61*/
62__stdcall unsigned long GetTickCount(void);
63#endif
64
65#if defined(WIN32) && !defined(__CYGWIN__)
66#include <X11/Xwinsock.h>
67#endif
68#include <X11/Xos.h>
69#include <stdio.h>
70#include <time.h>
71#if !defined(WIN32) || !defined(__MINGW32__)
72#include <sys/time.h>
73#include <sys/resource.h>
74# define SMART_SCHEDULE_POSSIBLE
75#endif
76#include "misc.h"
77#include <X11/X.h>
78#define XSERV_t
79#define TRANS_SERVER
80#define TRANS_REOPEN
81#include <X11/Xtrans/Xtrans.h>
82#include "input.h"
83#include "dixfont.h"
84#include "osdep.h"
85#include "extension.h"
86#ifdef X_POSIX_C_SOURCE
87#define _POSIX_C_SOURCE X_POSIX_C_SOURCE
88#include <signal.h>
89#undef _POSIX_C_SOURCE
90#else
91#if defined(_POSIX_SOURCE)
92#include <signal.h>
93#else
94#define _POSIX_SOURCE
95#include <signal.h>
96#undef _POSIX_SOURCE
97#endif
98#endif
99#ifndef WIN32
100#include <sys/wait.h>
101#endif
102#if !defined(SYSV) && !defined(WIN32)
103#include <sys/resource.h>
104#endif
105#include <sys/stat.h>
106#include <ctype.h> /* for isspace */
107#include <stdarg.h>
108
109#include <stdlib.h> /* for malloc() */
110
111#if defined(TCPCONN) || defined(STREAMSCONN)
112#ifndef WIN32
113#include <netdb.h>
114#endif
115#endif
116
117#include "opaque.h"
118
119#include "dixstruct.h"
120
121#include "xkbsrv.h"
122
123#include "picture.h"
124
125Bool noTestExtensions;
126
127#ifdef COMPOSITE
128Bool noCompositeExtension = FALSE;
129#endif
130
131#ifdef DAMAGE
132Bool noDamageExtension = FALSE;
133#endif
134#ifdef DBE
135Bool noDbeExtension = FALSE;
136#endif
137#ifdef DPMSExtension
138Bool noDPMSExtension = FALSE;
139#endif
140#ifdef GLXEXT
141Bool noGlxExtension = FALSE;
142#endif
143#ifdef SCREENSAVER
144Bool noScreenSaverExtension = FALSE;
145#endif
146#ifdef MITSHM
147Bool noMITShmExtension = FALSE;
148#endif
149#ifdef RANDR
150Bool noRRExtension = FALSE;
151#endif
152Bool noRenderExtension = FALSE;
153
154#ifdef XCSECURITY
155Bool noSecurityExtension = FALSE;
156#endif
157#ifdef RES
158Bool noResExtension = FALSE;
159#endif
160#ifdef XF86BIGFONT
161Bool noXFree86BigfontExtension = FALSE;
162#endif
163#ifdef XFreeXDGA
164Bool noXFree86DGAExtension = FALSE;
165#endif
166#ifdef XF86DRI
167Bool noXFree86DRIExtension = FALSE;
168#endif
169#ifdef XF86VIDMODE
170Bool noXFree86VidModeExtension = FALSE;
171#endif
172Bool noXFixesExtension = FALSE;
173#ifdef PANORAMIX
174/* Xinerama is disabled by default unless enabled via +xinerama */
175Bool noPanoramiXExtension = TRUE;
176#endif
177#ifdef XSELINUX
178Bool noSELinuxExtension = FALSE;
179int selinuxEnforcingState = SELINUX_MODE_DEFAULT;
180#endif
181#ifdef XV
182Bool noXvExtension = FALSE;
183#endif
184#ifdef DRI2
185Bool noDRI2Extension = FALSE;
186#endif
187
188Bool noGEExtension = FALSE;
189
190#define X_INCLUDE_NETDB_H
191#include <X11/Xos_r.h>
192
193#include <errno.h>
194
195Bool CoreDump;
196
197#ifdef PANORAMIX
198Bool PanoramiXExtensionDisabledHack = FALSE;
199#endif
200
201int auditTrailLevel = 1;
202
203char *SeatId = NULL;
204
205sig_atomic_t inSignalContext = FALSE;
206
207#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
208#define HAS_SAVED_IDS_AND_SETEUID
209#endif
210
211OsSigHandlerPtr
212OsSignal(int sig, OsSigHandlerPtr handler)
213{
214#if defined(WIN32) && !defined(__CYGWIN__)
215 return signal(sig, handler);
216#else
217 struct sigaction act, oact;
218
219 sigemptyset(&act.sa_mask);
220 if (handler != SIG_IGN)
221 sigaddset(&act.sa_mask, sig);
222 act.sa_flags = 0;
223 act.sa_handler = handler;
224 if (sigaction(sig, &act, &oact))
225 perror("sigaction");
226 return oact.sa_handler;
227#endif
228}
229
230/*
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.
235 */
236#define LOCK_DIR "/tmp"
237#define LOCK_TMP_PREFIX "/.tX"
238#define LOCK_PREFIX "/.X"
239#define LOCK_SUFFIX "-lock"
240
241#if !defined(WIN32) || defined(__CYGWIN__)
242#define LOCK_SERVER
243#endif
244
245#ifndef LOCK_SERVER
246void
247LockServer(void)
248{}
249
250void
251UnlockServer(void)
252{}
253#else /* LOCK_SERVER */
254static Bool StillLocking = FALSE;
255static char LockFile[PATH_MAX];
256static Bool nolock = FALSE;
257
258/*
259 * LockServer --
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.
263 */
264void
265LockServer(void)
266{
267 char tmp[PATH_MAX], pid_str[12];
268 int lfd, i, haslock, l_pid, t;
269 const char *tmppath = LOCK_DIR;
270 int len;
271 char port[20];
272
273 if (nolock)
274 return;
275 /*
276 * Path names
277 */
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);
286
287 /*
288 * Create a temporary file containing our PID. Attempt three times
289 * to create the file.
290 */
291 StillLocking = TRUE;
292 i = 0;
293 do {
294 i++;
295 lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
296 if (lfd < 0)
297 sleep(2);
298 else
299 break;
300 } while (i < 3);
301 if (lfd < 0) {
302 unlink(tmp);
303 i = 0;
304 do {
305 i++;
306 lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
307 if (lfd < 0)
308 sleep(2);
309 else
310 break;
311 } while (i < 3);
312 }
313 if (lfd < 0)
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);
318 (void) close(lfd);
319
320 /*
321 * OK. Now the tmp file exists. Try three times to move it in place
322 * for the lock.
323 */
324 i = 0;
325 haslock = 0;
326 while ((!haslock) && (i++ < 3)) {
327 haslock = (link(tmp, LockFile) == 0);
328 if (haslock) {
329 /*
330 * We're done.
331 */
332 break;
333 }
334 else {
335 /*
336 * Read the pid from the existing file
337 */
338 lfd = open(LockFile, O_RDONLY | O_NOFOLLOW);
339 if (lfd < 0) {
340 unlink(tmp);
341 FatalError("Can't read lock file %s\n", LockFile);
342 }
343 pid_str[0] = '\0';
344 if (read(lfd, pid_str, 11) != 11) {
345 /*
346 * Bogus lock file.
347 */
348 unlink(LockFile);
349 close(lfd);
350 continue;
351 }
352 pid_str[11] = '\0';
353 sscanf(pid_str, "%d", &l_pid);
354 close(lfd);
355
356 /*
357 * Now try to kill the PID to see if it exists.
358 */
359 errno = 0;
360 t = kill(l_pid, 0);
361 if ((t < 0) && (errno == ESRCH)) {
362 /*
363 * Stale lock file.
364 */
365 unlink(LockFile);
366 continue;
367 }
368 else if (((t < 0) && (errno == EPERM)) || (t == 0)) {
369 /*
370 * Process is still active.
371 */
372 unlink(tmp);
373 FatalError
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.");
377 }
378 }
379 }
380 unlink(tmp);
381 if (!haslock)
382 FatalError("Could not create server lock file: %s\n", LockFile);
383 StillLocking = FALSE;
384}
385
386/*
387 * UnlockServer --
388 * Remove the server lock file.
389 */
390void
391UnlockServer(void)
392{
393 if (nolock)
394 return;
395
396 if (!StillLocking) {
397
398 (void) unlink(LockFile);
399 }
400}
401#endif /* LOCK_SERVER */
402
403/* Force connections to close on SIGHUP from init */
404
405void
406AutoResetServer(int sig)
407{
408 int olderrno = errno;
409
410 dispatchException |= DE_RESET;
411 isItTimeToYield = TRUE;
412 errno = olderrno;
413}
414
415/* Force connections to close and then exit on SIGTERM, SIGINT */
416
417void
418GiveUp(int sig)
419{
420 int olderrno = errno;
421
422 dispatchException |= DE_TERMINATE;
423 isItTimeToYield = TRUE;
424 errno = olderrno;
425}
426
427#if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__)
428CARD32
429GetTimeInMillis(void)
430{
431 return GetTickCount();
432}
433CARD64
434GetTimeInMicros(void)
435{
436 return (CARD64) GetTickCount() * 1000;
437}
438#else
439CARD32
440GetTimeInMillis(void)
441{
442 struct timeval tv;
443
444#ifdef MONOTONIC_CLOCK
445 struct timespec tp;
446 static clockid_t clockid;
447
448 if (!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;
454 else
455#endif
456 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
457 clockid = CLOCK_MONOTONIC;
458 else
459 clockid = ~0L;
460 }
461 if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
462 return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
463#endif
464
465 X_GETTIMEOFDAY(&tv);
466 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
467}
468
469CARD64
470GetTimeInMicros(void)
471{
472 struct timeval tv;
473#ifdef MONOTONIC_CLOCK
474 struct timespec tp;
475 static clockid_t clockid;
476
477 if (!clockid) {
478 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
479 clockid = CLOCK_MONOTONIC;
480 else
481 clockid = ~0L;
482 }
483 if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
484 return (CARD64) tp.tv_sec * (CARD64)1000000 + tp.tv_nsec / 1000;
485#endif
486
487 X_GETTIMEOFDAY(&tv);
488 return (CARD64) tv.tv_sec * (CARD64)1000000000 + (CARD64) tv.tv_usec * 1000;
489}
490#endif
491
492void
493AdjustWaitForDelay(pointer waitTime, unsigned long newdelay)
494{
495 static struct timeval delay_val;
496 struct timeval **wt = (struct timeval **) waitTime;
497 unsigned long olddelay;
498
499 if (*wt == NULL) {
500 delay_val.tv_sec = newdelay / 1000;
501 delay_val.tv_usec = 1000 * (newdelay % 1000);
502 *wt = &delay_val;
503 }
504 else {
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);
509 }
510 }
511}
512
513void
514UseMsg(void)
515{
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");
530#ifdef DPMSExtension
531 ErrorF("-dpms disables VESA DPMS monitor control\n");
532#endif
533 ErrorF
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");
541#ifdef RLIMIT_DATA
542 ErrorF("-ld int limit data space to N Kb\n");
543#endif
544#ifdef RLIMIT_NOFILE
545 ErrorF("-lf int limit number of open files to N\n");
546#endif
547#ifdef RLIMIT_STACK
548 ErrorF("-ls int limit stack space to N Kb\n");
549#endif
550#ifdef LOCK_SERVER
551 ErrorF("-nolock disable the locking mechanism\n");
552#endif
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");
576#ifdef PANORAMIX
577 ErrorF("+xinerama Enable XINERAMA extension\n");
578 ErrorF("-xinerama Disable XINERAMA extension\n");
579#endif
580 ErrorF
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");
586#ifdef XDMCP
587 XdmcpUseMsg();
588#endif
589 XkbUseMsg();
590 ddxUseMsg();
591}
592
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 "-".
598 * --kvajk
599 */
600static int
601VerifyDisplayName(const char *d)
602{
603 int i;
604 int period_found = FALSE;
605 int after_period = 0;
606
607 if (d == (char *) 0)
608 return 0; /* null */
609 if (*d == '\0')
610 return 0; /* empty */
611 if (*d == '-')
612 return 0; /* could be confused for an option */
613 if (*d == '.')
614 return 0; /* must not equal "." or ".." */
615 if (strchr(d, '/') != (char *) 0)
616 return 0; /* very important!!! */
617
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)
620 */
621 for (i = 0; i < strlen(d); i++) {
622 if (!isdigit(d[i])) {
623 if (d[i] != '.' || period_found)
624 return 0;
625 period_found = TRUE;
626 } else if (period_found)
627 after_period++;
628
629 if (after_period > 2)
630 return 0;
631 }
632
633 /* don't allow for :0. */
634 if (period_found && after_period == 0)
635 return 0;
636
637 if (atol(d) > INT_MAX)
638 return 0;
639
640 return 1;
641}
642
643/*
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.
647 */
648void
649ProcessCommandLine(int argc, char *argv[])
650{
651 int i, skip;
652
653 defaultKeyboardControl.autoRepeat = TRUE;
654
655#ifdef NO_PART_NET
656 PartialNetwork = FALSE;
657#else
658 PartialNetwork = TRUE;
659#endif
660
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))) {
664 i += (skip - 1);
665 }
666 else if (argv[i][0] == ':') {
667 /* initialize display */
668 display = argv[i];
669 display++;
670 if (!VerifyDisplayName(display)) {
671 ErrorF("Bad display name: %s\n", display);
672 UseMsg();
673 FatalError("Bad display name, exiting: %s\n", display);
674 }
675 }
676 else if (strcmp(argv[i], "-a") == 0) {
677 if (++i < argc)
678 defaultPointerControl.num = atoi(argv[i]);
679 else
680 UseMsg();
681 }
682 else if (strcmp(argv[i], "-ac") == 0) {
683 defeatAccessControl = TRUE;
684 }
685 else if (strcmp(argv[i], "-audit") == 0) {
686 if (++i < argc)
687 auditTrailLevel = atoi(argv[i]);
688 else
689 UseMsg();
690 }
691 else if (strcmp(argv[i], "-auth") == 0) {
692 if (++i < argc)
693 InitAuthorization(argv[i]);
694 else
695 UseMsg();
696 }
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) {
703 if (++i < argc)
704 defaultKeyboardControl.click = atoi(argv[i]);
705 else
706 UseMsg();
707 }
708 else if (strcmp(argv[i], "-c") == 0) {
709 defaultKeyboardControl.click = 0;
710 }
711 else if (strcmp(argv[i], "-cc") == 0) {
712 if (++i < argc)
713 defaultColorVisualClass = atoi(argv[i]);
714 else
715 UseMsg();
716 }
717 else if (strcmp(argv[i], "-core") == 0) {
718#if !defined(WIN32) || !defined(__MINGW32__)
719 struct rlimit core_limit;
720
721 getrlimit(RLIMIT_CORE, &core_limit);
722 core_limit.rlim_cur = core_limit.rlim_max;
723 setrlimit(RLIMIT_CORE, &core_limit);
724#endif
725 CoreDump = TRUE;
726 }
727 else if (strcmp(argv[i], "-nocursor") == 0) {
728 EnableCursor = FALSE;
729 }
730 else if (strcmp(argv[i], "-dpi") == 0) {
731 if (++i < argc)
732 monitorResolution = atoi(argv[i]);
733 else
734 UseMsg();
735 }
736 else if (strcmp(argv[i], "-displayfd") == 0) {
737 if (++i < argc) {
738 displayfd = atoi(argv[i]);
739 display = NULL;
740#ifdef LOCK_SERVER
741 nolock = TRUE;
742#endif
743 }
744 else
745 UseMsg();
746 }
747#ifdef DPMSExtension
748 else if (strcmp(argv[i], "dpms") == 0)
749 /* ignored for compatibility */ ;
750 else if (strcmp(argv[i], "-dpms") == 0)
751 DPMSDisabledSwitch = TRUE;
752#endif
753 else if (strcmp(argv[i], "-deferglyphs") == 0) {
754 if (++i >= argc || !ParseGlyphCachingMode(argv[i]))
755 UseMsg();
756 }
757 else if (strcmp(argv[i], "-f") == 0) {
758 if (++i < argc)
759 defaultKeyboardControl.bell = atoi(argv[i]);
760 else
761 UseMsg();
762 }
763 else if (strcmp(argv[i], "-fc") == 0) {
764 if (++i < argc)
765 defaultCursorFont = argv[i];
766 else
767 UseMsg();
768 }
769 else if (strcmp(argv[i], "-fn") == 0) {
770 if (++i < argc)
771 defaultTextFont = argv[i];
772 else
773 UseMsg();
774 }
775 else if (strcmp(argv[i], "-fp") == 0) {
776 if (++i < argc) {
777 defaultFontPath = argv[i];
778 }
779 else
780 UseMsg();
781 }
782 else if (strcmp(argv[i], "-help") == 0) {
783 UseMsg();
784 exit(0);
785 }
786 else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) {
787 if (skip > 0)
788 i += skip - 1;
789 else
790 UseMsg();
791 }
792#ifdef RLIMIT_DATA
793 else if (strcmp(argv[i], "-ld") == 0) {
794 if (++i < argc) {
795 limitDataSpace = atoi(argv[i]);
796 if (limitDataSpace > 0)
797 limitDataSpace *= 1024;
798 }
799 else
800 UseMsg();
801 }
802#endif
803#ifdef RLIMIT_NOFILE
804 else if (strcmp(argv[i], "-lf") == 0) {
805 if (++i < argc)
806 limitNoFile = atoi(argv[i]);
807 else
808 UseMsg();
809 }
810#endif
811#ifdef RLIMIT_STACK
812 else if (strcmp(argv[i], "-ls") == 0) {
813 if (++i < argc) {
814 limitStackSpace = atoi(argv[i]);
815 if (limitStackSpace > 0)
816 limitStackSpace *= 1024;
817 }
818 else
819 UseMsg();
820 }
821#endif
822#ifdef LOCK_SERVER
823 else if (strcmp(argv[i], "-nolock") == 0) {
824#if !defined(WIN32) && !defined(__CYGWIN__)
825 if (getuid() != 0)
826 ErrorF
827 ("Warning: the -nolock option can only be used by root\n");
828 else
829#endif
830 nolock = TRUE;
831 }
832#endif
833 else if (strcmp(argv[i], "-nolisten") == 0) {
834 if (++i < argc) {
835 if (_XSERVTransNoListen(argv[i]))
836 ErrorF("Failed to disable listen for %s transport",
837 argv[i]);
838 }
839 else
840 UseMsg();
841 }
842 else if (strcmp(argv[i], "-noreset") == 0) {
843 dispatchExceptionAtReset = 0;
844 }
845 else if (strcmp(argv[i], "-reset") == 0) {
846 dispatchExceptionAtReset = DE_RESET;
847 }
848 else if (strcmp(argv[i], "-p") == 0) {
849 if (++i < argc)
850 defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) *
851 MILLI_PER_MIN;
852 else
853 UseMsg();
854 }
855 else if (strcmp(argv[i], "-pogo") == 0) {
856 dispatchException = DE_TERMINATE;
857 }
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) {
869 if (++i < argc)
870 defaultScreenSaverTime = ((CARD32) atoi(argv[i])) *
871 MILLI_PER_MIN;
872 else
873 UseMsg();
874 }
875 else if (strcmp(argv[i], "-seat") == 0) {
876 if (++i < argc)
877 SeatId = argv[i];
878 else
879 UseMsg();
880 }
881 else if (strcmp(argv[i], "-t") == 0) {
882 if (++i < argc)
883 defaultPointerControl.threshold = atoi(argv[i]);
884 else
885 UseMsg();
886 }
887 else if (strcmp(argv[i], "-terminate") == 0) {
888 dispatchExceptionAtReset = DE_TERMINATE;
889 }
890 else if (strcmp(argv[i], "-to") == 0) {
891 if (++i < argc)
892 TimeOutValue = ((CARD32) atoi(argv[i])) * MILLI_PER_SECOND;
893 else
894 UseMsg();
895 }
896 else if (strcmp(argv[i], "-tst") == 0) {
897 noTestExtensions = TRUE;
898 }
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)
906 whiteRoot = TRUE;
907 else if (strcmp(argv[i], "-background") == 0) {
908 if (++i < argc) {
909 if (!strcmp(argv[i], "none"))
910 bgNoneRoot = TRUE;
911 else
912 UseMsg();
913 }
914 }
915 else if (strcmp(argv[i], "-maxbigreqsize") == 0) {
916 if (++i < argc) {
917 long reqSizeArg = atol(argv[i]);
918
919 /* Request size > 128MB does not make much sense... */
920 if (reqSizeArg > 0L && reqSizeArg < 128L) {
921 maxBigRequestSize = (reqSizeArg * 1048576L) - 1L;
922 }
923 else {
924 UseMsg();
925 }
926 }
927 else {
928 UseMsg();
929 }
930 }
931#ifdef PANORAMIX
932 else if (strcmp(argv[i], "+xinerama") == 0) {
933 noPanoramiXExtension = FALSE;
934 }
935 else if (strcmp(argv[i], "-xinerama") == 0) {
936 noPanoramiXExtension = TRUE;
937 }
938 else if (strcmp(argv[i], "-disablexineramaextension") == 0) {
939 PanoramiXExtensionDisabledHack = TRUE;
940 }
941#endif
942 else if (strcmp(argv[i], "-I") == 0) {
943 /* ignore all remaining arguments */
944 break;
945 }
946 else if (strncmp(argv[i], "tty", 3) == 0) {
947 /* init supplies us with this useless information */
948 }
949#ifdef XDMCP
950 else if ((skip = XdmcpOptions(argc, argv, i)) != i) {
951 i = skip - 1;
952 }
953#endif
954#ifdef SMART_SCHEDULE_POSSIBLE
955 else if (strcmp(argv[i], "-dumbSched") == 0) {
956 SmartScheduleDisable = TRUE;
957 }
958 else if (strcmp(argv[i], "-schedInterval") == 0) {
959 if (++i < argc) {
960 SmartScheduleInterval = atoi(argv[i]);
961 SmartScheduleSlice = SmartScheduleInterval;
962 }
963 else
964 UseMsg();
965 }
966 else if (strcmp(argv[i], "-schedMax") == 0) {
967 if (++i < argc) {
968 SmartScheduleMaxSlice = atoi(argv[i]);
969 }
970 else
971 UseMsg();
972 }
973#endif
974 else if (strcmp(argv[i], "-render") == 0) {
975 if (++i < argc) {
976 int policy = PictureParseCmapPolicy(argv[i]);
977
978 if (policy != PictureCmapPolicyInvalid)
979 PictureCmapPolicy = policy;
980 else
981 UseMsg();
982 }
983 else
984 UseMsg();
985 }
986 else if (strcmp(argv[i], "-sigstop") == 0) {
987 RunFromSigStopParent = TRUE;
988 }
989 else if (strcmp(argv[i], "+extension") == 0) {
990 if (++i < argc) {
991 if (!EnableDisableExtension(argv[i], TRUE))
992 EnableDisableExtensionError(argv[i], TRUE);
993 }
994 else
995 UseMsg();
996 }
997 else if (strcmp(argv[i], "-extension") == 0) {
998 if (++i < argc) {
999 if (!EnableDisableExtension(argv[i], FALSE))
1000 EnableDisableExtensionError(argv[i], FALSE);
1001 }
1002 else
1003 UseMsg();
1004 }
1005 else {
1006 ErrorF("Unrecognized option: %s\n", argv[i]);
1007 UseMsg();
1008 FatalError("Unrecognized option: %s\n", argv[i]);
1009 }
1010 }
1011}
1012
1013/* Implement a simple-minded font authorization scheme. The authorization
1014 name is "hp-hostname-1", the contents are simply the host name. */
1015int
1016set_font_authorizations(char **authorizations, int *authlen, pointer client)
1017{
1018#define AUTHORIZATION_NAME "hp-hostname-1"
1019#if defined(TCPCONN) || defined(STREAMSCONN)
1020 static char *result = NULL;
1021 static char *p = NULL;
1022
1023 if (p == NULL) {
1024 char hname[1024], *hnameptr;
1025 unsigned int len;
1026
1027#if defined(IPv6) && defined(AF_INET6)
1028 struct addrinfo hints, *ai = NULL;
1029#else
1030 struct hostent *host;
1031
1032#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1033 _Xgethostbynameparams hparams;
1034#endif
1035#endif
1036
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;
1043 }
1044 else {
1045 hnameptr = hname;
1046 }
1047#else
1048 host = _XGethostbyname(hname, hparams);
1049 if (host == NULL)
1050 hnameptr = hname;
1051 else
1052 hnameptr = host->h_name;
1053#endif
1054
1055 len = strlen(hnameptr) + 1;
1056 result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4);
1057
1058 p = result;
1059 *p++ = sizeof(AUTHORIZATION_NAME) >> 8;
1060 *p++ = sizeof(AUTHORIZATION_NAME) & 0xff;
1061 *p++ = (len) >> 8;
1062 *p++ = (len & 0xff);
1063
1064 memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME));
1065 p += sizeof(AUTHORIZATION_NAME);
1066 memmove(p, hnameptr, len);
1067 p += len;
1068#if defined(IPv6) && defined(AF_INET6)
1069 if (ai) {
1070 freeaddrinfo(ai);
1071 }
1072#endif
1073 }
1074 *authlen = p - result;
1075 *authorizations = result;
1076 return 1;
1077#else /* TCPCONN */
1078 return 0;
1079#endif /* TCPCONN */
1080}
1081
1082void *
1083Xalloc(unsigned long amount)
1084{
1085 /*
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.
1089 *
1090 * -- Mikhail Gusarov
1091 */
1092 if ((long) amount <= 0)
1093 ErrorF("Warning: Xalloc: "
1094 "requesting unpleasantly large amount of memory: %lu bytes.\n",
1095 amount);
1096
1097 return malloc(amount);
1098}
1099
1100void *
1101XNFalloc(unsigned long amount)
1102{
1103 void *ptr = malloc(amount);
1104
1105 if (!ptr)
1106 FatalError("Out of memory");
1107 return ptr;
1108}
1109
1110void *
1111Xcalloc(unsigned long amount)
1112{
1113 return calloc(1, amount);
1114}
1115
1116void *
1117XNFcalloc(unsigned long amount)
1118{
1119 void *ret = calloc(1, amount);
1120
1121 if (!ret)
1122 FatalError("XNFcalloc: Out of memory");
1123 return ret;
1124}
1125
1126void *
1127Xrealloc(void *ptr, unsigned long amount)
1128{
1129 /*
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.
1133 *
1134 * -- Mikhail Gusarov
1135 */
1136 if ((long) amount <= 0)
1137 ErrorF("Warning: Xrealloc: "
1138 "requesting unpleasantly large amount of memory: %lu bytes.\n",
1139 amount);
1140
1141 return realloc(ptr, amount);
1142}
1143
1144void *
1145XNFrealloc(void *ptr, unsigned long amount)
1146{
1147 void *ret = realloc(ptr, amount);
1148
1149 if (!ret)
1150 FatalError("XNFrealloc: Out of memory");
1151 return ret;
1152}
1153
1154void
1155Xfree(void *ptr)
1156{
1157 free(ptr);
1158}
1159
1160char *
1161Xstrdup(const char *s)
1162{
1163 if (s == NULL)
1164 return NULL;
1165 return strdup(s);
1166}
1167
1168char *
1169XNFstrdup(const char *s)
1170{
1171 char *ret;
1172
1173 if (s == NULL)
1174 return NULL;
1175
1176 ret = strdup(s);
1177 if (!ret)
1178 FatalError("XNFstrdup: Out of memory");
1179 return ret;
1180}
1181
1182void
1183SmartScheduleStopTimer(void)
1184{
1185#ifdef SMART_SCHEDULE_POSSIBLE
1186 struct itimerval timer;
1187
1188 if (SmartScheduleDisable)
1189 return;
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);
1195#endif
1196}
1197
1198void
1199SmartScheduleStartTimer(void)
1200{
1201#ifdef SMART_SCHEDULE_POSSIBLE
1202 struct itimerval timer;
1203
1204 if (SmartScheduleDisable)
1205 return;
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);
1211#endif
1212}
1213
1214static void
1215SmartScheduleTimer(int sig)
1216{
1217 SmartScheduleTime += SmartScheduleInterval;
1218}
1219
1220void
1221SmartScheduleInit(void)
1222{
1223#ifdef SMART_SCHEDULE_POSSIBLE
1224 struct sigaction act;
1225
1226 if (SmartScheduleDisable)
1227 return;
1228
1229 memset((char *) &act, 0, sizeof(struct sigaction));
1230
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;
1238 }
1239#endif
1240}
1241
1242#ifdef SIG_BLOCK
1243static sigset_t PreviousSignalMask;
1244static int BlockedSignalCount;
1245#endif
1246
1247void
1248OsBlockSignals(void)
1249{
1250#ifdef SIG_BLOCK
1251 if (BlockedSignalCount++ == 0) {
1252 sigset_t set;
1253
1254#ifdef SIGIO
1255 OsBlockSIGIO();
1256#endif
1257 sigemptyset(&set);
1258 sigaddset(&set, SIGALRM);
1259 sigaddset(&set, SIGVTALRM);
1260#ifdef SIGWINCH
1261 sigaddset(&set, SIGWINCH);
1262#endif
1263 sigaddset(&set, SIGTSTP);
1264 sigaddset(&set, SIGTTIN);
1265 sigaddset(&set, SIGTTOU);
1266 sigaddset(&set, SIGCHLD);
1267 sigprocmask(SIG_BLOCK, &set, &PreviousSignalMask);
1268 }
1269#endif
1270}
1271
1272#ifdef SIG_BLOCK
1273static sig_atomic_t sigio_blocked;
1274static sigset_t PreviousSigIOMask;
1275#endif
1276
1277/**
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.
1280 */
1281int
1282OsBlockSIGIO(void)
1283{
1284#ifdef SIGIO
1285#ifdef SIG_BLOCK
1286 if (sigio_blocked++ == 0) {
1287 sigset_t set;
1288 int ret;
1289
1290 sigemptyset(&set);
1291 sigaddset(&set, SIGIO);
1292 sigprocmask(SIG_BLOCK, &set, &PreviousSigIOMask);
1293 ret = sigismember(&PreviousSigIOMask, SIGIO);
1294 return ret;
1295 }
1296#endif
1297#endif
1298 return 1;
1299}
1300
1301void
1302OsReleaseSIGIO(void)
1303{
1304#ifdef SIGIO
1305#ifdef SIG_BLOCK
1306 if (--sigio_blocked == 0) {
1307 sigprocmask(SIG_SETMASK, &PreviousSigIOMask, 0);
1308 } else if (sigio_blocked < 0) {
1309 BUG_WARN(sigio_blocked < 0);
1310 sigio_blocked = 0;
1311 }
1312#endif
1313#endif
1314}
1315
1316void
1317OsReleaseSignals(void)
1318{
1319#ifdef SIG_BLOCK
1320 if (--BlockedSignalCount == 0) {
1321 sigprocmask(SIG_SETMASK, &PreviousSignalMask, 0);
1322 OsReleaseSIGIO();
1323 }
1324#endif
1325}
1326
1327void
1328OsResetSignals(void)
1329{
1330#ifdef SIG_BLOCK
1331 while (BlockedSignalCount > 0)
1332 OsReleaseSignals();
1333#ifdef SIGIO
1334 while (sigio_blocked > 0)
1335 OsReleaseSIGIO();
1336#endif
1337#endif
1338}
1339
1340/*
1341 * Pending signals may interfere with core dumping. Provide a
1342 * mechanism to block signals when aborting.
1343 */
1344
1345void
1346OsAbort(void)
1347{
1348#ifndef __APPLE__
1349 OsBlockSignals();
1350#endif
1351 abort();
1352}
1353
1354#if !defined(WIN32)
1355/*
1356 * "safer" versions of system(3), popen(3) and pclose(3) which give up
1357 * all privs before running a command.
1358 *
1359 * This is based on the code in FreeBSD 2.2 libc.
1360 *
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.
1363 */
1364
1365int
1366System(const char *command)
1367{
1368 int pid, p;
1369 void (*csig) (int);
1370 int status;
1371
1372 if (!command)
1373 return 1;
1374
1375 csig = signal(SIGCHLD, SIG_DFL);
1376 if (csig == SIG_ERR) {
1377 perror("signal");
1378 return -1;
1379 }
1380 DebugF("System: `%s'\n", command);
1381
1382 switch (pid = fork()) {
1383 case -1: /* error */
1384 p = -1;
1385 case 0: /* child */
1386 if (setgid(getgid()) == -1)
1387 _exit(127);
1388 if (setuid(getuid()) == -1)
1389 _exit(127);
1390 execl("/bin/sh", "sh", "-c", command, (char *) NULL);
1391 _exit(127);
1392 default: /* parent */
1393 do {
1394 p = waitpid(pid, &status, 0);
1395 } while (p == -1 && errno == EINTR);
1396
1397 }
1398
1399 if (signal(SIGCHLD, csig) == SIG_ERR) {
1400 perror("signal");
1401 return -1;
1402 }
1403
1404 return p == -1 ? -1 : status;
1405}
1406
1407static struct pid {
1408 struct pid *next;
1409 FILE *fp;
1410 int pid;
1411} *pidlist;
1412
1413OsSigHandlerPtr old_alarm = NULL; /* XXX horrible awful hack */
1414
1415pointer
1416Popen(const char *command, const char *type)
1417{
1418 struct pid *cur;
1419 FILE *iop;
1420 int pdes[2], pid;
1421
1422 if (command == NULL || type == NULL)
1423 return NULL;
1424
1425 if ((*type != 'r' && *type != 'w') || type[1])
1426 return NULL;
1427
1428 if ((cur = malloc(sizeof(struct pid))) == NULL)
1429 return NULL;
1430
1431 if (pipe(pdes) < 0) {
1432 free(cur);
1433 return NULL;
1434 }
1435
1436 /* Ignore the smart scheduler while this is going on */
1437 old_alarm = OsSignal(SIGALRM, SIG_IGN);
1438 if (old_alarm == SIG_ERR) {
1439 close(pdes[0]);
1440 close(pdes[1]);
1441 free(cur);
1442 perror("signal");
1443 return NULL;
1444 }
1445
1446 switch (pid = fork()) {
1447 case -1: /* error */
1448 close(pdes[0]);
1449 close(pdes[1]);
1450 free(cur);
1451 if (OsSignal(SIGALRM, old_alarm) == SIG_ERR)
1452 perror("signal");
1453 return NULL;
1454 case 0: /* child */
1455 if (setgid(getgid()) == -1)
1456 _exit(127);
1457 if (setuid(getuid()) == -1)
1458 _exit(127);
1459 if (*type == 'r') {
1460 if (pdes[1] != 1) {
1461 /* stdout */
1462 dup2(pdes[1], 1);
1463 close(pdes[1]);
1464 }
1465 close(pdes[0]);
1466 }
1467 else {
1468 if (pdes[0] != 0) {
1469 /* stdin */
1470 dup2(pdes[0], 0);
1471 close(pdes[0]);
1472 }
1473 close(pdes[1]);
1474 }
1475 execl("/bin/sh", "sh", "-c", command, (char *) NULL);
1476 _exit(127);
1477 }
1478
1479 /* Avoid EINTR during stdio calls */
1480 OsBlockSignals();
1481
1482 /* parent */
1483 if (*type == 'r') {
1484 iop = fdopen(pdes[0], type);
1485 close(pdes[1]);
1486 }
1487 else {
1488 iop = fdopen(pdes[1], type);
1489 close(pdes[0]);
1490 }
1491
1492 cur->fp = iop;
1493 cur->pid = pid;
1494 cur->next = pidlist;
1495 pidlist = cur;
1496
1497 DebugF("Popen: `%s', fp = %p\n", command, iop);
1498
1499 return iop;
1500}
1501
1502/* fopen that drops privileges */
1503pointer
1504Fopen(const char *file, const char *type)
1505{
1506 FILE *iop;
1507
1508#ifndef HAS_SAVED_IDS_AND_SETEUID
1509 struct pid *cur;
1510 int pdes[2], pid;
1511
1512 if (file == NULL || type == NULL)
1513 return NULL;
1514
1515 if ((*type != 'r' && *type != 'w') || type[1])
1516 return NULL;
1517
1518 if ((cur = malloc(sizeof(struct pid))) == NULL)
1519 return NULL;
1520
1521 if (pipe(pdes) < 0) {
1522 free(cur);
1523 return NULL;
1524 }
1525
1526 switch (pid = fork()) {
1527 case -1: /* error */
1528 close(pdes[0]);
1529 close(pdes[1]);
1530 free(cur);
1531 return NULL;
1532 case 0: /* child */
1533 if (setgid(getgid()) == -1)
1534 _exit(127);
1535 if (setuid(getuid()) == -1)
1536 _exit(127);
1537 if (*type == 'r') {
1538 if (pdes[1] != 1) {
1539 /* stdout */
1540 dup2(pdes[1], 1);
1541 close(pdes[1]);
1542 }
1543 close(pdes[0]);
1544 }
1545 else {
1546 if (pdes[0] != 0) {
1547 /* stdin */
1548 dup2(pdes[0], 0);
1549 close(pdes[0]);
1550 }
1551 close(pdes[1]);
1552 }
1553 execl("/bin/cat", "cat", file, (char *) NULL);
1554 _exit(127);
1555 }
1556
1557 /* Avoid EINTR during stdio calls */
1558 OsBlockSignals();
1559
1560 /* parent */
1561 if (*type == 'r') {
1562 iop = fdopen(pdes[0], type);
1563 close(pdes[1]);
1564 }
1565 else {
1566 iop = fdopen(pdes[1], type);
1567 close(pdes[0]);
1568 }
1569
1570 cur->fp = iop;
1571 cur->pid = pid;
1572 cur->next = pidlist;
1573 pidlist = cur;
1574
1575 DebugF("Fopen(%s), fp = %p\n", file, iop);
1576
1577 return iop;
1578#else
1579 int ruid, euid;
1580
1581 ruid = getuid();
1582 euid = geteuid();
1583
1584 if (seteuid(ruid) == -1) {
1585 return NULL;
1586 }
1587 iop = fopen(file, type);
1588
1589 if (seteuid(euid) == -1) {
1590 fclose(iop);
1591 return NULL;
1592 }
1593 return iop;
1594#endif /* HAS_SAVED_IDS_AND_SETEUID */
1595}
1596
1597int
1598Pclose(pointer iop)
1599{
1600 struct pid *cur, *last;
1601 int pstat;
1602 int pid;
1603
1604 DebugF("Pclose: fp = %p\n", iop);
1605 fclose(iop);
1606
1607 for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
1608 if (cur->fp == iop)
1609 break;
1610 if (cur == NULL)
1611 return -1;
1612
1613 do {
1614 pid = waitpid(cur->pid, &pstat, 0);
1615 } while (pid == -1 && errno == EINTR);
1616
1617 if (last == NULL)
1618 pidlist = cur->next;
1619 else
1620 last->next = cur->next;
1621 free(cur);
1622
1623 /* allow EINTR again */
1624 OsReleaseSignals();
1625
1626 if (old_alarm && OsSignal(SIGALRM, old_alarm) == SIG_ERR) {
1627 perror("signal");
1628 return -1;
1629 }
1630
1631 return pid == -1 ? -1 : pstat;
1632}
1633
1634int
1635Fclose(pointer iop)
1636{
1637#ifdef HAS_SAVED_IDS_AND_SETEUID
1638 return fclose(iop);
1639#else
1640 return Pclose(iop);
1641#endif
1642}
1643
1644#endif /* !WIN32 */
1645
1646#ifdef WIN32
1647
1648#include <X11/Xwindows.h>
1649
1650const char *
1651Win32TempDir()
1652{
1653 static char buffer[PATH_MAX];
1654
1655 if (GetTempPath(sizeof(buffer), buffer)) {
1656 int len;
1657
1658 buffer[sizeof(buffer) - 1] = 0;
1659 len = strlen(buffer);
1660 if (len > 0)
1661 if (buffer[len - 1] == '\\')
1662 buffer[len - 1] = 0;
1663 return buffer;
1664 }
1665 if (getenv("TEMP") != NULL)
1666 return getenv("TEMP");
1667 else if (getenv("TMP") != NULL)
1668 return getenv("TMP");
1669 else
1670 return "/tmp";
1671}
1672
1673int
1674System(const char *cmdline)
1675{
1676 STARTUPINFO si;
1677 PROCESS_INFORMATION pi;
1678 DWORD dwExitCode;
1679 char *cmd = strdup(cmdline);
1680
1681 ZeroMemory(&si, sizeof(si));
1682 si.cb = sizeof(si);
1683 ZeroMemory(&pi, sizeof(pi));
1684
1685 if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
1686 LPVOID buffer;
1687
1688 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1689 FORMAT_MESSAGE_FROM_SYSTEM |
1690 FORMAT_MESSAGE_IGNORE_INSERTS,
1691 NULL,
1692 GetLastError(),
1693 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1694 (LPTSTR) &buffer, 0, NULL)) {
1695 ErrorF("[xkb] Starting '%s' failed!\n", cmdline);
1696 }
1697 else {
1698 ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer);
1699 LocalFree(buffer);
1700 }
1701
1702 free(cmd);
1703 return -1;
1704 }
1705 /* Wait until child process exits. */
1706 WaitForSingleObject(pi.hProcess, INFINITE);
1707
1708 GetExitCodeProcess(pi.hProcess, &dwExitCode);
1709
1710 /* Close process and thread handles. */
1711 CloseHandle(pi.hProcess);
1712 CloseHandle(pi.hThread);
1713 free(cmd);
1714
1715 return dwExitCode;
1716}
1717#endif
1718
1719/*
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.
1724 */
1725
1726/* Consider LD* variables insecure? */
1727#ifndef REMOVE_ENV_LD
1728#define REMOVE_ENV_LD 1
1729#endif
1730
1731/* Remove long environment variables? */
1732#ifndef REMOVE_LONG_ENV
1733#define REMOVE_LONG_ENV 1
1734#endif
1735
1736/*
1737 * Disallow stdout or stderr as pipes? It's possible to block the X server
1738 * when piping stdout+stderr to a pipe.
1739 *
1740 * Don't enable this because it looks like it's going to cause problems.
1741 */
1742#ifndef NO_OUTPUT_PIPES
1743#define NO_OUTPUT_PIPES 0
1744#endif
1745
1746/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
1747#ifndef CHECK_EUID
1748#ifndef WIN32
1749#define CHECK_EUID 1
1750#else
1751#define CHECK_EUID 0
1752#endif
1753#endif
1754
1755/*
1756 * Maybe the locale can be faked to make isprint(3) report that everything
1757 * is printable? Avoid it by default.
1758 */
1759#ifndef USE_ISPRINT
1760#define USE_ISPRINT 0
1761#endif
1762
1763#define MAX_ARG_LENGTH 128
1764#define MAX_ENV_LENGTH 256
1765#define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */
1766
1767#if USE_ISPRINT
1768#include <ctype.h>
1769#define checkPrintable(c) isprint(c)
1770#else
1771#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
1772#endif
1773
1774enum BadCode {
1775 NotBad = 0,
1776 UnsafeArg,
1777 ArgTooLong,
1778 UnprintableArg,
1779 EnvTooLong,
1780 OutputIsPipe,
1781 InternalError
1782};
1783
1784#if defined(VENDORSUPPORT)
1785#define BUGADDRESS VENDORSUPPORT
1786#elif defined(BUILDERADDR)
1787#define BUGADDRESS BUILDERADDR
1788#else
1789#define BUGADDRESS "xorg@freedesktop.org"
1790#endif
1791
1792void
1793CheckUserParameters(int argc, char **argv, char **envp)
1794{
1795 enum BadCode bad = NotBad;
1796 int i = 0, j;
1797 char *a, *e = NULL;
1798
1799#if CHECK_EUID
1800 if (geteuid() == 0 && getuid() != geteuid())
1801#endif
1802 {
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 */
1807 if (i >= argc)
1808 break;
1809 }
1810 else {
1811 if (strlen(argv[i]) > MAX_ARG_LENGTH) {
1812 bad = ArgTooLong;
1813 break;
1814 }
1815 }
1816 a = argv[i];
1817 while (*a) {
1818 if (checkPrintable(*a) == 0) {
1819 bad = UnprintableArg;
1820 break;
1821 }
1822 a++;
1823 }
1824 if (bad)
1825 break;
1826 }
1827 if (!bad) {
1828 /* Check each envp[] */
1829 for (i = 0; envp[i]; i++) {
1830
1831 /* Check for bad environment variables and values */
1832#if REMOVE_ENV_LD
1833 while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
1834 for (j = i; envp[j]; j++) {
1835 envp[j] = envp[j + 1];
1836 }
1837 }
1838#endif
1839 if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
1840#if REMOVE_LONG_ENV
1841 for (j = i; envp[j]; j++) {
1842 envp[j] = envp[j + 1];
1843 }
1844 i--;
1845#else
1846 char *eq;
1847 int len;
1848
1849 eq = strchr(envp[i], '=');
1850 if (!eq)
1851 continue;
1852 len = eq - envp[i];
1853 e = strndup(envp[i], len);
1854 if (!e) {
1855 bad = InternalError;
1856 break;
1857 }
1858 if (len >= 4 &&
1859 (strcmp(e + len - 4, "PATH") == 0 ||
1860 strcmp(e, "TERMCAP") == 0)) {
1861 if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
1862 bad = EnvTooLong;
1863 break;
1864 }
1865 else {
1866 free(e);
1867 }
1868 }
1869 else {
1870 bad = EnvTooLong;
1871 break;
1872 }
1873#endif
1874 }
1875 }
1876 }
1877#if NO_OUTPUT_PIPES
1878 if (!bad) {
1879 struct stat buf;
1880
1881 if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode))
1882 bad = OutputIsPipe;
1883 if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode))
1884 bad = OutputIsPipe;
1885 }
1886#endif
1887 }
1888 switch (bad) {
1889 case NotBad:
1890 return;
1891 case UnsafeArg:
1892 ErrorF("Command line argument number %d is unsafe\n", i);
1893 break;
1894 case ArgTooLong:
1895 ErrorF("Command line argument number %d is too long\n", i);
1896 break;
1897 case UnprintableArg:
1898 ErrorF("Command line argument number %d contains unprintable"
1899 " characters\n", i);
1900 break;
1901 case EnvTooLong:
1902 ErrorF("Environment variable `%s' is too long\n", e);
1903 break;
1904 case OutputIsPipe:
1905 ErrorF("Stdout and/or stderr is a pipe\n");
1906 break;
1907 case InternalError:
1908 ErrorF("Internal Error\n");
1909 break;
1910 default:
1911 ErrorF("Unknown error\n");
1912 break;
1913 }
1914 FatalError("X server aborted because of unsafe environment\n");
1915}
1916
1917/*
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).
1921 */
1922
1923#ifdef USE_PAM
1924#include <security/pam_appl.h>
1925#include <security/pam_misc.h>
1926#include <pwd.h>
1927#endif /* USE_PAM */
1928
1929void
1930CheckUserAuthorization(void)
1931{
1932#ifdef USE_PAM
1933 static struct pam_conv conv = {
1934 misc_conv,
1935 NULL
1936 };
1937
1938 pam_handle_t *pamh = NULL;
1939 struct passwd *pw;
1940 int retval;
1941
1942 if (getuid() != geteuid()) {
1943 pw = getpwuid(getuid());
1944 if (pw == NULL)
1945 FatalError("getpwuid() failed for uid %d\n", getuid());
1946
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");
1951
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");
1957 }
1958
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");
1964 }
1965
1966 /* this is not a session, so do not do session management */
1967 pam_end(pamh, PAM_SUCCESS);
1968 }
1969#endif
1970}
1971
1972/*
1973 * Tokenize a string into a NULL terminated array of strings. Always returns
1974 * an allocated array unless an error occurs.
1975 */
1976char **
1977xstrtokenize(const char *str, const char *separators)
1978{
1979 char **list, **nlist;
1980 char *tok, *tmp;
1981 unsigned num = 0, n;
1982
1983 if (!str)
1984 return NULL;
1985 list = calloc(1, sizeof(*list));
1986 if (!list)
1987 return NULL;
1988 tmp = strdup(str);
1989 if (!tmp)
1990 goto error;
1991 for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) {
1992 nlist = realloc(list, (num + 2) * sizeof(*list));
1993 if (!nlist)
1994 goto error;
1995 list = nlist;
1996 list[num] = strdup(tok);
1997 if (!list[num])
1998 goto error;
1999 list[++num] = NULL;
2000 }
2001 free(tmp);
2002 return list;
2003
2004 error:
2005 free(tmp);
2006 for (n = 0; n < num; n++)
2007 free(list[n]);
2008 free(list);
2009 return NULL;
2010}
2011
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.
2014 */
2015void
2016FormatInt64(int64_t num, char *string)
2017{
2018 if (num < 0) {
2019 string[0] = '-';
2020 num *= -1;
2021 string++;
2022 }
2023 FormatUInt64(num, string);
2024}
2025
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. */
2028void
2029FormatUInt64(uint64_t num, char *string)
2030{
2031 uint64_t divisor;
2032 int len;
2033 int i;
2034
2035 for (len = 1, divisor = 10;
2036 len < 20 && num / divisor;
2037 len++, divisor *= 10);
2038
2039 for (i = len, divisor = 1; i > 0; i--, divisor *= 10)
2040 string[i - 1] = '0' + ((num / divisor) % 10);
2041
2042 string[len] = '\0';
2043}
2044
2045/**
2046 * Format a double number as %.2f.
2047 */
2048void
2049FormatDouble(double dbl, char *string)
2050{
2051 int slen = 0;
2052 uint64_t frac;
2053
2054 frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5;
2055 frac %= 100;
2056
2057 /* write decimal part to string */
2058 if (dbl < 0 && dbl > -1)
2059 string[slen++] = '-';
2060 FormatInt64((int64_t)dbl, &string[slen]);
2061
2062 while(string[slen] != '\0')
2063 slen++;
2064
2065 /* append fractional part, but only if we have enough characters. We
2066 * expect string to be 21 chars (incl trailing \0) */
2067 if (slen <= 17) {
2068 string[slen++] = '.';
2069 if (frac < 10)
2070 string[slen++] = '0';
2071
2072 FormatUInt64(frac, &string[slen]);
2073 }
2074}
2075
2076
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. */
2079void
2080FormatUInt64Hex(uint64_t num, char *string)
2081{
2082 uint64_t divisor;
2083 int len;
2084 int i;
2085
2086 for (len = 1, divisor = 0x10;
2087 len < 16 && num / divisor;
2088 len++, divisor *= 0x10);
2089
2090 for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) {
2091 int val = (num / divisor) % 0x10;
2092
2093 if (val < 10)
2094 string[i - 1] = '0' + val;
2095 else
2096 string[i - 1] = 'a' + val - 10;
2097 }
2098
2099 string[len] = '\0';
2100}
2101
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
2106 */
2107int
2108os_move_fd(int fd)
2109{
2110 int newfd;
2111
2112#ifdef F_DUPFD_CLOEXEC
2113 newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS);
2114#else
2115 newfd = fcntl(fd, F_DUPFD, MAXCLIENTS);
2116#endif
2117 if (newfd < 0)
2118 return fd;
2119#ifndef F_DUPFD_CLOEXEC
2120 fcntl(newfd, F_SETFD, FD_CLOEXEC);
2121#endif
2122 close(fd);
2123 return newfd;
2124}