#include <grp.h>
#include <inttypes.h>
#include <libgen.h>
+#include <pthread.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include "parse.h"
#include "utils.h"
+#ifndef HAVE_STRLCPY
+#include "include/strlcpy.h"
+#endif
+
+#ifndef HAVE_STRLCAT
+#include "include/strlcat.h"
+#endif
+
#ifndef O_PATH
#define O_PATH 010000000
#endif
#define O_NOFOLLOW 00400000
#endif
-lxc_log_define(lxc_utils, lxc);
+lxc_log_define(utils, lxc);
/*
* if path is btrfs, tries to remove it and any subvolumes beneath it
struct stat mystat;
int rc;
- if (!direntp)
- break;
-
if (!strcmp(direntp->d_name, ".") ||
!strcmp(direntp->d_name, ".."))
continue;
failed = 1;
continue;
}
+
if (onedev && mystat.st_dev != pdev) {
/* TODO should we be checking /proc/self/mountinfo for
* pathname and not doing this if found? */
INFO("Removed btrfs subvolume at %s\n", pathname);
continue;
}
+
if (S_ISDIR(mystat.st_mode)) {
if (_recursive_rmdir(pathname, pdev, exclude, level+1, onedev) < 0)
failed=1;
return failed ? -1 : 0;
}
-/* We have two different magic values for overlayfs, yay. */
-#ifndef OVERLAYFS_SUPER_MAGIC
-#define OVERLAYFS_SUPER_MAGIC 0x794c764f
-#endif
-
-#ifndef OVERLAY_SUPER_MAGIC
-#define OVERLAY_SUPER_MAGIC 0x794c7630
-#endif
-
/* In overlayfs, st_dev is unreliable. So on overlayfs we don't do the
* lxc_rmdir_onedev()
*/
do {
dir = tmp + strspn(tmp, "/");
tmp = dir + strcspn(dir, "/");
+
makeme = strndup(orig, dir - orig);
if (*makeme) {
if (mkdir(makeme, mode) && errno != EEXIST) {
const char *homedir;
struct stat sb;
- if (stat(RUNTIME_PATH, &sb) < 0) {
+ if (stat(RUNTIME_PATH, &sb) < 0)
return NULL;
- }
if (geteuid() == sb.st_uid || getegid() == sb.st_gid) {
rundir = strdup(RUNTIME_PATH);
}
rundir = malloc(sizeof(char) * (17 + strlen(homedir)));
+ if (!rundir)
+ return NULL;
+
sprintf(rundir, "%s/.cache/lxc/run/", homedir);
return rundir;
if (ret == -1) {
if (errno == EINTR)
goto again;
+
return -1;
}
+
if (ret != pid)
goto again;
+
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
return -1;
+
return 0;
}
if (ret == -1) {
if (errno == EINTR)
goto again;
+
return -1;
}
- if (ret != pid)
- goto again;
- return status;
-}
-ssize_t lxc_write_nointr(int fd, const void* buf, size_t count)
-{
- ssize_t ret;
-again:
- ret = write(fd, buf, count);
- if (ret < 0 && errno == EINTR)
- goto again;
- return ret;
-}
-
-ssize_t lxc_read_nointr(int fd, void* buf, size_t count)
-{
- ssize_t ret;
-again:
- ret = read(fd, buf, count);
- if (ret < 0 && errno == EINTR)
+ if (ret != pid)
goto again;
- return ret;
-}
-ssize_t lxc_read_nointr_expect(int fd, void* buf, size_t count, const void* expected_buf)
-{
- ssize_t ret;
- ret = lxc_read_nointr(fd, buf, count);
- if (ret <= 0)
- return ret;
- if ((size_t)ret != count)
- return -1;
- if (expected_buf && memcmp(buf, expected_buf, count) != 0) {
- errno = EINVAL;
- return -1;
- }
- return ret;
+ return status;
}
#if HAVE_LIBGNUTLS
if (!fnam)
return -1;
+
f = fopen_cloexec(fnam, "r");
if (!f) {
SYSERROR("Error opening template");
return -1;
}
+
if (fseek(f, 0, SEEK_END) < 0) {
SYSERROR("Error seeking to end of template");
fclose(f);
return -1;
}
+
if ((flen = ftell(f)) < 0) {
SYSERROR("Error telling size of template");
fclose(f);
return -1;
}
+
if (fseek(f, 0, SEEK_SET) < 0) {
SYSERROR("Error seeking to start of template");
fclose(f);
return -1;
}
+
if ((buf = malloc(flen+1)) == NULL) {
SYSERROR("Out of memory");
fclose(f);
return -1;
}
+
if (fread(buf, 1, flen, f) != flen) {
SYSERROR("Failure reading template");
free(buf);
fclose(f);
return -1;
}
+
if (fclose(f) < 0) {
SYSERROR("Failre closing template");
free(buf);
return -1;
}
+
buf[flen] = '\0';
ret = gnutls_hash_fast(GNUTLS_DIG_SHA1, buf, flen, (void *)digest);
free(buf);
}
#endif
-char** lxc_va_arg_list_to_argv(va_list ap, size_t skip, int do_strdup)
-{
- va_list ap2;
- size_t count = 1 + skip;
- char **result;
-
- /* first determine size of argument list, we don't want to reallocate
- * constantly...
- */
- va_copy(ap2, ap);
- while (1) {
- char* arg = va_arg(ap2, char*);
- if (!arg)
- break;
- count++;
- }
- va_end(ap2);
-
- result = calloc(count, sizeof(char*));
- if (!result)
- return NULL;
- count = skip;
- while (1) {
- char* arg = va_arg(ap, char*);
- if (!arg)
- break;
- arg = do_strdup ? strdup(arg) : arg;
- if (!arg)
- goto oom;
- result[count++] = arg;
- }
-
- /* calloc has already set last element to NULL*/
- return result;
-
-oom:
- free(result);
- return NULL;
-}
-
-const char** lxc_va_arg_list_to_argv_const(va_list ap, size_t skip)
-{
- return (const char**)lxc_va_arg_list_to_argv(ap, skip, 0);
-}
-
struct lxc_popen_FILE *lxc_popen(const char *command)
{
int ret;
if (ret < 0)
_exit(EXIT_FAILURE);
- ret = sigprocmask(SIG_UNBLOCK, &mask, NULL);
+ ret = pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
if (ret < 0)
_exit(EXIT_FAILURE);
fp = malloc(sizeof(*fp));
if (!fp)
goto on_error;
+
memset(fp, 0, sizeof(*fp));
fp->child_pid = child_pid;
return wstatus;
}
-char *lxc_string_replace(const char *needle, const char *replacement, const char *haystack)
-{
- ssize_t len = -1, saved_len = -1;
- char *result = NULL;
- size_t replacement_len = strlen(replacement);
- size_t needle_len = strlen(needle);
-
- /* should be executed exactly twice */
- while (len == -1 || result == NULL) {
- char *p;
- char *last_p;
- ssize_t part_len;
-
- if (len != -1) {
- result = calloc(1, len + 1);
- if (!result)
- return NULL;
- saved_len = len;
- }
-
- len = 0;
-
- for (last_p = (char *)haystack, p = strstr(last_p, needle); p; last_p = p, p = strstr(last_p, needle)) {
- part_len = (ssize_t)(p - last_p);
- if (result && part_len > 0)
- memcpy(&result[len], last_p, part_len);
- len += part_len;
- if (result && replacement_len > 0)
- memcpy(&result[len], replacement, replacement_len);
- len += replacement_len;
- p += needle_len;
- }
- part_len = strlen(last_p);
- if (result && part_len > 0)
- memcpy(&result[len], last_p, part_len);
- len += part_len;
- }
-
- /* make sure we did the same thing twice,
- * once for calculating length, the other
- * time for copying data */
- if (saved_len != len) {
- free(result);
- return NULL;
- }
- /* make sure we didn't overwrite any buffer,
- * due to calloc the string should be 0-terminated */
- if (result[len] != '\0') {
- free(result);
- return NULL;
- }
-
- return result;
-}
-
-bool lxc_string_in_array(const char *needle, const char **haystack)
-{
- for (; haystack && *haystack; haystack++)
- if (!strcmp(needle, *haystack))
- return true;
- return false;
-}
-
-char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix)
-{
- char *result;
- char **p;
- size_t sep_len = strlen(sep);
- size_t result_len = use_as_prefix * sep_len;
-
- /* calculate new string length */
- for (p = (char **)parts; *p; p++)
- result_len += (p > (char **)parts) * sep_len + strlen(*p);
-
- result = calloc(result_len + 1, 1);
- if (!result)
- return NULL;
-
- if (use_as_prefix)
- strcpy(result, sep);
- for (p = (char **)parts; *p; p++) {
- if (p > (char **)parts)
- strcat(result, sep);
- strcat(result, *p);
- }
-
- return result;
-}
-
-char **lxc_normalize_path(const char *path)
-{
- char **components;
- char **p;
- size_t components_len = 0;
- size_t pos = 0;
-
- components = lxc_string_split(path, '/');
- if (!components)
- return NULL;
- for (p = components; *p; p++)
- components_len++;
-
- /* resolve '.' and '..' */
- for (pos = 0; pos < components_len; ) {
- if (!strcmp(components[pos], ".") || (!strcmp(components[pos], "..") && pos == 0)) {
- /* eat this element */
- free(components[pos]);
- memmove(&components[pos], &components[pos+1], sizeof(char *) * (components_len - pos));
- components_len--;
- } else if (!strcmp(components[pos], "..")) {
- /* eat this and the previous element */
- free(components[pos - 1]);
- free(components[pos]);
- memmove(&components[pos-1], &components[pos+1], sizeof(char *) * (components_len - pos));
- components_len -= 2;
- pos--;
- } else {
- pos++;
- }
- }
-
- return components;
-}
-
-char *lxc_deslashify(const char *path)
-{
- char *dup, *p;
- char **parts = NULL;
- size_t n, len;
-
- dup = strdup(path);
- if (!dup)
- return NULL;
-
- parts = lxc_normalize_path(dup);
- if (!parts) {
- free(dup);
- return NULL;
- }
-
- /* We'll end up here if path == "///" or path == "". */
- if (!*parts) {
- len = strlen(dup);
- if (!len) {
- lxc_free_array((void **)parts, free);
- return dup;
- }
- n = strcspn(dup, "/");
- if (n == len) {
- free(dup);
- lxc_free_array((void **)parts, free);
-
- p = strdup("/");
- if (!p)
- return NULL;
-
- return p;
- }
- }
-
- p = lxc_string_join("/", (const char **)parts, *dup == '/');
- free(dup);
- lxc_free_array((void **)parts, free);
- return p;
-}
-
-char *lxc_append_paths(const char *first, const char *second)
-{
- int ret;
- size_t len;
- char *result = NULL;
- const char *pattern = "%s%s";
-
- len = strlen(first) + strlen(second) + 1;
- if (second[0] != '/') {
- len += 1;
- pattern = "%s/%s";
- }
-
- result = calloc(1, len);
- if (!result)
- return NULL;
-
- ret = snprintf(result, len, pattern, first, second);
- if (ret < 0 || (size_t)ret >= len) {
- free(result);
- return NULL;
- }
-
- return result;
-}
-
-bool lxc_string_in_list(const char *needle, const char *haystack, char _sep)
-{
- char *token, *str, *saveptr = NULL;
- char sep[2] = { _sep, '\0' };
-
- if (!haystack || !needle)
- return 0;
-
- str = alloca(strlen(haystack)+1);
- strcpy(str, haystack);
- for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
- if (strcmp(needle, token) == 0)
- return 1;
- }
-
- return 0;
-}
-
-char **lxc_string_split(const char *string, char _sep)
-{
- char *token, *str, *saveptr = NULL;
- char sep[2] = {_sep, '\0'};
- char **tmp = NULL, **result = NULL;
- size_t result_capacity = 0;
- size_t result_count = 0;
- int r, saved_errno;
-
- if (!string)
- return calloc(1, sizeof(char *));
-
- str = alloca(strlen(string) + 1);
- strcpy(str, string);
- for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
- r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
- if (r < 0)
- goto error_out;
- result[result_count] = strdup(token);
- if (!result[result_count])
- goto error_out;
- result_count++;
- }
-
- /* if we allocated too much, reduce it */
- tmp = realloc(result, (result_count + 1) * sizeof(char *));
- if (!tmp)
- goto error_out;
- result = tmp;
- /* Make sure we don't return uninitialized memory. */
- if (result_count == 0)
- *result = NULL;
- return result;
-error_out:
- saved_errno = errno;
- lxc_free_array((void **)result, free);
- errno = saved_errno;
- return NULL;
-}
-
-static bool complete_word(char ***result, char *start, char *end, size_t *cap, size_t *cnt)
-{
- int r;
-
- r = lxc_grow_array((void ***)result, cap, 2 + *cnt, 16);
- if (r < 0)
- return false;
- (*result)[*cnt] = strndup(start, end - start);
- if (!(*result)[*cnt])
- return false;
- (*cnt)++;
-
- return true;
-}
-
-/*
- * Given a a string 'one two "three four"', split into three words,
- * one, two, and "three four"
- */
-char **lxc_string_split_quoted(char *string)
-{
- char *nextword = string, *p, state;
- char **result = NULL;
- size_t result_capacity = 0;
- size_t result_count = 0;
-
- if (!string || !*string)
- return calloc(1, sizeof(char *));
-
- // TODO I'm *not* handling escaped quote
- state = ' ';
- for (p = string; *p; p++) {
- switch(state) {
- case ' ':
- if (isspace(*p))
- continue;
- else if (*p == '"' || *p == '\'') {
- nextword = p;
- state = *p;
- continue;
- }
- nextword = p;
- state = 'a';
- continue;
- case 'a':
- if (isspace(*p)) {
- complete_word(&result, nextword, p, &result_capacity, &result_count);
- state = ' ';
- continue;
- }
- continue;
- case '"':
- case '\'':
- if (*p == state) {
- complete_word(&result, nextword+1, p, &result_capacity, &result_count);
- state = ' ';
- continue;
- }
- continue;
- }
- }
-
- if (state == 'a')
- complete_word(&result, nextword, p, &result_capacity, &result_count);
-
- return realloc(result, (result_count + 1) * sizeof(char *));
-}
-
-char **lxc_string_split_and_trim(const char *string, char _sep)
-{
- char *token, *str, *saveptr = NULL;
- char sep[2] = { _sep, '\0' };
- char **result = NULL;
- size_t result_capacity = 0;
- size_t result_count = 0;
- int r, saved_errno;
- size_t i = 0;
-
- if (!string)
- return calloc(1, sizeof(char *));
-
- str = alloca(strlen(string)+1);
- strcpy(str, string);
- for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
- while (token[0] == ' ' || token[0] == '\t')
- token++;
- i = strlen(token);
- while (i > 0 && (token[i - 1] == ' ' || token[i - 1] == '\t')) {
- token[i - 1] = '\0';
- i--;
- }
- r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
- if (r < 0)
- goto error_out;
- result[result_count] = strdup(token);
- if (!result[result_count])
- goto error_out;
- result_count++;
- }
-
- /* if we allocated too much, reduce it */
- return realloc(result, (result_count + 1) * sizeof(char *));
-error_out:
- saved_errno = errno;
- lxc_free_array((void **)result, free);
- errno = saved_errno;
- return NULL;
-}
-
-void lxc_free_array(void **array, lxc_free_fn element_free_fn)
-{
- void **p;
- for (p = array; p && *p; p++)
- element_free_fn(*p);
- free((void*)array);
-}
-
-int lxc_grow_array(void ***array, size_t* capacity, size_t new_size, size_t capacity_increment)
-{
- size_t new_capacity;
- void **new_array;
-
- /* first time around, catch some trivial mistakes of the user
- * only initializing one of these */
- if (!*array || !*capacity) {
- *array = NULL;
- *capacity = 0;
- }
-
- new_capacity = *capacity;
- while (new_size + 1 > new_capacity)
- new_capacity += capacity_increment;
- if (new_capacity != *capacity) {
- /* we have to reallocate */
- new_array = realloc(*array, new_capacity * sizeof(void *));
- if (!new_array)
- return -1;
- memset(&new_array[*capacity], 0, (new_capacity - (*capacity)) * sizeof(void *));
- *array = new_array;
- *capacity = new_capacity;
- }
-
- /* array has sufficient elements */
- return 0;
-}
-
-size_t lxc_array_len(void **array)
-{
- void **p;
- size_t result = 0;
-
- for (p = array; p && *p; p++)
- result++;
-
- return result;
-}
-
-int lxc_write_to_file(const char *filename, const void* buf, size_t count, bool add_newline)
-{
- int fd, saved_errno;
- ssize_t ret;
-
- fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0666);
- if (fd < 0)
- return -1;
- ret = lxc_write_nointr(fd, buf, count);
- if (ret < 0)
- goto out_error;
- if ((size_t)ret != count)
- goto out_error;
- if (add_newline) {
- ret = lxc_write_nointr(fd, "\n", 1);
- if (ret != 1)
- goto out_error;
- }
- close(fd);
- return 0;
-
-out_error:
- saved_errno = errno;
- close(fd);
- errno = saved_errno;
- return -1;
-}
-
-int lxc_read_from_file(const char *filename, void* buf, size_t count)
-{
- int fd = -1, saved_errno;
- ssize_t ret;
-
- fd = open(filename, O_RDONLY | O_CLOEXEC);
- if (fd < 0)
- return -1;
-
- if (!buf || !count) {
- char buf2[100];
- size_t count2 = 0;
- while ((ret = read(fd, buf2, 100)) > 0)
- count2 += ret;
- if (ret >= 0)
- ret = count2;
- } else {
- memset(buf, 0, count);
- ret = read(fd, buf, count);
- }
-
- if (ret < 0)
- ERROR("read %s: %s", filename, strerror(errno));
-
- saved_errno = errno;
- close(fd);
- errno = saved_errno;
- return ret;
-}
-
-void **lxc_append_null_to_array(void **array, size_t count)
-{
- void **temp;
-
- /* Append NULL to the array */
- if (count) {
- temp = realloc(array, (count + 1) * sizeof(*array));
- if (!temp) {
- size_t i;
- for (i = 0; i < count; i++)
- free(array[i]);
- free(array);
- return NULL;
- }
- array = temp;
- array[count] = NULL;
- }
- return array;
-}
-
int randseed(bool srand_it)
{
/*
if (f) {
int ret = fread(&seed, sizeof(seed), 1, f);
if (ret != 1)
- DEBUG("unable to fread /dev/urandom, %s, fallback to time+pid rand seed", strerror(errno));
+ SYSDEBUG("unable to fread /dev/urandom, fallback to time+pid rand seed");
+
fclose(f);
}
while (getline(&line, &sz, f) != -1) {
if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3)
continue;
+
+ if (hostid <= orig && hostid + range > orig) {
+ nsid += orig - hostid;
+ goto found;
+ }
+ }
+
+ nsid = LXC_INVALID_UID;
+
+found:
+ fclose(f);
+ free(line);
+ return nsid;
+}
+
+gid_t get_ns_gid(gid_t orig)
+{
+ char *line = NULL;
+ size_t sz = 0;
+ gid_t nsid, hostid, range;
+ FILE *f = fopen("/proc/self/gid_map", "r");
+ if (!f)
+ return 0;
+
+ while (getline(&line, &sz, f) != -1) {
+ if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3)
+ continue;
+
if (hostid <= orig && hostid + range > orig) {
nsid += orig - hostid;
goto found;
}
}
- nsid = 0;
+ nsid = LXC_INVALID_GID;
+
found:
fclose(f);
free(line);
if (ret < 0)
/* Could be something other than eexist, just say "no". */
return false;
+
return S_ISDIR(sb.st_mode);
}
return hval;
}
-/*
- * Detect whether / is mounted MS_SHARED. The only way I know of to
- * check that is through /proc/self/mountinfo.
- * I'm only checking for /. If the container rootfs or mount location
- * is MS_SHARED, but not '/', then you're out of luck - figuring that
- * out would be too much work to be worth it.
- */
-int detect_shared_rootfs(void)
+bool is_shared_mountpoint(const char *path)
{
- char buf[LXC_LINELEN], *p;
+ char buf[LXC_LINELEN];
FILE *f;
int i;
- char *p2;
+ char *p, *p2;
f = fopen("/proc/self/mountinfo", "r");
if (!f)
return 0;
+
while (fgets(buf, LXC_LINELEN, f)) {
for (p = buf, i = 0; p && i < 4; i++)
p = strchr(p + 1, ' ');
if (!p)
continue;
+
p2 = strchr(p + 1, ' ');
if (!p2)
continue;
+
*p2 = '\0';
- if (strcmp(p + 1, "/") == 0) {
- /* This is '/'. Is it shared? */
+ if (strcmp(p + 1, path) == 0) {
+ /* This is the path. Is it shared? */
p = strchr(p2 + 1, ' ');
if (p && strstr(p, "shared:")) {
fclose(f);
- return 1;
+ return true;
}
}
}
+
fclose(f);
+ return false;
+}
+
+/*
+ * Detect whether / is mounted MS_SHARED. The only way I know of to
+ * check that is through /proc/self/mountinfo.
+ * I'm only checking for /. If the container rootfs or mount location
+ * is MS_SHARED, but not '/', then you're out of luck - figuring that
+ * out would be too much work to be worth it.
+ */
+int detect_shared_rootfs(void)
+{
+ if (is_shared_mountpoint("/"))
+ return 1;
return 0;
}
-bool switch_to_ns(pid_t pid, const char *ns) {
+bool switch_to_ns(pid_t pid, const char *ns)
+{
int fd, ret;
char nspath[MAXPATHLEN];
fd = open(nspath, O_RDONLY);
if (fd < 0) {
- SYSERROR("failed to open %s", nspath);
+ SYSERROR("Failed to open %s", nspath);
return false;
}
ret = setns(fd, 0);
if (ret) {
- SYSERROR("failed to set process %d to %s of %d.", pid, ns, fd);
+ SYSERROR("Failed to set process %d to %s of %d.", pid, ns, fd);
close(fd);
return false;
}
+
close(fd);
return true;
}
p = strchr(p + 1, ' ');
if (!p)
continue;
+
p2 = strchr(p + 1, ' ');
if (!p2)
continue;
+
*p2 = '\0';
if (strcmp(p + 1, "/") == 0) {
/* This is '/'. Is it the ramfs? */
if (p && strncmp(p, "- rootfs rootfs ", 16) == 0) {
free(line);
fclose(f);
+ INFO("Rootfs is located on ramfs");
return true;
}
}
}
+
free(line);
fclose(f);
return false;
}
-char *on_path(const char *cmd, const char *rootfs) {
- char *path = NULL;
- char *entry = NULL;
- char *saveptr = NULL;
+char *on_path(const char *cmd, const char *rootfs)
+{
+ char *entry = NULL, *path = NULL;
char cmdpath[MAXPATHLEN];
int ret;
if (!path)
return NULL;
- entry = strtok_r(path, ":", &saveptr);
- while (entry) {
+ lxc_iterate_parts (entry, path, ":") {
if (rootfs)
- ret = snprintf(cmdpath, MAXPATHLEN, "%s/%s/%s", rootfs, entry, cmd);
+ ret = snprintf(cmdpath, MAXPATHLEN, "%s/%s/%s", rootfs,
+ entry, cmd);
else
ret = snprintf(cmdpath, MAXPATHLEN, "%s/%s", entry, cmd);
-
if (ret < 0 || ret >= MAXPATHLEN)
- goto next_loop;
+ continue;
if (access(cmdpath, X_OK) == 0) {
free(path);
return strdup(cmdpath);
}
-
-next_loop:
- entry = strtok_r(NULL, ":", &saveptr);
}
free(path);
return NULL;
}
-bool file_exists(const char *f)
-{
- struct stat statbuf;
-
- return stat(f, &statbuf) == 0;
-}
-
bool cgns_supported(void)
{
return file_exists("/proc/self/ns/cgroup");
if (!getenv("PATH")) {
if (setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 0))
SYSERROR("Failed to setenv");
+
env_set = 1;
}
ERROR("pathname too long");
goto out1;
}
+
if (access(retv, X_OK) == 0)
return retv;
ERROR("pathname too long");
goto out1;
}
+
if (access(retv, X_OK) == 0)
return retv;
ERROR("pathname too long");
goto out1;
}
+
if (access(retv, X_OK) == 0)
return retv;
ERROR("pathname too long");
goto out1;
}
+
if (access(retv, X_OK) == 0)
return retv;
WARN("Nonsense - name /lxc.init.static too long");
goto out1;
}
+
if (access(retv, X_OK) == 0)
return retv;
return NULL;
}
-int print_to_file(const char *file, const char *content)
-{
- FILE *f;
- int ret = 0;
-
- f = fopen(file, "w");
- if (!f)
- return -1;
- if (fprintf(f, "%s", content) != strlen(content))
- ret = -1;
- fclose(f);
- return ret;
-}
-
-int is_dir(const char *path)
-{
- struct stat statbuf;
- int ret = stat(path, &statbuf);
- if (ret == 0 && S_ISDIR(statbuf.st_mode))
- return 1;
- return 0;
-}
-
/*
* Given the '-t' template option to lxc-create, figure out what to
* do. If the template is a full executable path, use that. If it
}
len = strlen(LXCTEMPLATEDIR) + strlen(t) + strlen("/lxc-") + 1;
+
tpath = malloc(len);
if (!tpath)
return NULL;
+
ret = snprintf(tpath, len, "%s/lxc-%s", LXCTEMPLATEDIR, t);
if (ret < 0 || ret >= len) {
free(tpath);
return NULL;
}
+
if (access(tpath, X_OK) < 0) {
SYSERROR("bad template: %s", t);
free(tpath);
if (offset >= fulllen)
return NULL;
- while (path[offset] != '\0' && offset < fulllen)
+ while (offset < fulllen && path[offset] != '\0')
offset++;
- while (path[offset] == '\0' && offset < fulllen)
+
+ while (offset < fulllen && path[offset] == '\0')
offset++;
*offsetp = offset;
if (subdirlen < len)
return false;
+
if (strncmp(subdir, dir, len) != 0)
return false;
+
if (dir[len-1] == '/')
return true;
+
if (subdir[len] == '/' || subdirlen == len)
return true;
+
return false;
}
static int check_symlink(int fd)
{
struct stat sb;
- int ret = fstat(fd, &sb);
+ int ret;
+
+ ret = fstat(fd, &sb);
if (ret < 0)
return -ENOENT;
+
if (S_ISLNK(sb.st_mode))
return -ELOOP;
+
return 0;
}
target, prefix_skip);
return -EINVAL;
}
+
/*
* get_nextpath() expects the curlen argument to be
* on a (turned into \0) / or before it, so decrement
SYSERROR("Out of memory checking for symbolic link");
return -ENOMEM;
}
+
for (i = 0; i < fulllen; i++) {
if (dup[i] == '/')
dup[i] = '\0';
dirfd = open(prefix_skip, O_RDONLY);
if (dirfd < 0)
goto out;
+
while (1) {
int newfd, saved_errno;
char *nextpath;
if ((nextpath = get_nextpath(dup, &curlen, fulllen)) == NULL)
goto out;
+
newfd = open_if_safe(dirfd, nextpath);
saved_errno = errno;
close(dirfd);
+
dirfd = newfd;
if (newfd < 0) {
errno = saved_errno;
if (errno == ELOOP)
SYSERROR("%s in %s was a symbolic link!", nextpath, target);
+
goto out;
}
}
/* todo - allow symlinks for relative paths if 'allowsymlinks' option is passed */
if (flags & MS_BIND && src && src[0] != '/') {
INFO("this is a relative bind mount");
+
srcfd = open_without_symlink(src, NULL);
if (srcfd < 0)
return srcfd;
+
ret = snprintf(srcbuf, 50, "/proc/self/fd/%d", srcfd);
if (ret < 0 || ret > 50) {
close(srcfd);
close(srcfd);
errno = saved_errno;
}
+
return destfd;
}
if (ret < 0 || ret > 50) {
if (srcfd != -1)
close(srcfd);
+
close(destfd);
ERROR("Out of memory");
return -EINVAL;
saved_errno = errno;
if (srcfd != -1)
close(srcfd);
+
close(destfd);
if (ret < 0) {
errno = saved_errno;
{
char path[MAXPATHLEN];
int link_to_pid, linklen, mypid, ret;
- char link[LXC_NUMSTRLEN64] = {0};
+ char link[INTTYPE_TO_STRLEN(pid_t)] = {0};
ret = snprintf(path, MAXPATHLEN, "%s/proc/self", rootfs);
if (ret < 0 || ret >= MAXPATHLEN) {
return -1;
}
- linklen = readlink(path, link, LXC_NUMSTRLEN64);
+ linklen = readlink(path, link, sizeof(link));
ret = snprintf(path, MAXPATHLEN, "%s/proc", rootfs);
if (ret < 0 || ret >= MAXPATHLEN) {
if (linklen < 0) {
if (mkdir(path, 0755) && errno != EEXIST)
return -1;
+
goto domount;
- } else if (linklen >= LXC_NUMSTRLEN64) {
+ } else if (linklen >= sizeof(link)) {
link[linklen - 1] = '\0';
ERROR("readlink returned truncated content: \"%s\"", link);
return -1;
int null_stdfds(void)
{
int ret = -1;
- int fd = open_devnull();
+ int fd;
+ fd = open_devnull();
if (fd >= 0) {
ret = set_stdfds(fd);
close(fd);
return ret;
}
-/*
- * Return the number of lines in file @fn, or -1 on error
- */
-int lxc_count_file_lines(const char *fn)
-{
- FILE *f;
- char *line = NULL;
- size_t sz = 0;
- int n = 0;
-
- f = fopen_cloexec(fn, "r");
- if (!f)
- return -1;
-
- while (getline(&line, &sz, f) != -1) {
- n++;
- }
- free(line);
- fclose(f);
- return n;
-}
-
/* Check whether a signal is blocked by a process. */
/* /proc/pid-to-str/status\0 = (5 + 21 + 7 + 1) */
-#define __PROC_STATUS_LEN (5 + (LXC_NUMSTRLEN64) + 7 + 1)
-bool task_blocking_signal(pid_t pid, int signal)
+#define __PROC_STATUS_LEN (6 + INTTYPE_TO_STRLEN(pid_t) + 7 + 1)
+bool task_blocks_signal(pid_t pid, int signal)
{
- bool bret = false;
- char *line = NULL;
- long unsigned int sigblk = 0;
- size_t n = 0;
int ret;
- FILE *f;
-
char status[__PROC_STATUS_LEN];
+ FILE *f;
+ uint64_t sigblk = 0, one = 1;
+ size_t n = 0;
+ bool bret = false;
+ char *line = NULL;
ret = snprintf(status, __PROC_STATUS_LEN, "/proc/%d/status", pid);
if (ret < 0 || ret >= __PROC_STATUS_LEN)
return bret;
while (getline(&line, &n, f) != -1) {
- if (strncmp(line, "SigBlk:\t", 8))
+ char *numstr;
+
+ if (strncmp(line, "SigBlk:", 7))
continue;
- if (sscanf(line + 8, "%lx", &sigblk) != 1)
+ numstr = lxc_trim_whitespace_in_place(line + 7);
+ ret = lxc_safe_uint64(numstr, &sigblk, 16);
+ if (ret < 0)
goto out;
+
+ break;
}
- if (sigblk & (1LU << (signal - 1)))
+ if (sigblk & (one << (signal - 1)))
bret = true;
out:
return bret;
}
-static int lxc_append_null_to_list(void ***list)
-{
- int newentry = 0;
- void **tmp;
-
- if (*list)
- for (; (*list)[newentry]; newentry++) {
- ;
- }
-
- tmp = realloc(*list, (newentry + 2) * sizeof(void **));
- if (!tmp)
- return -1;
-
- *list = tmp;
- (*list)[newentry + 1] = NULL;
-
- return newentry;
-}
-
-int lxc_append_string(char ***list, char *entry)
-{
- char *copy;
- int newentry;
-
- newentry = lxc_append_null_to_list((void ***)list);
- if (newentry < 0)
- return -1;
-
- copy = strdup(entry);
- if (!copy)
- return -1;
-
- (*list)[newentry] = copy;
-
- return 0;
-}
-
int lxc_preserve_ns(const int pid, const char *ns)
{
int ret;
ret = snprintf(path, __NS_PATH_LEN, "/proc/%d/ns%s%s", pid,
!ns || strcmp(ns, "") == 0 ? "" : "/",
!ns || strcmp(ns, "") == 0 ? "" : ns);
- errno = EFBIG;
- if (ret < 0 || (size_t)ret >= __NS_PATH_LEN)
- return -EFBIG;
+ if (ret < 0 || (size_t)ret >= __NS_PATH_LEN) {
+ errno = EFBIG;
+ return -1;
+ }
return open(path, O_RDONLY | O_CLOEXEC);
}
-int lxc_safe_uint(const char *numstr, unsigned int *converted)
-{
- char *err = NULL;
- unsigned long int uli;
-
- while (isspace(*numstr))
- numstr++;
-
- if (*numstr == '-')
- return -EINVAL;
-
- errno = 0;
- uli = strtoul(numstr, &err, 0);
- if (errno == ERANGE && uli == ULONG_MAX)
- return -ERANGE;
-
- if (err == numstr || *err != '\0')
- return -EINVAL;
-
- if (uli > UINT_MAX)
- return -ERANGE;
-
- *converted = (unsigned int)uli;
- return 0;
-}
-
-int lxc_safe_ulong(const char *numstr, unsigned long *converted)
-{
- char *err = NULL;
- unsigned long int uli;
-
- while (isspace(*numstr))
- numstr++;
-
- if (*numstr == '-')
- return -EINVAL;
-
- errno = 0;
- uli = strtoul(numstr, &err, 0);
- if (errno == ERANGE && uli == ULONG_MAX)
- return -ERANGE;
-
- if (err == numstr || *err != '\0')
- return -EINVAL;
-
- *converted = uli;
- return 0;
-}
-
-int lxc_safe_int(const char *numstr, int *converted)
-{
- char *err = NULL;
- signed long int sli;
-
- errno = 0;
- sli = strtol(numstr, &err, 0);
- if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
- return -ERANGE;
-
- if (errno != 0 && sli == 0)
- return -EINVAL;
-
- if (err == numstr || *err != '\0')
- return -EINVAL;
-
- if (sli > INT_MAX || sli < INT_MIN)
- return -ERANGE;
-
- *converted = (int)sli;
- return 0;
-}
-
-int lxc_safe_long(const char *numstr, long int *converted)
-{
- char *err = NULL;
- signed long int sli;
-
- errno = 0;
- sli = strtol(numstr, &err, 0);
- if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
- return -ERANGE;
-
- if (errno != 0 && sli == 0)
- return -EINVAL;
-
- if (err == numstr || *err != '\0')
- return -EINVAL;
-
- *converted = sli;
- return 0;
-}
-
-int lxc_safe_long_long(const char *numstr, long long int *converted)
-{
- char *err = NULL;
- signed long long int sli;
-
- errno = 0;
- sli = strtoll(numstr, &err, 0);
- if (errno == ERANGE && (sli == LLONG_MAX || sli == LLONG_MIN))
- return -ERANGE;
-
- if (errno != 0 && sli == 0)
- return -EINVAL;
-
- if (err == numstr || *err != '\0')
- return -EINVAL;
-
- *converted = sli;
- return 0;
-}
-
int lxc_switch_uid_gid(uid_t uid, gid_t gid)
{
- if (setgid(gid) < 0) {
- SYSERROR("Failed to switch to gid %d.", gid);
- return -errno;
+ int ret = 0;
+
+ if (gid != LXC_INVALID_GID) {
+ ret = setgid(gid);
+ if (ret < 0) {
+ SYSERROR("Failed to switch to gid %d", gid);
+ return -1;
+ }
+ NOTICE("Switched to gid %d", gid);
}
- NOTICE("Switched to gid %d.", gid);
- if (setuid(uid) < 0) {
- SYSERROR("Failed to switch to uid %d.", uid);
- return -errno;
+ if (uid != LXC_INVALID_UID) {
+ ret = setuid(uid);
+ if (ret < 0) {
+ SYSERROR("Failed to switch to uid %d", uid);
+ return -1;
+ }
+ NOTICE("Switched to uid %d", uid);
}
- NOTICE("Switched to uid %d.", uid);
- return 0;
+ return ret;
}
/* Simple covenience function which enables uniform logging. */
-int lxc_setgroups(int size, gid_t list[])
+bool lxc_setgroups(int size, gid_t list[])
{
if (setgroups(size, list) < 0) {
- SYSERROR("Failed to setgroups().");
- return -errno;
+ SYSERROR("Failed to setgroups()");
+ return false;
}
- NOTICE("Dropped additional groups.");
+ NOTICE("Dropped additional groups");
- return 0;
+ return true;
}
static int lxc_get_unused_loop_dev_legacy(char *loop_name)
return -1;
while ((dp = readdir(dir))) {
- if (!dp)
- break;
-
if (strncmp(dp->d_name, "loop", 4) != 0)
continue;
*/
if (umounts != INT_MAX)
umounts++;
+
/* We succeeded in umounting. Make sure that there's no other
* mountpoint stacked underneath.
*/
int ret, fret, pipefd[2];
ssize_t bytes;
- /* Make sure our callers do not receive unitialized memory. */
+ /* Make sure our callers do not receive uninitialized memory. */
if (buf_size > 0 && buf)
buf[0] = '\0';
close(pipefd[1]);
if (buf && buf_size > 0) {
- bytes = read(pipefd[0], buf, buf_size - 1);
+ bytes = lxc_read_nointr(pipefd[0], buf, buf_size - 1);
if (bytes > 0)
buf[bytes - 1] = '\0';
}
return fret;
}
-char *must_make_path(const char *first, ...)
-{
- va_list args;
- char *cur, *dest;
- size_t full_len = strlen(first);
-
- dest = must_copy_string(first);
-
- va_start(args, first);
- while ((cur = va_arg(args, char *)) != NULL) {
- full_len += strlen(cur);
- if (cur[0] != '/')
- full_len++;
- dest = must_realloc(dest, full_len + 1);
- if (cur[0] != '/')
- strcat(dest, "/");
- strcat(dest, cur);
- }
- va_end(args);
-
- return dest;
-}
-
-char *must_append_path(char *first, ...)
-{
- char *cur;
- size_t full_len;
- va_list args;
- char *dest = first;
-
- full_len = strlen(first);
- va_start(args, first);
- while ((cur = va_arg(args, char *)) != NULL) {
- full_len += strlen(cur);
-
- if (cur[0] != '/')
- full_len++;
-
- dest = must_realloc(dest, full_len + 1);
-
- if (cur[0] != '/')
- strcat(dest, "/");
-
- strcat(dest, cur);
- }
- va_end(args);
-
- return dest;
-}
-
-char *must_copy_string(const char *entry)
-{
- char *ret;
-
- if (!entry)
- return NULL;
- do {
- ret = strdup(entry);
- } while (!ret);
-
- return ret;
-}
-
-void *must_realloc(void *orig, size_t sz)
-{
- void *ret;
-
- do {
- ret = realloc(orig, sz);
- } while (!ret);
-
- return ret;
-}
-
-bool is_fs_type(const struct statfs *fs, fs_type_magic magic_val)
-{
- return (fs->f_type == (fs_type_magic)magic_val);
-}
-
-bool has_fs_type(const char *path, fs_type_magic magic_val)
-{
- bool has_type;
- int ret;
- struct statfs sb;
-
- ret = statfs(path, &sb);
- if (ret < 0)
- return false;
-
- has_type = is_fs_type(&sb, magic_val);
- if (!has_type && magic_val == RAMFS_MAGIC)
- WARN("When the ramfs it a tmpfs statfs() might report tmpfs");
-
- return has_type;
-}
-
bool lxc_nic_exists(char *nic)
{
#define __LXC_SYS_CLASS_NET_LEN 15 + IFNAMSIZ + 1
return true;
}
-int lxc_make_tmpfile(char *template, bool rm)
-{
- int fd, ret;
-
- fd = mkstemp(template);
- if (fd < 0)
- return -1;
-
- if (!rm)
- return fd;
-
- ret = unlink(template);
- if (ret < 0) {
- close(fd);
- return -1;
- }
-
- return fd;
-}
-
-int parse_byte_size_string(const char *s, int64_t *converted)
-{
- int ret, suffix_len;
- long long int conv;
- int64_t mltpl, overflow;
- char *end;
- char dup[LXC_NUMSTRLEN64 + 2];
- char suffix[3] = {0};
-
- if (!s || !strcmp(s, ""))
- return -EINVAL;
-
- end = stpncpy(dup, s, sizeof(dup));
- if (*end != '\0')
- return -EINVAL;
-
- if (isdigit(*(end - 1)))
- suffix_len = 0;
- else if (isalpha(*(end - 1)))
- suffix_len = 1;
- else
- return -EINVAL;
-
- if (suffix_len > 0 && (end - 2) == dup && !isdigit(*(end - 2)))
- return -EINVAL;
-
- if (suffix_len > 0 && isalpha(*(end - 2)))
- suffix_len++;
-
- if (suffix_len > 0) {
- memcpy(suffix, end - suffix_len, suffix_len);
- *(suffix + suffix_len) = '\0';
- *(end - suffix_len) = '\0';
- }
- dup[lxc_char_right_gc(dup, strlen(dup))] = '\0';
-
- ret = lxc_safe_long_long(dup, &conv);
- if (ret < 0)
- return -ret;
-
- if (suffix_len != 2) {
- *converted = conv;
- return 0;
- }
-
- if (!strcmp(suffix, "kB"))
- mltpl = 1024;
- else if (!strcmp(suffix, "MB"))
- mltpl = 1024 * 1024;
- else if (!strcmp(suffix, "GB"))
- mltpl = 1024 * 1024 * 1024;
- else
- return -EINVAL;
-
- overflow = conv * mltpl;
- if (conv != 0 && (overflow / conv) != mltpl)
- return -ERANGE;
-
- *converted = overflow;
- return 0;
-}
-
uint64_t lxc_find_next_power2(uint64_t n)
{
/* 0 is not valid input. We return 0 to the caller since 0 is not a
int ret;
pid_t ppid;
- ret = prctl(PR_SET_PDEATHSIG, signal, 0, 0, 0);
+ ret = prctl(PR_SET_PDEATHSIG, prctl_arg(signal), prctl_arg(0),
+ prctl_arg(0), prctl_arg(0));
/* Check whether we have been orphaned. */
ppid = (pid_t)syscall(SYS_getppid);
return 0;
}
+
+int fd_cloexec(int fd, bool cloexec)
+{
+ int oflags, nflags;
+
+ oflags = fcntl(fd, F_GETFD, 0);
+ if (oflags < 0)
+ return -errno;
+
+ if (cloexec)
+ nflags = oflags | FD_CLOEXEC;
+ else
+ nflags = oflags & ~FD_CLOEXEC;
+
+ if (nflags == oflags)
+ return 0;
+
+ if (fcntl(fd, F_SETFD, nflags) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int recursive_destroy(char *dirname)
+{
+ int ret;
+ struct dirent *direntp;
+ DIR *dir;
+ int r = 0;
+
+ dir = opendir(dirname);
+ if (!dir)
+ return -1;
+
+ while ((direntp = readdir(dir))) {
+ char *pathname;
+ struct stat mystat;
+
+ if (!strcmp(direntp->d_name, ".") ||
+ !strcmp(direntp->d_name, ".."))
+ continue;
+
+ pathname = must_make_path(dirname, direntp->d_name, NULL);
+
+ ret = lstat(pathname, &mystat);
+ if (ret < 0) {
+ if (!r)
+ WARN("Failed to stat \"%s\"", pathname);
+
+ r = -1;
+ goto next;
+ }
+
+ if (!S_ISDIR(mystat.st_mode))
+ goto next;
+
+ ret = recursive_destroy(pathname);
+ if (ret < 0)
+ r = -1;
+
+ next:
+ free(pathname);
+ }
+
+ ret = rmdir(dirname);
+ if (ret < 0) {
+ if (!r)
+ SYSWARN("Failed to delete \"%s\"", dirname);
+
+ r = -1;
+ }
+
+ ret = closedir(dir);
+ if (ret < 0) {
+ if (!r)
+ SYSWARN("Failed to delete \"%s\"", dirname);
+
+ r = -1;
+ }
+
+ return r;
+}