From 749046e5e9f04b6b2fce95233904cccf83e31d0e Mon Sep 17 00:00:00 2001 From: "Enrico Weigelt, metux IT consult" Date: Tue, 20 Feb 2024 19:33:26 +0100 Subject: [PATCH] os: move out LockServer logic from util.c to serverlock.c Signed-off-by: Enrico Weigelt, metux IT consult Part-of: --- os/meson.build | 1 + os/serverlock.c | 248 ++++++++++++++++++++++++++++++++++++++++++++++++ os/serverlock.h | 1 + os/utils.c | 182 +---------------------------------- 4 files changed, 252 insertions(+), 180 deletions(-) create mode 100644 os/serverlock.c diff --git a/os/meson.build b/os/meson.build index 38d3d2fae..e12e2c9e7 100644 --- a/os/meson.build +++ b/os/meson.build @@ -12,6 +12,7 @@ srcs_os = [ 'mitauth.c', 'osinit.c', 'ospoll.c', + 'serverlock.c', 'string.c', 'utils.c', 'xdmauth.c', diff --git a/os/serverlock.c b/os/serverlock.c new file mode 100644 index 000000000..f5c03e32f --- /dev/null +++ b/os/serverlock.c @@ -0,0 +1,248 @@ +/* SPDX-License-Identifier: MIT OR X11 + * + * Copyright © 2024 Enrico Weigelt, metux IT consult + */ +/* + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1994 Quarterdeck Office Systems. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital and +Quarterdeck not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT +OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE +OR PERFORMANCE OF THIS SOFTWARE. + +*/ +#include + +#include +#include +#include +#include +#include +#include + +#include "dix/dix_priv.h" +#include "os/serverlock.h" +#include "os/osdep.h" + +#include "os.h" +#include "opaque.h" + +/* + * Explicit support for a server lock file like the ones used for UUCP. + * For architectures with virtual terminals that can run more than one + * server at a time. This keeps the servers from stomping on each other + * if the user forgets to give them different display numbers. + */ +#define LOCK_DIR "/tmp" +#define LOCK_TMP_PREFIX "/.tX" +#define LOCK_PREFIX "/.X" +#define LOCK_SUFFIX "-lock" + +#ifdef LOCK_SERVER + +static Bool StillLocking = FALSE; +static char LockFile[PATH_MAX]; +static Bool nolock = FALSE; + +/* + * LockServer -- + * Check if the server lock file exists. If so, check if the PID + * contained inside is valid. If so, then die. Otherwise, create + * the lock file containing the PID. + */ +void +LockServer(void) +{ + char tmp[PATH_MAX], pid_str[12]; + int lfd, i, haslock, l_pid, t; + const char *tmppath = LOCK_DIR; + int len; + char port[20]; + + if (nolock || NoListenAll) + return; + /* + * Path names + */ + snprintf(port, sizeof(port), "%d", atoi(display)); + len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) : + strlen(LOCK_TMP_PREFIX); + len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1; + if (len > sizeof(LockFile)) + FatalError("Display name `%s' is too long\n", port); + (void) sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port); + (void) sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port); + + /* + * Create a temporary file containing our PID. Attempt three times + * to create the file. + */ + StillLocking = TRUE; + i = 0; + do { + i++; + lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); + if (lfd < 0) + sleep(2); + else + break; + } while (i < 3); + if (lfd < 0) { + unlink(tmp); + i = 0; + do { + i++; + lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); + if (lfd < 0) + sleep(2); + else + break; + } while (i < 3); + } + if (lfd < 0) + FatalError("Could not create lock file in %s\n", tmp); + snprintf(pid_str, sizeof(pid_str), "%10lu\n", (unsigned long) getpid()); + if (write(lfd, pid_str, 11) != 11) + FatalError("Could not write pid to lock file in %s\n", tmp); + (void) fchmod(lfd, 0444); + (void) close(lfd); + + /* + * OK. Now the tmp file exists. Try three times to move it in place + * for the lock. + */ + i = 0; + haslock = 0; + while ((!haslock) && (i++ < 3)) { + haslock = (link(tmp, LockFile) == 0); + if (haslock) { + /* + * We're done. + */ + break; + } + else if (errno == EEXIST) { + /* + * Read the pid from the existing file + */ + lfd = open(LockFile, O_RDONLY | O_NOFOLLOW); + if (lfd < 0) { + unlink(tmp); + FatalError("Can't read lock file %s\n", LockFile); + } + pid_str[0] = '\0'; + if (read(lfd, pid_str, 11) != 11) { + /* + * Bogus lock file. + */ + unlink(LockFile); + close(lfd); + continue; + } + pid_str[11] = '\0'; + sscanf(pid_str, "%d", &l_pid); + close(lfd); + + /* + * Now try to kill the PID to see if it exists. + */ + errno = 0; + t = kill(l_pid, 0); + if ((t < 0) && (errno == ESRCH)) { + /* + * Stale lock file. + */ + unlink(LockFile); + continue; + } + else if (((t < 0) && (errno == EPERM)) || (t == 0)) { + /* + * Process is still active. + */ + unlink(tmp); + FatalError + ("Server is already active for display %s\n%s %s\n%s\n", + port, "\tIf this server is no longer running, remove", + LockFile, "\tand start again."); + } + } + else { + unlink(tmp); + FatalError + ("Linking lock file (%s) in place failed: %s\n", + LockFile, strerror(errno)); + } + } + unlink(tmp); + if (!haslock) + FatalError("Could not create server lock file: %s\n", LockFile); + StillLocking = FALSE; +} + +/* + * UnlockServer -- + * Remove the server lock file. + */ +void +UnlockServer(void) +{ + if (nolock || NoListenAll) + return; + + if (!StillLocking) { + + (void) unlink(LockFile); + } +} + +void DisableServerLock(void) { + nolock = TRUE; +} + +#else /* LOCK_SERVER */ + +void LockServer(void) {} +void UnlockServer(void) {} +void DisableServerLock(void) {} + +#endif /* LOCK_SERVER */ diff --git a/os/serverlock.h b/os/serverlock.h index 429c3a04b..ec74c2bb2 100644 --- a/os/serverlock.h +++ b/os/serverlock.h @@ -7,5 +7,6 @@ void LockServer(void); void UnlockServer(void); +void DisableServerLock(void); #endif /* _XSERVER_SERVERLOCK_H */ diff --git a/os/utils.c b/os/utils.c index e45683cef..ded9a463e 100644 --- a/os/utils.c +++ b/os/utils.c @@ -224,182 +224,6 @@ OsSignal(int sig, OsSigHandlerPtr handler) #endif } -/* - * Explicit support for a server lock file like the ones used for UUCP. - * For architectures with virtual terminals that can run more than one - * server at a time. This keeps the servers from stomping on each other - * if the user forgets to give them different display numbers. - */ -#define LOCK_DIR "/tmp" -#define LOCK_TMP_PREFIX "/.tX" -#define LOCK_PREFIX "/.X" -#define LOCK_SUFFIX "-lock" - -#ifndef LOCK_SERVER -void -LockServer(void) -{} - -void -UnlockServer(void) -{} -#else /* LOCK_SERVER */ -static Bool StillLocking = FALSE; -static char LockFile[PATH_MAX]; -static Bool nolock = FALSE; - -/* - * LockServer -- - * Check if the server lock file exists. If so, check if the PID - * contained inside is valid. If so, then die. Otherwise, create - * the lock file containing the PID. - */ -void -LockServer(void) -{ - char tmp[PATH_MAX], pid_str[12]; - int lfd, i, haslock, l_pid, t; - const char *tmppath = LOCK_DIR; - int len; - char port[20]; - - if (nolock || NoListenAll) - return; - /* - * Path names - */ - snprintf(port, sizeof(port), "%d", atoi(display)); - len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) : - strlen(LOCK_TMP_PREFIX); - len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1; - if (len > sizeof(LockFile)) - FatalError("Display name `%s' is too long\n", port); - (void) sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port); - (void) sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port); - - /* - * Create a temporary file containing our PID. Attempt three times - * to create the file. - */ - StillLocking = TRUE; - i = 0; - do { - i++; - lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); - if (lfd < 0) - sleep(2); - else - break; - } while (i < 3); - if (lfd < 0) { - unlink(tmp); - i = 0; - do { - i++; - lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); - if (lfd < 0) - sleep(2); - else - break; - } while (i < 3); - } - if (lfd < 0) - FatalError("Could not create lock file in %s\n", tmp); - snprintf(pid_str, sizeof(pid_str), "%10lu\n", (unsigned long) getpid()); - if (write(lfd, pid_str, 11) != 11) - FatalError("Could not write pid to lock file in %s\n", tmp); - (void) fchmod(lfd, 0444); - (void) close(lfd); - - /* - * OK. Now the tmp file exists. Try three times to move it in place - * for the lock. - */ - i = 0; - haslock = 0; - while ((!haslock) && (i++ < 3)) { - haslock = (link(tmp, LockFile) == 0); - if (haslock) { - /* - * We're done. - */ - break; - } - else if (errno == EEXIST) { - /* - * Read the pid from the existing file - */ - lfd = open(LockFile, O_RDONLY | O_NOFOLLOW); - if (lfd < 0) { - unlink(tmp); - FatalError("Can't read lock file %s\n", LockFile); - } - pid_str[0] = '\0'; - if (read(lfd, pid_str, 11) != 11) { - /* - * Bogus lock file. - */ - unlink(LockFile); - close(lfd); - continue; - } - pid_str[11] = '\0'; - sscanf(pid_str, "%d", &l_pid); - close(lfd); - - /* - * Now try to kill the PID to see if it exists. - */ - errno = 0; - t = kill(l_pid, 0); - if ((t < 0) && (errno == ESRCH)) { - /* - * Stale lock file. - */ - unlink(LockFile); - continue; - } - else if (((t < 0) && (errno == EPERM)) || (t == 0)) { - /* - * Process is still active. - */ - unlink(tmp); - FatalError - ("Server is already active for display %s\n%s %s\n%s\n", - port, "\tIf this server is no longer running, remove", - LockFile, "\tand start again."); - } - } - else { - unlink(tmp); - FatalError - ("Linking lock file (%s) in place failed: %s\n", - LockFile, strerror(errno)); - } - } - unlink(tmp); - if (!haslock) - FatalError("Could not create server lock file: %s\n", LockFile); - StillLocking = FALSE; -} - -/* - * UnlockServer -- - * Remove the server lock file. - */ -void -UnlockServer(void) -{ - if (nolock || NoListenAll) - return; - - if (!StillLocking) { - - (void) unlink(LockFile); - } -} -#endif /* LOCK_SERVER */ - /* Force connections to close on SIGHUP from init */ void @@ -763,9 +587,7 @@ ProcessCommandLine(int argc, char *argv[]) else if (strcmp(argv[i], "-displayfd") == 0) { if (++i < argc) { displayfd = atoi(argv[i]); -#ifdef LOCK_SERVER - nolock = TRUE; -#endif + DisableServerLock(); } else UseMsg(); @@ -854,7 +676,7 @@ ProcessCommandLine(int argc, char *argv[]) ("Warning: the -nolock option can only be used by root\n"); else #endif - nolock = TRUE; + DisableServerLock(); } #endif else if ( strcmp( argv[i], "-maxclients") == 0)