]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
utils: split into {file,string}_utils.{c,h}
authorChristian Brauner <christian.brauner@ubuntu.com>
Tue, 21 Aug 2018 10:59:07 +0000 (12:59 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Tue, 21 Aug 2018 11:00:20 +0000 (13:00 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
14 files changed:
src/lxc/Makefile.am
src/lxc/cmd/lxc_init.c
src/lxc/file_utils.c [new file with mode: 0644]
src/lxc/file_utils.h [new file with mode: 0644]
src/lxc/freezer.c
src/lxc/initutils.c
src/lxc/initutils.h
src/lxc/macro.h
src/lxc/parse.c
src/lxc/parse.h
src/lxc/string_utils.c [new file with mode: 0644]
src/lxc/string_utils.h [new file with mode: 0644]
src/lxc/utils.c
src/lxc/utils.h

index 75efa0a5726e6faea37c200976fba07c648fde38..6cd9dc3413eae0b5f7107fbd6d7ef3599871f03c 100644 (file)
@@ -11,6 +11,7 @@ noinst_HEADERS = attach.h \
                 confile_utils.h \
                 criu.h \
                 error.h \
+                file_utils.h \
                 initutils.h \
                 list.h \
                 log.h \
@@ -32,6 +33,7 @@ noinst_HEADERS = attach.h \
                 storage/storage.h \
                 storage/storage_utils.h \
                 storage/zfs.h \
+                string_utils.h \
                 terminal.h \
                 ../tests/lxctest.h \
                 tools/arguments.h \
@@ -93,6 +95,7 @@ liblxc_la_SOURCES = af_unix.c af_unix.h \
                    error.c error.h \
                    execute.c \
                    freezer.c \
+                   file_utils.c file_utils.h \
                    initutils.c initutils.h \
                    list.h \
                    log.c log.h \
@@ -122,6 +125,7 @@ liblxc_la_SOURCES = af_unix.c af_unix.h \
                    storage/storage.c storage/storage.h \
                    storage/storage_utils.c storage/storage_utils.h \
                    storage/zfs.c storage/zfs.h \
+                   string_utils.c string_utils.h \
                    sync.c sync.h \
                    terminal.c \
                    utils.c utils.h \
@@ -319,7 +323,8 @@ endif
 
 if ENABLE_COMMANDS
 # Binaries shipping with liblxc
-init_lxc_SOURCES = cmd/lxc_init.c
+init_lxc_SOURCES = cmd/lxc_init.c \
+                  string_utils.c string_utils.h
 lxc_monitord_SOURCES = cmd/lxc_monitord.c
 lxc_user_nic_SOURCES = cmd/lxc_user_nic.c \
                       log.c log.h \
@@ -332,6 +337,8 @@ lxc_usernsexec_SOURCES = cmd/lxc_usernsexec.c \
                         log.c log.h \
                         macro.h \
                         namespace.c namespace.h \
+                        file_utils.c file_utils.h \
+                        string_utils.c string_utils.h \
                         utils.c utils.h
 endif
 
@@ -350,10 +357,11 @@ init_lxc_static_SOURCES = cmd/lxc_init.c \
                          caps.c caps.h \
                          error.c error.h \
                          initutils.c initutils.h \
+                         file_utils.c file_utils.h \
                          log.c log.h \
                          macro.h \
                          namespace.c namespace.h \
-                         parse.c parse.h
+                         string_utils.c string_utils.h
 
 if !HAVE_GETLINE
 if HAVE_FGETLN
index 7595989a70fe13e89e2cbb58dec9bbc38608c909..362f5b495911c8a0475e63b2513620e0aa0e3b19 100644 (file)
@@ -44,6 +44,7 @@
 #include "log.h"
 #include "namespace.h"
 #include "parse.h"
+#include "string_utils.h"
 
 /* option keys for long only options */
 #define OPT_USAGE 0x1000
diff --git a/src/lxc/file_utils.c b/src/lxc/file_utils.c
new file mode 100644 (file)
index 0000000..89d90c2
--- /dev/null
@@ -0,0 +1,306 @@
+/* liblxcapi
+ *
+ * Copyright © 2018 Christian Brauner <christian.brauner@ubuntu.com>.
+ * Copyright © 2018 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/magic.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "file_utils.h"
+#include "log.h"
+#include "macro.h"
+#include "string.h"
+
+#ifndef NO_LOG
+lxc_log_define(file_utils, lxc);
+#endif
+
+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, mode);
+       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 = lxc_read_nointr(fd, buf2, 100)) > 0)
+                       count2 += ret;
+
+               if (ret >= 0)
+                       ret = count2;
+       } else {
+               memset(buf, 0, count);
+               ret = lxc_read_nointr(fd, buf, count);
+       }
+
+       saved_errno = errno;
+       close(fd);
+       errno = saved_errno;
+       return ret;
+}
+
+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)
+               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;
+}
+
+bool file_exists(const char *f)
+{
+       struct stat statbuf;
+
+       return stat(f, &statbuf) == 0;
+}
+
+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;
+
+       ret = stat(path, &statbuf);
+       if (ret == 0 && S_ISDIR(statbuf.st_mode))
+               return 1;
+
+       return 0;
+}
+
+/*
+ * 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;
+}
+
+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;
+}
+
+/* In overlayfs, st_dev is unreliable. So on overlayfs we don't do the
+ * lxc_rmdir_onedev()
+ */
+static bool is_native_overlayfs(const char *path)
+{
+       if (has_fs_type(path, OVERLAY_SUPER_MAGIC) ||
+           has_fs_type(path, OVERLAYFS_SUPER_MAGIC))
+               return true;
+
+       return false;
+}
+
+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;
+
+       return is_fs_type(&sb, magic_val);
+}
+
+bool fhas_fs_type(int fd, fs_type_magic magic_val)
+{
+       int ret;
+       struct statfs sb;
+
+       ret = fstatfs(fd, &sb);
+       if (ret < 0)
+               return false;
+
+       return is_fs_type(&sb, magic_val);
+}
+
+FILE *fopen_cloexec(const char *path, const char *mode)
+{
+       int open_mode = 0;
+       int step = 0;
+       int fd;
+       int saved_errno = 0;
+       FILE *ret;
+
+       if (!strncmp(mode, "r+", 2)) {
+               open_mode = O_RDWR;
+               step = 2;
+       } else if (!strncmp(mode, "r", 1)) {
+               open_mode = O_RDONLY;
+               step = 1;
+       } else if (!strncmp(mode, "w+", 2)) {
+               open_mode = O_RDWR | O_TRUNC | O_CREAT;
+               step = 2;
+       } else if (!strncmp(mode, "w", 1)) {
+               open_mode = O_WRONLY | O_TRUNC | O_CREAT;
+               step = 1;
+       } else if (!strncmp(mode, "a+", 2)) {
+               open_mode = O_RDWR | O_CREAT | O_APPEND;
+               step = 2;
+       } else if (!strncmp(mode, "a", 1)) {
+               open_mode = O_WRONLY | O_CREAT | O_APPEND;
+               step = 1;
+       }
+       for (; mode[step]; step++)
+               if (mode[step] == 'x')
+                       open_mode |= O_EXCL;
+       open_mode |= O_CLOEXEC;
+
+       fd = open(path, open_mode, 0666);
+       if (fd < 0)
+               return NULL;
+
+       ret = fdopen(fd, mode);
+       saved_errno = errno;
+       if (!ret)
+               close(fd);
+       errno = saved_errno;
+       return ret;
+}
diff --git a/src/lxc/file_utils.h b/src/lxc/file_utils.h
new file mode 100644 (file)
index 0000000..9467f53
--- /dev/null
@@ -0,0 +1,56 @@
+/* liblxcapi
+ *
+ * Copyright © 2018 Christian Brauner <christian.brauner@ubuntu.com>.
+ * Copyright © 2018 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __LXC_FILE_UTILS_H
+#define __LXC_FILE_UTILS_H
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+
+/* read and write whole files */
+extern int lxc_write_to_file(const char *filename, const void *buf,
+                            size_t count, bool add_newline, mode_t mode);
+extern int lxc_read_from_file(const char *filename, void *buf, size_t count);
+
+/* send and receive buffers completely */
+extern ssize_t lxc_write_nointr(int fd, const void *buf, size_t count);
+extern ssize_t lxc_read_nointr(int fd, void *buf, size_t count);
+extern ssize_t lxc_read_nointr_expect(int fd, void *buf, size_t count,
+                                     const void *expected_buf);
+extern bool file_exists(const char *f);
+extern int print_to_file(const char *file, const char *content);
+extern int is_dir(const char *path);
+extern int lxc_count_file_lines(const char *fn);
+extern int lxc_make_tmpfile(char *template, bool rm);
+
+/* __typeof__ should be safe to use with all compilers. */
+typedef __typeof__(((struct statfs *)NULL)->f_type) fs_type_magic;
+extern bool has_fs_type(const char *path, fs_type_magic magic_val);
+extern bool fhas_fs_type(int fd, fs_type_magic magic_val);
+extern bool is_fs_type(const struct statfs *fs, fs_type_magic magic_val);
+extern FILE *fopen_cloexec(const char *path, const char *mode);
+
+#endif /* __LXC_FILE_UTILS_H */
index 2103b50b9148429390e55d34efd79996c47c9633..a6b9da06135d062cb1be4b61ad448476d89472c2 100644 (file)
@@ -37,8 +37,8 @@
 #include "log.h"
 #include "lxc.h"
 #include "monitor.h"
-#include "parse.h"
 #include "state.h"
+#include "string_utils.h"
 
 lxc_log_define(freezer, lxc);
 
index cadd82757af81aa690ae1897f43f3c4fbcf3756b..9e5397aa698781fe921a0dde9eab01f1fe318724 100644 (file)
@@ -24,6 +24,7 @@
 #define _GNU_SOURCE
 #include <sys/prctl.h>
 
+#include "file_utils.h"
 #include "initutils.h"
 #include "log.h"
 #include "macro.h"
@@ -223,50 +224,6 @@ extern void remove_trailing_slashes(char *p)
                p[l] = '\0';
 }
 
-FILE *fopen_cloexec(const char *path, const char *mode)
-{
-       int open_mode = 0;
-       int step = 0;
-       int fd;
-       int saved_errno = 0;
-       FILE *ret;
-
-       if (!strncmp(mode, "r+", 2)) {
-               open_mode = O_RDWR;
-               step = 2;
-       } else if (!strncmp(mode, "r", 1)) {
-               open_mode = O_RDONLY;
-               step = 1;
-       } else if (!strncmp(mode, "w+", 2)) {
-               open_mode = O_RDWR | O_TRUNC | O_CREAT;
-               step = 2;
-       } else if (!strncmp(mode, "w", 1)) {
-               open_mode = O_WRONLY | O_TRUNC | O_CREAT;
-               step = 1;
-       } else if (!strncmp(mode, "a+", 2)) {
-               open_mode = O_RDWR | O_CREAT | O_APPEND;
-               step = 2;
-       } else if (!strncmp(mode, "a", 1)) {
-               open_mode = O_WRONLY | O_CREAT | O_APPEND;
-               step = 1;
-       }
-       for (; mode[step]; step++)
-               if (mode[step] == 'x')
-                       open_mode |= O_EXCL;
-       open_mode |= O_CLOEXEC;
-
-       fd = open(path, open_mode, 0666);
-       if (fd < 0)
-               return NULL;
-
-       ret = fdopen(fd, mode);
-       saved_errno = errno;
-       if (!ret)
-               close(fd);
-       errno = saved_errno;
-       return ret;
-}
-
 /*
  * 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).
index b815cd1943d1a534d5b05e0c35a169848f06be09..902663f3da04724ceac16ae146cbb05c34948e82 100644 (file)
@@ -72,7 +72,6 @@ extern const char *lxc_global_config_value(const char *option_name);
 
 /* open a file with O_CLOEXEC */
 extern void remove_trailing_slashes(char *p);
-extern FILE *fopen_cloexec(const char *path, const char *mode);
 extern int setproctitle(char *title);
 
 #endif /* __LXC_INITUTILS_H */
index 6113adc2e708415708d0ed23b95f6700379b2337..ee94d5f93aef40aac79039650f85c5f24e4abc43 100644 (file)
 #define NSFS_MAGIC 0x6e736673
 #endif
 
+/* 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
+
 /* Useful macros */
 /* Maximum number for 64 bit integer is a string with 21 digits: 2^64 - 1 = 21 */
 #define LXC_NUMSTRLEN64 21
@@ -222,4 +231,13 @@ extern int __build_bug_on_failed;
 #define MS_SLAVE (1 << 19)
 #endif
 
+/* open */
+#ifndef O_PATH
+#define O_PATH      010000000
+#endif
+
+#ifndef O_NOFOLLOW
+#define O_NOFOLLOW  00400000
+#endif
+
 #endif /* __LXC_MACRO_H */
index cd3110377535752dd056d47256ba7b7175072999..d1d7cf8e15a4560fa5840b3b3a1770d6263b505c 100644 (file)
@@ -139,55 +139,3 @@ int lxc_file_for_each_line(const char *file, lxc_file_cb callback, void *data)
        fclose(f);
        return err;
 }
-
-int lxc_char_left_gc(const char *buffer, size_t len)
-{
-       size_t i;
-
-       for (i = 0; i < len; i++) {
-               if (buffer[i] == ' ' ||
-                   buffer[i] == '\t')
-                       continue;
-
-               return i;
-       }
-
-       return 0;
-}
-
-int lxc_char_right_gc(const char *buffer, size_t len)
-{
-       int i;
-
-       for (i = len - 1; i >= 0; i--) {
-               if (buffer[i] == ' '  ||
-                   buffer[i] == '\t' ||
-                   buffer[i] == '\n' ||
-                   buffer[i] == '\0')
-                       continue;
-
-               return i + 1;
-       }
-
-       return 0;
-}
-
-char *lxc_trim_whitespace_in_place(char *buffer)
-{
-       buffer += lxc_char_left_gc(buffer, strlen(buffer));
-       buffer[lxc_char_right_gc(buffer, strlen(buffer))] = '\0';
-       return buffer;
-}
-
-int lxc_is_line_empty(const char *line)
-{
-       int i;
-       size_t len = strlen(line);
-
-       for (i = 0; i < len; i++)
-               if (line[i] != ' ' && line[i] != '\t' &&
-                   line[i] != '\n' && line[i] != '\r' &&
-                   line[i] != '\f' && line[i] != '\0')
-                       return 0;
-       return 1;
-}
index 9809e9cec09416f01e04638217e33810523d3522..913472740960baf6f3cee6e71f361f8bda95234f 100644 (file)
@@ -37,14 +37,6 @@ extern int lxc_file_for_each_line(const char *file, lxc_file_cb callback,
 extern int lxc_file_for_each_line_mmap(const char *file, lxc_file_cb callback,
                                       void *data);
 
-extern int lxc_char_left_gc(const char *buffer, size_t len);
-
-extern int lxc_char_right_gc(const char *buffer, size_t len);
-
-extern char *lxc_trim_whitespace_in_place(char *buffer);
-
-extern int lxc_is_line_empty(const char *line);
-
 /* mmap() wrapper. lxc_strmmap() will take care to \0-terminate files so that
  * normal string-handling functions can be used on the buffer. */
 extern void *lxc_strmmap(void *addr, size_t length, int prot, int flags, int fd,
diff --git a/src/lxc/string_utils.c b/src/lxc/string_utils.c
new file mode 100644 (file)
index 0000000..e5e8183
--- /dev/null
@@ -0,0 +1,983 @@
+/* liblxcapi
+ *
+ * Copyright © 2018 Christian Brauner <christian.brauner@ubuntu.com>.
+ * Copyright © 2018 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "log.h"
+#include "lxclock.h"
+#include "namespace.h"
+#include "parse.h"
+#include "string_utils.h"
+#include "utils.h"
+
+#ifndef HAVE_STRLCPY
+#include "include/strlcpy.h"
+#endif
+
+#ifndef HAVE_STRLCAT
+#include "include/strlcat.h"
+#endif
+
+#ifndef NO_LOG
+lxc_log_define(string_utils, lxc);
+#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);
+}
+
+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;
+       size_t buf_len;
+
+       /* calculate new string length */
+       for (p = (char **)parts; *p; p++)
+               result_len += (p > (char **)parts) * sep_len + strlen(*p);
+
+       buf_len = result_len + 1;
+       result = calloc(buf_len, 1);
+       if (!result)
+               return NULL;
+
+       if (use_as_prefix)
+               (void)strlcpy(result, sep, buf_len);
+
+       for (p = (char **)parts; *p; p++) {
+               if (p > (char **)parts)
+                       (void)strlcat(result, sep, buf_len);
+
+               (void)strlcat(result, *p, buf_len);
+       }
+
+       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;
+       char sep[2] = { _sep, '\0' };
+       size_t len;
+
+       if (!haystack || !needle)
+               return 0;
+
+       len = strlen(haystack);
+       str = alloca(len + 1);
+       (void)strlcpy(str, haystack, len + 1);
+
+       lxc_iterate_parts(token, str, sep)
+               if (strcmp(needle, token) == 0)
+                       return 1;
+
+       return 0;
+}
+
+char **lxc_string_split(const char *string, char _sep)
+{
+       char *token, *str;
+       char sep[2] = {_sep, '\0'};
+       char **tmp = NULL, **result = NULL;
+       size_t result_capacity = 0;
+       size_t result_count = 0;
+       int r, saved_errno;
+       size_t len;
+
+       if (!string)
+               return calloc(1, sizeof(char *));
+
+       len = strlen(string);
+       str = alloca(len + 1);
+       (void)strlcpy(str, string, len + 1);
+
+       lxc_iterate_parts(token, str, sep) {
+               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;
+       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;
+       size_t len;
+
+       if (!string)
+               return calloc(1, sizeof(char *));
+
+       len = strlen(string);
+       str = alloca(len + 1);
+       (void)strlcpy(str, string, len + 1);
+
+       lxc_iterate_parts(token, str, sep) {
+               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;
+}
+
+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;
+}
+
+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_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_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;
+       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;
+}
+
+char *must_concat(const char *first, ...)
+{
+       va_list args;
+       char *cur, *dest;
+       size_t cur_len, it_len;
+
+       dest = must_copy_string(first);
+       cur_len = it_len = strlen(first);
+
+       va_start(args, first);
+       while ((cur = va_arg(args, char *)) != NULL) {
+               it_len = strlen(cur);
+
+               dest = must_realloc(dest, cur_len + it_len + 1);
+
+               (void)memcpy(dest + cur_len, cur, it_len);
+               cur_len += it_len;
+       }
+       va_end(args);
+
+       dest[cur_len] = 0;
+       return dest;
+}
+
+char *must_make_path(const char *first, ...)
+{
+       va_list args;
+       char *cur, *dest;
+       size_t full_len = strlen(first);
+       size_t buf_len;
+
+       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++;
+
+               buf_len = full_len + 1;
+               dest = must_realloc(dest, buf_len);
+
+               if (cur[0] != '/')
+                       (void)strlcat(dest, "/", buf_len);
+               (void)strlcat(dest, cur, buf_len);
+       }
+       va_end(args);
+
+       return dest;
+}
+
+char *must_append_path(char *first, ...)
+{
+       char *cur;
+       size_t full_len;
+       va_list args;
+       char *dest = first;
+       size_t buf_len;
+
+       full_len = strlen(first);
+       va_start(args, first);
+       while ((cur = va_arg(args, char *)) != NULL) {
+               full_len += strlen(cur);
+               if (cur[0] != '/')
+                       full_len++;
+
+               buf_len = full_len + 1;
+               dest = must_realloc(dest, buf_len);
+
+               if (cur[0] != '/')
+                       (void)strlcat(dest, "/", buf_len);
+               (void)strlcat(dest, cur, buf_len);
+       }
+       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;
+}
+
+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;
+}
+
+void remove_trailing_newlines(char *l)
+{
+       char *p = l;
+
+       while (*p)
+               p++;
+
+       while (--p >= l && *p == '\n')
+               *p = '\0';
+}
+
+int lxc_char_left_gc(const char *buffer, size_t len)
+{
+       size_t i;
+
+       for (i = 0; i < len; i++) {
+               if (buffer[i] == ' ' ||
+                   buffer[i] == '\t')
+                       continue;
+
+               return i;
+       }
+
+       return 0;
+}
+
+int lxc_char_right_gc(const char *buffer, size_t len)
+{
+       int i;
+
+       for (i = len - 1; i >= 0; i--) {
+               if (buffer[i] == ' '  ||
+                   buffer[i] == '\t' ||
+                   buffer[i] == '\n' ||
+                   buffer[i] == '\0')
+                       continue;
+
+               return i + 1;
+       }
+
+       return 0;
+}
+
+char *lxc_trim_whitespace_in_place(char *buffer)
+{
+       buffer += lxc_char_left_gc(buffer, strlen(buffer));
+       buffer[lxc_char_right_gc(buffer, strlen(buffer))] = '\0';
+       return buffer;
+}
+
+int lxc_is_line_empty(const char *line)
+{
+       int i;
+       size_t len = strlen(line);
+
+       for (i = 0; i < len; i++)
+               if (line[i] != ' ' && line[i] != '\t' &&
+                   line[i] != '\n' && line[i] != '\r' &&
+                   line[i] != '\f' && line[i] != '\0')
+                       return 0;
+       return 1;
+}
diff --git a/src/lxc/string_utils.h b/src/lxc/string_utils.h
new file mode 100644 (file)
index 0000000..c1155f6
--- /dev/null
@@ -0,0 +1,131 @@
+/* liblxcapi
+ *
+ * Copyright © 2018 Christian Brauner <christian.brauner@ubuntu.com>.
+ * Copyright © 2018 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __LXC_STRING_UTILS_H
+#define __LXC_STRING_UTILS_H
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <linux/loop.h>
+#include <linux/magic.h>
+#include <linux/types.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+
+#ifdef HAVE_LINUX_MEMFD_H
+#include <linux/memfd.h>
+#endif
+
+#include "initutils.h"
+#include "macro.h"
+
+/* convert variadic argument lists to arrays (for execl type argument lists) */
+extern char **lxc_va_arg_list_to_argv(va_list ap, size_t skip, int do_strdup);
+extern const char **lxc_va_arg_list_to_argv_const(va_list ap, size_t skip);
+
+/*
+ * Some simple string functions; if they return pointers, they are allocated
+ * buffers.
+ */
+extern char *lxc_string_replace(const char *needle, const char *replacement,
+                               const char *haystack);
+extern bool lxc_string_in_array(const char *needle, const char **haystack);
+extern char *lxc_string_join(const char *sep, const char **parts,
+                            bool use_as_prefix);
+/*
+ * Normalize and split path: Leading and trailing / are removed, multiple
+ * / are compactified, .. and . are resolved (.. on the top level is considered
+ * identical to .).
+ * Examples:
+ *     /            ->   { NULL }
+ *     foo/../bar   ->   { bar, NULL }
+ *     ../../       ->   { NULL }
+ *     ./bar/baz/.. ->   { bar, NULL }
+ *     foo//bar     ->   { foo, bar, NULL }
+ */
+extern char **lxc_normalize_path(const char *path);
+
+/* remove multiple slashes from the path, e.g. ///foo//bar -> /foo/bar */
+extern char *lxc_deslashify(const char *path);
+extern char *lxc_append_paths(const char *first, const char *second);
+
+/*
+ * Note: the following two functions use strtok(), so they will never
+ *       consider an empty element, even if two delimiters are next to
+ *       each other.
+ */
+extern bool lxc_string_in_list(const char *needle, const char *haystack,
+                              char sep);
+extern char **lxc_string_split(const char *string, char sep);
+extern char **lxc_string_split_and_trim(const char *string, char sep);
+extern char **lxc_string_split_quoted(char *string);
+
+/* Append string to NULL-terminated string array. */
+extern int lxc_append_string(char ***list, char *entry);
+
+/* Some simple array manipulation utilities */
+typedef void (*lxc_free_fn)(void *);
+typedef void *(*lxc_dup_fn)(void *);
+extern int lxc_grow_array(void ***array, size_t *capacity, size_t new_size,
+                         size_t capacity_increment);
+extern void lxc_free_array(void **array, lxc_free_fn element_free_fn);
+extern size_t lxc_array_len(void **array);
+
+extern void **lxc_append_null_to_array(void **array, size_t count);
+extern void remove_trailing_newlines(char *l);
+
+/* Helper functions to parse numbers. */
+extern int lxc_safe_uint(const char *numstr, unsigned int *converted);
+extern int lxc_safe_int(const char *numstr, int *converted);
+extern int lxc_safe_long(const char *numstr, long int *converted);
+extern int lxc_safe_long_long(const char *numstr, long long int *converted);
+extern int lxc_safe_ulong(const char *numstr, unsigned long *converted);
+extern int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base);
+/* Handles B, kb, MB, GB. Detects overflows and reports -ERANGE. */
+extern int parse_byte_size_string(const char *s, int64_t *converted);
+
+/*
+ * Concatenate all passed-in strings into one path. Do not fail. If any piece
+ * is not prefixed with '/', add a '/'.
+ */
+__attribute__((sentinel)) extern char *must_concat(const char *first, ...);
+__attribute__((sentinel)) extern char *must_make_path(const char *first, ...);
+__attribute__((sentinel)) extern char *must_append_path(char *first, ...);
+
+/* Return copy of string @entry. Do not fail. */
+extern char *must_copy_string(const char *entry);
+
+/* Re-alllocate a pointer, do not fail */
+extern void *must_realloc(void *orig, size_t sz);
+
+extern int lxc_char_left_gc(const char *buffer, size_t len);
+
+extern int lxc_char_right_gc(const char *buffer, size_t len);
+
+extern char *lxc_trim_whitespace_in_place(char *buffer);
+
+extern int lxc_is_line_empty(const char *line);
+
+#endif /* __LXC_STRING_UTILS_H */
index 22c72272fb61841a98c4cbad04cc20a64e414ab8..58dd223a976ab793a1c5c7ca4afcb565d5a99701 100644 (file)
@@ -166,15 +166,6 @@ static int _recursive_rmdir(const char *dirname, dev_t pdev,
        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()
  */
@@ -327,47 +318,6 @@ 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)
-               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;
-}
-
 #if HAVE_LIBGNUTLS
 #include <gnutls/gnutls.h>
 #include <gnutls/crypto.h>
@@ -438,52 +388,6 @@ int sha1sum_file(char *fnam, unsigned char *digest)
 }
 #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;
@@ -598,539 +502,6 @@ int lxc_pclose(struct lxc_popen_FILE *fp)
        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;
-       size_t buf_len;
-
-       /* calculate new string length */
-       for (p = (char **)parts; *p; p++)
-               result_len += (p > (char **)parts) * sep_len + strlen(*p);
-
-       buf_len = result_len + 1;
-       result = calloc(buf_len, 1);
-       if (!result)
-               return NULL;
-
-       if (use_as_prefix)
-               (void)strlcpy(result, sep, buf_len);
-
-       for (p = (char **)parts; *p; p++) {
-               if (p > (char **)parts)
-                       (void)strlcat(result, sep, buf_len);
-
-               (void)strlcat(result, *p, buf_len);
-       }
-
-       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;
-       char sep[2] = { _sep, '\0' };
-       size_t len;
-
-       if (!haystack || !needle)
-               return 0;
-
-       len = strlen(haystack);
-       str = alloca(len + 1);
-       (void)strlcpy(str, haystack, len + 1);
-
-       lxc_iterate_parts(token, str, sep)
-               if (strcmp(needle, token) == 0)
-                       return 1;
-
-       return 0;
-}
-
-char **lxc_string_split(const char *string, char _sep)
-{
-       char *token, *str;
-       char sep[2] = {_sep, '\0'};
-       char **tmp = NULL, **result = NULL;
-       size_t result_capacity = 0;
-       size_t result_count = 0;
-       int r, saved_errno;
-       size_t len;
-
-       if (!string)
-               return calloc(1, sizeof(char *));
-
-       len = strlen(string);
-       str = alloca(len + 1);
-       (void)strlcpy(str, string, len + 1);
-
-       lxc_iterate_parts(token, str, sep) {
-               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;
-       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;
-       size_t len;
-
-       if (!string)
-               return calloc(1, sizeof(char *));
-
-       len = strlen(string);
-       str = alloca(len + 1);
-       (void)strlcpy(str, string, len + 1);
-
-       lxc_iterate_parts(token, str, sep) {
-               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, mode_t mode)
-{
-       int fd, saved_errno;
-       ssize_t ret;
-
-       fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
-       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 = lxc_read_nointr(fd, buf2, 100)) > 0)
-                       count2 += ret;
-
-               if (ret >= 0)
-                       ret = count2;
-       } else {
-               memset(buf, 0, count);
-               ret = lxc_read_nointr(fd, buf, count);
-       }
-
-       if (ret < 0)
-               SYSERROR("Read %s", filename);
-
-       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)
 {
        /*
@@ -1268,7 +639,8 @@ int detect_shared_rootfs(void)
        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];
 
@@ -1341,7 +713,8 @@ bool detect_ramfs_rootfs(void)
        return false;
 }
 
-char *on_path(const char *cmd, const char *rootfs) {
+char *on_path(const char *cmd, const char *rootfs)
+{
        char *entry = NULL, *path = NULL;
        char cmdpath[MAXPATHLEN];
        int ret;
@@ -1354,9 +727,10 @@ char *on_path(const char *cmd, const char *rootfs) {
        if (!path)
                return NULL;
 
-       lxc_iterate_parts(entry, path, ":") {
+       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)
@@ -1372,13 +746,6 @@ char *on_path(const char *cmd, const char *rootfs) {
        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");
@@ -1480,34 +847,6 @@ out1:
        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;
-
-       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
@@ -1919,29 +1258,6 @@ int null_stdfds(void)
        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 (6 + (LXC_NUMSTRLEN64) + 7 + 1)
@@ -1986,44 +1302,6 @@ 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;
@@ -2046,141 +1324,6 @@ int lxc_preserve_ns(const int pid, const char *ns)
        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_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;
-       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) {
@@ -2426,143 +1569,6 @@ int run_command(char *buf, size_t buf_size, int (*child_fn)(void *), void *args)
        return fret;
 }
 
-char *must_concat(const char *first, ...)
-{
-       va_list args;
-       char *cur, *dest;
-       size_t cur_len, it_len;
-
-       dest = must_copy_string(first);
-       cur_len = it_len = strlen(first);
-
-       va_start(args, first);
-       while ((cur = va_arg(args, char *)) != NULL) {
-               it_len = strlen(cur);
-
-               dest = must_realloc(dest, cur_len + it_len + 1);
-
-               (void)memcpy(dest + cur_len, cur, it_len);
-               cur_len += it_len;
-       }
-       va_end(args);
-
-       dest[cur_len] = 0;
-       return dest;
-}
-
-char *must_make_path(const char *first, ...)
-{
-       va_list args;
-       char *cur, *dest;
-       size_t full_len = strlen(first);
-       size_t buf_len;
-
-       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++;
-
-               buf_len = full_len + 1;
-               dest = must_realloc(dest, buf_len);
-
-               if (cur[0] != '/')
-                       (void)strlcat(dest, "/", buf_len);
-               (void)strlcat(dest, cur, buf_len);
-       }
-       va_end(args);
-
-       return dest;
-}
-
-char *must_append_path(char *first, ...)
-{
-       char *cur;
-       size_t full_len;
-       va_list args;
-       char *dest = first;
-       size_t buf_len;
-
-       full_len = strlen(first);
-       va_start(args, first);
-       while ((cur = va_arg(args, char *)) != NULL) {
-               full_len += strlen(cur);
-               if (cur[0] != '/')
-                       full_len++;
-
-               buf_len = full_len + 1;
-               dest = must_realloc(dest, buf_len);
-
-               if (cur[0] != '/')
-                       (void)strlcat(dest, "/", buf_len);
-               (void)strlcat(dest, cur, buf_len);
-       }
-       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 fhas_fs_type(int fd, fs_type_magic magic_val)
-{
-       int ret;
-       struct statfs sb;
-
-       ret = fstatfs(fd, &sb);
-       if (ret < 0)
-               return false;
-
-       return is_fs_type(&sb, magic_val);
-}
-
 bool lxc_nic_exists(char *nic)
 {
 #define __LXC_SYS_CLASS_NET_LEN 15 + IFNAMSIZ + 1
@@ -2584,91 +1590,6 @@ bool lxc_nic_exists(char *nic)
        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
@@ -2714,17 +1635,6 @@ int lxc_set_death_signal(int signal)
        return 0;
 }
 
-void remove_trailing_newlines(char *l)
-{
-       char *p = l;
-
-       while (*p)
-               p++;
-
-       while (--p >= l && *p == '\n')
-               *p = '\0';
-}
-
 int fd_cloexec(int fd, bool cloexec)
 {
        int oflags, nflags;
index 920f82faf826eee04ca9ef681f0121603b1fe6d9..f2d802991f8f6d5597175acbb188e21704f5aa11 100644 (file)
@@ -34,7 +34,6 @@
 #include <stdbool.h>
 #include <unistd.h>
 #include <linux/loop.h>
-#include <linux/magic.h>
 #include <linux/types.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
 #include <linux/memfd.h>
 #endif
 
+#include "file_utils.h"
 #include "initutils.h"
 #include "macro.h"
+#include "string_utils.h"
 
 /* returns 1 on success, 0 if there were any failures */
 extern int lxc_rmdir_onedev(const char *path, const char *exclude);
@@ -281,70 +282,11 @@ extern int lxc_pclose(struct lxc_popen_FILE *fp);
 extern int wait_for_pid(pid_t pid);
 extern int lxc_wait_for_pid_status(pid_t pid);
 
-/* send and receive buffers completely */
-extern ssize_t lxc_write_nointr(int fd, const void *buf, size_t count);
-extern ssize_t lxc_read_nointr(int fd, void *buf, size_t count);
-extern ssize_t lxc_read_nointr_expect(int fd, void *buf, size_t count,
-                                     const void *expected_buf);
 #if HAVE_LIBGNUTLS
 #define SHA_DIGEST_LENGTH 20
 extern int sha1sum_file(char *fnam, unsigned char *md_value);
 #endif
 
-/* read and write whole files */
-extern int lxc_write_to_file(const char *filename, const void *buf,
-                            size_t count, bool add_newline, mode_t mode);
-extern int lxc_read_from_file(const char *filename, void *buf, size_t count);
-
-/* convert variadic argument lists to arrays (for execl type argument lists) */
-extern char** lxc_va_arg_list_to_argv(va_list ap, size_t skip, int do_strdup);
-extern const char** lxc_va_arg_list_to_argv_const(va_list ap, size_t skip);
-
-/* Some simple string functions; if they return pointers, they are allocated
- * buffers.
- */
-extern char *lxc_string_replace(const char *needle, const char *replacement,
-                               const char *haystack);
-extern bool lxc_string_in_array(const char *needle, const char **haystack);
-extern char *lxc_string_join(const char *sep, const char **parts,
-                            bool use_as_prefix);
-/* Normalize and split path: Leading and trailing / are removed, multiple
- * / are compactified, .. and . are resolved (.. on the top level is considered
- * identical to .).
- * Examples:
- *     /            ->   { NULL }
- *     foo/../bar   ->   { bar, NULL }
- *     ../../       ->   { NULL }
- *     ./bar/baz/.. ->   { bar, NULL }
- *     foo//bar     ->   { foo, bar, NULL }
- */
-extern char **lxc_normalize_path(const char *path);
-/* remove multiple slashes from the path, e.g. ///foo//bar -> /foo/bar */
-extern char *lxc_deslashify(const char *path);
-extern char *lxc_append_paths(const char *first, const char *second);
-/* Note: the following two functions use strtok(), so they will never
- *       consider an empty element, even if two delimiters are next to
- *       each other.
- */
-extern bool lxc_string_in_list(const char *needle, const char *haystack,
-                              char sep);
-extern char **lxc_string_split(const char *string, char sep);
-extern char **lxc_string_split_and_trim(const char *string, char sep);
-extern char **lxc_string_split_quoted(char *string);
-/* Append string to NULL-terminated string array. */
-extern int lxc_append_string(char ***list, char *entry);
-
-/* some simple array manipulation utilities */
-typedef void (*lxc_free_fn)(void *);
-typedef void *(*lxc_dup_fn)(void *);
-extern int lxc_grow_array(void ***array, size_t *capacity, size_t new_size,
-                         size_t capacity_increment);
-extern void lxc_free_array(void **array, lxc_free_fn element_free_fn);
-extern size_t lxc_array_len(void **array);
-
-extern void **lxc_append_null_to_array(void **array, size_t count);
-extern void remove_trailing_newlines(char *l);
-
 /* initialize rand with urandom */
 extern int randseed(bool);
 
@@ -396,12 +338,9 @@ extern bool is_shared_mountpoint(const char *path);
 extern int detect_shared_rootfs(void);
 extern bool detect_ramfs_rootfs(void);
 extern char *on_path(const char *cmd, const char *rootfs);
-extern bool file_exists(const char *f);
 extern bool cgns_supported(void);
 extern char *choose_init(const char *rootfs);
-extern int print_to_file(const char *file, const char *content);
 extern bool switch_to_ns(pid_t pid, const char *ns);
-extern int is_dir(const char *path);
 extern char *get_template_path(const char *t);
 extern int safe_mount(const char *src, const char *dest, const char *fstype,
                      unsigned long flags, const void *data,
@@ -410,22 +349,11 @@ extern int lxc_mount_proc_if_needed(const char *rootfs);
 extern int open_devnull(void);
 extern int set_stdfds(int fd);
 extern int null_stdfds(void);
-extern int lxc_count_file_lines(const char *fn);
 extern int lxc_preserve_ns(const int pid, const char *ns);
 
 /* Check whether a signal is blocked by a process. */
 extern bool task_blocks_signal(pid_t pid, int signal);
 
-/* Helper functions to parse numbers. */
-extern int lxc_safe_uint(const char *numstr, unsigned int *converted);
-extern int lxc_safe_int(const char *numstr, int *converted);
-extern int lxc_safe_long(const char *numstr, long int *converted);
-extern int lxc_safe_long_long(const char *numstr, long long int *converted);
-extern int lxc_safe_ulong(const char *numstr, unsigned long *converted);
-extern int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base);
-/* Handles B, kb, MB, GB. Detects overflows and reports -ERANGE. */
-extern int parse_byte_size_string(const char *s, int64_t *converted);
-
 /* Switch to a new uid and gid. */
 extern int lxc_switch_uid_gid(uid_t uid, gid_t gid);
 extern int lxc_setgroups(int size, gid_t list[]);
@@ -468,13 +396,7 @@ extern char *must_copy_string(const char *entry);
 /* Re-alllocate a pointer, do not fail */
 extern void *must_realloc(void *orig, size_t sz);
 
-/* __typeof__ should be safe to use with all compilers. */
-typedef __typeof__(((struct statfs *)NULL)->f_type) fs_type_magic;
-extern bool has_fs_type(const char *path, fs_type_magic magic_val);
-extern bool fhas_fs_type(int fd, fs_type_magic magic_val);
-extern bool is_fs_type(const struct statfs *fs, fs_type_magic magic_val);
 extern bool lxc_nic_exists(char *nic);
-extern int lxc_make_tmpfile(char *template, bool rm);
 
 static inline uint64_t lxc_getpagesize(void)
 {