#include <grp.h>
#include <inttypes.h>
#include <libgen.h>
+#include <pthread.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include "log.h"
#include "lxclock.h"
#include "namespace.h"
+#include "parse.h"
#include "utils.h"
-#ifndef PR_SET_MM
-#define PR_SET_MM 35
-#endif
-
-#ifndef PR_SET_MM_MAP
-#define PR_SET_MM_MAP 14
-
-struct prctl_mm_map {
- uint64_t start_code;
- uint64_t end_code;
- uint64_t start_data;
- uint64_t end_data;
- uint64_t start_brk;
- uint64_t brk;
- uint64_t start_stack;
- uint64_t arg_start;
- uint64_t arg_end;
- uint64_t env_start;
- uint64_t env_end;
- uint64_t *auxv;
- uint32_t auxv_size;
- uint32_t exe_fd;
-};
+#ifndef HAVE_STRLCPY
+#include "include/strlcpy.h"
#endif
#ifndef O_PATH
*/
extern bool btrfs_try_remove_subvol(const char *path);
-static int _recursive_rmdir(char *dirname, dev_t pdev,
+static int _recursive_rmdir(const char *dirname, dev_t pdev,
const char *exclude, int level, bool onedev)
{
struct dirent *direntp;
struct stat mystat;
int rc;
- if (!direntp)
- break;
-
if (!strcmp(direntp->d_name, ".") ||
!strcmp(direntp->d_name, ".."))
continue;
}
/* returns 0 on success, -1 if there were any failures */
-extern int lxc_rmdir_onedev(char *path, const char *exclude)
+extern int lxc_rmdir_onedev(const char *path, const char *exclude)
{
struct stat mystat;
bool onedev = true;
- if (is_native_overlayfs(path)) {
+ if (is_native_overlayfs(path))
onedev = false;
- }
if (lstat(path, &mystat) < 0) {
if (errno == ENOENT)
return 0;
+
ERROR("Failed to stat %s", path);
return -1;
}
{
char *rundir;
const char *homedir;
+ struct stat sb;
+
+ if (stat(RUNTIME_PATH, &sb) < 0) {
+ return NULL;
+ }
- if (geteuid() == 0) {
+ if (geteuid() == sb.st_uid || getegid() == sb.st_gid) {
rundir = strdup(RUNTIME_PATH);
return rundir;
}
return (const char**)lxc_va_arg_list_to_argv(ap, skip, 0);
}
-extern struct lxc_popen_FILE *lxc_popen(const char *command)
+struct lxc_popen_FILE *lxc_popen(const char *command)
{
- struct lxc_popen_FILE *fp = NULL;
- int parent_end = -1, child_end = -1;
+ int ret;
int pipe_fds[2];
pid_t child_pid;
+ struct lxc_popen_FILE *fp = NULL;
- int r = pipe2(pipe_fds, O_CLOEXEC);
-
- if (r < 0) {
- ERROR("pipe2 failure");
+ ret = pipe2(pipe_fds, O_CLOEXEC);
+ if (ret < 0)
return NULL;
- }
-
- parent_end = pipe_fds[0];
- child_end = pipe_fds[1];
child_pid = fork();
+ if (child_pid < 0)
+ goto on_error;
- if (child_pid == 0) {
- /* child */
- int child_std_end = STDOUT_FILENO;
-
- close(parent_end);
- parent_end = -1;
+ if (!child_pid) {
+ sigset_t mask;
- if (child_end != child_std_end) {
- /* dup2() doesn't dup close-on-exec flag */
- dup2(child_end, child_std_end);
+ close(pipe_fds[0]);
- /* it's safe not to close child_end here
- * as it's marked close-on-exec anyway
- */
- } else {
- /*
- * The descriptor is already the one we will use.
- * But it must not be marked close-on-exec.
- * Undo the effects.
- */
- if (fcntl(child_end, F_SETFD, 0) != 0) {
- SYSERROR("Failed to remove FD_CLOEXEC from fd.");
- exit(127);
- }
- }
-
- /*
- * Unblock signals.
- * This is the main/only reason
- * why we do our lousy popen() emulation.
- */
- {
- sigset_t mask;
- sigfillset(&mask);
- sigprocmask(SIG_UNBLOCK, &mask, NULL);
+ /* duplicate stdout */
+ if (pipe_fds[1] != STDOUT_FILENO)
+ ret = dup2(pipe_fds[1], STDOUT_FILENO);
+ else
+ ret = fcntl(pipe_fds[1], F_SETFD, 0);
+ if (ret < 0) {
+ close(pipe_fds[1]);
+ _exit(EXIT_FAILURE);
}
- execl("/bin/sh", "sh", "-c", command, (char *) NULL);
- exit(127);
- }
+ /* duplicate stderr */
+ if (pipe_fds[1] != STDERR_FILENO)
+ ret = dup2(pipe_fds[1], STDERR_FILENO);
+ else
+ ret = fcntl(pipe_fds[1], F_SETFD, 0);
+ close(pipe_fds[1]);
+ if (ret < 0)
+ _exit(EXIT_FAILURE);
- /* parent */
+ /* unblock all signals */
+ ret = sigfillset(&mask);
+ if (ret < 0)
+ _exit(EXIT_FAILURE);
- close(child_end);
- child_end = -1;
+ ret = pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
+ if (ret < 0)
+ _exit(EXIT_FAILURE);
- if (child_pid < 0) {
- ERROR("fork failure");
- goto error;
+ execl("/bin/sh", "sh", "-c", command, (char *)NULL);
+ _exit(127);
}
- fp = calloc(1, sizeof(*fp));
- if (!fp) {
- ERROR("failed to allocate memory");
- goto error;
- }
+ close(pipe_fds[1]);
+ pipe_fds[1] = -1;
- fp->f = fdopen(parent_end, "r");
- if (!fp->f) {
- ERROR("fdopen failure");
- goto error;
- }
+ fp = malloc(sizeof(*fp));
+ if (!fp)
+ goto on_error;
+ memset(fp, 0, sizeof(*fp));
fp->child_pid = child_pid;
+ fp->pipe = pipe_fds[0];
+
+ /* From now on, closing fp->f will also close fp->pipe. So only ever
+ * call fclose(fp->f).
+ */
+ fp->f = fdopen(pipe_fds[0], "r");
+ if (!fp->f)
+ goto on_error;
return fp;
-error:
+on_error:
+ /* We can only close pipe_fds[0] if fdopen() didn't succeed or wasn't
+ * called yet. Otherwise the fd belongs to the file opened by fdopen()
+ * since it isn't dup()ed.
+ */
+ if (fp && !fp->f && pipe_fds[0] >= 0)
+ close(pipe_fds[0]);
- if (fp) {
- if (fp->f) {
- fclose(fp->f);
- parent_end = -1; /* so we do not close it second time */
- }
+ if (pipe_fds[1] >= 0)
+ close(pipe_fds[1]);
- free(fp);
- }
+ if (fp && fp->f)
+ fclose(fp->f);
- if (parent_end != -1)
- close(parent_end);
+ if (fp)
+ free(fp);
return NULL;
}
-extern int lxc_pclose(struct lxc_popen_FILE *fp)
+int lxc_pclose(struct lxc_popen_FILE *fp)
{
- FILE *f = NULL;
- pid_t child_pid = 0;
- int wstatus = 0;
pid_t wait_pid;
+ int wstatus = 0;
- if (fp) {
- f = fp->f;
- child_pid = fp->child_pid;
- /* free memory (we still need to close file stream) */
- free(fp);
- fp = NULL;
- }
-
- if (!f || fclose(f)) {
- ERROR("fclose failure");
+ if (!fp)
return -1;
- }
do {
- wait_pid = waitpid(child_pid, &wstatus, 0);
- } while (wait_pid == -1 && errno == EINTR);
+ wait_pid = waitpid(fp->child_pid, &wstatus, 0);
+ } while (wait_pid < 0 && errno == EINTR);
+
+ fclose(fp->f);
+ free(fp);
- if (wait_pid == -1) {
- ERROR("waitpid failure");
+ if (wait_pid < 0)
return -1;
- }
return wstatus;
}
return NULL;
if (use_as_prefix)
- strcpy(result, sep);
+ (void)strlcpy(result, sep, result_len + 1);
+
for (p = (char **)parts; *p; p++) {
if (p > (char **)parts)
strcat(result, sep);
char *lxc_append_paths(const char *first, const char *second)
{
- size_t len = strlen(first) + strlen(second) + 1;
- const char *pattern = "%s%s";
+ 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";
if (!result)
return NULL;
- snprintf(result, len, pattern, first, second);
+ ret = snprintf(result, len, pattern, first, second);
+ if (ret < 0 || (size_t)ret >= len) {
+ free(result);
+ return NULL;
+ }
+
return result;
}
{
char *token, *str, *saveptr = NULL;
char sep[2] = { _sep, '\0' };
+ size_t len;
if (!haystack || !needle)
return 0;
- str = alloca(strlen(haystack)+1);
- strcpy(str, haystack);
+ len = strlen(haystack);
+ str = alloca(len + 1);
+ (void)strlcpy(str, haystack, len + 1);
+
for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
if (strcmp(needle, token) == 0)
return 1;
size_t result_capacity = 0;
size_t result_count = 0;
int r, saved_errno;
+ size_t len;
if (!string)
return calloc(1, sizeof(char *));
- str = alloca(strlen(string) + 1);
- strcpy(str, string);
+ len = strlen(string);
+ str = alloca(len + 1);
+ (void)strlcpy(str, string, len + 1);
+
for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
if (r < 0)
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;
size_t result_count = 0;
int r, saved_errno;
size_t i = 0;
+ size_t len;
if (!string)
return calloc(1, sizeof(char *));
- str = alloca(strlen(string)+1);
- strcpy(str, string);
+ len = strlen(string);
+ str = alloca(len + 1);
+ (void)strlcpy(str, string, len + 1);
+
for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
while (token[0] == ' ' || token[0] == '\t')
token++;
return result;
}
-int lxc_write_to_file(const char *filename, const void* buf, size_t count, bool add_newline)
+int lxc_write_to_file(const char *filename, const void *buf, size_t count,
+ bool add_newline, mode_t mode)
{
int fd, saved_errno;
ssize_t ret;
- fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0666);
+ fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
if (fd < 0)
return -1;
ret = lxc_write_nointr(fd, buf, count);
return tpath;
}
-/*
- * Sets the process title to the specified title. Note that this may fail if
- * the kernel doesn't support PR_SET_MM_MAP (kernels <3.18).
- */
-int setproctitle(char *title)
-{
- static char *proctitle = NULL;
- char buf[2048], *tmp;
- FILE *f;
- int i, len, ret = 0;
-
- /* We don't really need to know all of this stuff, but unfortunately
- * PR_SET_MM_MAP requires us to set it all at once, so we have to
- * figure it out anyway.
- */
- unsigned long start_data, end_data, start_brk, start_code, end_code,
- start_stack, arg_start, arg_end, env_start, env_end,
- brk_val;
- struct prctl_mm_map prctl_map;
-
- f = fopen_cloexec("/proc/self/stat", "r");
- if (!f) {
- return -1;
- }
-
- tmp = fgets(buf, sizeof(buf), f);
- fclose(f);
- if (!tmp) {
- return -1;
- }
-
- /* Skip the first 25 fields, column 26-28 are start_code, end_code,
- * and start_stack */
- tmp = strchr(buf, ' ');
- for (i = 0; i < 24; i++) {
- if (!tmp)
- return -1;
- tmp = strchr(tmp+1, ' ');
- }
- if (!tmp)
- return -1;
-
- i = sscanf(tmp, "%lu %lu %lu", &start_code, &end_code, &start_stack);
- if (i != 3)
- return -1;
-
- /* Skip the next 19 fields, column 45-51 are start_data to arg_end */
- for (i = 0; i < 19; i++) {
- if (!tmp)
- return -1;
- tmp = strchr(tmp+1, ' ');
- }
-
- if (!tmp)
- return -1;
-
- i = sscanf(tmp, "%lu %lu %lu %*u %*u %lu %lu",
- &start_data,
- &end_data,
- &start_brk,
- &env_start,
- &env_end);
- if (i != 5)
- return -1;
-
- /* Include the null byte here, because in the calculations below we
- * want to have room for it. */
- len = strlen(title) + 1;
-
- proctitle = realloc(proctitle, len);
- if (!proctitle)
- return -1;
-
- arg_start = (unsigned long) proctitle;
- arg_end = arg_start + len;
-
- brk_val = syscall(__NR_brk, 0);
-
- prctl_map = (struct prctl_mm_map) {
- .start_code = start_code,
- .end_code = end_code,
- .start_stack = start_stack,
- .start_data = start_data,
- .end_data = end_data,
- .start_brk = start_brk,
- .brk = brk_val,
- .arg_start = arg_start,
- .arg_end = arg_end,
- .env_start = env_start,
- .env_end = env_end,
- .auxv = NULL,
- .auxv_size = 0,
- .exe_fd = -1,
- };
-
- ret = prctl(PR_SET_MM, PR_SET_MM_MAP, (long) &prctl_map, sizeof(prctl_map), 0);
- if (ret == 0)
- strcpy((char*)arg_start, title);
- else
- INFO("setting cmdline failed - %s", strerror(errno));
-
- return ret;
-}
-
/*
* @path: a pathname where / replaced with '\0'.
* @offsetp: pointer to int showing which path segment was last seen.
close(destfd);
if (ret < 0) {
errno = saved_errno;
- SYSERROR("Failed to mount %s onto %s", src, dest);
+ SYSERROR("Failed to mount %s onto %s", src ? src : "(null)", dest);
return ret;
}
return -1;
}
- mypid = getpid();
+ mypid = lxc_raw_getpid();
INFO("I am %d, /proc/self points to \"%s\"", mypid, link);
if (lxc_safe_int(link, &link_to_pid) < 0)
return n;
}
-void *lxc_strmmap(void *addr, size_t length, int prot, int flags, int fd,
- off_t offset)
-{
- void *tmp = NULL, *overlap = NULL;
-
- /* We establish an anonymous mapping that is one byte larger than the
- * underlying file. The pages handed to us are zero filled. */
- tmp = mmap(addr, length + 1, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (tmp == MAP_FAILED)
- return tmp;
-
- /* Now we establish a fixed-address mapping starting at the address we
- * received from our anonymous mapping and replace all bytes excluding
- * the additional \0-byte with the file. This allows us to use normal
- * string-handling functions. */
- overlap = mmap(tmp, length, prot, MAP_FIXED | flags, fd, offset);
- if (overlap == MAP_FAILED)
- munmap(tmp, length + 1);
-
- return overlap;
-}
-
-int lxc_strmunmap(void *addr, size_t length)
-{
- return munmap(addr, length + 1);
-}
-
/* 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 + (LXC_NUMSTRLEN64) + 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:
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 -1;
+ return -EFBIG;
return open(path, O_RDONLY | O_CLOEXEC);
}
return 0;
}
+int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base)
+{
+ char *err = NULL;
+ uint64_t u;
+
+ while (isspace(*numstr))
+ numstr++;
+
+ if (*numstr == '-')
+ return -EINVAL;
+
+ errno = 0;
+ u = strtoull(numstr, &err, base);
+ if (errno == ERANGE && u == ULLONG_MAX)
+ return -ERANGE;
+
+ if (err == numstr || *err != '\0')
+ return -EINVAL;
+
+ *converted = u;
+ return 0;
+}
+
int lxc_safe_int(const char *numstr, int *converted)
{
char *err = NULL;
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) {
return -1;
while ((dp = readdir(dir))) {
- if (!dp)
- break;
-
if (strncmp(dp->d_name, "loop", 4) != 0)
continue;
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';
return -1;
}
- child = fork();
+ child = lxc_raw_clone(0);
if (child < 0) {
close(pipefd[0]);
close(pipefd[1]);
if (ret < 0) {
SYSERROR("failed to duplicate std{err,out} file descriptor");
- exit(EXIT_FAILURE);
+ _exit(EXIT_FAILURE);
}
/* Does not return. */
child_fn(args);
ERROR("failed to exec command");
- exit(EXIT_FAILURE);
+ _exit(EXIT_FAILURE);
}
/* close the write-end of the pipe */
close(pipefd[1]);
- bytes = read(pipefd[0], buf, (buf_size > 0) ? (buf_size - 1) : 0);
- if (bytes > 0)
- buf[bytes - 1] = '\0';
+ if (buf && buf_size > 0) {
+ bytes = read(pipefd[0], buf, buf_size - 1);
+ if (bytes > 0)
+ buf[bytes - 1] = '\0';
+ }
fret = wait_for_pid(child);
/* close the read-end of the pipe */
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;
return true;
}
+
+int lxc_make_tmpfile(char *template, bool rm)
+{
+ int fd, ret;
+ mode_t msk;
+
+ msk = umask(0022);
+ fd = mkstemp(template);
+ umask(msk);
+ 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) - 1);
+ 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 (strcasecmp(suffix, "KB") == 0)
+ mltpl = 1024;
+ else if (strcasecmp(suffix, "MB") == 0)
+ mltpl = 1024 * 1024;
+ else if (strcasecmp(suffix, "GB") == 0)
+ 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
+ * valid power of two.
+ */
+ if (n == 0)
+ return 0;
+
+ if (!(n & (n - 1)))
+ return n;
+
+ while (n & (n - 1))
+ n = n & (n - 1);
+
+ n = n << 1;
+ return n;
+}
+
+int lxc_set_death_signal(int signal)
+{
+ int ret;
+ pid_t ppid;
+
+ ret = prctl(PR_SET_PDEATHSIG, signal, 0, 0, 0);
+
+ /* Check whether we have been orphaned. */
+ ppid = (pid_t)syscall(SYS_getppid);
+ if (ppid == 1) {
+ pid_t self;
+
+ self = lxc_raw_getpid();
+ ret = kill(self, SIGKILL);
+ if (ret < 0)
+ return -1;
+ }
+
+ if (ret < 0) {
+ SYSERROR("Failed to set PR_SET_PDEATHSIG to %d", signal);
+ return -1;
+ }
+
+ return 0;
+}
+
+void remove_trailing_newlines(char *l)
+{
+ char *p = l;
+
+ while (*p)
+ p++;
+
+ while (--p >= l && *p == '\n')
+ *p = '\0';
+}