]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/lxclock.c
confile: cleanup parse_line()
[mirror_lxc.git] / src / lxc / lxclock.c
index dd23530b077a31e651ea571248f3f7bd9747277e..318e5bf5a32afa58b1f1411ec0de91f643be4041 100644 (file)
@@ -1,37 +1,23 @@
-/* liblxcapi
- *
- * Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
- * Copyright © 2012 Canonical Ltd.
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
-
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
-
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
+/* SPDX-License-Identifier: LGPL-2.1+ */
 
-#define _GNU_SOURCE
-#include "lxclock.h"
-#include <malloc.h>
-#include <stdio.h>
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
 #include <errno.h>
-#include <unistd.h>
 #include <fcntl.h>
-#include <stdlib.h>
+#include <malloc.h>
 #include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/file.h>
+#include <unistd.h>
 
 #include <lxc/lxccontainer.h>
 
-#include "utils.h"
+#include "config.h"
 #include "log.h"
+#include "lxclock.h"
+#include "utils.h"
 
 #ifdef MUTEX_DEBUGGING
 #include <execinfo.h>
@@ -39,7 +25,7 @@
 
 #define MAX_STACKDEPTH 25
 
-lxc_log_define(lxc_lock, lxc);
+lxc_log_define(lxclock, lxc);
 
 #ifdef MUTEX_DEBUGGING
 static pthread_mutex_t thread_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
@@ -54,8 +40,8 @@ static inline void dump_stacktrace(void)
        size = backtrace(array, MAX_STACKDEPTH);
        strings = backtrace_symbols(array, size);
 
-       // Using fprintf here as our logging module is not thread safe
-       fprintf(stderr, "\tObtained %zu stack frames.\n", size);
+       /* Using fprintf here as our logging module is not thread safe. */
+       fprintf(stderr, "\tObtained %zu stack frames\n", size);
 
        for (i = 0; i < size; i++)
                fprintf(stderr, "\t\t%s\n", strings[i]);
@@ -72,10 +58,11 @@ static void lock_mutex(pthread_mutex_t *l)
 {
        int ret;
 
-       if ((ret = pthread_mutex_lock(l)) != 0) {
-               fprintf(stderr, "pthread_mutex_lock returned:%d %s\n", ret, strerror(ret));
+       ret = pthread_mutex_lock(l);
+       if (ret != 0) {
+               SYSERROR("Failed to acquire mutex");
                dump_stacktrace();
-               exit(1);
+               _exit(EXIT_FAILURE);
        }
 }
 
@@ -83,19 +70,19 @@ static void unlock_mutex(pthread_mutex_t *l)
 {
        int ret;
 
-       if ((ret = pthread_mutex_unlock(l)) != 0) {
-               fprintf(stderr, "pthread_mutex_unlock returned:%d %s\n", ret, strerror(ret));
+       ret = pthread_mutex_unlock(l);
+       if (ret != 0) {
+               SYSERROR("Failed to release mutex");
                dump_stacktrace();
-               exit(1);
+               _exit(EXIT_FAILURE);
        }
 }
 
 static char *lxclock_name(const char *p, const char *n)
 {
        int ret;
-       int len;
-       char *dest;
-       char *rundir;
+       size_t len;
+       char *dest, *rundir;
 
        /* lockfile will be:
         * "/run" + "/lxc/lock/$lxcpath/$lxcname + '\0' if root
@@ -104,23 +91,27 @@ static char *lxclock_name(const char *p, const char *n)
         */
 
        /* length of "/lxc/lock/" + $lxcpath + "/" + "." + $lxcname + '\0' */
-       len = strlen("/lxc/lock/") + strlen(n) + strlen(p) + 3;
+       len = STRLITERALLEN("/lxc/lock/") + strlen(n) + strlen(p) + 3;
+
        rundir = get_rundir();
        if (!rundir)
                return NULL;
+
        len += strlen(rundir);
 
-       if ((dest = malloc(len)) == NULL) {
+       dest = malloc(len);
+       if (!dest) {
                free(rundir);
                return NULL;
        }
 
        ret = snprintf(dest, len, "%s/lxc/lock/%s", rundir, p);
-       if (ret < 0 || ret >= len) {
+       if (ret < 0 || (size_t)ret >= len) {
                free(dest);
                free(rundir);
                return NULL;
        }
+
        ret = mkdir_p(dest, 0755);
        if (ret < 0) {
                free(dest);
@@ -130,26 +121,29 @@ static char *lxclock_name(const char *p, const char *n)
 
        ret = snprintf(dest, len, "%s/lxc/lock/%s/.%s", rundir, p, n);
        free(rundir);
-       if (ret < 0 || ret >= len) {
+       if (ret < 0 || (size_t)ret >= len) {
                free(dest);
                return NULL;
        }
+
        return dest;
 }
 
 static sem_t *lxc_new_unnamed_sem(void)
 {
-       sem_t *s;
        int ret;
+       sem_t *s;
 
        s = malloc(sizeof(*s));
        if (!s)
                return NULL;
+
        ret = sem_init(s, 0, 1);
-       if (ret) {
+       if (ret < 0) {
                free(s);
                return NULL;
        }
+
        return s;
 }
 
@@ -159,7 +153,7 @@ struct lxc_lock *lxc_newlock(const char *lxcpath, const char *name)
 
        l = malloc(sizeof(*l));
        if (!l)
-               goto out;
+               goto on_error;
 
        if (!name) {
                l->type = LXC_LOCK_ANON_SEM;
@@ -168,108 +162,129 @@ struct lxc_lock *lxc_newlock(const char *lxcpath, const char *name)
                        free(l);
                        l = NULL;
                }
-               goto out;
+
+               goto on_error;
        }
 
        l->type = LXC_LOCK_FLOCK;
        l->u.f.fname = lxclock_name(lxcpath, name);
        if (!l->u.f.fname) {
+               if (!name)
+                       free(l->u.sem);
                free(l);
                l = NULL;
-               goto out;
+               goto on_error;
        }
+
        l->u.f.fd = -1;
 
-out:
+on_error:
        return l;
 }
 
 int lxclock(struct lxc_lock *l, int timeout)
 {
-       int ret = -1, saved_errno = errno;
        struct flock lk;
+       int ret = -1, saved_errno = errno;
 
        switch(l->type) {
        case LXC_LOCK_ANON_SEM:
                if (!timeout) {
                        ret = sem_wait(l->u.sem);
-                       if (ret == -1)
+                       if (ret < 0)
                                saved_errno = errno;
                } else {
                        struct timespec ts;
-                       if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
+
+                       ret = clock_gettime(CLOCK_REALTIME, &ts);
+                       if (ret < 0) {
                                ret = -2;
-                               goto out;
+                               goto on_error;
                        }
+
                        ts.tv_sec += timeout;
                        ret = sem_timedwait(l->u.sem, &ts);
-                       if (ret == -1)
+                       if (ret < 0)
                                saved_errno = errno;
                }
+
                break;
        case LXC_LOCK_FLOCK:
                ret = -2;
                if (timeout) {
-                       ERROR("Error: timeout not supported with flock");
-                       ret = -2;
-                       goto out;
+                       ERROR("Timeouts are not supported with file locks");
+                       goto on_error;
                }
+
                if (!l->u.f.fname) {
-                       ERROR("Error: filename not set for flock");
-                       ret = -2;
-                       goto out;
+                       ERROR("No filename set for file lock");
+                       goto on_error;
                }
+
                if (l->u.f.fd == -1) {
-                       l->u.f.fd = open(l->u.f.fname, O_RDWR|O_CREAT,
-                                       S_IWUSR | S_IRUSR);
+                       l->u.f.fd = open(l->u.f.fname, O_CREAT | O_RDWR | O_NOFOLLOW | O_CLOEXEC | O_NOCTTY, S_IWUSR | S_IRUSR);
                        if (l->u.f.fd == -1) {
-                               ERROR("Error opening %s", l->u.f.fname);
+                               SYSERROR("Failed to open \"%s\"", l->u.f.fname);
                                saved_errno = errno;
-                               goto out;
+                               goto on_error;
                        }
                }
+
+               memset(&lk, 0, sizeof(struct flock));
+
                lk.l_type = F_WRLCK;
                lk.l_whence = SEEK_SET;
-               lk.l_start = 0;
-               lk.l_len = 0;
-               ret = fcntl(l->u.f.fd, F_SETLKW, &lk);
-               if (ret == -1)
+
+               ret = fcntl(l->u.f.fd, F_OFD_SETLKW, &lk);
+               if (ret < 0) {
+                       if (errno == EINVAL)
+                               ret = flock(l->u.f.fd, LOCK_EX);
                        saved_errno = errno;
+               }
+
                break;
        }
 
-out:
+on_error:
        errno = saved_errno;
        return ret;
 }
 
 int lxcunlock(struct lxc_lock *l)
 {
-       int ret = 0, saved_errno = errno;
        struct flock lk;
+       int ret = 0, saved_errno = errno;
 
-       switch(l->type) {
+       switch (l->type) {
        case LXC_LOCK_ANON_SEM:
-               if (!l->u.sem)
+               if (!l->u.sem) {
                        ret = -2;
-               else {
+               else {
                        ret = sem_post(l->u.sem);
                        saved_errno = errno;
                }
+
                break;
        case LXC_LOCK_FLOCK:
                if (l->u.f.fd != -1) {
+                       memset(&lk, 0, sizeof(struct flock));
+
                        lk.l_type = F_UNLCK;
                        lk.l_whence = SEEK_SET;
-                       lk.l_start = 0;
-                       lk.l_len = 0;
-                       ret = fcntl(l->u.f.fd, F_SETLK, &lk);
-                       if (ret < 0)
+
+                       ret = fcntl(l->u.f.fd, F_OFD_SETLK, &lk);
+                       if (ret < 0) {
+                               if (errno == EINVAL)
+                                       ret = flock(l->u.f.fd, LOCK_EX | LOCK_NB);
                                saved_errno = errno;
+                       }
+
                        close(l->u.f.fd);
                        l->u.f.fd = -1;
-               } else
+               } else {
                        ret = -2;
+               }
+
                break;
        }
 
@@ -288,6 +303,7 @@ void lxc_putlock(struct lxc_lock *l)
 {
        if (!l)
                return;
+
        switch(l->type) {
        case LXC_LOCK_ANON_SEM:
                if (l->u.sem) {
@@ -295,16 +311,20 @@ void lxc_putlock(struct lxc_lock *l)
                        free(l->u.sem);
                        l->u.sem = NULL;
                }
+
                break;
        case LXC_LOCK_FLOCK:
                if (l->u.f.fd != -1) {
                        close(l->u.f.fd);
                        l->u.f.fd = -1;
                }
+
                free(l->u.f.fname);
                l->u.f.fname = NULL;
+
                break;
        }
+
        free(l);
 }
 
@@ -318,23 +338,6 @@ void process_unlock(void)
        unlock_mutex(&thread_mutex);
 }
 
-/* One thread can do fork() while another one is holding a mutex.
- * There is only one thread in child just after the fork(), so no one will ever release that mutex.
- * We setup a "child" fork handler to unlock the mutex just after the fork().
- * For several mutex types, unlocking an unlocked mutex can lead to undefined behavior.
- * One way to deal with it is to setup "prepare" fork handler
- * to lock the mutex before fork() and both "parent" and "child" fork handlers
- * to unlock the mutex.
- * This forbids doing fork() while explicitly holding the lock.
- */
-#ifdef HAVE_PTHREAD_ATFORK
-__attribute__((constructor))
-static void process_lock_setup_atfork(void)
-{
-       pthread_atfork(process_lock, process_unlock, process_unlock);
-}
-#endif
-
 int container_mem_lock(struct lxc_container *c)
 {
        return lxclock(c->privlock, 0);
@@ -349,12 +352,16 @@ int container_disk_lock(struct lxc_container *c)
 {
        int ret;
 
-       if ((ret = lxclock(c->privlock, 0)))
+       ret = lxclock(c->privlock, 0);
+       if (ret < 0)
                return ret;
-       if ((ret = lxclock(c->slock, 0))) {
+
+       ret = lxclock(c->slock, 0);
+       if (ret < 0) {
                lxcunlock(c->privlock);
                return ret;
        }
+
        return 0;
 }