~ubuntu-branches/debian/wheezy/autofs/wheezy

« back to all changes in this revision

Viewing changes to lib/lock.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2008-03-08 01:36:09 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20080308013609-cvs4f2ecoyoism02
Tags: 4.1.4+debian-2.1
* Non-maintainer upload.
* High-urgency upload for RC bugfix.
* Add -DLDAP_DEPRECATED to CFLAGS, to fix compatibility with OpenLDAP
  2.4 on 64-bit architectures.  Closes: #463419.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ident "$Id: lock.c,v 1.15 2005/01/17 15:09:28 raven Exp $"
 
2
/* ----------------------------------------------------------------------- *
 
3
 *
 
4
 *  lock.c - autofs lockfile management
 
5
 *
 
6
 *   Copyright 2004 Ian Kent <raven@themaw.net>
 
7
 *
 
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
 
12
 *   version.
 
13
 *
 
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.
 
18
 *
 
19
 *   This code has adapted from that found in mount/fstab.c of the
 
20
 *   util-linux package.
 
21
 *
 
22
 * ----------------------------------------------------------------------- */
 
23
 
 
24
#include <sys/time.h>
 
25
#include <sys/types.h>
 
26
#include <sys/stat.h>
 
27
#include <time.h>
 
28
#include <unistd.h>
 
29
#include <string.h>
 
30
#include <fcntl.h>
 
31
#include <alloca.h>
 
32
#include <stdio.h>
 
33
#include <signal.h>
 
34
#include <syslog.h>
 
35
#include <errno.h>
 
36
 
 
37
#include "automount.h"
 
38
 
 
39
static void setup_locksigs(void);
 
40
static void reset_locksigs(void);
 
41
 
 
42
/*
 
43
 * If waiting for 30 secs is not enough then there's
 
44
 * probably no good the requestor continuing anyway?
 
45
 */
 
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
 
51
 
 
52
#define LOCK_FILE     AUTOFS_LOCK
 
53
 
 
54
/* Flag for already existing lock file. */
 
55
static int we_created_lockfile = 0;
 
56
 
 
57
/* Flag to indicate that signals have been set up. */
 
58
static int signals_have_been_setup = 0;
 
59
 
 
60
/* Save previous actions */
 
61
static struct sigaction actions[NSIG];
 
62
static struct sigaction sigusr1;
 
63
static struct sigaction sigusr2;
 
64
 
 
65
/* Flag to identify we got a TERM signal */
 
66
static int got_term = 0;
 
67
 
 
68
/* file descriptor of lock file */
 
69
static int fd = -1;
 
70
 
 
71
/* Ignore all signals except for SIGTERM */
 
72
static void handler(int sig)
 
73
{
 
74
        /* 
 
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.
 
79
         */
 
80
        if (sig == SIGQUIT || sig == SIGTERM || sig == SIGINT)
 
81
                got_term = 1;
 
82
}
 
83
 
 
84
static int lock_is_owned(int fd)
 
85
{
 
86
        int pid = 0, tries = 3;
 
87
 
 
88
        while (tries--) {
 
89
                char pidbuf[MAX_PIDSIZE + 1];
 
90
                int got;
 
91
 
 
92
                lseek(fd, 0, SEEK_SET);
 
93
                got = read(fd, pidbuf, MAX_PIDSIZE);
 
94
                /*
 
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.
 
98
                 */
 
99
                if (got > 0 && pidbuf[got - 1] == '\n') {
 
100
                        sscanf(pidbuf, "%d", &pid);
 
101
                        break;
 
102
                } else {
 
103
                        struct timespec t = { 0, 100000000 };
 
104
                        struct timespec r;
 
105
 
 
106
                        while (nanosleep(&t, &r) == -1 && errno == EINTR) {
 
107
                                /* So we can exit quickly, return owned */
 
108
                                if (got_term)
 
109
                                        return 1;
 
110
                                memcpy(&t, &r, sizeof(struct timespec));
 
111
                        }
 
112
                        continue;
 
113
                }
 
114
 
 
115
                /* Stale lockfile */
 
116
                if (!tries)
 
117
                        return 0;
 
118
        }
 
119
 
 
120
 
 
121
        if (pid) {
 
122
                int ret;
 
123
 
 
124
                ret = kill(pid, SIGCONT);
 
125
                /* 
 
126
                 * If lock file exists but is not owned by a process
 
127
                 * we return unowned status so we can get rid of it
 
128
                 * and continue.
 
129
                 */
 
130
                if (ret == -1 && errno == ESRCH)
 
131
                        return 0;
 
132
        } else {
 
133
                /*
 
134
                 * Odd, no pid in file - so what should we do?
 
135
                 * Assume something bad happened to owner and
 
136
                 * return unowned status.
 
137
                 */
 
138
                return 0;
 
139
        }
 
140
 
 
141
        return 1;
 
142
}
 
143
 
 
144
static void setup_locksigs(void)
 
145
{
 
146
        int sig = 0;
 
147
        struct sigaction sa;
 
148
 
 
149
        sa.sa_handler = handler;
 
150
        sa.sa_flags = 0;
 
151
        sigfillset(&sa.sa_mask);
 
152
 
 
153
        sigprocmask(SIG_BLOCK, &sa.sa_mask, NULL);
 
154
 
 
155
        while (sigismember(&sa.sa_mask, ++sig) != -1
 
156
                        && sig != SIGCHLD) {
 
157
                sigaction(sig, &sa, &actions[sig]);
 
158
        }
 
159
 
 
160
        sigaction(SIGUSR1, &sa, &sigusr1);
 
161
        sigaction(SIGUSR2, &sa, &sigusr2);
 
162
 
 
163
        signals_have_been_setup = 1;
 
164
        sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
 
165
}
 
166
 
 
167
static void reset_locksigs(void)
 
168
{
 
169
        int sig = 0;
 
170
        sigset_t fullset;
 
171
        
 
172
        sigfillset(&fullset);
 
173
        sigprocmask(SIG_BLOCK, &fullset, NULL);
 
174
 
 
175
        sigaction(SIGUSR1, &sigusr1, NULL);
 
176
        sigaction(SIGUSR2, &sigusr2, NULL);
 
177
 
 
178
        while (sigismember(&fullset, ++sig) != -1
 
179
                        && sig != SIGCHLD) {
 
180
                sigaction(sig, &actions[sig], NULL);
 
181
        }
 
182
 
 
183
        signals_have_been_setup = 0;
 
184
        sigprocmask(SIG_UNBLOCK, &fullset, NULL);
 
185
}
 
186
 
 
187
/* Remove lock file. */
 
188
void release_lock(void)
 
189
{
 
190
        if (fd > 0) {
 
191
                close(fd);
 
192
                fd = -1;
 
193
        }
 
194
 
 
195
        if (we_created_lockfile) {
 
196
                unlink (LOCK_FILE);
 
197
                we_created_lockfile = 0;
 
198
        }
 
199
 
 
200
        if (signals_have_been_setup)
 
201
                reset_locksigs();
 
202
}
 
203
 
 
204
/*
 
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.
 
208
 */
 
209
static int wait_for_lockf(const char *lockf)
 
210
{
 
211
        struct timespec t = { 0, WAIT_INTERVAL };
 
212
        struct timespec r;
 
213
        int ts_size = sizeof(struct timespec);
 
214
        int tries = WAIT_TRIES;
 
215
        int status = 0;
 
216
        struct stat st;
 
217
 
 
218
        while (tries-- && !status) {
 
219
                status = stat(lockf, &st);
 
220
                if (!status) {
 
221
                        while (nanosleep(&t, &r) == -1 && errno == EINTR) {
 
222
                                if (got_term)
 
223
                                        return 0;
 
224
                                memcpy(&t, &r, ts_size);
 
225
                        }
 
226
                }
 
227
        }
 
228
 
 
229
        if (tries < 0)
 
230
                return tries;
 
231
 
 
232
        return 1;
 
233
}
 
234
 
 
235
/*
 
236
 * Aquire lock file taking account of autofs signals.
 
237
 */
 
238
int aquire_lock(void)
 
239
{
 
240
        int tries = 3;
 
241
        char *linkf;
 
242
        int len;
 
243
 
 
244
        if (!signals_have_been_setup)
 
245
                setup_locksigs();
 
246
 
 
247
        len = strlen(LOCK_FILE) + MAX_PIDSIZE;
 
248
        linkf = alloca(len + 1);
 
249
        snprintf(linkf, len, "%s.%d", LOCK_FILE, getpid());
 
250
 
 
251
        /* Repeat until it was us who made the link */
 
252
        while (!we_created_lockfile) {
 
253
                int errsv, i, j;
 
254
 
 
255
                i = open(linkf, O_WRONLY|O_CREAT, 0);
 
256
                if (i < 0) {
 
257
                        release_lock();
 
258
                        return 0;
 
259
                }
 
260
                close(i);
 
261
 
 
262
                j = link(linkf, LOCK_FILE);
 
263
                errsv = errno;
 
264
 
 
265
                (void) unlink(linkf);
 
266
 
 
267
                if (j < 0 && errsv != EEXIST) {
 
268
                        release_lock();
 
269
                        return 0;
 
270
                }
 
271
 
 
272
                fd = open(LOCK_FILE, O_RDWR);
 
273
                if (fd < 0) {
 
274
                        /* Maybe the file was just deleted? */
 
275
                        if (errno == ENOENT && tries-- > 0)
 
276
                                continue;
 
277
                        release_lock();
 
278
                        return 0;
 
279
                }
 
280
 
 
281
                if (j == 0) {
 
282
                        char pidbuf[MAX_PIDSIZE + 1];
 
283
                        int pidlen;
 
284
 
 
285
                        pidlen = sprintf(pidbuf, "%d\n", getpid());
 
286
                        write(fd, pidbuf, pidlen);
 
287
 
 
288
                        we_created_lockfile = 1;
 
289
                } else {
 
290
                        int status;
 
291
                        char mess[128] =
 
292
                                "aquire_lock: can't lock lock file %s: %s";
 
293
 
 
294
                        /*
 
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
 
298
                         * wait.
 
299
                         */
 
300
                        if (!lock_is_owned(fd)) {
 
301
                                close(fd);
 
302
                                fd = -1;
 
303
                                unlink(LOCK_FILE);
 
304
                                continue;
 
305
                        }
 
306
 
 
307
                        status = wait_for_lockf(LOCK_FILE);
 
308
                        if (status < 0) {
 
309
                                release_lock();
 
310
                                crit(mess, "timed out", LOCK_FILE);
 
311
                                return 0;
 
312
                        } else if (!status) {
 
313
                                release_lock();
 
314
                                crit(mess, "interrupted", LOCK_FILE);
 
315
                                return 0;
 
316
                        }
 
317
                }
 
318
 
 
319
                if (got_term) {
 
320
                        got_term = 0;
 
321
                        release_lock();
 
322
                        return 0;
 
323
                }
 
324
                close(fd);
 
325
                fd = -1;
 
326
        }
 
327
 
 
328
        reset_locksigs();
 
329
        return 1;
 
330
}
 
331