]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/lxclock.c
confile: cleanup parse_line()
[mirror_lxc.git] / src / lxc / lxclock.c
CommitLineData
cc73685d 1/* SPDX-License-Identifier: LGPL-2.1+ */
72d0e1cb 2
d38dd64a
CB
3#ifndef _GNU_SOURCE
4#define _GNU_SOURCE 1
5#endif
df271a59 6#include <errno.h>
93dc5327 7#include <fcntl.h>
56474555 8#include <malloc.h>
052616eb 9#include <pthread.h>
56474555
CB
10#include <stdio.h>
11#include <stdlib.h>
12#include <sys/file.h>
13#include <unistd.h>
f2363e38 14
5cee8c50 15#include <lxc/lxccontainer.h>
72d0e1cb 16
d38dd64a
CB
17#include "config.h"
18#include "log.h"
ccfc84ca 19#include "lxclock.h"
f2363e38 20#include "utils.h"
f2363e38 21
41f68357
ÇO
22#ifdef MUTEX_DEBUGGING
23#include <execinfo.h>
24#endif
25
5b28d063
SH
26#define MAX_STACKDEPTH 25
27
ac2cecc4 28lxc_log_define(lxclock, lxc);
72d0e1cb 29
052616eb 30#ifdef MUTEX_DEBUGGING
74a3920a 31static pthread_mutex_t thread_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
41f68357 32
74a3920a 33static inline void dump_stacktrace(void)
41f68357
ÇO
34{
35 void *array[MAX_STACKDEPTH];
36 size_t size;
37 char **strings;
38 size_t i;
39
40 size = backtrace(array, MAX_STACKDEPTH);
41 strings = backtrace_symbols(array, size);
42
1a0e70ac 43 /* Using fprintf here as our logging module is not thread safe. */
b19aabf5 44 fprintf(stderr, "\tObtained %zu stack frames\n", size);
41f68357
ÇO
45
46 for (i = 0; i < size; i++)
47 fprintf(stderr, "\t\t%s\n", strings[i]);
48
157ad8d4 49 free(strings);
41f68357 50}
052616eb 51#else
74a3920a 52static pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER;
41f68357 53
74a3920a 54static inline void dump_stacktrace(void) {;}
052616eb 55#endif
df271a59 56
74a3920a 57static void lock_mutex(pthread_mutex_t *l)
41f68357
ÇO
58{
59 int ret;
60
7249588c
CB
61 ret = pthread_mutex_lock(l);
62 if (ret != 0) {
79cda71d 63 SYSERROR("Failed to acquire mutex");
41f68357 64 dump_stacktrace();
7249588c 65 _exit(EXIT_FAILURE);
41f68357
ÇO
66 }
67}
68
74a3920a 69static void unlock_mutex(pthread_mutex_t *l)
41f68357
ÇO
70{
71 int ret;
72
7249588c
CB
73 ret = pthread_mutex_unlock(l);
74 if (ret != 0) {
79cda71d 75 SYSERROR("Failed to release mutex");
41f68357 76 dump_stacktrace();
7249588c 77 _exit(EXIT_FAILURE);
41f68357
ÇO
78 }
79}
80
df271a59 81static char *lxclock_name(const char *p, const char *n)
72d0e1cb
SG
82{
83 int ret;
ecd8cb99
CB
84 size_t len;
85 char *dest, *rundir;
71b0fed6 86
469b5787 87 /* lockfile will be:
72cf81f6 88 * "/run" + "/lxc/lock/$lxcpath/$lxcname + '\0' if root
469b5787 89 * or
72cf81f6 90 * $XDG_RUNTIME_DIR + "/lxc/lock/$lxcpath/$lxcname + '\0' if non-root
469b5787
SH
91 */
92
72cf81f6 93 /* length of "/lxc/lock/" + $lxcpath + "/" + "." + $lxcname + '\0' */
6333c915 94 len = STRLITERALLEN("/lxc/lock/") + strlen(n) + strlen(p) + 3;
ecd8cb99 95
9e60f51d 96 rundir = get_rundir();
97a696c6
SG
97 if (!rundir)
98 return NULL;
79cda71d 99
469b5787
SH
100 len += strlen(rundir);
101
ecd8cb99
CB
102 dest = malloc(len);
103 if (!dest) {
44b9ae4b 104 free(rundir);
72d0e1cb 105 return NULL;
44b9ae4b 106 }
469b5787 107
72cf81f6 108 ret = snprintf(dest, len, "%s/lxc/lock/%s", rundir, p);
ecd8cb99 109 if (ret < 0 || (size_t)ret >= len) {
72d0e1cb 110 free(dest);
44b9ae4b 111 free(rundir);
72d0e1cb
SG
112 return NULL;
113 }
79cda71d 114
5cee8c50 115 ret = mkdir_p(dest, 0755);
5cee8c50 116 if (ret < 0) {
72cf81f6
SH
117 free(dest);
118 free(rundir);
119 return NULL;
120 }
72d0e1cb 121
72cf81f6 122 ret = snprintf(dest, len, "%s/lxc/lock/%s/.%s", rundir, p, n);
44b9ae4b 123 free(rundir);
ecd8cb99 124 if (ret < 0 || (size_t)ret >= len) {
df271a59
SH
125 free(dest);
126 return NULL;
127 }
79cda71d 128
df271a59 129 return dest;
72d0e1cb
SG
130}
131
132static sem_t *lxc_new_unnamed_sem(void)
133{
87677950 134 int ret;
ecd8cb99 135 sem_t *s;
72d0e1cb 136
87677950
SH
137 s = malloc(sizeof(*s));
138 if (!s)
139 return NULL;
79cda71d 140
87677950 141 ret = sem_init(s, 0, 1);
ecd8cb99 142 if (ret < 0) {
bdb539b8 143 free(s);
87677950 144 return NULL;
bdb539b8 145 }
79cda71d 146
87677950 147 return s;
72d0e1cb
SG
148}
149
df271a59 150struct lxc_lock *lxc_newlock(const char *lxcpath, const char *name)
72d0e1cb 151{
df271a59 152 struct lxc_lock *l;
72d0e1cb 153
df271a59
SH
154 l = malloc(sizeof(*l));
155 if (!l)
ecd8cb99 156 goto on_error;
72d0e1cb 157
df271a59
SH
158 if (!name) {
159 l->type = LXC_LOCK_ANON_SEM;
160 l->u.sem = lxc_new_unnamed_sem();
41c3b7c7
DE
161 if (!l->u.sem) {
162 free(l);
163 l = NULL;
164 }
79cda71d 165
ecd8cb99 166 goto on_error;
df271a59
SH
167 }
168
169 l->type = LXC_LOCK_FLOCK;
170 l->u.f.fname = lxclock_name(lxcpath, name);
171 if (!l->u.f.fname) {
b8a6a00c
TA
172 if (!name)
173 free(l->u.sem);
df271a59
SH
174 free(l);
175 l = NULL;
ecd8cb99 176 goto on_error;
df271a59 177 }
79cda71d 178
df271a59
SH
179 l->u.f.fd = -1;
180
ecd8cb99 181on_error:
df271a59 182 return l;
72d0e1cb
SG
183}
184
df271a59 185int lxclock(struct lxc_lock *l, int timeout)
72d0e1cb 186{
93dc5327 187 struct flock lk;
ecd8cb99 188 int ret = -1, saved_errno = errno;
72d0e1cb 189
df271a59
SH
190 switch(l->type) {
191 case LXC_LOCK_ANON_SEM:
192 if (!timeout) {
193 ret = sem_wait(l->u.sem);
b19aabf5 194 if (ret < 0)
df271a59
SH
195 saved_errno = errno;
196 } else {
197 struct timespec ts;
79cda71d 198
ecd8cb99
CB
199 ret = clock_gettime(CLOCK_REALTIME, &ts);
200 if (ret < 0) {
df271a59 201 ret = -2;
ecd8cb99 202 goto on_error;
df271a59 203 }
79cda71d 204
df271a59
SH
205 ts.tv_sec += timeout;
206 ret = sem_timedwait(l->u.sem, &ts);
b19aabf5 207 if (ret < 0)
df271a59
SH
208 saved_errno = errno;
209 }
ecd8cb99 210
df271a59
SH
211 break;
212 case LXC_LOCK_FLOCK:
213 ret = -2;
214 if (timeout) {
ecd8cb99
CB
215 ERROR("Timeouts are not supported with file locks");
216 goto on_error;
df271a59 217 }
79cda71d 218
df271a59 219 if (!l->u.f.fname) {
ecd8cb99
CB
220 ERROR("No filename set for file lock");
221 goto on_error;
df271a59 222 }
79cda71d 223
df271a59 224 if (l->u.f.fd == -1) {
b19aabf5 225 l->u.f.fd = open(l->u.f.fname, O_CREAT | O_RDWR | O_NOFOLLOW | O_CLOEXEC | O_NOCTTY, S_IWUSR | S_IRUSR);
df271a59 226 if (l->u.f.fd == -1) {
ecd8cb99 227 SYSERROR("Failed to open \"%s\"", l->u.f.fname);
98375790 228 saved_errno = errno;
ecd8cb99 229 goto on_error;
df271a59
SH
230 }
231 }
79cda71d 232
b19aabf5 233 memset(&lk, 0, sizeof(struct flock));
79cda71d 234
93dc5327
SH
235 lk.l_type = F_WRLCK;
236 lk.l_whence = SEEK_SET;
79cda71d 237
b19aabf5
CB
238 ret = fcntl(l->u.f.fd, F_OFD_SETLKW, &lk);
239 if (ret < 0) {
240 if (errno == EINVAL)
241 ret = flock(l->u.f.fd, LOCK_EX);
df271a59 242 saved_errno = errno;
b19aabf5 243 }
ecd8cb99 244
df271a59 245 break;
72d0e1cb
SG
246 }
247
ecd8cb99 248on_error:
df271a59 249 errno = saved_errno;
72d0e1cb
SG
250 return ret;
251}
252
df271a59 253int lxcunlock(struct lxc_lock *l)
72d0e1cb 254{
93dc5327 255 struct flock lk;
ecd8cb99 256 int ret = 0, saved_errno = errno;
df271a59 257
ecd8cb99 258 switch (l->type) {
df271a59 259 case LXC_LOCK_ANON_SEM:
ecd8cb99 260 if (!l->u.sem) {
df271a59 261 ret = -2;
ecd8cb99 262 } else {
df271a59
SH
263 ret = sem_post(l->u.sem);
264 saved_errno = errno;
659aa061 265 }
ecd8cb99 266
df271a59
SH
267 break;
268 case LXC_LOCK_FLOCK:
269 if (l->u.f.fd != -1) {
b19aabf5 270 memset(&lk, 0, sizeof(struct flock));
79cda71d 271
93dc5327
SH
272 lk.l_type = F_UNLCK;
273 lk.l_whence = SEEK_SET;
79cda71d 274
b19aabf5
CB
275 ret = fcntl(l->u.f.fd, F_OFD_SETLK, &lk);
276 if (ret < 0) {
277 if (errno == EINVAL)
278 ret = flock(l->u.f.fd, LOCK_EX | LOCK_NB);
df271a59 279 saved_errno = errno;
b19aabf5 280 }
79cda71d 281
df271a59
SH
282 close(l->u.f.fd);
283 l->u.f.fd = -1;
ecd8cb99 284 } else {
df271a59 285 ret = -2;
ecd8cb99
CB
286 }
287
df271a59
SH
288 break;
289 }
290
df271a59
SH
291 errno = saved_errno;
292 return ret;
293}
294
5cee8c50
SH
295/*
296 * lxc_putlock() is only called when a container_new() fails,
297 * or during container_put(), which is already guaranteed to
298 * only be done by one task.
299 * So the only exclusion we need to provide here is for regular
300 * thread safety (i.e. file descriptor table changes).
301 */
df271a59
SH
302void lxc_putlock(struct lxc_lock *l)
303{
df271a59 304 if (!l)
5cee8c50 305 return;
79cda71d 306
df271a59
SH
307 switch(l->type) {
308 case LXC_LOCK_ANON_SEM:
41c3b7c7 309 if (l->u.sem) {
527dacf6 310 sem_destroy(l->u.sem);
41c3b7c7
DE
311 free(l->u.sem);
312 l->u.sem = NULL;
313 }
ecd8cb99 314
df271a59
SH
315 break;
316 case LXC_LOCK_FLOCK:
317 if (l->u.f.fd != -1) {
318 close(l->u.f.fd);
319 l->u.f.fd = -1;
320 }
79cda71d 321
f10fad2f
ME
322 free(l->u.f.fname);
323 l->u.f.fname = NULL;
ecd8cb99 324
df271a59
SH
325 break;
326 }
ecd8cb99 327
41c3b7c7 328 free(l);
5cee8c50
SH
329}
330
025ed0f3 331void process_lock(void)
5cee8c50 332{
41f68357 333 lock_mutex(&thread_mutex);
5cee8c50
SH
334}
335
336void process_unlock(void)
337{
41f68357
ÇO
338 unlock_mutex(&thread_mutex);
339}
052616eb 340
5cee8c50
SH
341int container_mem_lock(struct lxc_container *c)
342{
343 return lxclock(c->privlock, 0);
344}
345
346void container_mem_unlock(struct lxc_container *c)
347{
348 lxcunlock(c->privlock);
349}
350
351int container_disk_lock(struct lxc_container *c)
352{
353 int ret;
354
ecd8cb99
CB
355 ret = lxclock(c->privlock, 0);
356 if (ret < 0)
5cee8c50 357 return ret;
79cda71d 358
ecd8cb99
CB
359 ret = lxclock(c->slock, 0);
360 if (ret < 0) {
5cee8c50
SH
361 lxcunlock(c->privlock);
362 return ret;
363 }
79cda71d 364
5cee8c50
SH
365 return 0;
366}
367
368void container_disk_unlock(struct lxc_container *c)
369{
370 lxcunlock(c->slock);
371 lxcunlock(c->privlock);
372}