ci: Check for DDXen to be built
[xserver.git] / os / serverlock.c
blob36efc9bc01b8cb23cc76d6fe0de44702cfef10ef
1 /* SPDX-License-Identifier: MIT OR X11
3 * Copyright © 2024 Enrico Weigelt, metux IT consult <info@metux.net>
4 */
5 /*
7 Copyright 1987, 1998 The Open Group
9 Permission to use, copy, modify, distribute, and sell this software and its
10 documentation for any purpose is hereby granted without fee, provided that
11 the above copyright notice appear in all copies and that both that
12 copyright notice and this permission notice appear in supporting
13 documentation.
15 The above copyright notice and this permission notice shall be included
16 in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
22 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 OTHER DEALINGS IN THE SOFTWARE.
26 Except as contained in this notice, the name of The Open Group shall
27 not be used in advertising or otherwise to promote the sale, use or
28 other dealings in this Software without prior written authorization
29 from The Open Group.
31 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
32 Copyright 1994 Quarterdeck Office Systems.
34 All Rights Reserved
36 Permission to use, copy, modify, and distribute this software and its
37 documentation for any purpose and without fee is hereby granted,
38 provided that the above copyright notice appear in all copies and that
39 both that copyright notice and this permission notice appear in
40 supporting documentation, and that the names of Digital and
41 Quarterdeck not be used in advertising or publicity pertaining to
42 distribution of the software without specific, written prior
43 permission.
45 DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
46 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
47 FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
48 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
49 OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
50 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
51 OR PERFORMANCE OF THIS SOFTWARE.
54 #include <dix-config.h>
56 #include <errno.h>
57 #include <fcntl.h>
58 #include <stdbool.h>
59 #include <string.h>
60 #include <sys/stat.h>
61 #include <unistd.h>
63 #include "dix/dix_priv.h"
64 #include "os/serverlock.h"
65 #include "os/osdep.h"
67 #include "os.h"
68 #include "opaque.h"
71 * Explicit support for a server lock file like the ones used for UUCP.
72 * For architectures with virtual terminals that can run more than one
73 * server at a time. This keeps the servers from stomping on each other
74 * if the user forgets to give them different display numbers.
76 #define LOCK_DIR "/tmp"
77 #define LOCK_TMP_PREFIX "/.tX"
78 #define LOCK_PREFIX "/.X"
79 #define LOCK_SUFFIX "-lock"
81 #ifdef LOCK_SERVER
83 static Bool StillLocking = FALSE;
84 static char LockFile[PATH_MAX];
85 static Bool nolock = FALSE;
88 * LockServer --
89 * Check if the server lock file exists. If so, check if the PID
90 * contained inside is valid. If so, then die. Otherwise, create
91 * the lock file containing the PID.
93 void
94 LockServer(void)
96 char tmp[PATH_MAX], pid_str[12];
97 int lfd, i, haslock, l_pid, t;
98 const char *tmppath = LOCK_DIR;
99 int len;
100 char port[20];
102 if (nolock || NoListenAll)
103 return;
105 * Path names
107 snprintf(port, sizeof(port), "%d", atoi(display));
108 len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) :
109 strlen(LOCK_TMP_PREFIX);
110 len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1;
111 if (len > sizeof(LockFile))
112 FatalError("Display name `%s' is too long\n", port);
113 (void) sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
114 (void) sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
117 * Create a temporary file containing our PID. Attempt three times
118 * to create the file.
120 StillLocking = TRUE;
121 i = 0;
122 do {
123 i++;
124 lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
125 if (lfd < 0)
126 sleep(2);
127 else
128 break;
129 } while (i < 3);
130 if (lfd < 0) {
131 unlink(tmp);
132 i = 0;
133 do {
134 i++;
135 lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
136 if (lfd < 0)
137 sleep(2);
138 else
139 break;
140 } while (i < 3);
142 if (lfd < 0)
143 FatalError("Could not create lock file in %s\n", tmp);
144 snprintf(pid_str, sizeof(pid_str), "%10lu\n", (unsigned long) getpid());
145 if (write(lfd, pid_str, 11) != 11)
146 FatalError("Could not write pid to lock file in %s\n", tmp);
147 (void) fchmod(lfd, 0444);
148 (void) close(lfd);
151 * OK. Now the tmp file exists. Try three times to move it in place
152 * for the lock.
154 i = 0;
155 haslock = 0;
156 while ((!haslock) && (i++ < 3)) {
157 haslock = (link(tmp, LockFile) == 0);
158 if (haslock) {
160 * We're done.
162 break;
164 else if (errno == EEXIST) {
166 * Read the pid from the existing file
168 lfd = open(LockFile, O_RDONLY | O_NOFOLLOW);
169 if (lfd < 0) {
170 unlink(tmp);
171 FatalError("Can't read lock file %s\n", LockFile);
173 pid_str[0] = '\0';
174 if (read(lfd, pid_str, 11) != 11) {
176 * Bogus lock file.
178 unlink(LockFile);
179 close(lfd);
180 continue;
182 pid_str[11] = '\0';
183 sscanf(pid_str, "%d", &l_pid);
184 close(lfd);
187 * Now try to kill the PID to see if it exists.
189 errno = 0;
190 t = kill(l_pid, 0);
191 if ((t < 0) && (errno == ESRCH)) {
193 * Stale lock file.
195 unlink(LockFile);
196 continue;
198 else if (((t < 0) && (errno == EPERM)) || (t == 0)) {
200 * Process is still active.
202 unlink(tmp);
203 FatalError
204 ("Server is already active for display %s\n%s %s\n%s\n",
205 port, "\tIf this server is no longer running, remove",
206 LockFile, "\tand start again.");
209 else {
210 unlink(tmp);
211 FatalError
212 ("Linking lock file (%s) in place failed: %s\n",
213 LockFile, strerror(errno));
216 unlink(tmp);
217 if (!haslock)
218 FatalError("Could not create server lock file: %s\n", LockFile);
219 StillLocking = FALSE;
223 * UnlockServer --
224 * Remove the server lock file.
226 void
227 UnlockServer(void)
229 if (nolock || NoListenAll)
230 return;
232 if (!StillLocking) {
234 (void) unlink(LockFile);
238 void DisableServerLock(void) {
239 nolock = TRUE;
242 void LockServerUseMsg(void) {
243 ErrorF("-nolock disable the locking mechanism\n");
246 #else /* LOCK_SERVER */
248 void LockServer(void) {}
249 void UnlockServer(void) {}
250 void DisableServerLock(void) {}
251 void LockServerUseMsg(void) {}
253 #endif /* LOCK_SERVER */