Closes #2073.
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
--- /dev/null
+/*
+ * Android c-library does not have getsubopt,
+ * so code lifted from uClibc
+ * http://git.uclibc.org/uClibc/tree/libc/unistd/getsubopt.c
+ */
+
+/* Parse comma separate list into words.
+ Copyright (C) 1996, 1997, 1999, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+ The GNU C 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.
+ The GNU C 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 the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+char *strchrnul(const char *s, int c)
+{
+ char *result;
+
+ result = strchr( s, c );
+
+ if( !result )
+ {
+ result = (char *)s + strlen( s );
+ }
+
+ return( result );
+}
+
+/* Parse comma separated suboption from *OPTIONP and match against
+ strings in TOKENS. If found return index and set *VALUEP to
+ optional value introduced by an equal sign. If the suboption is
+ not part of TOKENS return in *VALUEP beginning of unknown
+ suboption. On exit *OPTIONP is set to the beginning of the next
+ token or at the terminating NUL character. */
+int
+getsubopt (char **optionp, char *const *tokens, char **valuep)
+{
+ char *endp, *vstart;
+ int cnt;
+
+ if (**optionp == '\0')
+ return -1;
+
+ /* Find end of next token. */
+ endp = strchrnul (*optionp, ',');
+
+ /* Find start of value. */
+ vstart = memchr (*optionp, '=', endp - *optionp);
+ if (vstart == NULL)
+ vstart = endp;
+
+ /* Try to match the characters between *OPTIONP and VSTART against
+ one of the TOKENS. */
+ for (cnt = 0; tokens[cnt] != NULL; ++cnt)
+ if (strncmp (*optionp, tokens[cnt], vstart - *optionp) == 0
+ && tokens[cnt][vstart - *optionp] == '\0')
+ {
+ /* We found the current option in TOKENS. */
+ *valuep = vstart != endp ? vstart + 1 : NULL;
+
+ if (*endp != '\0')
+ *endp++ = '\0';
+ *optionp = endp;
+
+ return cnt;
+ }
+
+ /* The current suboption does not match any option. */
+ *valuep = *optionp;
+
+ if (*endp != '\0')
+ *endp++ = '\0';
+ *optionp = endp;
+
+ return -1;
+}
--- /dev/null
+#ifndef _GETSUBOPT_H
+#define _GETSUBOPT_H
+int getsubopt (char **optionp, char *const *tokens, char **valuep);
+#endif
*/
#define _GNU_SOURCE
-#include "config.h"
-
-#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
#include <getopt.h>
#include <signal.h>
-#include <stdio.h>
-#include <sys/types.h>
+#include <stdbool.h>
#include <stdint.h>
-#include <sys/wait.h>
+#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
-#include <ctype.h>
-#include <sys/stat.h>
-#include <fcntl.h>
+#include <string.h>
#include <time.h>
-#include <stdbool.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#include <lxc/lxccontainer.h>
-#include "attach.h"
-#include "log.h"
-#include "confile.h"
#include "arguments.h"
-#include "lxc.h"
-#include "conf.h"
-#include "state.h"
-#include "storage.h"
-#include "utils.h"
+#include "tool_utils.h"
#ifndef HAVE_GETSUBOPT
-#include <../include/getsubopt.h>
+#include "include/getsubopt.h"
#endif
enum mnttype {
if (lxc_log_init(&log))
exit(ret);
- lxc_log_options_no_override();
/* REMOVE IN LXC 3.0 */
setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);
static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num, struct lxc_arguments *arg)
{
- char upperdir[MAXPATHLEN];
- char workdir[MAXPATHLEN];
+ char upperdir[TOOL_MAXPATHLEN];
+ char workdir[TOOL_MAXPATHLEN];
unsigned int i;
int ret;
struct mnts *m = NULL;
for (i = 0, m = mnts; i < num; i++, m++) {
if ((m->mnt_type == LXC_MNT_OVL) || (m->mnt_type == LXC_MNT_AUFS)) {
- ret = snprintf(upperdir, MAXPATHLEN, "%s/%s/delta#XXXXXX",
+ ret = snprintf(upperdir, TOOL_MAXPATHLEN, "%s/%s/delta#XXXXXX",
arg->newpath, arg->newname);
- if (ret < 0 || ret >= MAXPATHLEN)
+ if (ret < 0 || ret >= TOOL_MAXPATHLEN)
return -1;
if (!mkdtemp(upperdir))
return -1;
}
if (m->mnt_type == LXC_MNT_OVL) {
- ret = snprintf(workdir, MAXPATHLEN, "%s/%s/work#XXXXXX",
+ ret = snprintf(workdir, TOOL_MAXPATHLEN, "%s/%s/work#XXXXXX",
arg->newpath, arg->newname);
- if (ret < 0 || ret >= MAXPATHLEN)
+ if (ret < 0 || ret >= TOOL_MAXPATHLEN)
return -1;
if (!mkdtemp(workdir))
return -1;
static int do_clone_ephemeral(struct lxc_container *c,
struct lxc_arguments *arg, char **args, int flags)
{
- char *bdev;
char *premount;
- char randname[MAXPATHLEN];
+ char randname[TOOL_MAXPATHLEN];
unsigned int i;
int ret = 0;
bool bret = true, started = false;
+ char *tmp_buf = randname;
struct lxc_container *clone;
lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
attach_options.env_policy = LXC_ATTACH_CLEAR_ENV;
if (!arg->newname) {
- ret = snprintf(randname, MAXPATHLEN, "%s/%s_XXXXXX", arg->newpath, arg->name);
- if (ret < 0 || ret >= MAXPATHLEN)
+ ret = snprintf(randname, TOOL_MAXPATHLEN, "%s/%s_XXXXXX", arg->newpath, arg->name);
+ if (ret < 0 || ret >= TOOL_MAXPATHLEN)
return -1;
if (!mkdtemp(randname))
return -1;
return -1;
if (arg->tmpfs) {
- bdev = c->lxc_conf->rootfs.bdev_type;
- if (bdev && strcmp(bdev, "dir")) {
- fprintf(stderr, "Cannot currently use tmpfs with %s storage backend.\n", bdev);
- goto destroy_and_put;
- }
-
premount = mount_tmpfs(arg->name, arg->newname, arg->newpath, arg);
if (!premount)
goto destroy_and_put;
destroy_and_put:
if (started)
clone->shutdown(clone, -1);
- if (!started || clone->lxc_conf->ephemeral != 1)
+ ret = clone->get_config_item(clone, "lxc.ephemeral", tmp_buf, TOOL_MAXPATHLEN);
+ if (ret > 0 && strcmp(tmp_buf, "0"))
clone->destroy(clone);
free_mnts();
lxc_container_put(clone);
#include <unistd.h>
#include <linux/sched.h>
#include <sys/prctl.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
*converted = sli;
return 0;
}
+
+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;
+}
+
+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;
+}
+
+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_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;
+}
+
+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;
+}
+
+size_t lxc_array_len(void **array)
+{
+ void **p;
+ size_t result = 0;
+
+ for (p = array; p && *p; p++)
+ result++;
+
+ return result;
+}
extern int lxc_safe_int(const char *numstr, int *converted);
extern int lxc_safe_long(const char *numstr, long int *converted);
+typedef void (*lxc_free_fn)(void *);
+extern void lxc_free_array(void **array, lxc_free_fn element_free_fn);
+extern size_t lxc_array_len(void **array);
+extern int lxc_grow_array(void ***array, size_t *capacity, size_t new_size,
+ size_t capacity_increment);
+extern char **lxc_string_split(const char *string, char _sep);
+extern char **lxc_normalize_path(const char *path);
+extern char *lxc_string_join(const char *sep, const char **parts,
+ bool use_as_prefix);
+
+extern int is_dir(const char *path);
+
#endif /* __LXC_UTILS_H */