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         if (!iop)
   1508             close(pdes[0]);
   1509     }
   1510     else {
   1511         iop = fdopen(pdes[1], type);
   1512         close(pdes[0]);
   1513         if (!iop)
   1514             close(pdes[1]);
   1515     }
   1516 
   1517     if (!iop) {
   1518         free(cur);
   1519 #ifdef HAVE_SETITIMER
   1520         if (SmartScheduleEnable() < 0)
   1521             perror("signal");
   1522 #endif
   1523         return NULL;
   1524     }
   1525 
   1526     cur->fp = iop;
   1527     cur->pid = pid;
   1528     cur->next = pidlist;
   1529     pidlist = cur;
   1530 
   1531     DebugF("Popen: `%s', fp = %p\n", command, iop);
   1532 
   1533     return iop;
   1534 }
   1535 
   1536 /* fopen that drops privileges */
   1537 void *
   1538 Fopen(const char *file, const char *type)
   1539 {
   1540     FILE *iop;
   1541 
   1542 #ifndef HAS_SAVED_IDS_AND_SETEUID
   1543     struct pid *cur;
   1544     int pdes[2], pid;
   1545 
   1546     if (file == NULL || type == NULL)
   1547         return NULL;
   1548 
   1549     if ((*type != 'r' && *type != 'w') || type[1])
   1550         return NULL;
   1551 
   1552     if ((cur = malloc(sizeof(struct pid))) == NULL)
   1553         return NULL;
   1554 
   1555     if (pipe(pdes) < 0) {
   1556         free(cur);
   1557         return NULL;
   1558     }
   1559 
   1560     switch (pid = fork()) {
   1561     case -1:                   /* error */
   1562         close(pdes[0]);
   1563         close(pdes[1]);
   1564         free(cur);
   1565         return NULL;
   1566     case 0:                    /* child */
   1567         if (setgid(getgid()) == -1)
   1568             _exit(127);
   1569         if (setuid(getuid()) == -1)
   1570             _exit(127);
   1571         if (*type == 'r') {
   1572             if (pdes[1] != 1) {
   1573                 /* stdout */
   1574                 dup2(pdes[1], 1);
   1575                 close(pdes[1]);
   1576             }
   1577             close(pdes[0]);
   1578         }
   1579         else {
   1580             if (pdes[0] != 0) {
   1581                 /* stdin */
   1582                 dup2(pdes[0], 0);
   1583                 close(pdes[0]);
   1584             }
   1585             close(pdes[1]);
   1586         }
   1587         execl("/bin/cat", "cat", file, (char *) NULL);
   1588         _exit(127);
   1589     }
   1590 
   1591     /* Avoid EINTR during stdio calls */
   1592     OsBlockSignals();
   1593 
   1594     /* parent */
   1595     if (*type == 'r') {
   1596         iop = fdopen(pdes[0], type);
   1597         close(pdes[1]);
   1598     }
   1599     else {
   1600         iop = fdopen(pdes[1], type);
   1601         close(pdes[0]);
   1602     }
   1603 
   1604     cur->fp = iop;
   1605     cur->pid = pid;
   1606     cur->next = pidlist;
   1607     pidlist = cur;
   1608 
   1609     DebugF("Fopen(%s), fp = %p\n", file, iop);
   1610 
   1611     return iop;
   1612 #else
   1613     int ruid, euid;
   1614 
   1615     ruid = getuid();
   1616     euid = geteuid();
   1617 
   1618     if (seteuid(ruid) == -1) {
   1619         return NULL;
   1620     }
   1621     iop = fopen(file, type);
   1622 
   1623     if (seteuid(euid) == -1) {
   1624         if (iop) {
   1625             fclose(iop);
   1626         }
   1627         return NULL;
   1628     }
   1629     return iop;
   1630 #endif                          /* HAS_SAVED_IDS_AND_SETEUID */
   1631 }
   1632 
   1633 int
   1634 Pclose(void *iop)
   1635 {
   1636     struct pid *cur, *last;
   1637     int pstat;
   1638     int pid;
   1639 
   1640     DebugF("Pclose: fp = %p\n", iop);
   1641     fclose(iop);
   1642 
   1643     for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
   1644         if (cur->fp == iop)
   1645             break;
   1646     if (cur == NULL)
   1647         return -1;
   1648 
   1649     do {
   1650         pid = waitpid(cur->pid, &pstat, 0);
   1651     } while (pid == -1 && errno == EINTR);
   1652 
   1653     if (last == NULL)
   1654         pidlist = cur->next;
   1655     else
   1656         last->next = cur->next;
   1657     free(cur);
   1658 
   1659     /* allow EINTR again */
   1660     OsReleaseSignals();
   1661 
   1662 #ifdef HAVE_SETITIMER
   1663     if (SmartScheduleEnable() < 0) {
   1664         perror("signal");
   1665         return -1;
   1666     }
   1667 #endif
   1668 
   1669     return pid == -1 ? -1 : pstat;
   1670 }
   1671 
   1672 int
   1673 Fclose(void *iop)
   1674 {
   1675 #ifdef HAS_SAVED_IDS_AND_SETEUID
   1676     return fclose(iop);
   1677 #else
   1678     return Pclose(iop);
   1679 #endif
   1680 }
   1681 
   1682 #endif                          /* !WIN32 */
   1683 
   1684 #ifdef WIN32
   1685 
   1686 #include <X11/Xwindows.h>
   1687 
   1688 const char *
   1689 Win32TempDir(void)
   1690 {
   1691     static char buffer[PATH_MAX];
   1692 
   1693     if (GetTempPath(sizeof(buffer), buffer)) {
   1694         int len;
   1695 
   1696         buffer[sizeof(buffer) - 1] = 0;
   1697         len = strlen(buffer);
   1698         if (len > 0)
   1699             if (buffer[len - 1] == '\\')
   1700                 buffer[len - 1] = 0;
   1701         return buffer;
   1702     }
   1703     if (getenv("TEMP") != NULL)
   1704         return getenv("TEMP");
   1705     else if (getenv("TMP") != NULL)
   1706         return getenv("TMP");
   1707     else
   1708         return "/tmp";
   1709 }
   1710 
   1711 int
   1712 System(const char *cmdline)
   1713 {
   1714     STARTUPINFO si;
   1715     PROCESS_INFORMATION pi;
   1716     DWORD dwExitCode;
   1717     char *cmd = strdup(cmdline);
   1718 
   1719     ZeroMemory(&si, sizeof(si));
   1720     si.cb = sizeof(si);
   1721     ZeroMemory(&pi, sizeof(pi));
   1722 
   1723     if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
   1724         LPVOID buffer;
   1725 
   1726         if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
   1727                            FORMAT_MESSAGE_FROM_SYSTEM |
   1728                            FORMAT_MESSAGE_IGNORE_INSERTS,
   1729                            NULL,
   1730                            GetLastError(),
   1731                            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
   1732                            (LPTSTR) &buffer, 0, NULL)) {
   1733             ErrorF("[xkb] Starting '%s' failed!\n", cmdline);
   1734         }
   1735         else {
   1736             ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer);
   1737             LocalFree(buffer);
   1738         }
   1739 
   1740         free(cmd);
   1741         return -1;
   1742     }
   1743     /* Wait until child process exits. */
   1744     WaitForSingleObject(pi.hProcess, INFINITE);
   1745 
   1746     GetExitCodeProcess(pi.hProcess, &dwExitCode);
   1747 
   1748     /* Close process and thread handles. */
   1749     CloseHandle(pi.hProcess);
   1750     CloseHandle(pi.hThread);
   1751     free(cmd);
   1752 
   1753     return dwExitCode;
   1754 }
   1755 #endif
   1756 
   1757 Bool
   1758 PrivsElevated(void)
   1759 {
   1760     static Bool privsTested = FALSE;
   1761     static Bool privsElevated = TRUE;
   1762 
   1763     if (!privsTested) {
   1764 #if defined(WIN32)
   1765         privsElevated = FALSE;
   1766 #else
   1767         if ((getuid() != geteuid()) || (getgid() != getegid())) {
   1768             privsElevated = TRUE;
   1769         }
   1770         else {
   1771 #if defined(HAVE_ISSETUGID)
   1772             privsElevated = issetugid();
   1773 #elif defined(HAVE_GETRESUID)
   1774             uid_t ruid, euid, suid;
   1775             gid_t rgid, egid, sgid;
   1776 
   1777             if ((getresuid(&ruid, &euid, &suid) == 0) &&
   1778                 (getresgid(&rgid, &egid, &sgid) == 0)) {
   1779                 privsElevated = (euid != suid) || (egid != sgid);
   1780             }
   1781             else {
   1782                 printf("Failed getresuid or getresgid");
   1783                 /* Something went wrong, make defensive assumption */
   1784                 privsElevated = TRUE;
   1785             }
   1786 #else
   1787             if (getuid() == 0) {
   1788                 /* running as root: uid==euid==0 */
   1789                 privsElevated = FALSE;
   1790             }
   1791             else {
   1792                 /*
   1793                  * If there are saved ID's the process might still be privileged
   1794                  * even though the above test succeeded. If issetugid() and
   1795                  * getresgid() aren't available, test this by trying to set
   1796                  * euid to 0.
   1797                  */
   1798                 unsigned int oldeuid;
   1799 
   1800                 oldeuid = geteuid();
   1801 
   1802                 if (seteuid(0) != 0) {
   1803                     privsElevated = FALSE;
   1804                 }
   1805                 else {
   1806                     if (seteuid(oldeuid) != 0) {
   1807                         FatalError("Failed to drop privileges.  Exiting\n");
   1808                     }
   1809                     privsElevated = TRUE;
   1810                 }
   1811             }
   1812 #endif
   1813         }
   1814 #endif
   1815         privsTested = TRUE;
   1816     }
   1817     return privsElevated;
   1818 }
   1819 
   1820 /*
   1821  * CheckUserParameters: check for long command line arguments and long
   1822  * environment variables.  By default, these checks are only done when
   1823  * the server's euid != ruid.  In 3.3.x, these checks were done in an
   1824  * external wrapper utility.
   1825  */
   1826 
   1827 /* Consider LD* variables insecure? */
   1828 #ifndef REMOVE_ENV_LD
   1829 #define REMOVE_ENV_LD 1
   1830 #endif
   1831 
   1832 /* Remove long environment variables? */
   1833 #ifndef REMOVE_LONG_ENV
   1834 #define REMOVE_LONG_ENV 1
   1835 #endif
   1836 
   1837 /*
   1838  * Disallow stdout or stderr as pipes?  It's possible to block the X server
   1839  * when piping stdout+stderr to a pipe.
   1840  *
   1841  * Don't enable this because it looks like it's going to cause problems.
   1842  */
   1843 #ifndef NO_OUTPUT_PIPES
   1844 #define NO_OUTPUT_PIPES 0
   1845 #endif
   1846 
   1847 /* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
   1848 #ifndef CHECK_EUID
   1849 #ifndef WIN32
   1850 #define CHECK_EUID 1
   1851 #else
   1852 #define CHECK_EUID 0
   1853 #endif
   1854 #endif
   1855 
   1856 /*
   1857  * Maybe the locale can be faked to make isprint(3) report that everything
   1858  * is printable?  Avoid it by default.
   1859  */
   1860 #ifndef USE_ISPRINT
   1861 #define USE_ISPRINT 0
   1862 #endif
   1863 
   1864 #define MAX_ARG_LENGTH          128
   1865 #define MAX_ENV_LENGTH          256
   1866 #define MAX_ENV_PATH_LENGTH     2048    /* Limit for *PATH and TERMCAP */
   1867 
   1868 #if USE_ISPRINT
   1869 #include <ctype.h>
   1870 #define checkPrintable(c) isprint(c)
   1871 #else
   1872 #define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
   1873 #endif
   1874 
   1875 enum BadCode {
   1876     NotBad = 0,
   1877     UnsafeArg,
   1878     ArgTooLong,
   1879     UnprintableArg,
   1880     EnvTooLong,
   1881     OutputIsPipe,
   1882     InternalError
   1883 };
   1884 
   1885 #if defined(VENDORSUPPORT)
   1886 #define BUGADDRESS VENDORSUPPORT
   1887 #elif defined(BUILDERADDR)
   1888 #define BUGADDRESS BUILDERADDR
   1889 #else
   1890 #define BUGADDRESS "xorg (at) freedesktop.org"
   1891 #endif
   1892 
   1893 void
   1894 CheckUserParameters(int argc, char **argv, char **envp)
   1895 {
   1896     enum BadCode bad = NotBad;
   1897     int i = 0, j;
   1898     char *a, *e = NULL;
   1899 
   1900 #if CHECK_EUID
   1901     if (PrivsElevated())
   1902 #endif
   1903     {
   1904         /* Check each argv[] */
   1905         for (i = 1; i < argc; i++) {
   1906             if (strcmp(argv[i], "-fp") == 0) {
   1907                 i++;            /* continue with next argument. skip the length check */
   1908                 if (i >= argc)
   1909                     break;
   1910             }
   1911             else {
   1912                 if (strlen(argv[i]) > MAX_ARG_LENGTH) {
   1913                     bad = ArgTooLong;
   1914                     break;
   1915                 }
   1916             }
   1917             a = argv[i];
   1918             while (*a) {
   1919                 if (checkPrintable(*a) == 0) {
   1920                     bad = UnprintableArg;
   1921                     break;
   1922                 }
   1923                 a++;
   1924             }
   1925             if (bad)
   1926                 break;
   1927         }
   1928         if (!bad) {
   1929             /* Check each envp[] */
   1930             for (i = 0; envp[i]; i++) {
   1931 
   1932                 /* Check for bad environment variables and values */
   1933 #if REMOVE_ENV_LD
   1934                 while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
   1935                     for (j = i; envp[j]; j++) {
   1936                         envp[j] = envp[j + 1];
   1937                     }
   1938                 }
   1939 #endif
   1940                 if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
   1941 #if REMOVE_LONG_ENV
   1942                     for (j = i; envp[j]; j++) {
   1943                         envp[j] = envp[j + 1];
   1944                     }
   1945                     i--;
   1946 #else
   1947                     char *eq;
   1948                     int len;
   1949 
   1950                     eq = strchr(envp[i], '=');
   1951                     if (!eq)
   1952                         continue;
   1953                     len = eq - envp[i];
   1954                     e = strndup(envp[i], len);
   1955                     if (!e) {
   1956                         bad = InternalError;
   1957                         break;
   1958                     }
   1959                     if (len >= 4 &&
   1960                         (strcmp(e + len - 4, "PATH") == 0 ||
   1961                          strcmp(e, "TERMCAP") == 0)) {
   1962                         if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
   1963                             bad = EnvTooLong;
   1964                             break;
   1965                         }
   1966                         else {
   1967                             free(e);
   1968                         }
   1969                     }
   1970                     else {
   1971                         bad = EnvTooLong;
   1972                         break;
   1973                     }
   1974 #endif
   1975                 }
   1976             }
   1977         }
   1978 #if NO_OUTPUT_PIPES
   1979         if (!bad) {
   1980             struct stat buf;
   1981 
   1982             if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode))
   1983                 bad = OutputIsPipe;
   1984             if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode))
   1985                 bad = OutputIsPipe;
   1986         }
   1987 #endif
   1988     }
   1989     switch (bad) {
   1990     case NotBad:
   1991         return;
   1992     case UnsafeArg:
   1993         ErrorF("Command line argument number %d is unsafe\n", i);
   1994         break;
   1995     case ArgTooLong:
   1996         ErrorF("Command line argument number %d is too long\n", i);
   1997         break;
   1998     case UnprintableArg:
   1999         ErrorF("Command line argument number %d contains unprintable"
   2000                " characters\n", i);
   2001         break;
   2002     case EnvTooLong:
   2003         ErrorF("Environment variable `%s' is too long\n", e);
   2004         break;
   2005     case OutputIsPipe:
   2006         ErrorF("Stdout and/or stderr is a pipe\n");
   2007         break;
   2008     case InternalError:
   2009         ErrorF("Internal Error\n");
   2010         break;
   2011     default:
   2012         ErrorF("Unknown error\n");
   2013         break;
   2014     }
   2015     FatalError("X server aborted because of unsafe environment\n");
   2016 }
   2017 
   2018 /*
   2019  * CheckUserAuthorization: check if the user is allowed to start the
   2020  * X server.  This usually means some sort of PAM checking, and it is
   2021  * usually only done for setuid servers (uid != euid).
   2022  */
   2023 
   2024 #ifdef USE_PAM
   2025 #include <security/pam_appl.h>
   2026 #include <security/pam_misc.h>
   2027 #include <pwd.h>
   2028 #endif                          /* USE_PAM */
   2029 
   2030 void
   2031 CheckUserAuthorization(void)
   2032 {
   2033 #ifdef USE_PAM
   2034     static struct pam_conv conv = {
   2035         misc_conv,
   2036         NULL
   2037     };
   2038 
   2039     pam_handle_t *pamh = NULL;
   2040     struct passwd *pw;
   2041     int retval;
   2042 
   2043     if (getuid() != geteuid()) {
   2044         pw = getpwuid(getuid());
   2045         if (pw == NULL)
   2046             FatalError("getpwuid() failed for uid %d\n", getuid());
   2047 
   2048         retval = pam_start("xserver", pw->pw_name, &conv, &pamh);
   2049         if (retval != PAM_SUCCESS)
   2050             FatalError("pam_start() failed.\n"
   2051                        "\tMissing or mangled PAM config file or module?\n");
   2052 
   2053         retval = pam_authenticate(pamh, 0);
   2054         if (retval != PAM_SUCCESS) {
   2055             pam_end(pamh, retval);
   2056             FatalError("PAM authentication failed, cannot start X server.\n"
   2057                        "\tPerhaps you do not have console ownership?\n");
   2058         }
   2059 
   2060         retval = pam_acct_mgmt(pamh, 0);
   2061         if (retval != PAM_SUCCESS) {
   2062             pam_end(pamh, retval);
   2063             FatalError("PAM authentication failed, cannot start X server.\n"
   2064                        "\tPerhaps you do not have console ownership?\n");
   2065         }
   2066 
   2067         /* this is not a session, so do not do session management */
   2068         pam_end(pamh, PAM_SUCCESS);
   2069     }
   2070 #endif
   2071 }
   2072 
   2073 /*
   2074  * Tokenize a string into a NULL terminated array of strings. Always returns
   2075  * an allocated array unless an error occurs.
   2076  */
   2077 char **
   2078 xstrtokenize(const char *str, const char *separators)
   2079 {
   2080     char **list, **nlist;
   2081     char *tok, *tmp;
   2082     unsigned num = 0, n;
   2083 
   2084     if (!str)
   2085         return NULL;
   2086     list = calloc(1, sizeof(*list));
   2087     if (!list)
   2088         return NULL;
   2089     tmp = strdup(str);
   2090     if (!tmp)
   2091         goto error;
   2092     for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) {
   2093         nlist = reallocarray(list, num + 2, sizeof(*list));
   2094         if (!nlist)
   2095             goto error;
   2096         list = nlist;
   2097         list[num] = strdup(tok);
   2098         if (!list[num])
   2099             goto error;
   2100         list[++num] = NULL;
   2101     }
   2102     free(tmp);
   2103     return list;
   2104 
   2105  error:
   2106     free(tmp);
   2107     for (n = 0; n < num; n++)
   2108         free(list[n]);
   2109     free(list);
   2110     return NULL;
   2111 }
   2112 
   2113 /* Format a signed number into a string in a signal safe manner. The string
   2114  * should be at least 21 characters in order to handle all int64_t values.
   2115  */
   2116 void
   2117 FormatInt64(int64_t num, char *string)
   2118 {
   2119     uint64_t unum = num;
   2120 
   2121     if (num < 0) {
   2122         string[0] = '-';
   2123         unum = num * -1;
   2124         string++;
   2125     }
   2126     FormatUInt64(unum, string);
   2127 }
   2128 
   2129 /* Format a number into a string in a signal safe manner. The string should be
   2130  * at least 21 characters in order to handle all uint64_t values. */
   2131 void
   2132 FormatUInt64(uint64_t num, char *string)
   2133 {
   2134     uint64_t divisor;
   2135     int len;
   2136     int i;
   2137 
   2138     for (len = 1, divisor = 10;
   2139          len < 20 && num / divisor;
   2140          len++, divisor *= 10);
   2141 
   2142     for (i = len, divisor = 1; i > 0; i--, divisor *= 10)
   2143         string[i - 1] = '0' + ((num / divisor) % 10);
   2144 
   2145     string[len] = '\0';
   2146 }
   2147 
   2148 /**
   2149  * Format a double number as %.2f.
   2150  */
   2151 void
   2152 FormatDouble(double dbl, char *string)
   2153 {
   2154     int slen = 0;
   2155     uint64_t frac;
   2156 
   2157     frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5;
   2158     frac %= 100;
   2159 
   2160     /* write decimal part to string */
   2161     if (dbl < 0 && dbl > -1)
   2162         string[slen++] = '-';
   2163     FormatInt64((int64_t)dbl, &string[slen]);
   2164 
   2165     while(string[slen] != '\0')
   2166         slen++;
   2167 
   2168     /* append fractional part, but only if we have enough characters. We
   2169      * expect string to be 21 chars (incl trailing \0) */
   2170     if (slen <= 17) {
   2171         string[slen++] = '.';
   2172         if (frac < 10)
   2173             string[slen++] = '0';
   2174 
   2175         FormatUInt64(frac, &string[slen]);
   2176     }
   2177 }
   2178 
   2179 
   2180 /* Format a number into a hexadecimal string in a signal safe manner. The string
   2181  * should be at least 17 characters in order to handle all uint64_t values. */
   2182 void
   2183 FormatUInt64Hex(uint64_t num, char *string)
   2184 {
   2185     uint64_t divisor;
   2186     int len;
   2187     int i;
   2188 
   2189     for (len = 1, divisor = 0x10;
   2190          len < 16 && num / divisor;
   2191          len++, divisor *= 0x10);
   2192 
   2193     for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) {
   2194         int val = (num / divisor) % 0x10;
   2195 
   2196         if (val < 10)
   2197             string[i - 1] = '0' + val;
   2198         else
   2199             string[i - 1] = 'a' + val - 10;
   2200     }
   2201 
   2202     string[len] = '\0';
   2203 }
   2204 
   2205 #if !defined(WIN32) || defined(__CYGWIN__)
   2206 /* Move a file descriptor out of the way of our select mask; this
   2207  * is useful for file descriptors which will never appear in the
   2208  * select mask to avoid reducing the number of clients that can
   2209  * connect to the server
   2210  */
   2211 int
   2212 os_move_fd(int fd)
   2213 {
   2214     int newfd;
   2215 
   2216 #ifdef F_DUPFD_CLOEXEC
   2217     newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS);
   2218 #else
   2219     newfd = fcntl(fd, F_DUPFD, MAXCLIENTS);
   2220 #endif
   2221     if (newfd < 0)
   2222         return fd;
   2223 #ifndef F_DUPFD_CLOEXEC
   2224     fcntl(newfd, F_SETFD, FD_CLOEXEC);
   2225 #endif
   2226     close(fd);
   2227     return newfd;
   2228 }
   2229 #endif
   2230