-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * 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+ */
+
+#include "config.h"
-#define _GNU_SOURCE
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/wait.h>
#include "log.h"
+#include "memory_utils.h"
#include "nbd.h"
#include "storage.h"
#include "storage_utils.h"
+#include "syscall_wrappers.h"
#include "utils.h"
+#ifndef HAVE_STRLCPY
+#include "strlcpy.h"
+#endif
+
lxc_log_define(nbd, lxc);
struct nbd_attach_data {
const char *path;
};
-static bool clone_attach_nbd(const char *nbd, const char *path);
static int do_attach_nbd(void *d);
+static bool clone_attach_nbd(const char *nbd, const char *path);
static bool nbd_busy(int idx);
static void nbd_detach(const char *path);
static int nbd_get_partition(const char *src);
bool attach_nbd(char *src, struct lxc_conf *conf)
{
- char *orig = alloca(strlen(src)+1), *p, path[50];
+ __do_free char *orig = NULL;
+ char *p, path[50];
int i = 0;
- strcpy(orig, src);
+ orig = must_copy_string(src);
/* if path is followed by a partition, drop that for now */
p = strchr(orig, ':');
if (p)
*p = '\0';
- while (1) {
+
+ for (;;) {
sprintf(path, "/dev/nbd%d", i);
+
if (!file_exists(path))
return false;
+
if (nbd_busy(i)) {
i++;
continue;
}
+
if (!clone_attach_nbd(path, orig))
return false;
+
conf->nbd_idx = i;
return true;
}
}
int nbd_create(struct lxc_storage *bdev, const char *dest, const char *n,
- struct bdev_specs *specs)
+ struct bdev_specs *specs, const struct lxc_conf *conf)
{
return -ENOSYS;
}
}
/* It might take awhile for the partition files to show up */
- if (partition) {
+ if (partition)
if (!wait_for_partition(path))
return -2;
- }
+
ret = mount_unknown_fs(path, bdev->dest, bdev->mntopts);
if (ret < 0)
ERROR("Error mounting %s", bdev->src);
{
if (strncmp(path, "nbd:", 4) == 0)
return true;
+
return false;
}
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
SYSERROR("Error blocking signals for nbd watcher");
- exit(1);
+ exit(EXIT_FAILURE);
}
sfd = signalfd(-1, &mask, 0);
if (sfd == -1) {
SYSERROR("Error opening signalfd for nbd task");
- exit(1);
+ exit(EXIT_FAILURE);
}
- if (prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0) < 0)
+ if (prctl(PR_SET_PDEATHSIG, prctl_arg(SIGHUP), prctl_arg(0),
+ prctl_arg(0), prctl_arg(0)) < 0)
SYSERROR("Error setting parent death signal for nbd watcher");
pid = fork();
if (fdsi.ssi_signo == SIGHUP) {
/* container has exited */
nbd_detach(nbd);
- exit(0);
+ exit(EXIT_SUCCESS);
} else if (fdsi.ssi_signo == SIGCHLD) {
int status;
+
/* If qemu-nbd fails, or is killed by a signal,
* then exit */
while (waitpid(-1, &status, WNOHANG) > 0) {
if ((WIFEXITED(status) && WEXITSTATUS(status) != 0) ||
WIFSIGNALED(status)) {
nbd_detach(nbd);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
}
}
close(sfd);
+
if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
WARN("Warning: unblocking signals for nbd watcher");
execlp("qemu-nbd", "qemu-nbd", "-c", nbd, path, (char *)NULL);
SYSERROR("Error executing qemu-nbd");
- exit(1);
+ _exit(EXIT_FAILURE);
}
static bool clone_attach_nbd(const char *nbd, const char *path)
data.nbd = nbd;
data.path = path;
- pid = lxc_clone(do_attach_nbd, &data, CLONE_NEWPID);
+ pid = lxc_clone(do_attach_nbd, &data, CLONE_NEWPID, NULL);
if (pid < 0)
return false;
+
return true;
}
ret = snprintf(path, 100, "/sys/block/nbd%d/pid", idx);
if (ret < 0 || ret >= 100)
return true;
+
return file_exists(path);
}
SYSERROR("Error forking to detach nbd");
return;
}
+
if (pid) {
ret = wait_for_pid(pid);
if (ret < 0)
ERROR("nbd disconnect returned an error");
return;
}
+
execlp("qemu-nbd", "qemu-nbd", "-d", path, (char *)NULL);
SYSERROR("Error executing qemu-nbd");
- exit(1);
+ _exit(EXIT_FAILURE);
}
/*
char *p = strchr(src, ':');
if (!p)
return 0;
+
p = strchr(p+1, ':');
if (!p)
return 0;
+
p++;
+
if (*p < '1' || *p > '9')
return 0;
+
return *p - '0';
}
static bool wait_for_partition(const char *path)
{
int count = 0;
+
while (count < 5) {
if (file_exists(path))
return true;
+
sleep(1);
count++;
}
+
ERROR("Device %s did not show up after 5 seconds", path);
return false;
}