blob: 20423c7d4a852f3a77b4c34c4a5a20261f5bc01c [file] [log] [blame]
Alistair Delvabeaee832021-02-24 11:27:23 -08001/* Copyright 2005,2009,2018 Alain Knaff.
2 * This file is part of mtools.
3 *
4 * Mtools is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Mtools is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Create an advisory lock on the device to prevent concurrent writes.
18 * Uses either lockf, flock, or fcntl locking methods. See the Makefile
19 * and the Configure files for how to specify the proper method.
20 */
21
22#include "sysincludes.h"
23#include "mtools.h"
24#include "lockdev.h"
25
26#if (defined HAVE_SIGACTION && defined HAVE_ALARM)
27# define ALRM
28#endif
29
30
31#if (defined(HAVE_FLOCK) && defined (LOCK_EX) && (defined(LOCK_NB) || defined(ALRM)))
Yi Kong39bbd962022-01-09 19:41:38 +080032
Alistair Delvabeaee832021-02-24 11:27:23 -080033# ifdef ALRM
34# define USE_FLOCK_W
35# else
36# define USE_FLOCK
37# endif
38
39#else /* FLOCK */
40
41#if (defined(HAVE_LOCKF) && (defined(F_TLOCK) || defined(ALRM)))
42
43# ifdef ALRM
44# define USE_LOCKF_W
45# else
46# define USE_LOCKF
47# endif
Yi Kong39bbd962022-01-09 19:41:38 +080048
Alistair Delvabeaee832021-02-24 11:27:23 -080049#else /* LOCKF */
50
51#if (defined(F_SETLK) && defined(F_WRLCK))
52
53# if (defined ALRM && defined F_SETLKW)
54# define USE_SETLK_W
55# else
56# define USE_SETLK_W
57# endif
58
59#else
60
61#endif /* FCNTL */
62#endif /* LOCKF */
63#endif /* FLOCK */
64
65#if defined(USE_FLOCK_W) || defined(USE_LOCKF_W) || defined (USE_SETLK_W)
66static void alrm(int a UNUSEDP) {
67}
68#endif
69
70int lock_dev(int fd, int mode, struct device *dev)
71{
72 unsigned int retries = 0;
73 if(IS_NOLOCK(dev))
74 return 0;
75
76 while(1) {
77 int ret=0;
78#if defined(USE_FLOCK_W) || defined(USE_LOCKF_W) || defined (USE_SETLK_W)
79 struct sigaction alrm_action, old_alrm_action;
Yi Kong39bbd962022-01-09 19:41:38 +080080 unsigned int old_alrm = alarm(0);
Alistair Delvabeaee832021-02-24 11:27:23 -080081 memset(&alrm_action, 0, sizeof(alrm_action));
82 alrm_action.sa_handler = alrm;
83 alrm_action.sa_flags = 0;
84 sigaction(SIGALRM, &alrm_action, &old_alrm_action);
85 alarm(mtools_lock_timeout);
86#endif
87
88#ifdef USE_FLOCK
89 ret = flock(fd, (mode ? LOCK_EX : LOCK_SH)|LOCK_NB);
90#endif
Yi Kong39bbd962022-01-09 19:41:38 +080091
Alistair Delvabeaee832021-02-24 11:27:23 -080092#ifdef USE_FLOCK_W
93 ret = flock(fd, (mode ? LOCK_EX : LOCK_SH));
94#endif
95
96#if (defined(USE_LOCKF) || defined(USE_LOCKF_W))
97 if(mode)
98# ifdef USE_LOCKF
99 ret = lockf(fd, F_TLOCK, 0);
100# else
101 ret = lockf(fd, F_LOCK, 0);
102# endif
103 else
104 ret = 0;
105#endif
Yi Kong39bbd962022-01-09 19:41:38 +0800106
Alistair Delvabeaee832021-02-24 11:27:23 -0800107#if (defined(USE_SETLK) || defined(USE_SETLK_W))
108 {
109 struct flock flk;
110 flk.l_type = mode ? F_WRLCK : F_RDLCK;
111 flk.l_whence = 0;
112 flk.l_start = 0L;
113 flk.l_len = 0L;
114
115# ifdef USE_SETLK_W
116 ret = fcntl(fd, F_SETLKW, &flk);
117# else
118 ret = fcntl(fd, F_SETLK, &flk);
119# endif
120 }
121#endif
Yi Kong39bbd962022-01-09 19:41:38 +0800122
Alistair Delvabeaee832021-02-24 11:27:23 -0800123#if defined(USE_FLOCK_W) || defined(USE_LOCKF_W) || defined (USE_SETLK_W)
124 /* Cancel the alarm */
125 sigaction(SIGALRM, &old_alrm_action, NULL);
126 alarm(old_alrm);
127#endif
128
129 if(ret < 0) {
130#if defined(USE_FLOCK_W) || defined(USE_LOCKF_W) || defined (USE_SETLK_W)
131 /* ALARM fired ==> this means we are still locked */
132 if(errno == EINTR) {
133 return 1;
134 }
135#endif
Yi Kong39bbd962022-01-09 19:41:38 +0800136
Alistair Delvabeaee832021-02-24 11:27:23 -0800137 if(
138#ifdef EWOULDBLOCK
139 (errno != EWOULDBLOCK)
140#else
141 1
142#endif
143 &&
144#ifdef EAGAIN
145 (errno != EAGAIN)
146#else
147 1
148#endif
149 &&
150#ifdef EINTR
151 (errno != EINTR)
152#else
153 1
154#endif
155 ) {
156 /* Error other than simply being locked */
157 return -1;
158 }
159 /* Locked ==> continue until timeout */
160 } else /* no error => we got the lock! */
161 return 0;
162
163#ifdef HAVE_USLEEP
164 if(retries++ < mtools_lock_timeout * 10)
165 usleep(100000);
166#else
167 if(retries++ < mtools_lock_timeout)
168 sleep(1);
169#endif
170 else
171 /* waited for too long => give up */
172 return 1;
173 }
174}