Home | History | Annotate | Line # | Download | only in os
      1 /*
      2 
      3 Copyright 1987, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included
     12 in all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 OTHER DEALINGS IN THE SOFTWARE.
     21 
     22 Except as contained in this notice, the name of The Open Group shall
     23 not be used in advertising or otherwise to promote the sale, use or
     24 other dealings in this Software without prior written authorization
     25 from The Open Group.
     26 
     27 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
     28 Copyright 1994 Quarterdeck Office Systems.
     29 
     30                         All Rights Reserved
     31 
     32 Permission to use, copy, modify, and distribute this software and its
     33 documentation for any purpose and without fee is hereby granted,
     34 provided that the above copyright notice appear in all copies and that
     35 both that copyright notice and this permission notice appear in
     36 supporting documentation, and that the names of Digital and
     37 Quarterdeck not be used in advertising or publicity pertaining to
     38 distribution of the software without specific, written prior
     39 permission.
     40 
     41 DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
     42 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
     43 FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
     44 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
     45 OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
     46 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
     47 OR PERFORMANCE OF THIS SOFTWARE.
     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 #endif
     75 #include "misc.h"
     76 #include <X11/X.h>
     77 #define XSERV_t
     78 #define TRANS_SERVER
     79 #define TRANS_REOPEN
     80 #include <X11/Xtrans/Xtrans.h>
     81 #include "input.h"
     82 #include "dixfont.h"
     83 #include <X11/fonts/libxfont2.h>
     84 #include "osdep.h"
     85 #include "extension.h"
     86 #include <signal.h>
     87 #ifndef WIN32
     88 #include <sys/wait.h>
     89 #endif
     90 #if !defined(SYSV) && !defined(WIN32)
     91 #include <sys/resource.h>
     92 #endif
     93 #include <sys/stat.h>
     94 #include <ctype.h>              /* for isspace */
     95 #include <stdarg.h>
     96 
     97 #include <stdlib.h>             /* for malloc() */
     98 
     99 #if defined(TCPCONN)
    100 #ifndef WIN32
    101 #include <netdb.h>
    102 #endif
    103 #endif
    104 
    105 #include "opaque.h"
    106 
    107 #include "dixstruct.h"
    108 
    109 #include "xkbsrv.h"
    110 
    111 #include "picture.h"
    112 
    113 #include "miinitext.h"
    114 
    115 #include "present.h"
    116 
    117 Bool noTestExtensions;
    118 
    119 #ifdef COMPOSITE
    120 Bool noCompositeExtension = FALSE;
    121 #endif
    122 
    123 #ifdef DAMAGE
    124 Bool noDamageExtension = FALSE;
    125 #endif
    126 #ifdef DBE
    127 Bool noDbeExtension = FALSE;
    128 #endif
    129 #ifdef DPMSExtension
    130 #include "dpmsproc.h"
    131 Bool noDPMSExtension = FALSE;
    132 #endif
    133 #ifdef GLXEXT
    134 Bool noGlxExtension = FALSE;
    135 #endif
    136 #ifdef SCREENSAVER
    137 Bool noScreenSaverExtension = FALSE;
    138 #endif
    139 #ifdef MITSHM
    140 Bool noMITShmExtension = FALSE;
    141 #endif
    142 #ifdef RANDR
    143 Bool noRRExtension = FALSE;
    144 #endif
    145 Bool noRenderExtension = FALSE;
    146 
    147 #ifdef XCSECURITY
    148 Bool noSecurityExtension = FALSE;
    149 #endif
    150 #ifdef RES
    151 Bool noResExtension = FALSE;
    152 #endif
    153 #ifdef XF86BIGFONT
    154 Bool noXFree86BigfontExtension = FALSE;
    155 #endif
    156 #ifdef XFreeXDGA
    157 Bool noXFree86DGAExtension = FALSE;
    158 #endif
    159 #ifdef XF86DRI
    160 Bool noXFree86DRIExtension = FALSE;
    161 #endif
    162 #ifdef XF86VIDMODE
    163 Bool noXFree86VidModeExtension = FALSE;
    164 #endif
    165 Bool noXFixesExtension = FALSE;
    166 #ifdef PANORAMIX
    167 /* Xinerama is disabled by default unless enabled via +xinerama */
    168 Bool noPanoramiXExtension = TRUE;
    169 #endif
    170 #ifdef XSELINUX
    171 Bool noSELinuxExtension = FALSE;
    172 int selinuxEnforcingState = SELINUX_MODE_DEFAULT;
    173 #endif
    174 #ifdef XV
    175 Bool noXvExtension = FALSE;
    176 #endif
    177 #ifdef DRI2
    178 Bool noDRI2Extension = FALSE;
    179 #endif
    180 
    181 Bool noGEExtension = FALSE;
    182 
    183 #define X_INCLUDE_NETDB_H
    184 #include <X11/Xos_r.h>
    185 
    186 #include <errno.h>
    187 
    188 Bool CoreDump;
    189 
    190 Bool enableIndirectGLX = FALSE;
    191 
    192 Bool AllowByteSwappedClients = TRUE;
    193 
    194 #ifdef PANORAMIX
    195 Bool PanoramiXExtensionDisabledHack = FALSE;
    196 #endif
    197 
    198 int auditTrailLevel = 1;
    199 
    200 char *SeatId = NULL;
    201 
    202 sig_atomic_t inSignalContext = FALSE;
    203 
    204 #if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
    205 #define HAS_SAVED_IDS_AND_SETEUID
    206 #endif
    207 
    208 #ifdef MONOTONIC_CLOCK
    209 static clockid_t clockid;
    210 #endif
    211 
    212 OsSigHandlerPtr
    213 OsSignal(int sig, OsSigHandlerPtr handler)
    214 {
    215 #if defined(WIN32) && !defined(__CYGWIN__)
    216     return signal(sig, handler);
    217 #else
    218     struct sigaction act, oact;
    219 
    220     sigemptyset(&act.sa_mask);
    221     if (handler != SIG_IGN)
    222         sigaddset(&act.sa_mask, sig);
    223     act.sa_flags = 0;
    224     act.sa_handler = handler;
    225     if (sigaction(sig, &act, &oact))
    226         perror("sigaction");
    227     return oact.sa_handler;
    228 #endif
    229 }
    230 
    231 /*
    232  * Explicit support for a server lock file like the ones used for UUCP.
    233  * For architectures with virtual terminals that can run more than one
    234  * server at a time.  This keeps the servers from stomping on each other
    235  * if the user forgets to give them different display numbers.
    236  */
    237 #define LOCK_DIR "/tmp"
    238 #define LOCK_TMP_PREFIX "/.tX"
    239 #define LOCK_PREFIX "/.X"
    240 #define LOCK_SUFFIX "-lock"
    241 
    242 #if !defined(WIN32) || defined(__CYGWIN__)
    243 #define LOCK_SERVER
    244 #endif
    245 
    246 #ifndef LOCK_SERVER
    247 void
    248 LockServer(void)
    249 {}
    250 
    251 void
    252 UnlockServer(void)
    253 {}
    254 #else /* LOCK_SERVER */
    255 static Bool StillLocking = FALSE;
    256 static char LockFile[PATH_MAX];
    257 static Bool nolock = FALSE;
    258 
    259 /*
    260  * LockServer --
    261  *      Check if the server lock file exists.  If so, check if the PID
    262  *      contained inside is valid.  If so, then die.  Otherwise, create
    263  *      the lock file containing the PID.
    264  */
    265 void
    266 LockServer(void)
    267 {
    268     char tmp[PATH_MAX], pid_str[12];
    269     int lfd, i, haslock, l_pid, t;
    270     const char *tmppath = LOCK_DIR;
    271     int len;
    272     char port[20];
    273 
    274     if (nolock || NoListenAll)
    275         return;
    276     /*
    277      * Path names
    278      */
    279     snprintf(port, sizeof(port), "%d", atoi(display));
    280     len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) :
    281         strlen(LOCK_TMP_PREFIX);
    282     len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1;
    283     if (len > sizeof(LockFile))
    284         FatalError("Display name `%s' is too long\n", port);
    285     (void) sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
    286     (void) sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
    287 
    288     /*
    289      * Create a temporary file containing our PID.  Attempt three times
    290      * to create the file.
    291      */
    292     StillLocking = TRUE;
    293     i = 0;
    294     do {
    295         i++;
    296         lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
    297         if (lfd < 0)
    298             sleep(2);
    299         else
    300             break;
    301     } while (i < 3);
    302     if (lfd < 0) {
    303         unlink(tmp);
    304         i = 0;
    305         do {
    306             i++;
    307             lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
    308             if (lfd < 0)
    309                 sleep(2);
    310             else
    311                 break;
    312         } while (i < 3);
    313     }
    314     if (lfd < 0)
    315         FatalError("Could not create lock file in %s\n", tmp);
    316     snprintf(pid_str, sizeof(pid_str), "%10lu\n", (unsigned long) getpid());
    317     if (write(lfd, pid_str, 11) != 11)
    318         FatalError("Could not write pid to lock file in %s\n", tmp);
    319     (void) fchmod(lfd, 0444);
    320     (void) close(lfd);
    321 
    322     /*
    323      * OK.  Now the tmp file exists.  Try three times to move it in place
    324      * for the lock.
    325      */
    326     i = 0;
    327     haslock = 0;
    328     while ((!haslock) && (i++ < 3)) {
    329         haslock = (link(tmp, LockFile) == 0);
    330         if (haslock) {
    331             /*
    332              * We're done.
    333              */
    334             break;
    335         }
    336         else if (errno == EEXIST) {
    337             /*
    338              * Read the pid from the existing file
    339              */
    340             lfd = open(LockFile, O_RDONLY | O_NOFOLLOW);
    341             if (lfd < 0) {
    342                 unlink(tmp);
    343                 FatalError("Can't read lock file %s\n", LockFile);
    344             }
    345             pid_str[0] = '\0';
    346             if (read(lfd, pid_str, 11) != 11) {
    347                 /*
    348                  * Bogus lock file.
    349                  */
    350                 unlink(LockFile);
    351                 close(lfd);
    352                 continue;
    353             }
    354             pid_str[11] = '\0';
    355             sscanf(pid_str, "%d", &l_pid);
    356             close(lfd);
    357 
    358             /*
    359              * Now try to kill the PID to see if it exists.
    360              */
    361             errno = 0;
    362             t = kill(l_pid, 0);
    363             if ((t < 0) && (errno == ESRCH)) {
    364                 /*
    365                  * Stale lock file.
    366                  */
    367                 unlink(LockFile);
    368                 continue;
    369             }
    370             else if (((t < 0) && (errno == EPERM)) || (t == 0)) {
    371                 /*
    372                  * Process is still active.
    373                  */
    374                 unlink(tmp);
    375                 FatalError
    376                     ("Server is already active for display %s\n%s %s\n%s\n",
    377                      port, "\tIf this server is no longer running, remove",
    378                      LockFile, "\tand start again.");
    379             }
    380         }
    381         else {
    382             unlink(tmp);
    383             FatalError
    384                 ("Linking lock file (%s) in place failed: %s\n",
    385                  LockFile, strerror(errno));
    386         }
    387     }
    388     unlink(tmp);
    389     if (!haslock)
    390         FatalError("Could not create server lock file: %s\n", LockFile);
    391     StillLocking = FALSE;
    392 }
    393 
    394 /*
    395  * UnlockServer --
    396  *      Remove the server lock file.
    397  */
    398 void
    399 UnlockServer(void)
    400 {
    401     if (nolock || NoListenAll)
    402         return;
    403 
    404     if (!StillLocking) {
    405 
    406         (void) unlink(LockFile);
    407     }
    408 }
    409 #endif /* LOCK_SERVER */
    410 
    411 /* Force connections to close on SIGHUP from init */
    412 
    413 void
    414 AutoResetServer(int sig)
    415 {
    416     int olderrno = errno;
    417 
    418     dispatchException |= DE_RESET;
    419     isItTimeToYield = TRUE;
    420     errno = olderrno;
    421 }
    422 
    423 /* Force connections to close and then exit on SIGTERM, SIGINT */
    424 
    425 void
    426 GiveUp(int sig)
    427 {
    428     int olderrno = errno;
    429 
    430     dispatchException |= DE_TERMINATE;
    431     isItTimeToYield = TRUE;
    432     errno = olderrno;
    433 }
    434 
    435 #ifdef MONOTONIC_CLOCK
    436 void
    437 ForceClockId(clockid_t forced_clockid)
    438 {
    439     struct timespec tp;
    440 
    441     BUG_RETURN (clockid);
    442 
    443     clockid = forced_clockid;
    444 
    445     if (clock_gettime(clockid, &tp) != 0) {
    446         FatalError("Forced clock id failed to retrieve current time: %s\n",
    447                    strerror(errno));
    448         return;
    449     }
    450 }
    451 #endif
    452 
    453 #if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__)
    454 CARD32
    455 GetTimeInMillis(void)
    456 {
    457     return GetTickCount();
    458 }
    459 CARD64
    460 GetTimeInMicros(void)
    461 {
    462     return (CARD64) GetTickCount() * 1000;
    463 }
    464 #else
    465 CARD32
    466 GetTimeInMillis(void)
    467 {
    468     struct timeval tv;
    469 
    470 #ifdef MONOTONIC_CLOCK
    471     struct timespec tp;
    472 
    473     if (!clockid) {
    474 #ifdef CLOCK_MONOTONIC_COARSE
    475         if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
    476             (tp.tv_nsec / 1000) <= 1000 &&
    477             clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
    478             clockid = CLOCK_MONOTONIC_COARSE;
    479         else
    480 #endif
    481         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
    482             clockid = CLOCK_MONOTONIC;
    483         else
    484             clockid = ~0L;
    485     }
    486     if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
    487         return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
    488 #endif
    489 
    490     X_GETTIMEOFDAY(&tv);
    491     return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
    492 }
    493 
    494 CARD64
    495 GetTimeInMicros(void)
    496 {
    497     struct timeval tv;
    498 #ifdef MONOTONIC_CLOCK
    499     struct timespec tp;
    500     static clockid_t uclockid;
    501 
    502     if (!uclockid) {
    503         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
    504             uclockid = CLOCK_MONOTONIC;
    505         else
    506             uclockid = ~0L;
    507     }
    508     if (uclockid != ~0L && clock_gettime(uclockid, &tp) == 0)
    509         return (CARD64) tp.tv_sec * (CARD64)1000000 + tp.tv_nsec / 1000;
    510 #endif
    511 
    512     X_GETTIMEOFDAY(&tv);
    513     return (CARD64) tv.tv_sec * (CARD64)1000000 + (CARD64) tv.tv_usec;
    514 }
    515 #endif
    516 
    517 void
    518 UseMsg(void)
    519 {
    520     ErrorF("use: X [:<display>] [option]\n");
    521     ErrorF("-a #                   default pointer acceleration (factor)\n");
    522     ErrorF("-ac                    disable access control restrictions\n");
    523     ErrorF("-audit int             set audit trail level\n");
    524     ErrorF("-auth file             select authorization file\n");
    525     ErrorF("-br                    create root window with black background\n");
    526     ErrorF("+bs                    enable any backing store support\n");
    527     ErrorF("-bs                    disable any backing store support\n");
    528     ErrorF("+byteswappedclients    Allow clients with endianess different to that of the server\n");
    529     ErrorF("-byteswappedclients    Prohibit clients with endianess different to that of the server\n");
    530     ErrorF("-c                     turns off key-click\n");
    531     ErrorF("c #                    key-click volume (0-100)\n");
    532     ErrorF("-cc int                default color visual class\n");
    533     ErrorF("-nocursor              disable the cursor\n");
    534     ErrorF("-core                  generate core dump on fatal error\n");
    535     ErrorF("-displayfd fd          file descriptor to write display number to when ready to connect\n");
    536     ErrorF("-dpi int               screen resolution in dots per inch\n");
    537 #ifdef DPMSExtension
    538     ErrorF("-dpms                  disables VESA DPMS monitor control\n");
    539 #endif
    540     ErrorF
    541         ("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n");
    542     ErrorF("-f #                   bell base (0-100)\n");
    543     ErrorF("-fakescreenfps #       fake screen default fps (1-600)\n");
    544     ErrorF("-fp string             default font path\n");
    545     ErrorF("-help                  prints message with these options\n");
    546     ErrorF("+iglx                  Allow creating indirect GLX contexts\n");
    547     ErrorF("-iglx                  Prohibit creating indirect GLX contexts (default)\n");
    548     ErrorF("-I                     ignore all remaining arguments\n");
    549 #ifdef RLIMIT_DATA
    550     ErrorF("-ld int                limit data space to N Kb\n");
    551 #endif
    552 #ifdef RLIMIT_NOFILE
    553     ErrorF("-lf int                limit number of open files to N\n");
    554 #endif
    555 #ifdef RLIMIT_STACK
    556     ErrorF("-ls int                limit stack space to N Kb\n");
    557 #endif
    558 #ifdef LOCK_SERVER
    559     ErrorF("-nolock                disable the locking mechanism\n");
    560 #endif
    561     ErrorF("-maxclients n          set maximum number of clients (power of two)\n");
    562     ErrorF("-nolisten string       don't listen on protocol\n");
    563     ErrorF("-listen string         listen on protocol\n");
    564     ErrorF("-noreset               don't reset after last client exists\n");
    565     ErrorF("-background [none]     create root window with no background\n");
    566     ErrorF("-reset                 reset after last client exists\n");
    567     ErrorF("-p #                   screen-saver pattern duration (minutes)\n");
    568     ErrorF("-pn                    accept failure to listen on all ports\n");
    569     ErrorF("-nopn                  reject failure to listen on all ports\n");
    570     ErrorF("-r                     turns off auto-repeat\n");
    571     ErrorF("r                      turns on auto-repeat \n");
    572     ErrorF("-render [default|mono|gray|color] set render color alloc policy\n");
    573     ErrorF("-retro                 start with classic stipple and cursor\n");
    574     ErrorF("-noretro               start with black background and no cursor\n");
    575     ErrorF("-s #                   screen-saver timeout (minutes)\n");
    576     ErrorF("-seat string           seat to run on\n");
    577     ErrorF("-t #                   default pointer threshold (pixels/t)\n");
    578     ErrorF("-terminate [delay]     terminate at server reset (optional delay in sec)\n");
    579     ErrorF("-tst                   disable testing extensions\n");
    580     ErrorF("ttyxx                  server started from init on /dev/ttyxx\n");
    581     ErrorF("v                      video blanking for screen-saver\n");
    582     ErrorF("-v                     screen-saver without video blanking\n");
    583     ErrorF("-wr                    create root window with white background\n");
    584     ErrorF("-maxbigreqsize         set maximal bigrequest size \n");
    585 #ifdef PANORAMIX
    586     ErrorF("+xinerama              Enable XINERAMA extension\n");
    587     ErrorF("-xinerama              Disable XINERAMA extension\n");
    588 #endif
    589     ErrorF
    590         ("-dumbSched             Disable smart scheduling and threaded input, enable old behavior\n");
    591     ErrorF("-schedInterval int     Set scheduler interval in msec\n");
    592     ErrorF("-sigstop               Enable SIGSTOP based startup\n");
    593     ErrorF("+extension name        Enable extension\n");
    594     ErrorF("-extension name        Disable extension\n");
    595     ListStaticExtensions();
    596 #ifdef XDMCP
    597     XdmcpUseMsg();
    598 #endif
    599     XkbUseMsg();
    600     ddxUseMsg();
    601 }
    602 
    603 /*  This function performs a rudimentary sanity check
    604  *  on the display name passed in on the command-line,
    605  *  since this string is used to generate filenames.
    606  *  It is especially important that the display name
    607  *  not contain a "/" and not start with a "-".
    608  *                                            --kvajk
    609  */
    610 static int
    611 VerifyDisplayName(const char *d)
    612 {
    613     int i;
    614     int period_found = FALSE;
    615     int after_period = 0;
    616 
    617     if (d == (char *) 0)
    618         return 0;               /*  null  */
    619     if (*d == '\0')
    620         return 0;               /*  empty  */
    621     if (*d == '-')
    622         return 0;               /*  could be confused for an option  */
    623     if (*d == '.')
    624         return 0;               /*  must not equal "." or ".."  */
    625     if (strchr(d, '/') != (char *) 0)
    626         return 0;               /*  very important!!!  */
    627 
    628     /* Since we run atoi() on the display later, only allow
    629        for digits, or exception of :0.0 and similar (two decimal points max)
    630        */
    631     for (i = 0; i < strlen(d); i++) {
    632         if (!isdigit(d[i])) {
    633             if (d[i] != '.' || period_found)
    634                 return 0;
    635             period_found = TRUE;
    636         } else if (period_found)
    637             after_period++;
    638 
    639         if (after_period > 2)
    640             return 0;
    641     }
    642 
    643     /* don't allow for :0. */
    644     if (period_found && after_period == 0)
    645         return 0;
    646 
    647     if (atol(d) > INT_MAX)
    648         return 0;
    649 
    650     return 1;
    651 }
    652 
    653 static const char *defaultNoListenList[] = {
    654 #ifndef LISTEN_TCP
    655     "tcp",
    656 #endif
    657 #ifndef LISTEN_UNIX
    658     "unix",
    659 #endif
    660 #ifndef LISTEN_LOCAL
    661     "local",
    662 #endif
    663     NULL
    664 };
    665 
    666 /*
    667  * This function parses the command line. Handles device-independent fields
    668  * and allows ddx to handle additional fields.  It is not allowed to modify
    669  * argc or any of the strings pointed to by argv.
    670  */
    671 void
    672 ProcessCommandLine(int argc, char *argv[])
    673 {
    674     int i, skip;
    675 
    676     defaultKeyboardControl.autoRepeat = TRUE;
    677 
    678 #ifdef NO_PART_NET
    679     PartialNetwork = FALSE;
    680 #else
    681     PartialNetwork = TRUE;
    682 #endif
    683 
    684     for (i = 0; defaultNoListenList[i] != NULL; i++) {
    685         if (_XSERVTransNoListen(defaultNoListenList[i]))
    686                     ErrorF("Failed to disable listen for %s transport",
    687                            defaultNoListenList[i]);
    688     }
    689 
    690     for (i = 1; i < argc; i++) {
    691         /* call ddx first, so it can peek/override if it wants */
    692         if ((skip = ddxProcessArgument(argc, argv, i))) {
    693             i += (skip - 1);
    694         }
    695         else if (argv[i][0] == ':') {
    696             /* initialize display */
    697             display = argv[i];
    698             explicit_display = TRUE;
    699             display++;
    700             if (!VerifyDisplayName(display)) {
    701                 ErrorF("Bad display name: %s\n", display);
    702                 UseMsg();
    703                 FatalError("Bad display name, exiting: %s\n", display);
    704             }
    705         }
    706         else if (strcmp(argv[i], "-a") == 0) {
    707             if (++i < argc)
    708                 defaultPointerControl.num = atoi(argv[i]);
    709             else
    710                 UseMsg();
    711         }
    712         else if (strcmp(argv[i], "-ac") == 0) {
    713             defeatAccessControl = TRUE;
    714         }
    715         else if (strcmp(argv[i], "-audit") == 0) {
    716             if (++i < argc)
    717                 auditTrailLevel = atoi(argv[i]);
    718             else
    719                 UseMsg();
    720         }
    721         else if (strcmp(argv[i], "-auth") == 0) {
    722             if (++i < argc)
    723                 InitAuthorization(argv[i]);
    724             else
    725                 UseMsg();
    726         }
    727         else if (strcmp(argv[i], "-byteswappedclients") == 0) {
    728             AllowByteSwappedClients = FALSE;
    729         } else if (strcmp(argv[i], "+byteswappedclients") == 0) {
    730             AllowByteSwappedClients = TRUE;
    731         }
    732         else if (strcmp(argv[i], "-br") == 0);  /* default */
    733         else if (strcmp(argv[i], "+bs") == 0)
    734             enableBackingStore = TRUE;
    735         else if (strcmp(argv[i], "-bs") == 0)
    736             disableBackingStore = TRUE;
    737         else if (strcmp(argv[i], "c") == 0) {
    738             if (++i < argc)
    739                 defaultKeyboardControl.click = atoi(argv[i]);
    740             else
    741                 UseMsg();
    742         }
    743         else if (strcmp(argv[i], "-c") == 0) {
    744             defaultKeyboardControl.click = 0;
    745         }
    746         else if (strcmp(argv[i], "-cc") == 0) {
    747             if (++i < argc)
    748                 defaultColorVisualClass = atoi(argv[i]);
    749             else
    750                 UseMsg();
    751         }
    752         else if (strcmp(argv[i], "-core") == 0) {
    753 #if !defined(WIN32) || !defined(__MINGW32__)
    754             struct rlimit core_limit;
    755 
    756             if (getrlimit(RLIMIT_CORE, &core_limit) != -1) {
    757                 core_limit.rlim_cur = core_limit.rlim_max;
    758                 setrlimit(RLIMIT_CORE, &core_limit);
    759             }
    760 #endif
    761             CoreDump = TRUE;
    762         }
    763         else if (strcmp(argv[i], "-nocursor") == 0) {
    764             EnableCursor = FALSE;
    765         }
    766         else if (strcmp(argv[i], "-dpi") == 0) {
    767             if (++i < argc)
    768                 monitorResolution = atoi(argv[i]);
    769             else
    770                 UseMsg();
    771         }
    772         else if (strcmp(argv[i], "-displayfd") == 0) {
    773             if (++i < argc) {
    774                 displayfd = atoi(argv[i]);
    775 #ifdef LOCK_SERVER
    776                 nolock = TRUE;
    777 #endif
    778             }
    779             else
    780                 UseMsg();
    781         }
    782 #ifdef DPMSExtension
    783         else if (strcmp(argv[i], "dpms") == 0)
    784             /* ignored for compatibility */ ;
    785         else if (strcmp(argv[i], "-dpms") == 0)
    786             DPMSDisabledSwitch = TRUE;
    787 #endif
    788         else if (strcmp(argv[i], "-deferglyphs") == 0) {
    789             if (++i >= argc || !xfont2_parse_glyph_caching_mode(argv[i]))
    790                 UseMsg();
    791         }
    792         else if (strcmp(argv[i], "-f") == 0) {
    793             if (++i < argc)
    794                 defaultKeyboardControl.bell = atoi(argv[i]);
    795             else
    796                 UseMsg();
    797         }
    798         else if (strcmp(argv[i], "-fakescreenfps") == 0) {
    799 #ifdef PRESENT
    800             if (++i < argc) {
    801                 FakeScreenFps = (uint32_t) atoi(argv[i]);
    802                 if (FakeScreenFps < 1 || FakeScreenFps > 600)
    803                     FatalError("fakescreenfps must be an integer in [1;600] range\n");
    804             }
    805             else
    806                 UseMsg();
    807 #else
    808             FatalError("fakescreenfps not available without PRESENT\n");
    809             UseMsg();
    810 #endif
    811         }
    812         else if (strcmp(argv[i], "-fp") == 0) {
    813             if (++i < argc) {
    814                 defaultFontPath = argv[i];
    815             }
    816             else
    817                 UseMsg();
    818         }
    819         else if (strcmp(argv[i], "-help") == 0) {
    820             UseMsg();
    821             exit(0);
    822         }
    823         else if (strcmp(argv[i], "+iglx") == 0)
    824             enableIndirectGLX = TRUE;
    825         else if (strcmp(argv[i], "-iglx") == 0)
    826             enableIndirectGLX = FALSE;
    827         else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) {
    828             if (skip > 0)
    829                 i += skip - 1;
    830             else
    831                 UseMsg();
    832         }
    833 #ifdef RLIMIT_DATA
    834         else if (strcmp(argv[i], "-ld") == 0) {
    835             if (++i < argc) {
    836                 limitDataSpace = atoi(argv[i]);
    837                 if (limitDataSpace > 0)
    838                     limitDataSpace *= 1024;
    839             }
    840             else
    841                 UseMsg();
    842         }
    843 #endif
    844 #ifdef RLIMIT_NOFILE
    845         else if (strcmp(argv[i], "-lf") == 0) {
    846             if (++i < argc)
    847                 limitNoFile = atoi(argv[i]);
    848             else
    849                 UseMsg();
    850         }
    851 #endif
    852 #ifdef RLIMIT_STACK
    853         else if (strcmp(argv[i], "-ls") == 0) {
    854             if (++i < argc) {
    855                 limitStackSpace = atoi(argv[i]);
    856                 if (limitStackSpace > 0)
    857                     limitStackSpace *= 1024;
    858             }
    859             else
    860                 UseMsg();
    861         }
    862 #endif
    863 #ifdef LOCK_SERVER
    864         else if (strcmp(argv[i], "-nolock") == 0) {
    865 #if !defined(WIN32) && !defined(__CYGWIN__)
    866             if (getuid() != 0)
    867                 ErrorF
    868                     ("Warning: the -nolock option can only be used by root\n");
    869             else
    870 #endif
    871                 nolock = TRUE;
    872         }
    873 #endif
    874 	else if ( strcmp( argv[i], "-maxclients") == 0)
    875 	{
    876 	    if (++i < argc) {
    877 		LimitClients = atoi(argv[i]);
    878 		if (LimitClients != 64 &&
    879 		    LimitClients != 128 &&
    880 		    LimitClients != 256 &&
    881 		    LimitClients != 512 &&
    882                     LimitClients != 1024 &&
    883                     LimitClients != 2048) {
    884 		    FatalError("maxclients must be one of 64, 128, 256, 512, 1024 or 2048\n");
    885 		}
    886 	    } else
    887 		UseMsg();
    888 	}
    889         else if (strcmp(argv[i], "-nolisten") == 0) {
    890             if (++i < argc) {
    891                 if (_XSERVTransNoListen(argv[i]))
    892                     ErrorF("Failed to disable listen for %s transport",
    893                            argv[i]);
    894             }
    895             else
    896                 UseMsg();
    897         }
    898         else if (strcmp(argv[i], "-listen") == 0) {
    899             if (++i < argc) {
    900                 if (_XSERVTransListen(argv[i]))
    901                     ErrorF("Failed to enable listen for %s transport",
    902                            argv[i]);
    903             }
    904             else
    905                 UseMsg();
    906         }
    907         else if (strcmp(argv[i], "-noreset") == 0) {
    908             dispatchExceptionAtReset = 0;
    909         }
    910         else if (strcmp(argv[i], "-reset") == 0) {
    911             dispatchExceptionAtReset = DE_RESET;
    912         }
    913         else if (strcmp(argv[i], "-p") == 0) {
    914             if (++i < argc)
    915                 defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) *
    916                     MILLI_PER_MIN;
    917             else
    918                 UseMsg();
    919         }
    920         else if (strcmp(argv[i], "-pogo") == 0) {
    921             dispatchException = DE_TERMINATE;
    922         }
    923         else if (strcmp(argv[i], "-pn") == 0)
    924             PartialNetwork = TRUE;
    925         else if (strcmp(argv[i], "-nopn") == 0)
    926             PartialNetwork = FALSE;
    927         else if (strcmp(argv[i], "r") == 0)
    928             defaultKeyboardControl.autoRepeat = TRUE;
    929         else if (strcmp(argv[i], "-r") == 0)
    930             defaultKeyboardControl.autoRepeat = FALSE;
    931         else if (strcmp(argv[i], "-retro") == 0)
    932             party_like_its_1989 = TRUE;
    933 	else if (strcmp(argv[i], "-noretro") == 0)
    934 	    party_like_its_1989 = FALSE;
    935         else if (strcmp(argv[i], "-s") == 0) {
    936             if (++i < argc)
    937                 defaultScreenSaverTime = ((CARD32) atoi(argv[i])) *
    938                     MILLI_PER_MIN;
    939             else
    940                 UseMsg();
    941         }
    942         else if (strcmp(argv[i], "-seat") == 0) {
    943             if (++i < argc)
    944                 SeatId = argv[i];
    945             else
    946                 UseMsg();
    947         }
    948         else if (strcmp(argv[i], "-t") == 0) {
    949             if (++i < argc)
    950                 defaultPointerControl.threshold = atoi(argv[i]);
    951             else
    952                 UseMsg();
    953         }
    954         else if (strcmp(argv[i], "-terminate") == 0) {
    955             dispatchExceptionAtReset = DE_TERMINATE;
    956             terminateDelay = -1;
    957             if ((i + 1 < argc) && (isdigit(*argv[i + 1])))
    958                terminateDelay = atoi(argv[++i]);
    959             terminateDelay = max(0, terminateDelay);
    960         }
    961         else if (strcmp(argv[i], "-tst") == 0) {
    962             noTestExtensions = TRUE;
    963         }
    964         else if (strcmp(argv[i], "v") == 0)
    965             defaultScreenSaverBlanking = PreferBlanking;
    966         else if (strcmp(argv[i], "-v") == 0)
    967             defaultScreenSaverBlanking = DontPreferBlanking;
    968         else if (strcmp(argv[i], "-wr") == 0)
    969             whiteRoot = TRUE;
    970         else if (strcmp(argv[i], "-background") == 0) {
    971             if (++i < argc) {
    972                 if (!strcmp(argv[i], "none"))
    973                     bgNoneRoot = TRUE;
    974                 else
    975                     UseMsg();
    976             }
    977         }
    978         else if (strcmp(argv[i], "-maxbigreqsize") == 0) {
    979             if (++i < argc) {
    980                 long reqSizeArg = atol(argv[i]);
    981 
    982                 /* Request size > 128MB does not make much sense... */
    983                 if (reqSizeArg > 0L && reqSizeArg < 128L) {
    984                     maxBigRequestSize = (reqSizeArg * 1048576L) - 1L;
    985                 }
    986                 else {
    987                     UseMsg();
    988                 }
    989             }
    990             else {
    991                 UseMsg();
    992             }
    993         }
    994 #ifdef PANORAMIX
    995         else if (strcmp(argv[i], "+xinerama") == 0) {
    996             noPanoramiXExtension = FALSE;
    997         }
    998         else if (strcmp(argv[i], "-xinerama") == 0) {
    999             noPanoramiXExtension = TRUE;
   1000         }
   1001         else if (strcmp(argv[i], "-disablexineramaextension") == 0) {
   1002             PanoramiXExtensionDisabledHack = TRUE;
   1003         }
   1004 #endif
   1005         else if (strcmp(argv[i], "-I") == 0) {
   1006             /* ignore all remaining arguments */
   1007             break;
   1008         }
   1009         else if (strncmp(argv[i], "tty", 3) == 0) {
   1010             /* init supplies us with this useless information */
   1011         }
   1012 #ifdef XDMCP
   1013         else if ((skip = XdmcpOptions(argc, argv, i)) != i) {
   1014             i = skip - 1;
   1015         }
   1016 #endif
   1017         else if (strcmp(argv[i], "-dumbSched") == 0) {
   1018             InputThreadEnable = FALSE;
   1019 #ifdef HAVE_SETITIMER
   1020             SmartScheduleSignalEnable = FALSE;
   1021 #endif
   1022         }
   1023         else if (strcmp(argv[i], "-schedInterval") == 0) {
   1024             if (++i < argc) {
   1025                 SmartScheduleInterval = atoi(argv[i]);
   1026                 SmartScheduleSlice = SmartScheduleInterval;
   1027             }
   1028             else
   1029                 UseMsg();
   1030         }
   1031         else if (strcmp(argv[i], "-schedMax") == 0) {
   1032             if (++i < argc) {
   1033                 SmartScheduleMaxSlice = atoi(argv[i]);
   1034             }
   1035             else
   1036                 UseMsg();
   1037         }
   1038         else if (strcmp(argv[i], "-render") == 0) {
   1039             if (++i < argc) {
   1040                 int policy = PictureParseCmapPolicy(argv[i]);
   1041 
   1042                 if (policy != PictureCmapPolicyInvalid)
   1043                     PictureCmapPolicy = policy;
   1044                 else
   1045                     UseMsg();
   1046             }
   1047             else
   1048                 UseMsg();
   1049         }
   1050         else if (strcmp(argv[i], "-sigstop") == 0) {
   1051             RunFromSigStopParent = TRUE;
   1052         }
   1053         else if (strcmp(argv[i], "+extension") == 0) {
   1054             if (++i < argc) {
   1055                 if (!EnableDisableExtension(argv[i], TRUE))
   1056                     EnableDisableExtensionError(argv[i], TRUE);
   1057             }
   1058             else
   1059                 UseMsg();
   1060         }
   1061         else if (strcmp(argv[i], "-extension") == 0) {
   1062             if (++i < argc) {
   1063                 if (!EnableDisableExtension(argv[i], FALSE))
   1064                     EnableDisableExtensionError(argv[i], FALSE);
   1065             }
   1066             else
   1067                 UseMsg();
   1068         }
   1069         else {
   1070             ErrorF("Unrecognized option: %s\n", argv[i]);
   1071             UseMsg();
   1072             FatalError("Unrecognized option: %s\n", argv[i]);
   1073         }
   1074     }
   1075 }
   1076 
   1077 /* Implement a simple-minded font authorization scheme.  The authorization
   1078    name is "hp-hostname-1", the contents are simply the host name. */
   1079 int
   1080 set_font_authorizations(char **authorizations, int *authlen, void *client)
   1081 {
   1082 #define AUTHORIZATION_NAME "hp-hostname-1"
   1083 #if defined(TCPCONN)
   1084     static char *result = NULL;
   1085     static char *p = NULL;
   1086 
   1087     if (p == NULL) {
   1088         char hname[1024], *hnameptr;
   1089         unsigned int len;
   1090 
   1091 #if defined(IPv6) && defined(AF_INET6)
   1092         struct addrinfo hints, *ai = NULL;
   1093 #else
   1094         struct hostent *host;
   1095 
   1096 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
   1097         _Xgethostbynameparams hparams;
   1098 #endif
   1099 #endif
   1100 
   1101         gethostname(hname, 1024);
   1102 #if defined(IPv6) && defined(AF_INET6)
   1103         memset(&hints, 0, sizeof(hints));
   1104         hints.ai_flags = AI_CANONNAME;
   1105         if (getaddrinfo(hname, NULL, &hints, &ai) == 0) {
   1106             hnameptr = ai->ai_canonname;
   1107         }
   1108         else {
   1109             hnameptr = hname;
   1110         }
   1111 #else
   1112         host = _XGethostbyname(hname, hparams);
   1113         if (host == NULL)
   1114             hnameptr = hname;
   1115         else
   1116             hnameptr = host->h_name;
   1117 #endif
   1118 
   1119         len = strlen(hnameptr) + 1;
   1120         result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4);
   1121 
   1122         p = result;
   1123         *p++ = sizeof(AUTHORIZATION_NAME) >> 8;
   1124         *p++ = sizeof(AUTHORIZATION_NAME) & 0xff;
   1125         *p++ = (len) >> 8;
   1126         *p++ = (len & 0xff);
   1127 
   1128         memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME));
   1129         p += sizeof(AUTHORIZATION_NAME);
   1130         memmove(p, hnameptr, len);
   1131         p += len;
   1132 #if defined(IPv6) && defined(AF_INET6)
   1133         if (ai) {
   1134             freeaddrinfo(ai);
   1135         }
   1136 #endif
   1137     }
   1138     *authlen = p - result;
   1139     *authorizations = result;
   1140     return 1;
   1141 #else                           /* TCPCONN */
   1142     return 0;
   1143 #endif                          /* TCPCONN */
   1144 }
   1145 
   1146 void *
   1147 XNFalloc(unsigned long amount)
   1148 {
   1149     void *ptr = malloc(amount);
   1150 
   1151     if (!ptr)
   1152         FatalError("Out of memory");
   1153     return ptr;
   1154 }
   1155 
   1156 /* The original XNFcalloc was used with the xnfcalloc macro which multiplied
   1157  * the arguments at the call site without allowing calloc to check for overflow.
   1158  * XNFcallocarray was added to fix that without breaking ABI.
   1159  */
   1160 void *
   1161 XNFcalloc(unsigned long amount)
   1162 {
   1163     return XNFcallocarray(1, amount);
   1164 }
   1165 
   1166 void *
   1167 XNFcallocarray(size_t nmemb, size_t size)
   1168 {
   1169     void *ret = calloc(nmemb, size);
   1170 
   1171     if (!ret)
   1172         FatalError("XNFcalloc: Out of memory");
   1173     return ret;
   1174 }
   1175 
   1176 void *
   1177 XNFrealloc(void *ptr, unsigned long amount)
   1178 {
   1179     void *ret = realloc(ptr, amount);
   1180 
   1181     if (!ret)
   1182         FatalError("XNFrealloc: Out of memory");
   1183     return ret;
   1184 }
   1185 
   1186 void *
   1187 XNFreallocarray(void *ptr, size_t nmemb, size_t size)
   1188 {
   1189     void *ret = reallocarray(ptr, nmemb, size);
   1190 
   1191     if (!ret)
   1192         FatalError("XNFreallocarray: Out of memory");
   1193     return ret;
   1194 }
   1195 
   1196 char *
   1197 Xstrdup(const char *s)
   1198 {
   1199     if (s == NULL)
   1200         return NULL;
   1201     return strdup(s);
   1202 }
   1203 
   1204 char *
   1205 XNFstrdup(const char *s)
   1206 {
   1207     char *ret;
   1208 
   1209     if (s == NULL)
   1210         return NULL;
   1211 
   1212     ret = strdup(s);
   1213     if (!ret)
   1214         FatalError("XNFstrdup: Out of memory");
   1215     return ret;
   1216 }
   1217 
   1218 void
   1219 SmartScheduleStopTimer(void)
   1220 {
   1221 #ifdef HAVE_SETITIMER
   1222     struct itimerval timer;
   1223 
   1224     if (!SmartScheduleSignalEnable)
   1225         return;
   1226     timer.it_interval.tv_sec = 0;
   1227     timer.it_interval.tv_usec = 0;
   1228     timer.it_value.tv_sec = 0;
   1229     timer.it_value.tv_usec = 0;
   1230     (void) setitimer(ITIMER_REAL, &timer, 0);
   1231 #endif
   1232 }
   1233 
   1234 void
   1235 SmartScheduleStartTimer(void)
   1236 {
   1237 #ifdef HAVE_SETITIMER
   1238     struct itimerval timer;
   1239 
   1240     if (!SmartScheduleSignalEnable)
   1241         return;
   1242     timer.it_interval.tv_sec = 0;
   1243     timer.it_interval.tv_usec = SmartScheduleInterval * 1000;
   1244     timer.it_value.tv_sec = 0;
   1245     timer.it_value.tv_usec = SmartScheduleInterval * 1000;
   1246     setitimer(ITIMER_REAL, &timer, 0);
   1247 #endif
   1248 }
   1249 
   1250 #ifdef HAVE_SETITIMER
   1251 static void
   1252 SmartScheduleTimer(int sig)
   1253 {
   1254     SmartScheduleTime += SmartScheduleInterval;
   1255 }
   1256 
   1257 static int
   1258 SmartScheduleEnable(void)
   1259 {
   1260     int ret = 0;
   1261     struct sigaction act;
   1262 
   1263     if (!SmartScheduleSignalEnable)
   1264         return 0;
   1265 
   1266     memset((char *) &act, 0, sizeof(struct sigaction));
   1267 
   1268     /* Set up the timer signal function */
   1269     act.sa_flags = SA_RESTART;
   1270     act.sa_handler = SmartScheduleTimer;
   1271     sigemptyset(&act.sa_mask);
   1272     sigaddset(&act.sa_mask, SIGALRM);
   1273     ret = sigaction(SIGALRM, &act, 0);
   1274     return ret;
   1275 }
   1276 
   1277 static int
   1278 SmartSchedulePause(void)
   1279 {
   1280     int ret = 0;
   1281     struct sigaction act;
   1282 
   1283     if (!SmartScheduleSignalEnable)
   1284         return 0;
   1285 
   1286     memset((char *) &act, 0, sizeof(struct sigaction));
   1287 
   1288     act.sa_handler = SIG_IGN;
   1289     sigemptyset(&act.sa_mask);
   1290     ret = sigaction(SIGALRM, &act, 0);
   1291     return ret;
   1292 }
   1293 #endif
   1294 
   1295 void
   1296 SmartScheduleInit(void)
   1297 {
   1298 #ifdef HAVE_SETITIMER
   1299     if (SmartScheduleEnable() < 0) {
   1300         perror("sigaction for smart scheduler");
   1301         SmartScheduleSignalEnable = FALSE;
   1302     }
   1303 #endif
   1304 }
   1305 
   1306 #ifdef HAVE_SIGPROCMASK
   1307 static sigset_t PreviousSignalMask;
   1308 static int BlockedSignalCount;
   1309 #endif
   1310 
   1311 void
   1312 OsBlockSignals(void)
   1313 {
   1314 #ifdef HAVE_SIGPROCMASK
   1315     if (BlockedSignalCount++ == 0) {
   1316         sigset_t set;
   1317 
   1318         sigemptyset(&set);
   1319         sigaddset(&set, SIGALRM);
   1320         sigaddset(&set, SIGVTALRM);
   1321 #ifdef SIGWINCH
   1322         sigaddset(&set, SIGWINCH);
   1323 #endif
   1324         sigaddset(&set, SIGTSTP);
   1325         sigaddset(&set, SIGTTIN);
   1326         sigaddset(&set, SIGTTOU);
   1327         sigaddset(&set, SIGCHLD);
   1328         xthread_sigmask(SIG_BLOCK, &set, &PreviousSignalMask);
   1329     }
   1330 #endif
   1331 }
   1332 
   1333 void
   1334 OsReleaseSignals(void)
   1335 {
   1336 #ifdef HAVE_SIGPROCMASK
   1337     if (--BlockedSignalCount == 0) {
   1338         xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0);
   1339     }
   1340 #endif
   1341 }
   1342 
   1343 void
   1344 OsResetSignals(void)
   1345 {
   1346 #ifdef HAVE_SIGPROCMASK
   1347     while (BlockedSignalCount > 0)
   1348         OsReleaseSignals();
   1349     input_force_unlock();
   1350 #endif
   1351 }
   1352 
   1353 /*
   1354  * Pending signals may interfere with core dumping. Provide a
   1355  * mechanism to block signals when aborting.
   1356  */
   1357 
   1358 void
   1359 OsAbort(void)
   1360 {
   1361 #ifndef __APPLE__
   1362     OsBlockSignals();
   1363 #endif
   1364 #if !defined(WIN32) || defined(__CYGWIN__)
   1365     /* abort() raises SIGABRT, so we have to stop handling that to prevent
   1366      * recursion
   1367      */
   1368     OsSignal(SIGABRT, SIG_DFL);
   1369 #endif
   1370     abort();
   1371 }
   1372 
   1373 #if !defined(WIN32)
   1374 /*
   1375  * "safer" versions of system(3), popen(3) and pclose(3) which give up
   1376  * all privs before running a command.
   1377  *
   1378  * This is based on the code in FreeBSD 2.2 libc.
   1379  *
   1380  * XXX It'd be good to redirect stderr so that it ends up in the log file
   1381  * as well.  As it is now, xkbcomp messages don't end up in the log file.
   1382  */
   1383 
   1384 int
   1385 System(const char *command)
   1386 {
   1387     int pid, p;
   1388     void (*csig) (int);
   1389     int status;
   1390 
   1391     if (!command)
   1392         return 1;
   1393 
   1394     csig = OsSignal(SIGCHLD, SIG_DFL);
   1395     if (csig == SIG_ERR) {
   1396         perror("signal");
   1397         return -1;
   1398     }
   1399     DebugF("System: `%s'\n", command);
   1400 
   1401     switch (pid = fork()) {
   1402     case -1:                   /* error */
   1403         p = -1;
   1404         break;
   1405     case 0:                    /* child */
   1406         if (setgid(getgid()) == -1)
   1407             _exit(127);
   1408         if (setuid(getuid()) == -1)
   1409             _exit(127);
   1410         execl("/bin/sh", "sh", "-c", command, (char *) NULL);
   1411         _exit(127);
   1412     default:                   /* parent */
   1413         do {
   1414             p = waitpid(pid, &status, 0);
   1415         } while (p == -1 && errno == EINTR);
   1416 
   1417     }
   1418 
   1419     if (OsSignal(SIGCHLD, csig) == SIG_ERR) {
   1420         perror("signal");
   1421         return -1;
   1422     }
   1423 
   1424     return p == -1 ? -1 : status;
   1425 }
   1426 
   1427 static struct pid {
   1428     struct pid *next;
   1429     FILE *fp;
   1430     int pid;
   1431 } *pidlist;
   1432 
   1433 void *
   1434 Popen(const char *command, const char *type)
   1435 {
   1436     struct pid *cur;
   1437     FILE *iop;
   1438     int pdes[2], pid;
   1439 
   1440     if (command == NULL || type == NULL)
   1441         return NULL;
   1442 
   1443     if ((*type != 'r' && *type != 'w') || type[1])
   1444         return NULL;
   1445 
   1446     if ((cur = malloc(sizeof(struct pid))) == NULL)
   1447         return NULL;
   1448 
   1449     if (pipe(pdes) < 0) {
   1450         free(cur);
   1451         return NULL;
   1452     }
   1453 
   1454     /* Ignore the smart scheduler while this is going on */
   1455 #ifdef HAVE_SETITIMER
   1456     if (SmartSchedulePause() < 0) {
   1457         close(pdes[0]);
   1458         close(pdes[1]);
   1459         free(cur);
   1460         perror("signal");
   1461         return NULL;
   1462     }
   1463 #endif
   1464 
   1465     switch (pid = fork()) {
   1466     case -1:                   /* error */
   1467         close(pdes[0]);
   1468         close(pdes[1]);
   1469         free(cur);
   1470 #ifdef HAVE_SETITIMER
   1471         if (SmartScheduleEnable() < 0)
   1472             perror("signal");
   1473 #endif
   1474         return NULL;
   1475     case 0:                    /* child */
   1476         if (setgid(getgid()) == -1)
   1477             _exit(127);
   1478         if (setuid(getuid()) == -1)
   1479             _exit(127);
   1480         if (*type == 'r') {
   1481             if (pdes[1] != 1) {
   1482                 /* stdout */
   1483                 dup2(pdes[1], 1);
   1484                 close(pdes[1]);
   1485             }
   1486             close(pdes[0]);
   1487         }
   1488         else {
   1489             if (pdes[0] != 0) {
   1490                 /* stdin */
   1491                 dup2(pdes[0], 0);
   1492                 close(pdes[0]);
   1493             }
   1494             close(pdes[1]);
   1495         }
   1496         execl("/bin/sh", "sh", "-c", command, (char *) NULL);
   1497         _exit(127);
   1498     }
   1499 
   1500     /* Avoid EINTR during stdio calls */
   1501     OsBlockSignals();
   1502 
   1503     /* parent */
   1504     if (*type == 'r') {
   1505         iop = fdopen(pdes[0], type);
   1506         close(pdes[1]);
   1507     }
   1508     else {
   1509         iop = fdopen(pdes[1], type);
   1510         close(pdes[0]);
   1511     }
   1512 
   1513     cur->fp = iop;
   1514     cur->pid = pid;
   1515     cur->next = pidlist;
   1516     pidlist = cur;
   1517 
   1518     DebugF("Popen: `%s', fp = %p\n", command, iop);
   1519 
   1520     return iop;
   1521 }
   1522 
   1523 /* fopen that drops privileges */
   1524 void *
   1525 Fopen(const char *file, const char *type)
   1526 {
   1527     FILE *iop;
   1528 
   1529 #ifndef HAS_SAVED_IDS_AND_SETEUID
   1530     struct pid *cur;
   1531     int pdes[2], pid;
   1532 
   1533     if (file == NULL || type == NULL)
   1534         return NULL;
   1535 
   1536     if ((*type != 'r' && *type != 'w') || type[1])
   1537         return NULL;
   1538 
   1539     if ((cur = malloc(sizeof(struct pid))) == NULL)
   1540         return NULL;
   1541 
   1542     if (pipe(pdes) < 0) {
   1543         free(cur);
   1544         return NULL;
   1545     }
   1546 
   1547     switch (pid = fork()) {
   1548     case -1:                   /* error */
   1549         close(pdes[0]);
   1550         close(pdes[1]);
   1551         free(cur);
   1552         return NULL;
   1553     case 0:                    /* child */
   1554         if (setgid(getgid()) == -1)
   1555             _exit(127);
   1556         if (setuid(getuid()) == -1)
   1557             _exit(127);
   1558         if (*type == 'r') {
   1559             if (pdes[1] != 1) {
   1560                 /* stdout */
   1561                 dup2(pdes[1], 1);
   1562                 close(pdes[1]);
   1563             }
   1564             close(pdes[0]);
   1565         }
   1566         else {
   1567             if (pdes[0] != 0) {
   1568                 /* stdin */
   1569                 dup2(pdes[0], 0);
   1570                 close(pdes[0]);
   1571             }
   1572             close(pdes[1]);
   1573         }
   1574         execl("/bin/cat", "cat", file, (char *) NULL);
   1575         _exit(127);
   1576     }
   1577 
   1578     /* Avoid EINTR during stdio calls */
   1579     OsBlockSignals();
   1580 
   1581     /* parent */
   1582     if (*type == 'r') {
   1583         iop = fdopen(pdes[0], type);
   1584         close(pdes[1]);
   1585     }
   1586     else {
   1587         iop = fdopen(pdes[1], type);
   1588         close(pdes[0]);
   1589     }
   1590 
   1591     cur->fp = iop;
   1592     cur->pid = pid;
   1593     cur->next = pidlist;
   1594     pidlist = cur;
   1595 
   1596     DebugF("Fopen(%s), fp = %p\n", file, iop);
   1597 
   1598     return iop;
   1599 #else
   1600     int ruid, euid;
   1601 
   1602     ruid = getuid();
   1603     euid = geteuid();
   1604 
   1605     if (seteuid(ruid) == -1) {
   1606         return NULL;
   1607     }
   1608     iop = fopen(file, type);
   1609 
   1610     if (seteuid(euid) == -1) {
   1611         if (iop) {
   1612             fclose(iop);
   1613         }
   1614         return NULL;
   1615     }
   1616     return iop;
   1617 #endif                          /* HAS_SAVED_IDS_AND_SETEUID */
   1618 }
   1619 
   1620 int
   1621 Pclose(void *iop)
   1622 {
   1623     struct pid *cur, *last;
   1624     int pstat;
   1625     int pid;
   1626 
   1627     DebugF("Pclose: fp = %p\n", iop);
   1628     fclose(iop);
   1629 
   1630     for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
   1631         if (cur->fp == iop)
   1632             break;
   1633     if (cur == NULL)
   1634         return -1;
   1635 
   1636     do {
   1637         pid = waitpid(cur->pid, &pstat, 0);
   1638     } while (pid == -1 && errno == EINTR);
   1639 
   1640     if (last == NULL)
   1641         pidlist = cur->next;
   1642     else
   1643         last->next = cur->next;
   1644     free(cur);
   1645 
   1646     /* allow EINTR again */
   1647     OsReleaseSignals();
   1648 
   1649 #ifdef HAVE_SETITIMER
   1650     if (SmartScheduleEnable() < 0) {
   1651         perror("signal");
   1652         return -1;
   1653     }
   1654 #endif
   1655 
   1656     return pid == -1 ? -1 : pstat;
   1657 }
   1658 
   1659 int
   1660 Fclose(void *iop)
   1661 {
   1662 #ifdef HAS_SAVED_IDS_AND_SETEUID
   1663     return fclose(iop);
   1664 #else
   1665     return Pclose(iop);
   1666 #endif
   1667 }
   1668 
   1669 #endif                          /* !WIN32 */
   1670 
   1671 #ifdef WIN32
   1672 
   1673 #include <X11/Xwindows.h>
   1674 
   1675 const char *
   1676 Win32TempDir(void)
   1677 {
   1678     static char buffer[PATH_MAX];
   1679 
   1680     if (GetTempPath(sizeof(buffer), buffer)) {
   1681         int len;
   1682 
   1683         buffer[sizeof(buffer) - 1] = 0;
   1684         len = strlen(buffer);
   1685         if (len > 0)
   1686             if (buffer[len - 1] == '\\')
   1687                 buffer[len - 1] = 0;
   1688         return buffer;
   1689     }
   1690     if (getenv("TEMP") != NULL)
   1691         return getenv("TEMP");
   1692     else if (getenv("TMP") != NULL)
   1693         return getenv("TMP");
   1694     else
   1695         return "/tmp";
   1696 }
   1697 
   1698 int
   1699 System(const char *cmdline)
   1700 {
   1701     STARTUPINFO si;
   1702     PROCESS_INFORMATION pi;
   1703     DWORD dwExitCode;
   1704     char *cmd = strdup(cmdline);
   1705 
   1706     ZeroMemory(&si, sizeof(si));
   1707     si.cb = sizeof(si);
   1708     ZeroMemory(&pi, sizeof(pi));
   1709 
   1710     if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
   1711         LPVOID buffer;
   1712 
   1713         if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
   1714                            FORMAT_MESSAGE_FROM_SYSTEM |
   1715                            FORMAT_MESSAGE_IGNORE_INSERTS,
   1716                            NULL,
   1717                            GetLastError(),
   1718                            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
   1719                            (LPTSTR) &buffer, 0, NULL)) {
   1720             ErrorF("[xkb] Starting '%s' failed!\n", cmdline);
   1721         }
   1722         else {
   1723             ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer);
   1724             LocalFree(buffer);
   1725         }
   1726 
   1727         free(cmd);
   1728         return -1;
   1729     }
   1730     /* Wait until child process exits. */
   1731     WaitForSingleObject(pi.hProcess, INFINITE);
   1732 
   1733     GetExitCodeProcess(pi.hProcess, &dwExitCode);
   1734 
   1735     /* Close process and thread handles. */
   1736     CloseHandle(pi.hProcess);
   1737     CloseHandle(pi.hThread);
   1738     free(cmd);
   1739 
   1740     return dwExitCode;
   1741 }
   1742 #endif
   1743 
   1744 Bool
   1745 PrivsElevated(void)
   1746 {
   1747     static Bool privsTested = FALSE;
   1748     static Bool privsElevated = TRUE;
   1749 
   1750     if (!privsTested) {
   1751 #if defined(WIN32)
   1752         privsElevated = FALSE;
   1753 #else
   1754         if ((getuid() != geteuid()) || (getgid() != getegid())) {
   1755             privsElevated = TRUE;
   1756         }
   1757         else {
   1758 #if defined(HAVE_ISSETUGID)
   1759             privsElevated = issetugid();
   1760 #elif defined(HAVE_GETRESUID)
   1761             uid_t ruid, euid, suid;
   1762             gid_t rgid, egid, sgid;
   1763 
   1764             if ((getresuid(&ruid, &euid, &suid) == 0) &&
   1765                 (getresgid(&rgid, &egid, &sgid) == 0)) {
   1766                 privsElevated = (euid != suid) || (egid != sgid);
   1767             }
   1768             else {
   1769                 printf("Failed getresuid or getresgid");
   1770                 /* Something went wrong, make defensive assumption */
   1771                 privsElevated = TRUE;
   1772             }
   1773 #else
   1774             if (getuid() == 0) {
   1775                 /* running as root: uid==euid==0 */
   1776                 privsElevated = FALSE;
   1777             }
   1778             else {
   1779                 /*
   1780                  * If there are saved ID's the process might still be privileged
   1781                  * even though the above test succeeded. If issetugid() and
   1782                  * getresgid() aren't available, test this by trying to set
   1783                  * euid to 0.
   1784                  */
   1785                 unsigned int oldeuid;
   1786 
   1787                 oldeuid = geteuid();
   1788 
   1789                 if (seteuid(0) != 0) {
   1790                     privsElevated = FALSE;
   1791                 }
   1792                 else {
   1793                     if (seteuid(oldeuid) != 0) {
   1794                         FatalError("Failed to drop privileges.  Exiting\n");
   1795                     }
   1796                     privsElevated = TRUE;
   1797                 }
   1798             }
   1799 #endif
   1800         }
   1801 #endif
   1802         privsTested = TRUE;
   1803     }
   1804     return privsElevated;
   1805 }
   1806 
   1807 /*
   1808  * CheckUserParameters: check for long command line arguments and long
   1809  * environment variables.  By default, these checks are only done when
   1810  * the server's euid != ruid.  In 3.3.x, these checks were done in an
   1811  * external wrapper utility.
   1812  */
   1813 
   1814 /* Consider LD* variables insecure? */
   1815 #ifndef REMOVE_ENV_LD
   1816 #define REMOVE_ENV_LD 1
   1817 #endif
   1818 
   1819 /* Remove long environment variables? */
   1820 #ifndef REMOVE_LONG_ENV
   1821 #define REMOVE_LONG_ENV 1
   1822 #endif
   1823 
   1824 /*
   1825  * Disallow stdout or stderr as pipes?  It's possible to block the X server
   1826  * when piping stdout+stderr to a pipe.
   1827  *
   1828  * Don't enable this because it looks like it's going to cause problems.
   1829  */
   1830 #ifndef NO_OUTPUT_PIPES
   1831 #define NO_OUTPUT_PIPES 0
   1832 #endif
   1833 
   1834 /* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
   1835 #ifndef CHECK_EUID
   1836 #ifndef WIN32
   1837 #define CHECK_EUID 1
   1838 #else
   1839 #define CHECK_EUID 0
   1840 #endif
   1841 #endif
   1842 
   1843 /*
   1844  * Maybe the locale can be faked to make isprint(3) report that everything
   1845  * is printable?  Avoid it by default.
   1846  */
   1847 #ifndef USE_ISPRINT
   1848 #define USE_ISPRINT 0
   1849 #endif
   1850 
   1851 #define MAX_ARG_LENGTH          128
   1852 #define MAX_ENV_LENGTH          256
   1853 #define MAX_ENV_PATH_LENGTH     2048    /* Limit for *PATH and TERMCAP */
   1854 
   1855 #if USE_ISPRINT
   1856 #include <ctype.h>
   1857 #define checkPrintable(c) isprint(c)
   1858 #else
   1859 #define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
   1860 #endif
   1861 
   1862 enum BadCode {
   1863     NotBad = 0,
   1864     UnsafeArg,
   1865     ArgTooLong,
   1866     UnprintableArg,
   1867     EnvTooLong,
   1868     OutputIsPipe,
   1869     InternalError
   1870 };
   1871 
   1872 #if defined(VENDORSUPPORT)
   1873 #define BUGADDRESS VENDORSUPPORT
   1874 #elif defined(BUILDERADDR)
   1875 #define BUGADDRESS BUILDERADDR
   1876 #else
   1877 #define BUGADDRESS "xorg (at) freedesktop.org"
   1878 #endif
   1879 
   1880 void
   1881 CheckUserParameters(int argc, char **argv, char **envp)
   1882 {
   1883     enum BadCode bad = NotBad;
   1884     int i = 0, j;
   1885     char *a, *e = NULL;
   1886 
   1887 #if CHECK_EUID
   1888     if (PrivsElevated())
   1889 #endif
   1890     {
   1891         /* Check each argv[] */
   1892         for (i = 1; i < argc; i++) {
   1893             if (strcmp(argv[i], "-fp") == 0) {
   1894                 i++;            /* continue with next argument. skip the length check */
   1895                 if (i >= argc)
   1896                     break;
   1897             }
   1898             else {
   1899                 if (strlen(argv[i]) > MAX_ARG_LENGTH) {
   1900                     bad = ArgTooLong;
   1901                     break;
   1902                 }
   1903             }
   1904             a = argv[i];
   1905             while (*a) {
   1906                 if (checkPrintable(*a) == 0) {
   1907                     bad = UnprintableArg;
   1908                     break;
   1909                 }
   1910                 a++;
   1911             }
   1912             if (bad)
   1913                 break;
   1914         }
   1915         if (!bad) {
   1916             /* Check each envp[] */
   1917             for (i = 0; envp[i]; i++) {
   1918 
   1919                 /* Check for bad environment variables and values */
   1920 #if REMOVE_ENV_LD
   1921                 while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
   1922                     for (j = i; envp[j]; j++) {
   1923                         envp[j] = envp[j + 1];
   1924                     }
   1925                 }
   1926 #endif
   1927                 if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
   1928 #if REMOVE_LONG_ENV
   1929                     for (j = i; envp[j]; j++) {
   1930                         envp[j] = envp[j + 1];
   1931                     }
   1932                     i--;
   1933 #else
   1934                     char *eq;
   1935                     int len;
   1936 
   1937                     eq = strchr(envp[i], '=');
   1938                     if (!eq)
   1939                         continue;
   1940                     len = eq - envp[i];
   1941                     e = strndup(envp[i], len);
   1942                     if (!e) {
   1943                         bad = InternalError;
   1944                         break;
   1945                     }
   1946                     if (len >= 4 &&
   1947                         (strcmp(e + len - 4, "PATH") == 0 ||
   1948                          strcmp(e, "TERMCAP") == 0)) {
   1949                         if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
   1950                             bad = EnvTooLong;
   1951                             break;
   1952                         }
   1953                         else {
   1954                             free(e);
   1955                         }
   1956                     }
   1957                     else {
   1958                         bad = EnvTooLong;
   1959                         break;
   1960                     }
   1961 #endif
   1962                 }
   1963             }
   1964         }
   1965 #if NO_OUTPUT_PIPES
   1966         if (!bad) {
   1967             struct stat buf;
   1968 
   1969             if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode))
   1970                 bad = OutputIsPipe;
   1971             if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode))
   1972                 bad = OutputIsPipe;
   1973         }
   1974 #endif
   1975     }
   1976     switch (bad) {
   1977     case NotBad:
   1978         return;
   1979     case UnsafeArg:
   1980         ErrorF("Command line argument number %d is unsafe\n", i);
   1981         break;
   1982     case ArgTooLong:
   1983         ErrorF("Command line argument number %d is too long\n", i);
   1984         break;
   1985     case UnprintableArg:
   1986         ErrorF("Command line argument number %d contains unprintable"
   1987                " characters\n", i);
   1988         break;
   1989     case EnvTooLong:
   1990         ErrorF("Environment variable `%s' is too long\n", e);
   1991         break;
   1992     case OutputIsPipe:
   1993         ErrorF("Stdout and/or stderr is a pipe\n");
   1994         break;
   1995     case InternalError:
   1996         ErrorF("Internal Error\n");
   1997         break;
   1998     default:
   1999         ErrorF("Unknown error\n");
   2000         break;
   2001     }
   2002     FatalError("X server aborted because of unsafe environment\n");
   2003 }
   2004 
   2005 /*
   2006  * CheckUserAuthorization: check if the user is allowed to start the
   2007  * X server.  This usually means some sort of PAM checking, and it is
   2008  * usually only done for setuid servers (uid != euid).
   2009  */
   2010 
   2011 #ifdef USE_PAM
   2012 #include <security/pam_appl.h>
   2013 #include <security/pam_misc.h>
   2014 #include <pwd.h>
   2015 #endif                          /* USE_PAM */
   2016 
   2017 void
   2018 CheckUserAuthorization(void)
   2019 {
   2020 #ifdef USE_PAM
   2021     static struct pam_conv conv = {
   2022         misc_conv,
   2023         NULL
   2024     };
   2025 
   2026     pam_handle_t *pamh = NULL;
   2027     struct passwd *pw;
   2028     int retval;
   2029 
   2030     if (getuid() != geteuid()) {
   2031         pw = getpwuid(getuid());
   2032         if (pw == NULL)
   2033             FatalError("getpwuid() failed for uid %d\n", getuid());
   2034 
   2035         retval = pam_start("xserver", pw->pw_name, &conv, &pamh);
   2036         if (retval != PAM_SUCCESS)
   2037             FatalError("pam_start() failed.\n"
   2038                        "\tMissing or mangled PAM config file or module?\n");
   2039 
   2040         retval = pam_authenticate(pamh, 0);
   2041         if (retval != PAM_SUCCESS) {
   2042             pam_end(pamh, retval);
   2043             FatalError("PAM authentication failed, cannot start X server.\n"
   2044                        "\tPerhaps you do not have console ownership?\n");
   2045         }
   2046 
   2047         retval = pam_acct_mgmt(pamh, 0);
   2048         if (retval != PAM_SUCCESS) {
   2049             pam_end(pamh, retval);
   2050             FatalError("PAM authentication failed, cannot start X server.\n"
   2051                        "\tPerhaps you do not have console ownership?\n");
   2052         }
   2053 
   2054         /* this is not a session, so do not do session management */
   2055         pam_end(pamh, PAM_SUCCESS);
   2056     }
   2057 #endif
   2058 }
   2059 
   2060 /*
   2061  * Tokenize a string into a NULL terminated array of strings. Always returns
   2062  * an allocated array unless an error occurs.
   2063  */
   2064 char **
   2065 xstrtokenize(const char *str, const char *separators)
   2066 {
   2067     char **list, **nlist;
   2068     char *tok, *tmp;
   2069     unsigned num = 0, n;
   2070 
   2071     if (!str)
   2072         return NULL;
   2073     list = calloc(1, sizeof(*list));
   2074     if (!list)
   2075         return NULL;
   2076     tmp = strdup(str);
   2077     if (!tmp)
   2078         goto error;
   2079     for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) {
   2080         nlist = reallocarray(list, num + 2, sizeof(*list));
   2081         if (!nlist)
   2082             goto error;
   2083         list = nlist;
   2084         list[num] = strdup(tok);
   2085         if (!list[num])
   2086             goto error;
   2087         list[++num] = NULL;
   2088     }
   2089     free(tmp);
   2090     return list;
   2091 
   2092  error:
   2093     free(tmp);
   2094     for (n = 0; n < num; n++)
   2095         free(list[n]);
   2096     free(list);
   2097     return NULL;
   2098 }
   2099 
   2100 /* Format a signed number into a string in a signal safe manner. The string
   2101  * should be at least 21 characters in order to handle all int64_t values.
   2102  */
   2103 void
   2104 FormatInt64(int64_t num, char *string)
   2105 {
   2106     uint64_t unum = num;
   2107 
   2108     if (num < 0) {
   2109         string[0] = '-';
   2110         unum = num * -1;
   2111         string++;
   2112     }
   2113     FormatUInt64(unum, string);
   2114 }
   2115 
   2116 /* Format a number into a string in a signal safe manner. The string should be
   2117  * at least 21 characters in order to handle all uint64_t values. */
   2118 void
   2119 FormatUInt64(uint64_t num, char *string)
   2120 {
   2121     uint64_t divisor;
   2122     int len;
   2123     int i;
   2124 
   2125     for (len = 1, divisor = 10;
   2126          len < 20 && num / divisor;
   2127          len++, divisor *= 10);
   2128 
   2129     for (i = len, divisor = 1; i > 0; i--, divisor *= 10)
   2130         string[i - 1] = '0' + ((num / divisor) % 10);
   2131 
   2132     string[len] = '\0';
   2133 }
   2134 
   2135 /**
   2136  * Format a double number as %.2f.
   2137  */
   2138 void
   2139 FormatDouble(double dbl, char *string)
   2140 {
   2141     int slen = 0;
   2142     uint64_t frac;
   2143 
   2144     frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5;
   2145     frac %= 100;
   2146 
   2147     /* write decimal part to string */
   2148     if (dbl < 0 && dbl > -1)
   2149         string[slen++] = '-';
   2150     FormatInt64((int64_t)dbl, &string[slen]);
   2151 
   2152     while(string[slen] != '\0')
   2153         slen++;
   2154 
   2155     /* append fractional part, but only if we have enough characters. We
   2156      * expect string to be 21 chars (incl trailing \0) */
   2157     if (slen <= 17) {
   2158         string[slen++] = '.';
   2159         if (frac < 10)
   2160             string[slen++] = '0';
   2161 
   2162         FormatUInt64(frac, &string[slen]);
   2163     }
   2164 }
   2165 
   2166 
   2167 /* Format a number into a hexadecimal string in a signal safe manner. The string
   2168  * should be at least 17 characters in order to handle all uint64_t values. */
   2169 void
   2170 FormatUInt64Hex(uint64_t num, char *string)
   2171 {
   2172     uint64_t divisor;
   2173     int len;
   2174     int i;
   2175 
   2176     for (len = 1, divisor = 0x10;
   2177          len < 16 && num / divisor;
   2178          len++, divisor *= 0x10);
   2179 
   2180     for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) {
   2181         int val = (num / divisor) % 0x10;
   2182 
   2183         if (val < 10)
   2184             string[i - 1] = '0' + val;
   2185         else
   2186             string[i - 1] = 'a' + val - 10;
   2187     }
   2188 
   2189     string[len] = '\0';
   2190 }
   2191 
   2192 #if !defined(WIN32) || defined(__CYGWIN__)
   2193 /* Move a file descriptor out of the way of our select mask; this
   2194  * is useful for file descriptors which will never appear in the
   2195  * select mask to avoid reducing the number of clients that can
   2196  * connect to the server
   2197  */
   2198 int
   2199 os_move_fd(int fd)
   2200 {
   2201     int newfd;
   2202 
   2203 #ifdef F_DUPFD_CLOEXEC
   2204     newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS);
   2205 #else
   2206     newfd = fcntl(fd, F_DUPFD, MAXCLIENTS);
   2207 #endif
   2208     if (newfd < 0)
   2209         return fd;
   2210 #ifndef F_DUPFD_CLOEXEC
   2211     fcntl(newfd, F_SETFD, FD_CLOEXEC);
   2212 #endif
   2213     close(fd);
   2214     return newfd;
   2215 }
   2216 #endif
   2217