1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
/* ========================================================================
* Copyright 2008-2009 Mark Crispin
* ========================================================================
*/
/*
* Program: Safe File Lock for Linux
*
* Author: Mark Crispin
*
* Date: 20 April 2005
* Last Edited: 18 May 2009
*
* Previous versions of this file were:
*
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*/
#undef flock
#include <sys/vfs.h>
#ifndef NFS_SUPER_MAGIC
#define NFS_SUPER_MAGIC 0x6969
#endif
int safe_flock (int fd,int op)
{
struct statfs sfbuf;
char tmp[MAILTMPLEN];
int e;
int logged = 0;
/* Check for NFS because Linux 2.6 broke flock() on NFS. Instead of being
* a no-op, flock() on NFS now returns ENOLCK. Read
* https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=123415
* for the gruesome details.
*/
/* check filesystem type */
while ((e = fstatfs (fd,&sfbuf)) && (errno == EINTR));
if (!e) switch (sfbuf.f_type) {
case NFS_SUPER_MAGIC: /* always a fast no-op on NFS */
break;
default: /* allow on other filesystem types */
/* do the lock */
while (flock (fd,op)) switch (errno) {
case EINTR: /* interrupt */
break;
case ENOLCK: /* lock table is full */
sprintf (tmp,"File locking failure: %s",strerror (errno));
mm_log (tmp,WARN); /* give the user a warning of what happened */
if (!logged++) syslog (LOG_ERR,"%s",tmp);
/* return failure if non-blocking lock */
if (op & LOCK_NB) return -1;
sleep (5); /* slow down in case it loops */
break;
case EWOULDBLOCK: /* file is locked, LOCK_NB should be set */
if (op & LOCK_NB) return -1;
case EBADF: /* not valid open file descriptor */
case EINVAL: /* invalid operator */
default: /* other error code? */
sprintf (tmp,"Unexpected file locking failure: %s",strerror (errno));
fatal (tmp);
}
break;
}
return 0; /* success */
}
|