Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 1 | /* 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 Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 32 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 33 | # 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 Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 48 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 49 | #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) |
| 66 | static void alrm(int a UNUSEDP) { |
| 67 | } |
| 68 | #endif |
| 69 | |
| 70 | int 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 Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 80 | unsigned int old_alrm = alarm(0); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 81 | 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 Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 91 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 92 | #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 Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 106 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 107 | #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 Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 122 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 123 | #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 Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 136 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 137 | 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 | } |