1
#ident "$Id: lock.c,v 1.15 2005/01/17 15:09:28 raven Exp $"
2
/* ----------------------------------------------------------------------- *
4
* lock.c - autofs lockfile management
6
* Copyright 2004 Ian Kent <raven@themaw.net>
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
11
* USA; either version 2 of the License, or (at your option) any later
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* This code has adapted from that found in mount/fstab.c of the
22
* ----------------------------------------------------------------------- */
25
#include <sys/types.h>
37
#include "automount.h"
39
static void setup_locksigs(void);
40
static void reset_locksigs(void);
43
* If waiting for 30 secs is not enough then there's
44
* probably no good the requestor continuing anyway?
46
/* LOCK_TIMEOUT = WAIT_INTERVAL/10**9 * WAIT_TRIES */
47
#define WAIT_INTERVAL 100000000L
48
#define WAIT_TRIES 300
49
#define LOCK_RETRIES 3
50
#define MAX_PIDSIZE 20
52
#define LOCK_FILE AUTOFS_LOCK
54
/* Flag for already existing lock file. */
55
static int we_created_lockfile = 0;
57
/* Flag to indicate that signals have been set up. */
58
static int signals_have_been_setup = 0;
60
/* Save previous actions */
61
static struct sigaction actions[NSIG];
62
static struct sigaction sigusr1;
63
static struct sigaction sigusr2;
65
/* Flag to identify we got a TERM signal */
66
static int got_term = 0;
68
/* file descriptor of lock file */
71
/* Ignore all signals except for SIGTERM */
72
static void handler(int sig)
75
* We need ignore most signals as there are quite a few sent
76
* during shutdown. We must continue to wait for the lock.
77
* We should use the USR2 signal for normal operation
78
* and only use a TERM signal to shutdown harshly.
80
if (sig == SIGQUIT || sig == SIGTERM || sig == SIGINT)
84
static int lock_is_owned(int fd)
86
int pid = 0, tries = 3;
89
char pidbuf[MAX_PIDSIZE + 1];
92
lseek(fd, 0, SEEK_SET);
93
got = read(fd, pidbuf, MAX_PIDSIZE);
95
* We add a terminator to the pid to verify write complete.
96
* If the write isn't finish in 300 milliseconds then it's
97
* probably a stale lock file.
99
if (got > 0 && pidbuf[got - 1] == '\n') {
100
sscanf(pidbuf, "%d", &pid);
103
struct timespec t = { 0, 100000000 };
106
while (nanosleep(&t, &r) == -1 && errno == EINTR) {
107
/* So we can exit quickly, return owned */
110
memcpy(&t, &r, sizeof(struct timespec));
124
ret = kill(pid, SIGCONT);
126
* If lock file exists but is not owned by a process
127
* we return unowned status so we can get rid of it
130
if (ret == -1 && errno == ESRCH)
134
* Odd, no pid in file - so what should we do?
135
* Assume something bad happened to owner and
136
* return unowned status.
144
static void setup_locksigs(void)
149
sa.sa_handler = handler;
151
sigfillset(&sa.sa_mask);
153
sigprocmask(SIG_BLOCK, &sa.sa_mask, NULL);
155
while (sigismember(&sa.sa_mask, ++sig) != -1
157
sigaction(sig, &sa, &actions[sig]);
160
sigaction(SIGUSR1, &sa, &sigusr1);
161
sigaction(SIGUSR2, &sa, &sigusr2);
163
signals_have_been_setup = 1;
164
sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
167
static void reset_locksigs(void)
172
sigfillset(&fullset);
173
sigprocmask(SIG_BLOCK, &fullset, NULL);
175
sigaction(SIGUSR1, &sigusr1, NULL);
176
sigaction(SIGUSR2, &sigusr2, NULL);
178
while (sigismember(&fullset, ++sig) != -1
180
sigaction(sig, &actions[sig], NULL);
183
signals_have_been_setup = 0;
184
sigprocmask(SIG_UNBLOCK, &fullset, NULL);
187
/* Remove lock file. */
188
void release_lock(void)
195
if (we_created_lockfile) {
197
we_created_lockfile = 0;
200
if (signals_have_been_setup)
205
* Wait for a lock file to be removed.
206
* Return -1 for a timeout, 0 if a termination signal
207
* is received or 1 for success.
209
static int wait_for_lockf(const char *lockf)
211
struct timespec t = { 0, WAIT_INTERVAL };
213
int ts_size = sizeof(struct timespec);
214
int tries = WAIT_TRIES;
218
while (tries-- && !status) {
219
status = stat(lockf, &st);
221
while (nanosleep(&t, &r) == -1 && errno == EINTR) {
224
memcpy(&t, &r, ts_size);
236
* Aquire lock file taking account of autofs signals.
238
int aquire_lock(void)
244
if (!signals_have_been_setup)
247
len = strlen(LOCK_FILE) + MAX_PIDSIZE;
248
linkf = alloca(len + 1);
249
snprintf(linkf, len, "%s.%d", LOCK_FILE, getpid());
251
/* Repeat until it was us who made the link */
252
while (!we_created_lockfile) {
255
i = open(linkf, O_WRONLY|O_CREAT, 0);
262
j = link(linkf, LOCK_FILE);
265
(void) unlink(linkf);
267
if (j < 0 && errsv != EEXIST) {
272
fd = open(LOCK_FILE, O_RDWR);
274
/* Maybe the file was just deleted? */
275
if (errno == ENOENT && tries-- > 0)
282
char pidbuf[MAX_PIDSIZE + 1];
285
pidlen = sprintf(pidbuf, "%d\n", getpid());
286
write(fd, pidbuf, pidlen);
288
we_created_lockfile = 1;
292
"aquire_lock: can't lock lock file %s: %s";
295
* Someone else made the link.
296
* If the lock file is not owned by anyone
297
* clean it up and try again, otherwise we
300
if (!lock_is_owned(fd)) {
307
status = wait_for_lockf(LOCK_FILE);
310
crit(mess, "timed out", LOCK_FILE);
312
} else if (!status) {
314
crit(mess, "interrupted", LOCK_FILE);