1706f2543Smrg/*
2706f2543Smrg
3706f2543SmrgCopyright 1987, 1998  The Open Group
4706f2543Smrg
5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that
7706f2543Smrgthe above copyright notice appear in all copies and that both that
8706f2543Smrgcopyright notice and this permission notice appear in supporting
9706f2543Smrgdocumentation.
10706f2543Smrg
11706f2543SmrgThe above copyright notice and this permission notice shall be included
12706f2543Smrgin all copies or substantial portions of the Software.
13706f2543Smrg
14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15706f2543SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16706f2543SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17706f2543SmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18706f2543SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19706f2543SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20706f2543SmrgOTHER DEALINGS IN THE SOFTWARE.
21706f2543Smrg
22706f2543SmrgExcept as contained in this notice, the name of The Open Group shall
23706f2543Smrgnot be used in advertising or otherwise to promote the sale, use or
24706f2543Smrgother dealings in this Software without prior written authorization
25706f2543Smrgfrom The Open Group.
26706f2543Smrg
27706f2543Smrg
28706f2543SmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
29706f2543SmrgCopyright 1994 Quarterdeck Office Systems.
30706f2543Smrg
31706f2543Smrg                        All Rights Reserved
32706f2543Smrg
33706f2543SmrgPermission to use, copy, modify, and distribute this software and its
34706f2543Smrgdocumentation for any purpose and without fee is hereby granted,
35706f2543Smrgprovided that the above copyright notice appear in all copies and that
36706f2543Smrgboth that copyright notice and this permission notice appear in
37706f2543Smrgsupporting documentation, and that the names of Digital and
38706f2543SmrgQuarterdeck not be used in advertising or publicity pertaining to
39706f2543Smrgdistribution of the software without specific, written prior
40706f2543Smrgpermission.
41706f2543Smrg
42706f2543SmrgDIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
43706f2543SmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
44706f2543SmrgFITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
45706f2543SmrgOR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
46706f2543SmrgOF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
47706f2543SmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
48706f2543SmrgOR PERFORMANCE OF THIS SOFTWARE.
49706f2543Smrg
50706f2543Smrg*/
51706f2543Smrg
52706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
53706f2543Smrg#include <dix-config.h>
54706f2543Smrg#endif
55706f2543Smrg
56706f2543Smrg#ifdef __CYGWIN__
57706f2543Smrg#include <stdlib.h>
58706f2543Smrg#include <signal.h>
59706f2543Smrg/*
60706f2543Smrg   Sigh... We really need a prototype for this to know it is stdcall,
61706f2543Smrg   but #include-ing <windows.h> here is not a good idea...
62706f2543Smrg*/
63706f2543Smrg__stdcall unsigned long GetTickCount(void);
64706f2543Smrg#endif
65706f2543Smrg
66706f2543Smrg#if defined(WIN32) && !defined(__CYGWIN__)
67706f2543Smrg#include <X11/Xwinsock.h>
68706f2543Smrg#endif
69706f2543Smrg#include <X11/Xos.h>
70706f2543Smrg#include <stdio.h>
71706f2543Smrg#include <time.h>
72706f2543Smrg#if !defined(WIN32) || !defined(__MINGW32__)
73706f2543Smrg#include <sys/time.h>
74706f2543Smrg#include <sys/resource.h>
75706f2543Smrg#endif
76706f2543Smrg#include "misc.h"
77706f2543Smrg#include <X11/X.h>
78706f2543Smrg#define XSERV_t
79706f2543Smrg#define TRANS_SERVER
80706f2543Smrg#define TRANS_REOPEN
81706f2543Smrg#include <X11/Xtrans/Xtrans.h>
82706f2543Smrg#include "input.h"
83706f2543Smrg#include "dixfont.h"
84706f2543Smrg#include "osdep.h"
85706f2543Smrg#include "extension.h"
86706f2543Smrg#ifdef X_POSIX_C_SOURCE
87706f2543Smrg#define _POSIX_C_SOURCE X_POSIX_C_SOURCE
88706f2543Smrg#include <signal.h>
89706f2543Smrg#undef _POSIX_C_SOURCE
90706f2543Smrg#else
91706f2543Smrg#if defined(_POSIX_SOURCE)
92706f2543Smrg#include <signal.h>
93706f2543Smrg#else
94706f2543Smrg#define _POSIX_SOURCE
95706f2543Smrg#include <signal.h>
96706f2543Smrg#undef _POSIX_SOURCE
97706f2543Smrg#endif
98706f2543Smrg#endif
99706f2543Smrg#ifndef WIN32
100706f2543Smrg#include <sys/wait.h>
101706f2543Smrg#endif
102706f2543Smrg#if !defined(SYSV) && !defined(WIN32)
103706f2543Smrg#include <sys/resource.h>
104706f2543Smrg#endif
105706f2543Smrg#include <sys/stat.h>
106706f2543Smrg#include <ctype.h>    /* for isspace */
107706f2543Smrg#include <stdarg.h>
108706f2543Smrg
109706f2543Smrg#include <stdlib.h>	/* for malloc() */
110706f2543Smrg
111706f2543Smrg#if defined(TCPCONN) || defined(STREAMSCONN)
112706f2543Smrg# ifndef WIN32
113706f2543Smrg#  include <netdb.h>
114706f2543Smrg# endif
115706f2543Smrg#endif
116706f2543Smrg
117706f2543Smrg#include "opaque.h"
118706f2543Smrg
119706f2543Smrg#include "dixstruct.h"
120706f2543Smrg
121706f2543Smrg#include "xkbsrv.h"
122706f2543Smrg
123706f2543Smrg#include "picture.h"
124706f2543Smrg
125706f2543SmrgBool noTestExtensions;
126706f2543Smrg#ifdef COMPOSITE
127706f2543SmrgBool noCompositeExtension = FALSE;
128706f2543Smrg#endif
129706f2543Smrg
130706f2543Smrg#ifdef DAMAGE
131706f2543SmrgBool noDamageExtension = FALSE;
132706f2543Smrg#endif
133706f2543Smrg#ifdef DBE
134706f2543SmrgBool noDbeExtension = FALSE;
135706f2543Smrg#endif
136706f2543Smrg#ifdef DPMSExtension
137706f2543SmrgBool noDPMSExtension = FALSE;
138706f2543Smrg#endif
139706f2543Smrg#ifdef GLXEXT
140706f2543SmrgBool noGlxExtension = FALSE;
141706f2543SmrgBool noGlxVisualInit = FALSE;
142706f2543Smrg#endif
143706f2543Smrg#ifdef SCREENSAVER
144706f2543SmrgBool noScreenSaverExtension = FALSE;
145706f2543Smrg#endif
146706f2543Smrg#ifdef MITSHM
147706f2543SmrgBool noMITShmExtension = FALSE;
148706f2543Smrg#endif
149706f2543Smrg#ifdef RANDR
150706f2543SmrgBool noRRExtension = FALSE;
151706f2543Smrg#endif
152706f2543SmrgBool noRenderExtension = FALSE;
153706f2543Smrg#ifdef XCSECURITY
154706f2543SmrgBool noSecurityExtension = FALSE;
155706f2543Smrg#endif
156706f2543Smrg#ifdef RES
157706f2543SmrgBool noResExtension = FALSE;
158706f2543Smrg#endif
159706f2543Smrg#ifdef XF86BIGFONT
160706f2543SmrgBool noXFree86BigfontExtension = FALSE;
161706f2543Smrg#endif
162706f2543Smrg#ifdef XFreeXDGA
163706f2543SmrgBool noXFree86DGAExtension = FALSE;
164706f2543Smrg#endif
165706f2543Smrg#ifdef XF86DRI
166706f2543SmrgBool noXFree86DRIExtension = FALSE;
167706f2543Smrg#endif
168706f2543Smrg#ifdef XF86VIDMODE
169706f2543SmrgBool noXFree86VidModeExtension = FALSE;
170706f2543Smrg#endif
171706f2543Smrg#ifdef XFIXES
172706f2543SmrgBool noXFixesExtension = FALSE;
173706f2543Smrg#endif
174706f2543Smrg#ifdef PANORAMIX
175706f2543Smrg/* Xinerama is disabled by default unless enabled via +xinerama */
176706f2543SmrgBool noPanoramiXExtension = TRUE;
177706f2543Smrg#endif
178706f2543Smrg#ifdef XSELINUX
179706f2543SmrgBool noSELinuxExtension = FALSE;
180706f2543Smrgint selinuxEnforcingState = SELINUX_MODE_DEFAULT;
181706f2543Smrg#endif
182706f2543Smrg#ifdef XV
183706f2543SmrgBool noXvExtension = FALSE;
184706f2543Smrg#endif
185706f2543Smrg#ifdef DRI2
186706f2543SmrgBool noDRI2Extension = FALSE;
187706f2543Smrg#endif
188706f2543Smrg
189706f2543SmrgBool noGEExtension = FALSE;
190706f2543Smrg
191706f2543Smrg#define X_INCLUDE_NETDB_H
192706f2543Smrg#include <X11/Xos_r.h>
193706f2543Smrg
194706f2543Smrg#include <errno.h>
195706f2543Smrg
196706f2543SmrgBool CoreDump;
197706f2543Smrg
198706f2543Smrg#ifdef PANORAMIX
199706f2543SmrgBool PanoramiXExtensionDisabledHack = FALSE;
200706f2543Smrg#endif
201706f2543Smrg
202706f2543Smrgint auditTrailLevel = 1;
203706f2543Smrg
204706f2543Smrg#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
205706f2543Smrg#define HAS_SAVED_IDS_AND_SETEUID
206706f2543Smrg#endif
207706f2543Smrg
208706f2543SmrgOsSigHandlerPtr
209706f2543SmrgOsSignal(int sig, OsSigHandlerPtr handler)
210706f2543Smrg{
211706f2543Smrg    struct sigaction act, oact;
212706f2543Smrg
213706f2543Smrg    sigemptyset(&act.sa_mask);
214706f2543Smrg    if (handler != SIG_IGN)
215706f2543Smrg	sigaddset(&act.sa_mask, sig);
216706f2543Smrg    act.sa_flags = 0;
217706f2543Smrg    act.sa_handler = handler;
218706f2543Smrg    if (sigaction(sig, &act, &oact))
219706f2543Smrg      perror("sigaction");
220706f2543Smrg    return oact.sa_handler;
221706f2543Smrg}
222706f2543Smrg
223706f2543Smrg/*
224706f2543Smrg * Explicit support for a server lock file like the ones used for UUCP.
225706f2543Smrg * For architectures with virtual terminals that can run more than one
226706f2543Smrg * server at a time.  This keeps the servers from stomping on each other
227706f2543Smrg * if the user forgets to give them different display numbers.
228706f2543Smrg */
229706f2543Smrg#define LOCK_DIR "/tmp"
230706f2543Smrg#define LOCK_TMP_PREFIX "/.tX"
231706f2543Smrg#define LOCK_PREFIX "/.X"
232706f2543Smrg#define LOCK_SUFFIX "-lock"
233706f2543Smrg
234706f2543Smrg#ifndef PATH_MAX
235706f2543Smrg#include <sys/param.h>
236706f2543Smrg#ifndef PATH_MAX
237706f2543Smrg#ifdef MAXPATHLEN
238706f2543Smrg#define PATH_MAX MAXPATHLEN
239706f2543Smrg#else
240706f2543Smrg#define PATH_MAX 1024
241706f2543Smrg#endif
242706f2543Smrg#endif
243706f2543Smrg#endif
244706f2543Smrg
245706f2543Smrgstatic Bool StillLocking = FALSE;
246706f2543Smrgstatic char LockFile[PATH_MAX];
247706f2543Smrgstatic Bool nolock = FALSE;
248706f2543Smrg
249706f2543Smrg/*
250706f2543Smrg * LockServer --
251706f2543Smrg *      Check if the server lock file exists.  If so, check if the PID
252706f2543Smrg *      contained inside is valid.  If so, then die.  Otherwise, create
253706f2543Smrg *      the lock file containing the PID.
254706f2543Smrg */
255706f2543Smrgvoid
256706f2543SmrgLockServer(void)
257706f2543Smrg{
258706f2543Smrg  char tmp[PATH_MAX], pid_str[12];
259706f2543Smrg  int lfd, i, haslock, l_pid, t;
260706f2543Smrg  char *tmppath = NULL;
261706f2543Smrg  int len;
262706f2543Smrg  char port[20];
263706f2543Smrg
264706f2543Smrg  if (nolock) return;
265706f2543Smrg  /*
266706f2543Smrg   * Path names
267706f2543Smrg   */
268706f2543Smrg  tmppath = LOCK_DIR;
269706f2543Smrg
270706f2543Smrg  sprintf(port, "%d", atoi(display));
271706f2543Smrg  len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) :
272706f2543Smrg						strlen(LOCK_TMP_PREFIX);
273706f2543Smrg  len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1;
274706f2543Smrg  if (len > sizeof(LockFile))
275706f2543Smrg    FatalError("Display name `%s' is too long\n", port);
276706f2543Smrg  (void)sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
277706f2543Smrg  (void)sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
278706f2543Smrg
279706f2543Smrg  /*
280706f2543Smrg   * Create a temporary file containing our PID.  Attempt three times
281706f2543Smrg   * to create the file.
282706f2543Smrg   */
283706f2543Smrg  StillLocking = TRUE;
284706f2543Smrg  i = 0;
285706f2543Smrg  do {
286706f2543Smrg    i++;
287706f2543Smrg    lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
288706f2543Smrg    if (lfd < 0)
289706f2543Smrg       sleep(2);
290706f2543Smrg    else
291706f2543Smrg       break;
292706f2543Smrg  } while (i < 3);
293706f2543Smrg  if (lfd < 0) {
294706f2543Smrg    unlink(tmp);
295706f2543Smrg    i = 0;
296706f2543Smrg    do {
297706f2543Smrg      i++;
298706f2543Smrg      lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
299706f2543Smrg      if (lfd < 0)
300706f2543Smrg         sleep(2);
301706f2543Smrg      else
302706f2543Smrg         break;
303706f2543Smrg    } while (i < 3);
304706f2543Smrg  }
305706f2543Smrg  if (lfd < 0)
306706f2543Smrg    FatalError("Could not create lock file in %s\n", tmp);
307706f2543Smrg  (void) sprintf(pid_str, "%10ld\n", (long)getpid());
308706f2543Smrg  (void) write(lfd, pid_str, 11);
309706f2543Smrg  (void) fchmod(lfd, 0444);
310706f2543Smrg  (void) close(lfd);
311706f2543Smrg
312706f2543Smrg  /*
313706f2543Smrg   * OK.  Now the tmp file exists.  Try three times to move it in place
314706f2543Smrg   * for the lock.
315706f2543Smrg   */
316706f2543Smrg  i = 0;
317706f2543Smrg  haslock = 0;
318706f2543Smrg  while ((!haslock) && (i++ < 3)) {
319706f2543Smrg    haslock = (link(tmp,LockFile) == 0);
320706f2543Smrg    if (haslock) {
321706f2543Smrg      /*
322706f2543Smrg       * We're done.
323706f2543Smrg       */
324706f2543Smrg      break;
325706f2543Smrg    }
326706f2543Smrg    else {
327706f2543Smrg      /*
328706f2543Smrg       * Read the pid from the existing file
329706f2543Smrg       */
330706f2543Smrg      lfd = open(LockFile, O_RDONLY|O_NOFOLLOW);
331706f2543Smrg      if (lfd < 0) {
332706f2543Smrg        unlink(tmp);
333706f2543Smrg        FatalError("Can't read lock file %s\n", LockFile);
334706f2543Smrg      }
335706f2543Smrg      pid_str[0] = '\0';
336706f2543Smrg      if (read(lfd, pid_str, 11) != 11) {
337706f2543Smrg        /*
338706f2543Smrg         * Bogus lock file.
339706f2543Smrg         */
340706f2543Smrg        unlink(LockFile);
341706f2543Smrg        close(lfd);
342706f2543Smrg        continue;
343706f2543Smrg      }
344706f2543Smrg      pid_str[11] = '\0';
345706f2543Smrg      sscanf(pid_str, "%d", &l_pid);
346706f2543Smrg      close(lfd);
347706f2543Smrg
348706f2543Smrg      /*
349706f2543Smrg       * Now try to kill the PID to see if it exists.
350706f2543Smrg       */
351706f2543Smrg      errno = 0;
352706f2543Smrg      t = kill(l_pid, 0);
353706f2543Smrg      if ((t< 0) && (errno == ESRCH)) {
354706f2543Smrg        /*
355706f2543Smrg         * Stale lock file.
356706f2543Smrg         */
357706f2543Smrg        unlink(LockFile);
358706f2543Smrg        continue;
359706f2543Smrg      }
360706f2543Smrg      else if (((t < 0) && (errno == EPERM)) || (t == 0)) {
361706f2543Smrg        /*
362706f2543Smrg         * Process is still active.
363706f2543Smrg         */
364706f2543Smrg        unlink(tmp);
365706f2543Smrg	FatalError("Server is already active for display %s\n%s %s\n%s\n",
366706f2543Smrg		   port, "\tIf this server is no longer running, remove",
367706f2543Smrg		   LockFile, "\tand start again.");
368706f2543Smrg      }
369706f2543Smrg    }
370706f2543Smrg  }
371706f2543Smrg  unlink(tmp);
372706f2543Smrg  if (!haslock)
373706f2543Smrg    FatalError("Could not create server lock file: %s\n", LockFile);
374706f2543Smrg  StillLocking = FALSE;
375706f2543Smrg}
376706f2543Smrg
377706f2543Smrg/*
378706f2543Smrg * UnlockServer --
379706f2543Smrg *      Remove the server lock file.
380706f2543Smrg */
381706f2543Smrgvoid
382706f2543SmrgUnlockServer(void)
383706f2543Smrg{
384706f2543Smrg  if (nolock) return;
385706f2543Smrg
386706f2543Smrg  if (!StillLocking){
387706f2543Smrg
388706f2543Smrg  (void) unlink(LockFile);
389706f2543Smrg  }
390706f2543Smrg}
391706f2543Smrg
392706f2543Smrg/* Force connections to close on SIGHUP from init */
393706f2543Smrg
394706f2543Smrgvoid
395706f2543SmrgAutoResetServer (int sig)
396706f2543Smrg{
397706f2543Smrg    int olderrno = errno;
398706f2543Smrg
399706f2543Smrg    dispatchException |= DE_RESET;
400706f2543Smrg    isItTimeToYield = TRUE;
401706f2543Smrg    errno = olderrno;
402706f2543Smrg}
403706f2543Smrg
404706f2543Smrg/* Force connections to close and then exit on SIGTERM, SIGINT */
405706f2543Smrg
406706f2543Smrgvoid
407706f2543SmrgGiveUp(int sig)
408706f2543Smrg{
409706f2543Smrg    int olderrno = errno;
410706f2543Smrg
411706f2543Smrg    dispatchException |= DE_TERMINATE;
412706f2543Smrg    isItTimeToYield = TRUE;
413706f2543Smrg    errno = olderrno;
414706f2543Smrg}
415706f2543Smrg
416706f2543Smrg#if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__)
417706f2543SmrgCARD32
418706f2543SmrgGetTimeInMillis (void)
419706f2543Smrg{
420706f2543Smrg  return GetTickCount ();
421706f2543Smrg}
422706f2543Smrg#else
423706f2543SmrgCARD32
424706f2543SmrgGetTimeInMillis(void)
425706f2543Smrg{
426706f2543Smrg    struct timeval tv;
427706f2543Smrg
428706f2543Smrg#ifdef MONOTONIC_CLOCK
429706f2543Smrg    struct timespec tp;
430706f2543Smrg    static clockid_t clockid;
431706f2543Smrg    if (!clockid) {
432706f2543Smrg#ifdef CLOCK_MONOTONIC_COARSE
433706f2543Smrg        if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
434706f2543Smrg            (tp.tv_nsec / 1000) <= 1000 &&
435706f2543Smrg            clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
436706f2543Smrg            clockid = CLOCK_MONOTONIC_COARSE;
437706f2543Smrg        else
438706f2543Smrg#endif
439706f2543Smrg        if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
440706f2543Smrg            clockid = CLOCK_MONOTONIC;
441706f2543Smrg        else
442706f2543Smrg            clockid = ~0L;
443706f2543Smrg    }
444706f2543Smrg    if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
445706f2543Smrg        return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
446706f2543Smrg#endif
447706f2543Smrg
448706f2543Smrg    X_GETTIMEOFDAY(&tv);
449706f2543Smrg    return(tv.tv_sec * 1000) + (tv.tv_usec / 1000);
450706f2543Smrg}
451706f2543Smrg#endif
452706f2543Smrg
453706f2543Smrgvoid
454706f2543SmrgAdjustWaitForDelay (pointer waitTime, unsigned long newdelay)
455706f2543Smrg{
456706f2543Smrg    static struct timeval   delay_val;
457706f2543Smrg    struct timeval	    **wt = (struct timeval **) waitTime;
458706f2543Smrg    unsigned long	    olddelay;
459706f2543Smrg
460706f2543Smrg    if (*wt == NULL)
461706f2543Smrg    {
462706f2543Smrg	delay_val.tv_sec = newdelay / 1000;
463706f2543Smrg	delay_val.tv_usec = 1000 * (newdelay % 1000);
464706f2543Smrg	*wt = &delay_val;
465706f2543Smrg    }
466706f2543Smrg    else
467706f2543Smrg    {
468706f2543Smrg	olddelay = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000;
469706f2543Smrg	if (newdelay < olddelay)
470706f2543Smrg	{
471706f2543Smrg	    (*wt)->tv_sec = newdelay / 1000;
472706f2543Smrg	    (*wt)->tv_usec = 1000 * (newdelay % 1000);
473706f2543Smrg	}
474706f2543Smrg    }
475706f2543Smrg}
476706f2543Smrg
477706f2543Smrgvoid UseMsg(void)
478706f2543Smrg{
479706f2543Smrg    ErrorF("use: X [:<display>] [option]\n");
480706f2543Smrg    ErrorF("-a #                   default pointer acceleration (factor)\n");
481706f2543Smrg    ErrorF("-ac                    disable access control restrictions\n");
482706f2543Smrg    ErrorF("-audit int             set audit trail level\n");
483706f2543Smrg    ErrorF("-auth file             select authorization file\n");
484706f2543Smrg    ErrorF("-br                    create root window with black background\n");
485706f2543Smrg    ErrorF("+bs                    enable any backing store support\n");
486706f2543Smrg    ErrorF("-bs                    disable any backing store support\n");
487706f2543Smrg    ErrorF("-c                     turns off key-click\n");
488706f2543Smrg    ErrorF("c #                    key-click volume (0-100)\n");
489706f2543Smrg    ErrorF("-cc int                default color visual class\n");
490706f2543Smrg    ErrorF("-nocursor              disable the cursor\n");
491706f2543Smrg    ErrorF("-core                  generate core dump on fatal error\n");
492706f2543Smrg    ErrorF("-dpi int               screen resolution in dots per inch\n");
493706f2543Smrg#ifdef DPMSExtension
494706f2543Smrg    ErrorF("-dpms                  disables VESA DPMS monitor control\n");
495706f2543Smrg#endif
496706f2543Smrg    ErrorF("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n");
497706f2543Smrg    ErrorF("-f #                   bell base (0-100)\n");
498706f2543Smrg    ErrorF("-fc string             cursor font\n");
499706f2543Smrg    ErrorF("-fn string             default font name\n");
500706f2543Smrg    ErrorF("-fp string             default font path\n");
501706f2543Smrg    ErrorF("-help                  prints message with these options\n");
502706f2543Smrg    ErrorF("-I                     ignore all remaining arguments\n");
503706f2543Smrg#ifdef RLIMIT_DATA
504706f2543Smrg    ErrorF("-ld int                limit data space to N Kb\n");
505706f2543Smrg#endif
506706f2543Smrg#ifdef RLIMIT_NOFILE
507706f2543Smrg    ErrorF("-lf int                limit number of open files to N\n");
508706f2543Smrg#endif
509706f2543Smrg#ifdef RLIMIT_STACK
510706f2543Smrg    ErrorF("-ls int                limit stack space to N Kb\n");
511706f2543Smrg#endif
512706f2543Smrg    ErrorF("-nolock                disable the locking mechanism\n");
513706f2543Smrg    ErrorF("-nolisten string       don't listen on protocol\n");
514706f2543Smrg    ErrorF("-noreset               don't reset after last client exists\n");
515706f2543Smrg    ErrorF("-background [none]     create root window with no background\n");
516706f2543Smrg    ErrorF("-reset                 reset after last client exists\n");
517706f2543Smrg    ErrorF("-p #                   screen-saver pattern duration (minutes)\n");
518706f2543Smrg    ErrorF("-pn                    accept failure to listen on all ports\n");
519706f2543Smrg    ErrorF("-nopn                  reject failure to listen on all ports\n");
520706f2543Smrg    ErrorF("-r                     turns off auto-repeat\n");
521706f2543Smrg    ErrorF("r                      turns on auto-repeat \n");
522706f2543Smrg    ErrorF("-render [default|mono|gray|color] set render color alloc policy\n");
523706f2543Smrg    ErrorF("-retro                 start with classic stipple and cursor\n");
524706f2543Smrg    ErrorF("-noretro               start with black background and no cursor\n");
525706f2543Smrg    ErrorF("-s #                   screen-saver timeout (minutes)\n");
526706f2543Smrg    ErrorF("-t #                   default pointer threshold (pixels/t)\n");
527706f2543Smrg    ErrorF("-terminate             terminate at server reset\n");
528706f2543Smrg    ErrorF("-to #                  connection time out\n");
529706f2543Smrg    ErrorF("-tst                   disable testing extensions\n");
530706f2543Smrg    ErrorF("ttyxx                  server started from init on /dev/ttyxx\n");
531706f2543Smrg    ErrorF("v                      video blanking for screen-saver\n");
532706f2543Smrg    ErrorF("-v                     screen-saver without video blanking\n");
533706f2543Smrg    ErrorF("-wm                    WhenMapped default backing-store\n");
534706f2543Smrg    ErrorF("-wr                    create root window with white background\n");
535706f2543Smrg    ErrorF("-maxbigreqsize         set maximal bigrequest size \n");
536706f2543Smrg#ifdef PANORAMIX
537706f2543Smrg    ErrorF("+xinerama              Enable XINERAMA extension\n");
538706f2543Smrg    ErrorF("-xinerama              Disable XINERAMA extension\n");
539706f2543Smrg#endif
540706f2543Smrg    ErrorF("-dumbSched             Disable smart scheduling, enable old behavior\n");
541706f2543Smrg    ErrorF("-schedInterval int     Set scheduler interval in msec\n");
542706f2543Smrg    ErrorF("-sigstop               Enable SIGSTOP based startup\n");
543706f2543Smrg    ErrorF("+extension name        Enable extension\n");
544706f2543Smrg    ErrorF("-extension name        Disable extension\n");
545706f2543Smrg#ifdef XDMCP
546706f2543Smrg    XdmcpUseMsg();
547706f2543Smrg#endif
548706f2543Smrg    XkbUseMsg();
549706f2543Smrg    ddxUseMsg();
550706f2543Smrg}
551706f2543Smrg
552706f2543Smrg/*  This function performs a rudimentary sanity check
553706f2543Smrg *  on the display name passed in on the command-line,
554706f2543Smrg *  since this string is used to generate filenames.
555706f2543Smrg *  It is especially important that the display name
556706f2543Smrg *  not contain a "/" and not start with a "-".
557706f2543Smrg *                                            --kvajk
558706f2543Smrg */
559706f2543Smrgstatic int
560706f2543SmrgVerifyDisplayName(const char *d)
561706f2543Smrg{
562706f2543Smrg    if ( d == (char *)0 ) return 0;  /*  null  */
563706f2543Smrg    if ( *d == '\0' ) return 0;  /*  empty  */
564706f2543Smrg    if ( *d == '-' ) return 0;  /*  could be confused for an option  */
565706f2543Smrg    if ( *d == '.' ) return 0;  /*  must not equal "." or ".."  */
566706f2543Smrg    if ( strchr(d, '/') != (char *)0 ) return 0;  /*  very important!!!  */
567706f2543Smrg    return 1;
568706f2543Smrg}
569706f2543Smrg
570706f2543Smrg/*
571706f2543Smrg * This function parses the command line. Handles device-independent fields
572706f2543Smrg * and allows ddx to handle additional fields.  It is not allowed to modify
573706f2543Smrg * argc or any of the strings pointed to by argv.
574706f2543Smrg */
575706f2543Smrgvoid
576706f2543SmrgProcessCommandLine(int argc, char *argv[])
577706f2543Smrg{
578706f2543Smrg    int i, skip;
579706f2543Smrg
580706f2543Smrg    defaultKeyboardControl.autoRepeat = TRUE;
581706f2543Smrg
582706f2543Smrg#ifdef NO_PART_NET
583706f2543Smrg    PartialNetwork = FALSE;
584706f2543Smrg#else
585706f2543Smrg    PartialNetwork = TRUE;
586706f2543Smrg#endif
587706f2543Smrg
588706f2543Smrg    for ( i = 1; i < argc; i++ )
589706f2543Smrg    {
590706f2543Smrg	/* call ddx first, so it can peek/override if it wants */
591706f2543Smrg        if((skip = ddxProcessArgument(argc, argv, i)))
592706f2543Smrg	{
593706f2543Smrg	    i += (skip - 1);
594706f2543Smrg	}
595706f2543Smrg	else if(argv[i][0] ==  ':')
596706f2543Smrg	{
597706f2543Smrg	    /* initialize display */
598706f2543Smrg	    display = argv[i];
599706f2543Smrg	    display++;
600706f2543Smrg            if( ! VerifyDisplayName( display ) ) {
601706f2543Smrg                ErrorF("Bad display name: %s\n", display);
602706f2543Smrg                UseMsg();
603706f2543Smrg		FatalError("Bad display name, exiting: %s\n", display);
604706f2543Smrg            }
605706f2543Smrg	}
606706f2543Smrg	else if ( strcmp( argv[i], "-a") == 0)
607706f2543Smrg	{
608706f2543Smrg	    if(++i < argc)
609706f2543Smrg	        defaultPointerControl.num = atoi(argv[i]);
610706f2543Smrg	    else
611706f2543Smrg		UseMsg();
612706f2543Smrg	}
613706f2543Smrg	else if ( strcmp( argv[i], "-ac") == 0)
614706f2543Smrg	{
615706f2543Smrg	    defeatAccessControl = TRUE;
616706f2543Smrg	}
617706f2543Smrg	else if ( strcmp( argv[i], "-audit") == 0)
618706f2543Smrg	{
619706f2543Smrg	    if(++i < argc)
620706f2543Smrg	        auditTrailLevel = atoi(argv[i]);
621706f2543Smrg	    else
622706f2543Smrg		UseMsg();
623706f2543Smrg	}
624706f2543Smrg	else if ( strcmp( argv[i], "-auth") == 0)
625706f2543Smrg	{
626706f2543Smrg	    if(++i < argc)
627706f2543Smrg	        InitAuthorization (argv[i]);
628706f2543Smrg	    else
629706f2543Smrg		UseMsg();
630706f2543Smrg	}
631706f2543Smrg	else if ( strcmp( argv[i], "-br") == 0) ; /* default */
632706f2543Smrg	else if ( strcmp( argv[i], "+bs") == 0)
633706f2543Smrg	    enableBackingStore = TRUE;
634706f2543Smrg	else if ( strcmp( argv[i], "-bs") == 0)
635706f2543Smrg	    disableBackingStore = TRUE;
636706f2543Smrg	else if ( strcmp( argv[i], "c") == 0)
637706f2543Smrg	{
638706f2543Smrg	    if(++i < argc)
639706f2543Smrg	        defaultKeyboardControl.click = atoi(argv[i]);
640706f2543Smrg	    else
641706f2543Smrg		UseMsg();
642706f2543Smrg	}
643706f2543Smrg	else if ( strcmp( argv[i], "-c") == 0)
644706f2543Smrg	{
645706f2543Smrg	    defaultKeyboardControl.click = 0;
646706f2543Smrg	}
647706f2543Smrg	else if ( strcmp( argv[i], "-cc") == 0)
648706f2543Smrg	{
649706f2543Smrg	    if(++i < argc)
650706f2543Smrg	        defaultColorVisualClass = atoi(argv[i]);
651706f2543Smrg	    else
652706f2543Smrg		UseMsg();
653706f2543Smrg	}
654706f2543Smrg	else if ( strcmp( argv[i], "-core") == 0)
655706f2543Smrg	{
656706f2543Smrg#if !defined(WIN32) || !defined(__MINGW32__)
657706f2543Smrg	    struct rlimit   core_limit;
658706f2543Smrg	    if (getrlimit (RLIMIT_CORE, &core_limit) != -1) {
659706f2543Smrg		    core_limit.rlim_cur = core_limit.rlim_max;
660706f2543Smrg		    setrlimit (RLIMIT_CORE, &core_limit);
661706f2543Smrg	    }
662706f2543Smrg#endif
663706f2543Smrg	    CoreDump = TRUE;
664706f2543Smrg	}
665706f2543Smrg        else if ( strcmp( argv[i], "-nocursor") == 0)
666706f2543Smrg        {
667706f2543Smrg            EnableCursor = FALSE;
668706f2543Smrg        }
669706f2543Smrg        else if ( strcmp( argv[i], "-dpi") == 0)
670706f2543Smrg	{
671706f2543Smrg	    if(++i < argc)
672706f2543Smrg	        monitorResolution = atoi(argv[i]);
673706f2543Smrg	    else
674706f2543Smrg		UseMsg();
675706f2543Smrg	}
676706f2543Smrg#ifdef DPMSExtension
677706f2543Smrg	else if ( strcmp( argv[i], "dpms") == 0)
678706f2543Smrg	    /* ignored for compatibility */ ;
679706f2543Smrg	else if ( strcmp( argv[i], "-dpms") == 0)
680706f2543Smrg	    DPMSDisabledSwitch = TRUE;
681706f2543Smrg#endif
682706f2543Smrg	else if ( strcmp( argv[i], "-deferglyphs") == 0)
683706f2543Smrg	{
684706f2543Smrg	    if(++i >= argc || !ParseGlyphCachingMode(argv[i]))
685706f2543Smrg		UseMsg();
686706f2543Smrg	}
687706f2543Smrg	else if ( strcmp( argv[i], "-f") == 0)
688706f2543Smrg	{
689706f2543Smrg	    if(++i < argc)
690706f2543Smrg	        defaultKeyboardControl.bell = atoi(argv[i]);
691706f2543Smrg	    else
692706f2543Smrg		UseMsg();
693706f2543Smrg	}
694706f2543Smrg	else if ( strcmp( argv[i], "-fc") == 0)
695706f2543Smrg	{
696706f2543Smrg	    if(++i < argc)
697706f2543Smrg	        defaultCursorFont = argv[i];
698706f2543Smrg	    else
699706f2543Smrg		UseMsg();
700706f2543Smrg	}
701706f2543Smrg	else if ( strcmp( argv[i], "-fn") == 0)
702706f2543Smrg	{
703706f2543Smrg	    if(++i < argc)
704706f2543Smrg	        defaultTextFont = argv[i];
705706f2543Smrg	    else
706706f2543Smrg		UseMsg();
707706f2543Smrg	}
708706f2543Smrg	else if ( strcmp( argv[i], "-fp") == 0)
709706f2543Smrg	{
710706f2543Smrg	    if(++i < argc)
711706f2543Smrg	    {
712706f2543Smrg	        defaultFontPath = argv[i];
713706f2543Smrg	    }
714706f2543Smrg	    else
715706f2543Smrg		UseMsg();
716706f2543Smrg	}
717706f2543Smrg	else if ( strcmp( argv[i], "-help") == 0)
718706f2543Smrg	{
719706f2543Smrg	    UseMsg();
720706f2543Smrg	    exit(0);
721706f2543Smrg	}
722706f2543Smrg        else if ( (skip=XkbProcessArguments(argc,argv,i))!=0 ) {
723706f2543Smrg	    if (skip>0)
724706f2543Smrg		 i+= skip-1;
725706f2543Smrg	    else UseMsg();
726706f2543Smrg	}
727706f2543Smrg#ifdef RLIMIT_DATA
728706f2543Smrg	else if ( strcmp( argv[i], "-ld") == 0)
729706f2543Smrg	{
730706f2543Smrg	    if(++i < argc)
731706f2543Smrg	    {
732706f2543Smrg	        limitDataSpace = atoi(argv[i]);
733706f2543Smrg		if (limitDataSpace > 0)
734706f2543Smrg		    limitDataSpace *= 1024;
735706f2543Smrg	    }
736706f2543Smrg	    else
737706f2543Smrg		UseMsg();
738706f2543Smrg	}
739706f2543Smrg#endif
740706f2543Smrg#ifdef RLIMIT_NOFILE
741706f2543Smrg	else if ( strcmp( argv[i], "-lf") == 0)
742706f2543Smrg	{
743706f2543Smrg	    if(++i < argc)
744706f2543Smrg	        limitNoFile = atoi(argv[i]);
745706f2543Smrg	    else
746706f2543Smrg		UseMsg();
747706f2543Smrg	}
748706f2543Smrg#endif
749706f2543Smrg#ifdef RLIMIT_STACK
750706f2543Smrg	else if ( strcmp( argv[i], "-ls") == 0)
751706f2543Smrg	{
752706f2543Smrg	    if(++i < argc)
753706f2543Smrg	    {
754706f2543Smrg	        limitStackSpace = atoi(argv[i]);
755706f2543Smrg		if (limitStackSpace > 0)
756706f2543Smrg		    limitStackSpace *= 1024;
757706f2543Smrg	    }
758706f2543Smrg	    else
759706f2543Smrg		UseMsg();
760706f2543Smrg	}
761706f2543Smrg#endif
762706f2543Smrg	else if ( strcmp ( argv[i], "-nolock") == 0)
763706f2543Smrg	{
764706f2543Smrg#if !defined(WIN32) && !defined(__CYGWIN__)
765706f2543Smrg	  if (getuid() != 0)
766706f2543Smrg	    ErrorF("Warning: the -nolock option can only be used by root\n");
767706f2543Smrg	  else
768706f2543Smrg#endif
769706f2543Smrg	    nolock = TRUE;
770706f2543Smrg	}
771706f2543Smrg	else if ( strcmp( argv[i], "-nolisten") == 0)
772706f2543Smrg	{
773706f2543Smrg            if(++i < argc) {
774706f2543Smrg		if (_XSERVTransNoListen(argv[i]))
775706f2543Smrg		    FatalError ("Failed to disable listen for %s transport",
776706f2543Smrg				argv[i]);
777706f2543Smrg	   } else
778706f2543Smrg		UseMsg();
779706f2543Smrg	}
780706f2543Smrg	else if ( strcmp( argv[i], "-noreset") == 0)
781706f2543Smrg	{
782706f2543Smrg	    dispatchExceptionAtReset = 0;
783706f2543Smrg	}
784706f2543Smrg	else if ( strcmp( argv[i], "-reset") == 0)
785706f2543Smrg	{
786706f2543Smrg	    dispatchExceptionAtReset = DE_RESET;
787706f2543Smrg	}
788706f2543Smrg	else if ( strcmp( argv[i], "-p") == 0)
789706f2543Smrg	{
790706f2543Smrg	    if(++i < argc)
791706f2543Smrg	        defaultScreenSaverInterval = ((CARD32)atoi(argv[i])) *
792706f2543Smrg					     MILLI_PER_MIN;
793706f2543Smrg	    else
794706f2543Smrg		UseMsg();
795706f2543Smrg	}
796706f2543Smrg	else if (strcmp(argv[i], "-pogo") == 0)
797706f2543Smrg	{
798706f2543Smrg	    dispatchException = DE_TERMINATE;
799706f2543Smrg	}
800706f2543Smrg	else if ( strcmp( argv[i], "-pn") == 0)
801706f2543Smrg	    PartialNetwork = TRUE;
802706f2543Smrg	else if ( strcmp( argv[i], "-nopn") == 0)
803706f2543Smrg	    PartialNetwork = FALSE;
804706f2543Smrg	else if ( strcmp( argv[i], "r") == 0)
805706f2543Smrg	    defaultKeyboardControl.autoRepeat = TRUE;
806706f2543Smrg	else if ( strcmp( argv[i], "-r") == 0)
807706f2543Smrg	    defaultKeyboardControl.autoRepeat = FALSE;
808706f2543Smrg	else if ( strcmp( argv[i], "-retro") == 0)
809706f2543Smrg	    party_like_its_1989 = TRUE;
810706f2543Smrg	else if ( strcmp( argv[i], "-noretro") == 0)
811706f2543Smrg	    party_like_its_1989 = FALSE;
812706f2543Smrg	else if ( strcmp( argv[i], "-s") == 0)
813706f2543Smrg	{
814706f2543Smrg	    if(++i < argc)
815706f2543Smrg	        defaultScreenSaverTime = ((CARD32)atoi(argv[i])) *
816706f2543Smrg					 MILLI_PER_MIN;
817706f2543Smrg	    else
818706f2543Smrg		UseMsg();
819706f2543Smrg	}
820706f2543Smrg	else if ( strcmp( argv[i], "-t") == 0)
821706f2543Smrg	{
822706f2543Smrg	    if(++i < argc)
823706f2543Smrg	        defaultPointerControl.threshold = atoi(argv[i]);
824706f2543Smrg	    else
825706f2543Smrg		UseMsg();
826706f2543Smrg	}
827706f2543Smrg	else if ( strcmp( argv[i], "-terminate") == 0)
828706f2543Smrg	{
829706f2543Smrg	    dispatchExceptionAtReset = DE_TERMINATE;
830706f2543Smrg	}
831706f2543Smrg	else if ( strcmp( argv[i], "-to") == 0)
832706f2543Smrg	{
833706f2543Smrg	    if(++i < argc)
834706f2543Smrg		TimeOutValue = ((CARD32)atoi(argv[i])) * MILLI_PER_SECOND;
835706f2543Smrg	    else
836706f2543Smrg		UseMsg();
837706f2543Smrg	}
838706f2543Smrg	else if ( strcmp( argv[i], "-tst") == 0)
839706f2543Smrg	{
840706f2543Smrg	    noTestExtensions = TRUE;
841706f2543Smrg	}
842706f2543Smrg	else if ( strcmp( argv[i], "v") == 0)
843706f2543Smrg	    defaultScreenSaverBlanking = PreferBlanking;
844706f2543Smrg	else if ( strcmp( argv[i], "-v") == 0)
845706f2543Smrg	    defaultScreenSaverBlanking = DontPreferBlanking;
846706f2543Smrg	else if ( strcmp( argv[i], "-wm") == 0)
847706f2543Smrg	    defaultBackingStore = WhenMapped;
848706f2543Smrg        else if ( strcmp( argv[i], "-wr") == 0)
849706f2543Smrg            whiteRoot = TRUE;
850706f2543Smrg        else if ( strcmp( argv[i], "-background") == 0) {
851706f2543Smrg            if(++i < argc) {
852706f2543Smrg                if (!strcmp ( argv[i], "none"))
853706f2543Smrg                    bgNoneRoot = TRUE;
854706f2543Smrg                else
855706f2543Smrg                    UseMsg();
856706f2543Smrg            }
857706f2543Smrg        }
858706f2543Smrg        else if ( strcmp( argv[i], "-maxbigreqsize") == 0) {
859706f2543Smrg             if(++i < argc) {
860706f2543Smrg                 long reqSizeArg = atol(argv[i]);
861706f2543Smrg
862706f2543Smrg                 /* Request size > 128MB does not make much sense... */
863706f2543Smrg                 if( reqSizeArg > 0L && reqSizeArg < 128L ) {
864706f2543Smrg                     maxBigRequestSize = (reqSizeArg * 1048576L) - 1L;
865706f2543Smrg                 }
866706f2543Smrg                 else
867706f2543Smrg                 {
868706f2543Smrg                     UseMsg();
869706f2543Smrg                 }
870706f2543Smrg             }
871706f2543Smrg             else
872706f2543Smrg             {
873706f2543Smrg                 UseMsg();
874706f2543Smrg             }
875706f2543Smrg         }
876706f2543Smrg#ifdef PANORAMIX
877706f2543Smrg	else if ( strcmp( argv[i], "+xinerama") == 0){
878706f2543Smrg	    noPanoramiXExtension = FALSE;
879706f2543Smrg	}
880706f2543Smrg	else if ( strcmp( argv[i], "-xinerama") == 0){
881706f2543Smrg	    noPanoramiXExtension = TRUE;
882706f2543Smrg	}
883706f2543Smrg	else if ( strcmp( argv[i], "-disablexineramaextension") == 0){
884706f2543Smrg	    PanoramiXExtensionDisabledHack = TRUE;
885706f2543Smrg	}
886706f2543Smrg#endif
887706f2543Smrg	else if ( strcmp( argv[i], "-I") == 0)
888706f2543Smrg	{
889706f2543Smrg	    /* ignore all remaining arguments */
890706f2543Smrg	    break;
891706f2543Smrg	}
892706f2543Smrg	else if (strncmp (argv[i], "tty", 3) == 0)
893706f2543Smrg	{
894706f2543Smrg            /* init supplies us with this useless information */
895706f2543Smrg	}
896706f2543Smrg#ifdef XDMCP
897706f2543Smrg	else if ((skip = XdmcpOptions(argc, argv, i)) != i)
898706f2543Smrg	{
899706f2543Smrg	    i = skip - 1;
900706f2543Smrg	}
901706f2543Smrg#endif
902706f2543Smrg	else if ( strcmp( argv[i], "-dumbSched") == 0)
903706f2543Smrg	{
904706f2543Smrg	    SmartScheduleDisable = TRUE;
905706f2543Smrg	}
906706f2543Smrg	else if ( strcmp( argv[i], "-schedInterval") == 0)
907706f2543Smrg	{
908706f2543Smrg	    if (++i < argc)
909706f2543Smrg	    {
910706f2543Smrg		SmartScheduleInterval = atoi(argv[i]);
911706f2543Smrg		SmartScheduleSlice = SmartScheduleInterval;
912706f2543Smrg	    }
913706f2543Smrg	    else
914706f2543Smrg		UseMsg();
915706f2543Smrg	}
916706f2543Smrg	else if ( strcmp( argv[i], "-schedMax") == 0)
917706f2543Smrg	{
918706f2543Smrg	    if (++i < argc)
919706f2543Smrg	    {
920706f2543Smrg		SmartScheduleMaxSlice = atoi(argv[i]);
921706f2543Smrg	    }
922706f2543Smrg	    else
923706f2543Smrg		UseMsg();
924706f2543Smrg	}
925706f2543Smrg	else if ( strcmp( argv[i], "-render" ) == 0)
926706f2543Smrg	{
927706f2543Smrg	    if (++i < argc)
928706f2543Smrg	    {
929706f2543Smrg		int policy = PictureParseCmapPolicy (argv[i]);
930706f2543Smrg
931706f2543Smrg		if (policy != PictureCmapPolicyInvalid)
932706f2543Smrg		    PictureCmapPolicy = policy;
933706f2543Smrg		else
934706f2543Smrg		    UseMsg ();
935706f2543Smrg	    }
936706f2543Smrg	    else
937706f2543Smrg		UseMsg ();
938706f2543Smrg	}
939706f2543Smrg	else if ( strcmp( argv[i], "-sigstop") == 0)
940706f2543Smrg	{
941706f2543Smrg	    RunFromSigStopParent = TRUE;
942706f2543Smrg	}
943706f2543Smrg	else if ( strcmp( argv[i], "+extension") == 0)
944706f2543Smrg	{
945706f2543Smrg	    if (++i < argc)
946706f2543Smrg	    {
947706f2543Smrg		if (!EnableDisableExtension(argv[i], TRUE))
948706f2543Smrg		    EnableDisableExtensionError(argv[i], TRUE);
949706f2543Smrg	    }
950706f2543Smrg	    else
951706f2543Smrg		UseMsg();
952706f2543Smrg	}
953706f2543Smrg	else if ( strcmp( argv[i], "-extension") == 0)
954706f2543Smrg	{
955706f2543Smrg	    if (++i < argc)
956706f2543Smrg	    {
957706f2543Smrg		if (!EnableDisableExtension(argv[i], FALSE))
958706f2543Smrg		    EnableDisableExtensionError(argv[i], FALSE);
959706f2543Smrg	    }
960706f2543Smrg	    else
961706f2543Smrg		UseMsg();
962706f2543Smrg	}
963706f2543Smrg 	else
964706f2543Smrg 	{
965706f2543Smrg	    ErrorF("Unrecognized option: %s\n", argv[i]);
966706f2543Smrg	    UseMsg();
967706f2543Smrg	    FatalError("Unrecognized option: %s\n", argv[i]);
968706f2543Smrg        }
969706f2543Smrg    }
970706f2543Smrg}
971706f2543Smrg
972706f2543Smrg/* Implement a simple-minded font authorization scheme.  The authorization
973706f2543Smrg   name is "hp-hostname-1", the contents are simply the host name. */
974706f2543Smrgint
975706f2543Smrgset_font_authorizations(char **authorizations, int *authlen, pointer client)
976706f2543Smrg{
977706f2543Smrg#define AUTHORIZATION_NAME "hp-hostname-1"
978706f2543Smrg#if defined(TCPCONN) || defined(STREAMSCONN)
979706f2543Smrg    static char *result = NULL;
980706f2543Smrg    static char *p = NULL;
981706f2543Smrg
982706f2543Smrg    if (p == NULL)
983706f2543Smrg    {
984706f2543Smrg	char hname[1024], *hnameptr;
985706f2543Smrg	unsigned int len;
986706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
987706f2543Smrg	struct addrinfo hints, *ai = NULL;
988706f2543Smrg#else
989706f2543Smrg	struct hostent *host;
990706f2543Smrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
991706f2543Smrg	_Xgethostbynameparams hparams;
992706f2543Smrg#endif
993706f2543Smrg#endif
994706f2543Smrg
995706f2543Smrg	gethostname(hname, 1024);
996706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
997706f2543Smrg	memset(&hints, 0, sizeof(hints));
998706f2543Smrg	hints.ai_flags = AI_CANONNAME;
999706f2543Smrg	if (getaddrinfo(hname, NULL, &hints, &ai) == 0) {
1000706f2543Smrg	    hnameptr = ai->ai_canonname;
1001706f2543Smrg	} else {
1002706f2543Smrg	    hnameptr = hname;
1003706f2543Smrg	}
1004706f2543Smrg#else
1005706f2543Smrg	host = _XGethostbyname(hname, hparams);
1006706f2543Smrg	if (host == NULL)
1007706f2543Smrg	    hnameptr = hname;
1008706f2543Smrg	else
1009706f2543Smrg	    hnameptr = host->h_name;
1010706f2543Smrg#endif
1011706f2543Smrg
1012706f2543Smrg	len = strlen(hnameptr) + 1;
1013706f2543Smrg	result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4);
1014706f2543Smrg
1015706f2543Smrg	p = result;
1016706f2543Smrg        *p++ = sizeof(AUTHORIZATION_NAME) >> 8;
1017706f2543Smrg        *p++ = sizeof(AUTHORIZATION_NAME) & 0xff;
1018706f2543Smrg        *p++ = (len) >> 8;
1019706f2543Smrg        *p++ = (len & 0xff);
1020706f2543Smrg
1021706f2543Smrg	memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME));
1022706f2543Smrg	p += sizeof(AUTHORIZATION_NAME);
1023706f2543Smrg	memmove(p, hnameptr, len);
1024706f2543Smrg	p += len;
1025706f2543Smrg#if defined(IPv6) && defined(AF_INET6)
1026706f2543Smrg	if (ai) {
1027706f2543Smrg	    freeaddrinfo(ai);
1028706f2543Smrg	}
1029706f2543Smrg#endif
1030706f2543Smrg    }
1031706f2543Smrg    *authlen = p - result;
1032706f2543Smrg    *authorizations = result;
1033706f2543Smrg    return 1;
1034706f2543Smrg#else /* TCPCONN */
1035706f2543Smrg    return 0;
1036706f2543Smrg#endif /* TCPCONN */
1037706f2543Smrg}
1038706f2543Smrg
1039706f2543Smrgvoid *
1040706f2543SmrgXalloc(unsigned long amount)
1041706f2543Smrg{
1042706f2543Smrg    /*
1043706f2543Smrg     * Xalloc used to return NULL when large amount of memory is requested. In
1044706f2543Smrg     * order to catch the buggy callers this warning has been added, slated to
1045706f2543Smrg     * removal by anyone who touches this code (or just looks at it) in 2011.
1046706f2543Smrg     *
1047706f2543Smrg     * -- Mikhail Gusarov
1048706f2543Smrg     */
1049706f2543Smrg    if ((long)amount <= 0)
1050706f2543Smrg	ErrorF("Warning: Xalloc: "
1051706f2543Smrg	       "requesting unpleasantly large amount of memory: %lu bytes.\n",
1052706f2543Smrg               amount);
1053706f2543Smrg
1054706f2543Smrg    return malloc(amount);
1055706f2543Smrg}
1056706f2543Smrg
1057706f2543Smrgvoid *
1058706f2543SmrgXNFalloc(unsigned long amount)
1059706f2543Smrg{
1060706f2543Smrg    void *ptr = malloc(amount);
1061706f2543Smrg    if (!ptr)
1062706f2543Smrg        FatalError("Out of memory");
1063706f2543Smrg    return ptr;
1064706f2543Smrg}
1065706f2543Smrg
1066706f2543Smrgvoid *
1067706f2543SmrgXcalloc(unsigned long amount)
1068706f2543Smrg{
1069706f2543Smrg    return calloc(1, amount);
1070706f2543Smrg}
1071706f2543Smrg
1072706f2543Smrgvoid *
1073706f2543SmrgXNFcalloc(unsigned long amount)
1074706f2543Smrg{
1075706f2543Smrg    void *ret = calloc(1, amount);
1076706f2543Smrg    if (!ret)
1077706f2543Smrg        FatalError("XNFcalloc: Out of memory");
1078706f2543Smrg    return ret;
1079706f2543Smrg}
1080706f2543Smrg
1081706f2543Smrgvoid *
1082706f2543SmrgXrealloc(void *ptr, unsigned long amount)
1083706f2543Smrg{
1084706f2543Smrg    /*
1085706f2543Smrg     * Xrealloc used to return NULL when large amount of memory is requested. In
1086706f2543Smrg     * order to catch the buggy callers this warning has been added, slated to
1087706f2543Smrg     * removal by anyone who touches this code (or just looks at it) in 2011.
1088706f2543Smrg     *
1089706f2543Smrg     * -- Mikhail Gusarov
1090706f2543Smrg     */
1091706f2543Smrg    if ((long)amount <= 0)
1092706f2543Smrg	ErrorF("Warning: Xrealloc: "
1093706f2543Smrg	       "requesting unpleasantly large amount of memory: %lu bytes.\n",
1094706f2543Smrg               amount);
1095706f2543Smrg
1096706f2543Smrg    return realloc(ptr, amount);
1097706f2543Smrg}
1098706f2543Smrg
1099706f2543Smrgvoid *
1100706f2543SmrgXNFrealloc(void *ptr, unsigned long amount)
1101706f2543Smrg{
1102706f2543Smrg    void *ret = realloc(ptr, amount);
1103706f2543Smrg    if (!ret)
1104706f2543Smrg	FatalError("XNFrealloc: Out of memory");
1105706f2543Smrg    return ret;
1106706f2543Smrg}
1107706f2543Smrg
1108706f2543Smrgvoid
1109706f2543SmrgXfree(void *ptr)
1110706f2543Smrg{
1111706f2543Smrg    free(ptr);
1112706f2543Smrg}
1113706f2543Smrg
1114706f2543Smrg
1115706f2543Smrgchar *
1116706f2543SmrgXstrdup(const char *s)
1117706f2543Smrg{
1118706f2543Smrg    if (s == NULL)
1119706f2543Smrg	return NULL;
1120706f2543Smrg    return strdup(s);
1121706f2543Smrg}
1122706f2543Smrg
1123706f2543Smrgchar *
1124706f2543SmrgXNFstrdup(const char *s)
1125706f2543Smrg{
1126706f2543Smrg    char *ret;
1127706f2543Smrg
1128706f2543Smrg    if (s == NULL)
1129706f2543Smrg	return NULL;
1130706f2543Smrg
1131706f2543Smrg    ret = strdup(s);
1132706f2543Smrg    if (!ret)
1133706f2543Smrg	FatalError("XNFstrdup: Out of memory");
1134706f2543Smrg    return ret;
1135706f2543Smrg}
1136706f2543Smrg
1137706f2543Smrgvoid
1138706f2543SmrgSmartScheduleStopTimer (void)
1139706f2543Smrg{
1140706f2543Smrg    struct itimerval	timer;
1141706f2543Smrg
1142706f2543Smrg    if (SmartScheduleDisable)
1143706f2543Smrg	return;
1144706f2543Smrg    timer.it_interval.tv_sec = 0;
1145706f2543Smrg    timer.it_interval.tv_usec = 0;
1146706f2543Smrg    timer.it_value.tv_sec = 0;
1147706f2543Smrg    timer.it_value.tv_usec = 0;
1148706f2543Smrg    (void) setitimer (ITIMER_REAL, &timer, 0);
1149706f2543Smrg}
1150706f2543Smrg
1151706f2543Smrgvoid
1152706f2543SmrgSmartScheduleStartTimer (void)
1153706f2543Smrg{
1154706f2543Smrg    struct itimerval	timer;
1155706f2543Smrg
1156706f2543Smrg    if (SmartScheduleDisable)
1157706f2543Smrg	return;
1158706f2543Smrg    timer.it_interval.tv_sec = 0;
1159706f2543Smrg    timer.it_interval.tv_usec = SmartScheduleInterval * 1000;
1160706f2543Smrg    timer.it_value.tv_sec = 0;
1161706f2543Smrg    timer.it_value.tv_usec = SmartScheduleInterval * 1000;
1162706f2543Smrg    setitimer (ITIMER_REAL, &timer, 0);
1163706f2543Smrg}
1164706f2543Smrg
1165706f2543Smrgstatic void
1166706f2543SmrgSmartScheduleTimer (int sig)
1167706f2543Smrg{
1168706f2543Smrg    SmartScheduleTime += SmartScheduleInterval;
1169706f2543Smrg}
1170706f2543Smrg
1171706f2543Smrgvoid
1172706f2543SmrgSmartScheduleInit (void)
1173706f2543Smrg{
1174706f2543Smrg    struct sigaction	act;
1175706f2543Smrg
1176706f2543Smrg    if (SmartScheduleDisable)
1177706f2543Smrg	return;
1178706f2543Smrg
1179706f2543Smrg    memset((char *) &act, 0, sizeof(struct sigaction));
1180706f2543Smrg
1181706f2543Smrg    /* Set up the timer signal function */
1182706f2543Smrg    act.sa_handler = SmartScheduleTimer;
1183706f2543Smrg    sigemptyset (&act.sa_mask);
1184706f2543Smrg    sigaddset (&act.sa_mask, SIGALRM);
1185706f2543Smrg    if (sigaction (SIGALRM, &act, 0) < 0)
1186706f2543Smrg    {
1187706f2543Smrg	perror ("sigaction for smart scheduler");
1188706f2543Smrg	SmartScheduleDisable = TRUE;
1189706f2543Smrg    }
1190706f2543Smrg}
1191706f2543Smrg
1192706f2543Smrg#ifdef SIG_BLOCK
1193706f2543Smrgstatic sigset_t	PreviousSignalMask;
1194706f2543Smrgstatic int	BlockedSignalCount;
1195706f2543Smrg#endif
1196706f2543Smrg
1197706f2543Smrgvoid
1198706f2543SmrgOsBlockSignals (void)
1199706f2543Smrg{
1200706f2543Smrg#ifdef SIG_BLOCK
1201706f2543Smrg    if (BlockedSignalCount++ == 0)
1202706f2543Smrg    {
1203706f2543Smrg	sigset_t    set;
1204706f2543Smrg
1205706f2543Smrg	sigemptyset (&set);
1206706f2543Smrg	sigaddset (&set, SIGALRM);
1207706f2543Smrg	sigaddset (&set, SIGVTALRM);
1208706f2543Smrg#ifdef SIGWINCH
1209706f2543Smrg	sigaddset (&set, SIGWINCH);
1210706f2543Smrg#endif
1211706f2543Smrg#ifdef SIGIO
1212706f2543Smrg	sigaddset (&set, SIGIO);
1213706f2543Smrg#endif
1214706f2543Smrg	sigaddset (&set, SIGTSTP);
1215706f2543Smrg	sigaddset (&set, SIGTTIN);
1216706f2543Smrg	sigaddset (&set, SIGTTOU);
1217706f2543Smrg	sigaddset (&set, SIGCHLD);
1218706f2543Smrg	sigprocmask (SIG_BLOCK, &set, &PreviousSignalMask);
1219706f2543Smrg    }
1220706f2543Smrg#endif
1221706f2543Smrg}
1222706f2543Smrg
1223706f2543Smrgvoid
1224706f2543SmrgOsReleaseSignals (void)
1225706f2543Smrg{
1226706f2543Smrg#ifdef SIG_BLOCK
1227706f2543Smrg    if (--BlockedSignalCount == 0)
1228706f2543Smrg    {
1229706f2543Smrg	sigprocmask (SIG_SETMASK, &PreviousSignalMask, 0);
1230706f2543Smrg    }
1231706f2543Smrg#endif
1232706f2543Smrg}
1233706f2543Smrg
1234706f2543Smrg/*
1235706f2543Smrg * Pending signals may interfere with core dumping. Provide a
1236706f2543Smrg * mechanism to block signals when aborting.
1237706f2543Smrg */
1238706f2543Smrg
1239706f2543Smrgvoid
1240706f2543SmrgOsAbort (void)
1241706f2543Smrg{
1242706f2543Smrg#ifndef __APPLE__
1243706f2543Smrg    OsBlockSignals();
1244706f2543Smrg#endif
1245706f2543Smrg    abort();
1246706f2543Smrg}
1247706f2543Smrg
1248706f2543Smrg#if !defined(WIN32)
1249706f2543Smrg/*
1250706f2543Smrg * "safer" versions of system(3), popen(3) and pclose(3) which give up
1251706f2543Smrg * all privs before running a command.
1252706f2543Smrg *
1253706f2543Smrg * This is based on the code in FreeBSD 2.2 libc.
1254706f2543Smrg *
1255706f2543Smrg * XXX It'd be good to redirect stderr so that it ends up in the log file
1256706f2543Smrg * as well.  As it is now, xkbcomp messages don't end up in the log file.
1257706f2543Smrg */
1258706f2543Smrg
1259706f2543Smrgint
1260706f2543SmrgSystem(char *command)
1261706f2543Smrg{
1262706f2543Smrg    int pid, p;
1263706f2543Smrg    void (*csig)(int);
1264706f2543Smrg    int status;
1265706f2543Smrg
1266706f2543Smrg    if (!command)
1267706f2543Smrg	return 1;
1268706f2543Smrg
1269706f2543Smrg    csig = signal(SIGCHLD, SIG_DFL);
1270706f2543Smrg    if (csig == SIG_ERR) {
1271706f2543Smrg      perror("signal");
1272706f2543Smrg      return -1;
1273706f2543Smrg    }
1274706f2543Smrg    DebugF("System: `%s'\n", command);
1275706f2543Smrg
1276706f2543Smrg    switch (pid = fork()) {
1277706f2543Smrg    case -1:	/* error */
1278706f2543Smrg	p = -1;
1279706f2543Smrg    case 0:	/* child */
1280706f2543Smrg	if (setgid(getgid()) == -1)
1281706f2543Smrg	    _exit(127);
1282706f2543Smrg	if (setuid(getuid()) == -1)
1283706f2543Smrg	    _exit(127);
1284706f2543Smrg	execl("/bin/sh", "sh", "-c", command, (char *)NULL);
1285706f2543Smrg	_exit(127);
1286706f2543Smrg    default:	/* parent */
1287706f2543Smrg	do {
1288706f2543Smrg	    p = waitpid(pid, &status, 0);
1289706f2543Smrg	} while (p == -1 && errno == EINTR);
1290706f2543Smrg
1291706f2543Smrg    }
1292706f2543Smrg
1293706f2543Smrg    if (signal(SIGCHLD, csig) == SIG_ERR) {
1294706f2543Smrg      perror("signal");
1295706f2543Smrg      return -1;
1296706f2543Smrg    }
1297706f2543Smrg
1298706f2543Smrg    return p == -1 ? -1 : status;
1299706f2543Smrg}
1300706f2543Smrg
1301706f2543Smrgstatic struct pid {
1302706f2543Smrg    struct pid *next;
1303706f2543Smrg    FILE *fp;
1304706f2543Smrg    int pid;
1305706f2543Smrg} *pidlist;
1306706f2543Smrg
1307706f2543SmrgOsSigHandlerPtr old_alarm = NULL; /* XXX horrible awful hack */
1308706f2543Smrg
1309706f2543Smrgpointer
1310706f2543SmrgPopen(char *command, char *type)
1311706f2543Smrg{
1312706f2543Smrg    struct pid *cur;
1313706f2543Smrg    FILE *iop;
1314706f2543Smrg    int pdes[2], pid;
1315706f2543Smrg
1316706f2543Smrg    if (command == NULL || type == NULL)
1317706f2543Smrg	return NULL;
1318706f2543Smrg
1319706f2543Smrg    if ((*type != 'r' && *type != 'w') || type[1])
1320706f2543Smrg	return NULL;
1321706f2543Smrg
1322706f2543Smrg    if ((cur = malloc(sizeof(struct pid))) == NULL)
1323706f2543Smrg	return NULL;
1324706f2543Smrg
1325706f2543Smrg    if (pipe(pdes) < 0) {
1326706f2543Smrg	free(cur);
1327706f2543Smrg	return NULL;
1328706f2543Smrg    }
1329706f2543Smrg
1330706f2543Smrg    /* Ignore the smart scheduler while this is going on */
1331706f2543Smrg    old_alarm = OsSignal(SIGALRM, SIG_IGN);
1332706f2543Smrg    if (old_alarm == SIG_ERR) {
1333706f2543Smrg      close(pdes[0]);
1334706f2543Smrg      close(pdes[1]);
1335706f2543Smrg      free(cur);
1336706f2543Smrg      perror("signal");
1337706f2543Smrg      return NULL;
1338706f2543Smrg    }
1339706f2543Smrg
1340706f2543Smrg    switch (pid = fork()) {
1341706f2543Smrg    case -1: 	/* error */
1342706f2543Smrg	close(pdes[0]);
1343706f2543Smrg	close(pdes[1]);
1344706f2543Smrg	free(cur);
1345706f2543Smrg	if (OsSignal(SIGALRM, old_alarm) == SIG_ERR)
1346706f2543Smrg	  perror("signal");
1347706f2543Smrg	return NULL;
1348706f2543Smrg    case 0:	/* child */
1349706f2543Smrg	if (setgid(getgid()) == -1)
1350706f2543Smrg	    _exit(127);
1351706f2543Smrg	if (setuid(getuid()) == -1)
1352706f2543Smrg	    _exit(127);
1353706f2543Smrg	if (*type == 'r') {
1354706f2543Smrg	    if (pdes[1] != 1) {
1355706f2543Smrg		/* stdout */
1356706f2543Smrg		dup2(pdes[1], 1);
1357706f2543Smrg		close(pdes[1]);
1358706f2543Smrg	    }
1359706f2543Smrg	    close(pdes[0]);
1360706f2543Smrg	} else {
1361706f2543Smrg	    if (pdes[0] != 0) {
1362706f2543Smrg		/* stdin */
1363706f2543Smrg		dup2(pdes[0], 0);
1364706f2543Smrg		close(pdes[0]);
1365706f2543Smrg	    }
1366706f2543Smrg	    close(pdes[1]);
1367706f2543Smrg	}
1368706f2543Smrg	execl("/bin/sh", "sh", "-c", command, (char *)NULL);
1369706f2543Smrg	_exit(127);
1370706f2543Smrg    }
1371706f2543Smrg
1372706f2543Smrg    /* Avoid EINTR during stdio calls */
1373706f2543Smrg    OsBlockSignals ();
1374706f2543Smrg
1375706f2543Smrg    /* parent */
1376706f2543Smrg    if (*type == 'r') {
1377706f2543Smrg	iop = fdopen(pdes[0], type);
1378706f2543Smrg	close(pdes[1]);
1379706f2543Smrg    } else {
1380706f2543Smrg	iop = fdopen(pdes[1], type);
1381706f2543Smrg	close(pdes[0]);
1382706f2543Smrg    }
1383706f2543Smrg
1384706f2543Smrg    cur->fp = iop;
1385706f2543Smrg    cur->pid = pid;
1386706f2543Smrg    cur->next = pidlist;
1387706f2543Smrg    pidlist = cur;
1388706f2543Smrg
1389706f2543Smrg    DebugF("Popen: `%s', fp = %p\n", command, iop);
1390706f2543Smrg
1391706f2543Smrg    return iop;
1392706f2543Smrg}
1393706f2543Smrg
1394706f2543Smrg/* fopen that drops privileges */
1395706f2543Smrgpointer
1396706f2543SmrgFopen(char *file, char *type)
1397706f2543Smrg{
1398706f2543Smrg    FILE *iop;
1399706f2543Smrg#ifndef HAS_SAVED_IDS_AND_SETEUID
1400706f2543Smrg    struct pid *cur;
1401706f2543Smrg    int pdes[2], pid;
1402706f2543Smrg
1403706f2543Smrg    if (file == NULL || type == NULL)
1404706f2543Smrg	return NULL;
1405706f2543Smrg
1406706f2543Smrg    if ((*type != 'r' && *type != 'w') || type[1])
1407706f2543Smrg	return NULL;
1408706f2543Smrg
1409706f2543Smrg    if ((cur = malloc(sizeof(struct pid))) == NULL)
1410706f2543Smrg	return NULL;
1411706f2543Smrg
1412706f2543Smrg    if (pipe(pdes) < 0) {
1413706f2543Smrg	free(cur);
1414706f2543Smrg	return NULL;
1415706f2543Smrg    }
1416706f2543Smrg
1417706f2543Smrg    switch (pid = fork()) {
1418706f2543Smrg    case -1: 	/* error */
1419706f2543Smrg	close(pdes[0]);
1420706f2543Smrg	close(pdes[1]);
1421706f2543Smrg	free(cur);
1422706f2543Smrg	return NULL;
1423706f2543Smrg    case 0:	/* child */
1424706f2543Smrg	if (setgid(getgid()) == -1)
1425706f2543Smrg	    _exit(127);
1426706f2543Smrg	if (setuid(getuid()) == -1)
1427706f2543Smrg	    _exit(127);
1428706f2543Smrg	if (*type == 'r') {
1429706f2543Smrg	    if (pdes[1] != 1) {
1430706f2543Smrg		/* stdout */
1431706f2543Smrg		dup2(pdes[1], 1);
1432706f2543Smrg		close(pdes[1]);
1433706f2543Smrg	    }
1434706f2543Smrg	    close(pdes[0]);
1435706f2543Smrg	} else {
1436706f2543Smrg	    if (pdes[0] != 0) {
1437706f2543Smrg		/* stdin */
1438706f2543Smrg		dup2(pdes[0], 0);
1439706f2543Smrg		close(pdes[0]);
1440706f2543Smrg	    }
1441706f2543Smrg	    close(pdes[1]);
1442706f2543Smrg	}
1443706f2543Smrg	execl("/bin/cat", "cat", file, (char *)NULL);
1444706f2543Smrg	_exit(127);
1445706f2543Smrg    }
1446706f2543Smrg
1447706f2543Smrg    /* Avoid EINTR during stdio calls */
1448706f2543Smrg    OsBlockSignals ();
1449706f2543Smrg
1450706f2543Smrg    /* parent */
1451706f2543Smrg    if (*type == 'r') {
1452706f2543Smrg	iop = fdopen(pdes[0], type);
1453706f2543Smrg	close(pdes[1]);
1454706f2543Smrg    } else {
1455706f2543Smrg	iop = fdopen(pdes[1], type);
1456706f2543Smrg	close(pdes[0]);
1457706f2543Smrg    }
1458706f2543Smrg
1459706f2543Smrg    cur->fp = iop;
1460706f2543Smrg    cur->pid = pid;
1461706f2543Smrg    cur->next = pidlist;
1462706f2543Smrg    pidlist = cur;
1463706f2543Smrg
1464706f2543Smrg    DebugF("Fopen(%s), fp = %p\n", file, iop);
1465706f2543Smrg
1466706f2543Smrg    return iop;
1467706f2543Smrg#else
1468706f2543Smrg    int ruid, euid;
1469706f2543Smrg
1470706f2543Smrg    ruid = getuid();
1471706f2543Smrg    euid = geteuid();
1472706f2543Smrg
1473706f2543Smrg    if (seteuid(ruid) == -1) {
1474706f2543Smrg	    return NULL;
1475706f2543Smrg    }
1476706f2543Smrg    iop = fopen(file, type);
1477706f2543Smrg
1478706f2543Smrg    if (seteuid(euid) == -1) {
1479706f2543Smrg	    fclose(iop);
1480706f2543Smrg	    return NULL;
1481706f2543Smrg    }
1482706f2543Smrg    return iop;
1483706f2543Smrg#endif /* HAS_SAVED_IDS_AND_SETEUID */
1484706f2543Smrg}
1485706f2543Smrg
1486706f2543Smrgint
1487706f2543SmrgPclose(pointer iop)
1488706f2543Smrg{
1489706f2543Smrg    struct pid *cur, *last;
1490706f2543Smrg    int pstat;
1491706f2543Smrg    int pid;
1492706f2543Smrg
1493706f2543Smrg    DebugF("Pclose: fp = %p\n", iop);
1494706f2543Smrg    fclose(iop);
1495706f2543Smrg
1496706f2543Smrg    for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
1497706f2543Smrg	if (cur->fp == iop)
1498706f2543Smrg	    break;
1499706f2543Smrg    if (cur == NULL)
1500706f2543Smrg	return -1;
1501706f2543Smrg
1502706f2543Smrg    do {
1503706f2543Smrg	pid = waitpid(cur->pid, &pstat, 0);
1504706f2543Smrg    } while (pid == -1 && errno == EINTR);
1505706f2543Smrg
1506706f2543Smrg    if (last == NULL)
1507706f2543Smrg	pidlist = cur->next;
1508706f2543Smrg    else
1509706f2543Smrg	last->next = cur->next;
1510706f2543Smrg    free(cur);
1511706f2543Smrg
1512706f2543Smrg    /* allow EINTR again */
1513706f2543Smrg    OsReleaseSignals ();
1514706f2543Smrg
1515706f2543Smrg    if (old_alarm && OsSignal(SIGALRM, old_alarm) == SIG_ERR) {
1516706f2543Smrg      perror("signal");
1517706f2543Smrg      return -1;
1518706f2543Smrg    }
1519706f2543Smrg
1520706f2543Smrg    return pid == -1 ? -1 : pstat;
1521706f2543Smrg}
1522706f2543Smrg
1523706f2543Smrgint
1524706f2543SmrgFclose(pointer iop)
1525706f2543Smrg{
1526706f2543Smrg#ifdef HAS_SAVED_IDS_AND_SETEUID
1527706f2543Smrg    return fclose(iop);
1528706f2543Smrg#else
1529706f2543Smrg    return Pclose(iop);
1530706f2543Smrg#endif
1531706f2543Smrg}
1532706f2543Smrg
1533706f2543Smrg#endif /* !WIN32 */
1534706f2543Smrg
1535706f2543Smrg
1536706f2543Smrg/*
1537706f2543Smrg * CheckUserParameters: check for long command line arguments and long
1538706f2543Smrg * environment variables.  By default, these checks are only done when
1539706f2543Smrg * the server's euid != ruid.  In 3.3.x, these checks were done in an
1540706f2543Smrg * external wrapper utility.
1541706f2543Smrg */
1542706f2543Smrg
1543706f2543Smrg/* Consider LD* variables insecure? */
1544706f2543Smrg#ifndef REMOVE_ENV_LD
1545706f2543Smrg#define REMOVE_ENV_LD 1
1546706f2543Smrg#endif
1547706f2543Smrg
1548706f2543Smrg/* Remove long environment variables? */
1549706f2543Smrg#ifndef REMOVE_LONG_ENV
1550706f2543Smrg#define REMOVE_LONG_ENV 1
1551706f2543Smrg#endif
1552706f2543Smrg
1553706f2543Smrg/*
1554706f2543Smrg * Disallow stdout or stderr as pipes?  It's possible to block the X server
1555706f2543Smrg * when piping stdout+stderr to a pipe.
1556706f2543Smrg *
1557706f2543Smrg * Don't enable this because it looks like it's going to cause problems.
1558706f2543Smrg */
1559706f2543Smrg#ifndef NO_OUTPUT_PIPES
1560706f2543Smrg#define NO_OUTPUT_PIPES 0
1561706f2543Smrg#endif
1562706f2543Smrg
1563706f2543Smrg
1564706f2543Smrg/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
1565706f2543Smrg#ifndef CHECK_EUID
1566706f2543Smrg#ifndef WIN32
1567706f2543Smrg#define CHECK_EUID 1
1568706f2543Smrg#else
1569706f2543Smrg#define CHECK_EUID 0
1570706f2543Smrg#endif
1571706f2543Smrg#endif
1572706f2543Smrg
1573706f2543Smrg/*
1574706f2543Smrg * Maybe the locale can be faked to make isprint(3) report that everything
1575706f2543Smrg * is printable?  Avoid it by default.
1576706f2543Smrg */
1577706f2543Smrg#ifndef USE_ISPRINT
1578706f2543Smrg#define USE_ISPRINT 0
1579706f2543Smrg#endif
1580706f2543Smrg
1581706f2543Smrg#define MAX_ARG_LENGTH          128
1582706f2543Smrg#define MAX_ENV_LENGTH          256
1583706f2543Smrg#define MAX_ENV_PATH_LENGTH     2048	/* Limit for *PATH and TERMCAP */
1584706f2543Smrg
1585706f2543Smrg#if USE_ISPRINT
1586706f2543Smrg#include <ctype.h>
1587706f2543Smrg#define checkPrintable(c) isprint(c)
1588706f2543Smrg#else
1589706f2543Smrg#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
1590706f2543Smrg#endif
1591706f2543Smrg
1592706f2543Smrgenum BadCode {
1593706f2543Smrg    NotBad = 0,
1594706f2543Smrg    UnsafeArg,
1595706f2543Smrg    ArgTooLong,
1596706f2543Smrg    UnprintableArg,
1597706f2543Smrg    EnvTooLong,
1598706f2543Smrg    OutputIsPipe,
1599706f2543Smrg    InternalError
1600706f2543Smrg};
1601706f2543Smrg
1602706f2543Smrg#if defined(VENDORSUPPORT)
1603706f2543Smrg#define BUGADDRESS VENDORSUPPORT
1604706f2543Smrg#elif defined(BUILDERADDR)
1605706f2543Smrg#define BUGADDRESS BUILDERADDR
1606706f2543Smrg#else
1607706f2543Smrg#define BUGADDRESS "xorg@freedesktop.org"
1608706f2543Smrg#endif
1609706f2543Smrg
1610706f2543Smrgvoid
1611706f2543SmrgCheckUserParameters(int argc, char **argv, char **envp)
1612706f2543Smrg{
1613706f2543Smrg    enum BadCode bad = NotBad;
1614706f2543Smrg    int i = 0, j;
1615706f2543Smrg    char *a, *e = NULL;
1616706f2543Smrg
1617706f2543Smrg#if CHECK_EUID
1618706f2543Smrg    if (geteuid() == 0 && getuid() != geteuid())
1619706f2543Smrg#endif
1620706f2543Smrg    {
1621706f2543Smrg	/* Check each argv[] */
1622706f2543Smrg	for (i = 1; i < argc; i++) {
1623706f2543Smrg	    if (strcmp(argv[i], "-fp") == 0)
1624706f2543Smrg	    {
1625706f2543Smrg		i++; /* continue with next argument. skip the length check */
1626706f2543Smrg		if (i >= argc)
1627706f2543Smrg		    break;
1628706f2543Smrg	    } else
1629706f2543Smrg	    {
1630706f2543Smrg		if (strlen(argv[i]) > MAX_ARG_LENGTH) {
1631706f2543Smrg		    bad = ArgTooLong;
1632706f2543Smrg		    break;
1633706f2543Smrg		}
1634706f2543Smrg	    }
1635706f2543Smrg	    a = argv[i];
1636706f2543Smrg	    while (*a) {
1637706f2543Smrg		if (checkPrintable(*a) == 0) {
1638706f2543Smrg		    bad = UnprintableArg;
1639706f2543Smrg		    break;
1640706f2543Smrg		}
1641706f2543Smrg		a++;
1642706f2543Smrg	    }
1643706f2543Smrg	    if (bad)
1644706f2543Smrg		break;
1645706f2543Smrg	}
1646706f2543Smrg	if (!bad) {
1647706f2543Smrg	    /* Check each envp[] */
1648706f2543Smrg	    for (i = 0; envp[i]; i++) {
1649706f2543Smrg
1650706f2543Smrg		/* Check for bad environment variables and values */
1651706f2543Smrg#if REMOVE_ENV_LD
1652706f2543Smrg		while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
1653706f2543Smrg		    for (j = i; envp[j]; j++) {
1654706f2543Smrg			envp[j] = envp[j+1];
1655706f2543Smrg		    }
1656706f2543Smrg		}
1657706f2543Smrg#endif
1658706f2543Smrg		if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
1659706f2543Smrg#if REMOVE_LONG_ENV
1660706f2543Smrg		    for (j = i; envp[j]; j++) {
1661706f2543Smrg			envp[j] = envp[j+1];
1662706f2543Smrg		    }
1663706f2543Smrg		    i--;
1664706f2543Smrg#else
1665706f2543Smrg		    char *eq;
1666706f2543Smrg		    int len;
1667706f2543Smrg
1668706f2543Smrg		    eq = strchr(envp[i], '=');
1669706f2543Smrg		    if (!eq)
1670706f2543Smrg			continue;
1671706f2543Smrg		    len = eq - envp[i];
1672706f2543Smrg		    e = malloc(len + 1);
1673706f2543Smrg		    if (!e) {
1674706f2543Smrg			bad = InternalError;
1675706f2543Smrg			break;
1676706f2543Smrg		    }
1677706f2543Smrg		    strncpy(e, envp[i], len);
1678706f2543Smrg		    e[len] = 0;
1679706f2543Smrg		    if (len >= 4 &&
1680706f2543Smrg			(strcmp(e + len - 4, "PATH") == 0 ||
1681706f2543Smrg			 strcmp(e, "TERMCAP") == 0)) {
1682706f2543Smrg			if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
1683706f2543Smrg			    bad = EnvTooLong;
1684706f2543Smrg			    break;
1685706f2543Smrg			} else {
1686706f2543Smrg			    free(e);
1687706f2543Smrg			}
1688706f2543Smrg		    } else {
1689706f2543Smrg			bad = EnvTooLong;
1690706f2543Smrg			break;
1691706f2543Smrg		    }
1692706f2543Smrg#endif
1693706f2543Smrg		}
1694706f2543Smrg	    }
1695706f2543Smrg	}
1696706f2543Smrg#if NO_OUTPUT_PIPES
1697706f2543Smrg	if (!bad) {
1698706f2543Smrg	    struct stat buf;
1699706f2543Smrg
1700706f2543Smrg	    if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode))
1701706f2543Smrg		bad = OutputIsPipe;
1702706f2543Smrg	    if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode))
1703706f2543Smrg		bad = OutputIsPipe;
1704706f2543Smrg	}
1705706f2543Smrg#endif
1706706f2543Smrg    }
1707706f2543Smrg    switch (bad) {
1708706f2543Smrg    case NotBad:
1709706f2543Smrg	return;
1710706f2543Smrg    case UnsafeArg:
1711706f2543Smrg	ErrorF("Command line argument number %d is unsafe\n", i);
1712706f2543Smrg	break;
1713706f2543Smrg    case ArgTooLong:
1714706f2543Smrg	ErrorF("Command line argument number %d is too long\n", i);
1715706f2543Smrg	break;
1716706f2543Smrg    case UnprintableArg:
1717706f2543Smrg	ErrorF("Command line argument number %d contains unprintable"
1718706f2543Smrg		" characters\n", i);
1719706f2543Smrg	break;
1720706f2543Smrg    case EnvTooLong:
1721706f2543Smrg	ErrorF("Environment variable `%s' is too long\n", e);
1722706f2543Smrg	break;
1723706f2543Smrg    case OutputIsPipe:
1724706f2543Smrg	ErrorF("Stdout and/or stderr is a pipe\n");
1725706f2543Smrg	break;
1726706f2543Smrg    case InternalError:
1727706f2543Smrg	ErrorF("Internal Error\n");
1728706f2543Smrg	break;
1729706f2543Smrg    default:
1730706f2543Smrg	ErrorF("Unknown error\n");
1731706f2543Smrg	break;
1732706f2543Smrg    }
1733706f2543Smrg    FatalError("X server aborted because of unsafe environment\n");
1734706f2543Smrg}
1735706f2543Smrg
1736706f2543Smrg/*
1737706f2543Smrg * CheckUserAuthorization: check if the user is allowed to start the
1738706f2543Smrg * X server.  This usually means some sort of PAM checking, and it is
1739706f2543Smrg * usually only done for setuid servers (uid != euid).
1740706f2543Smrg */
1741706f2543Smrg
1742706f2543Smrg#ifdef USE_PAM
1743706f2543Smrg#include <security/pam_appl.h>
1744706f2543Smrg#include <security/pam_misc.h>
1745706f2543Smrg#include <pwd.h>
1746706f2543Smrg#endif /* USE_PAM */
1747706f2543Smrg
1748706f2543Smrgvoid
1749706f2543SmrgCheckUserAuthorization(void)
1750706f2543Smrg{
1751706f2543Smrg#ifdef USE_PAM
1752706f2543Smrg    static struct pam_conv conv = {
1753706f2543Smrg	misc_conv,
1754706f2543Smrg	NULL
1755706f2543Smrg    };
1756706f2543Smrg
1757706f2543Smrg    pam_handle_t *pamh = NULL;
1758706f2543Smrg    struct passwd *pw;
1759706f2543Smrg    int retval;
1760706f2543Smrg
1761706f2543Smrg    if (getuid() != geteuid()) {
1762706f2543Smrg	pw = getpwuid(getuid());
1763706f2543Smrg	if (pw == NULL)
1764706f2543Smrg	    FatalError("getpwuid() failed for uid %d\n", getuid());
1765706f2543Smrg
1766706f2543Smrg	retval = pam_start("xserver", pw->pw_name, &conv, &pamh);
1767706f2543Smrg	if (retval != PAM_SUCCESS)
1768706f2543Smrg	    FatalError("pam_start() failed.\n"
1769706f2543Smrg			"\tMissing or mangled PAM config file or module?\n");
1770706f2543Smrg
1771706f2543Smrg	retval = pam_authenticate(pamh, 0);
1772706f2543Smrg	if (retval != PAM_SUCCESS) {
1773706f2543Smrg	    pam_end(pamh, retval);
1774706f2543Smrg	    FatalError("PAM authentication failed, cannot start X server.\n"
1775706f2543Smrg			"\tPerhaps you do not have console ownership?\n");
1776706f2543Smrg	}
1777706f2543Smrg
1778706f2543Smrg	retval = pam_acct_mgmt(pamh, 0);
1779706f2543Smrg	if (retval != PAM_SUCCESS) {
1780706f2543Smrg	    pam_end(pamh, retval);
1781706f2543Smrg	    FatalError("PAM authentication failed, cannot start X server.\n"
1782706f2543Smrg			"\tPerhaps you do not have console ownership?\n");
1783706f2543Smrg	}
1784706f2543Smrg
1785706f2543Smrg	/* this is not a session, so do not do session management */
1786706f2543Smrg	pam_end(pamh, PAM_SUCCESS);
1787706f2543Smrg    }
1788706f2543Smrg#endif
1789706f2543Smrg}
1790706f2543Smrg
1791706f2543Smrg/*
1792706f2543Smrg * Tokenize a string into a NULL terminated array of strings. Always returns
1793706f2543Smrg * an allocated array unless an error occurs.
1794706f2543Smrg */
1795706f2543Smrgchar**
1796706f2543Smrgxstrtokenize(const char *str, const char *separators)
1797706f2543Smrg{
1798706f2543Smrg    char **list, **nlist;
1799706f2543Smrg    char *tok, *tmp;
1800706f2543Smrg    unsigned num = 0, n;
1801706f2543Smrg
1802706f2543Smrg    if (!str)
1803706f2543Smrg        return NULL;
1804706f2543Smrg    list = calloc(1, sizeof(*list));
1805706f2543Smrg    if (!list)
1806706f2543Smrg        return NULL;
1807706f2543Smrg    tmp = strdup(str);
1808706f2543Smrg    if (!tmp)
1809706f2543Smrg        goto error;
1810706f2543Smrg    for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) {
1811706f2543Smrg        nlist = realloc(list, (num + 2) * sizeof(*list));
1812706f2543Smrg        if (!nlist)
1813706f2543Smrg            goto error;
1814706f2543Smrg        list = nlist;
1815706f2543Smrg        list[num] = strdup(tok);
1816706f2543Smrg        if (!list[num])
1817706f2543Smrg            goto error;
1818706f2543Smrg        list[++num] = NULL;
1819706f2543Smrg    }
1820706f2543Smrg    free(tmp);
1821706f2543Smrg    return list;
1822706f2543Smrg
1823706f2543Smrgerror:
1824706f2543Smrg    free(tmp);
1825706f2543Smrg    for (n = 0; n < num; n++)
1826706f2543Smrg        free(list[n]);
1827706f2543Smrg    free(list);
1828706f2543Smrg    return NULL;
1829706f2543Smrg}
1830