xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

utils.c (58181B)


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