server: implement -s bans
[rb-79.git] / locks.c
blob439541dffe1803a6bba858905c1638b3acba45d8
1 /*
2 * Copyright (c) 2017-2020, De Rais <derais@cock.li>
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/stat.h>
24 #include <time.h>
25 #include <unistd.h>
27 #include "macros.h"
28 #include "rb79.h"
30 static int *lock_table = 0;
31 static size_t lock_table_len = 0;
32 static int lock_recent;
35 * Set up the lock files and make sure we can connect to them.
37 * Preconditions:
39 * - setup_locks() was not invoked more recently than clean_locks().
41 * Postconditions (success):
43 * - Any other function in this file may be safely called.
45 int
46 setup_locks(const struct configuration *conf)
48 int ret = -1;
49 char *path = 0;
50 size_t len = 0;
52 if (lock_table) {
53 return 0;
56 if (!(lock_table = calloc(conf->boards_num, sizeof *lock_table))) {
57 PERROR_MESSAGE("malloc");
58 ERROR_MESSAGE("Cannot set up locks");
59 goto done;
62 for (size_t j = 0; j < conf->boards_num; ++j) {
63 lock_table[j] = -1;
66 /* Locks for each board */
67 for (size_t j = 0; j < conf->boards_num; ++j) {
68 len = snprintf(0, 0, "%s/lock_board_%s", conf->work_path,
69 conf->boards[j].name);
71 if (len + 1 < len) {
72 ERROR_MESSAGE("overflow");
73 goto done;
76 if (!(path = malloc(len + 1))) {
77 PERROR_MESSAGE("malloc");
78 goto done;
81 sprintf(path, "%s/lock_board_%s", conf->work_path,
82 conf->boards[j].name);
84 if (!(lock_table[j] = open(path, O_RDWR | O_CREAT, 0700))) {
85 PERROR_MESSAGE("open");
86 ERROR_MESSAGE("Cannot open or create lock file %s",
87 path);
88 goto done;
91 free(path);
92 path = 0;
95 lock_table_len = conf->boards_num;
97 /* Lock for the recent page */
98 len = snprintf(0, 0, "%s/lock_recent", conf->work_path);
100 if (len + 1 < len) {
101 ERROR_MESSAGE("overflow");
102 goto done;
105 if (!(path = malloc(len + 1))) {
106 PERROR_MESSAGE("malloc");
107 goto done;
110 sprintf(path, "%s/lock_recent", conf->work_path);
112 if (!(lock_recent = open(path, O_RDWR | O_CREAT, 0700))) {
113 PERROR_MESSAGE("open");
114 ERROR_MESSAGE("Cannot open or create lock file %s", path);
115 goto done;
118 free(path);
119 path = 0;
121 /* Now we've got all the locks */
122 ret = 0;
123 done:
124 free(path);
126 return ret;
130 * Get a lock for a board
132 * Preconditions:
134 * - board_idx represents a board.
136 * - The lock for board_idx is not held in this program.
138 * Postconditions (success):
140 * - The lock for board_idx is now held by this program.
143 lock_acquire(size_t board_idx)
145 int ret = -1;
147 if (!lock_table ||
148 lock_table[board_idx] < 0) {
149 ERROR_MESSAGE("lock_table isn't set up yet");
150 goto done;
153 if (lockf(lock_table[board_idx], F_LOCK, 0) < 0) {
154 PERROR_MESSAGE("lockf");
155 ERROR_MESSAGE("Cannot lock board %zu", board_idx);
156 goto done;
159 ret = 0;
160 done:
162 return ret;
166 * Get a lock for the recent page
168 * Preconditions:
170 * - The lock for the recent page is not held in this program.
172 * Postconditions (success):
174 * - The lock for the recent page is now held by this program.
177 lock_acquire_recent(void)
179 int ret = -1;
181 if (lock_recent < 0) {
182 ERROR_MESSAGE("lock_recent isn't set up yet");
183 goto done;
186 if (lockf(lock_recent, F_LOCK, 0) < 0) {
187 PERROR_MESSAGE("lockf");
188 ERROR_MESSAGE("Cannot lock recent page");
189 goto done;
192 ret = 0;
193 done:
195 return ret;
199 * Release a lock for a board
201 * Preconditions:
203 * - board_idx represents a board.
205 * - The lock for board_idx is held in this program.
207 * Postconditions (success):
209 * - The lock for board_idx is now not held by this program.
212 lock_release(size_t board_idx)
214 if (!lock_table ||
215 lock_table[board_idx] < 0) {
216 return 0;
219 if (lockf(lock_table[board_idx], F_ULOCK, 0) < 0) {
220 PERROR_MESSAGE("lockf");
221 ERROR_MESSAGE("Cannot release lock for board %zu", board_idx);
223 return -1;
226 return 0;
230 * Release a lock for a board
232 * Preconditions:
234 * - The lock for the recent page is held in this program.
236 * Postconditions (success):
238 * - The lock for the recent page is now not held by this program.
241 lock_release_recent(void)
243 if (lock_recent < 0) {
244 return 0;
247 if (lockf(lock_recent, F_ULOCK, 0) < 0) {
248 PERROR_MESSAGE("lockf");
249 ERROR_MESSAGE("Cannot release lock for recent page");
251 return -1;
254 return 0;
258 * Clean up any memory from this file
260 * Postconditions (success):
262 * - Valgrind won't report any memory leaks from this file.
264 * - setup_locks() can be safely called again.
267 clean_locks(void)
269 if (!lock_table) {
270 return 0;
273 for (size_t j = 0; j < lock_table_len; ++j) {
274 lock_release(j);
275 close(lock_table[j]);
278 free(lock_table);
279 lock_table = 0;
280 lock_release_recent();
281 close(lock_recent);
283 return 0;