Hello community, here is the log from the commit of package lxcfs for openSUSE:Factory checked in at 2016-09-05 21:21:50 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/lxcfs (Old) and /work/SRC/openSUSE:Factory/.lxcfs.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "lxcfs" Changes: -------- --- /work/SRC/openSUSE:Factory/lxcfs/lxcfs.changes 2016-08-03 11:43:10.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.lxcfs.new/lxcfs.changes 2016-09-05 21:23:13.000000000 +0200 @@ -1,0 +2,34 @@ +Wed Aug 31 11:43:16 UTC 2016 - [email protected] + +- update lxcfs to 2.0.3 +- add 0001-Fix-test_reload-for-lxcfs-chroot.patch +- add 0002-Virtualize-more-of-the-meminfo-fields.patch +- add 0003-pam-fix-race-in-cgroup-creation.patch +- add 0004-meminfo-don-t-show-negative-swapfree.patch +- add 0005-bindings-improve-debugging.patch +- add 0006-bindings-use-openat-fd-for-fstatat-unlinkat.patch +- add 0007-bindings-close-open-fds-on-error.patch +- add 0008-bindings-grant-access-to-var-lib-lxcfs.patch +- add 0009-bindings-enable-access-to-var-lib-lxcfs-cgroup.patch +- add 0010-bindings-allow-access-to-var-lib-lxcfs-proc.patch +- add 0011-lxcfs-bindings-show-.-and-.-dir-entries.patch +- add 0012-lxcfs-better-fs-behavior-on-var-lib-lxcfs.patch +- add 0013-bindings-non-functional-changes.patch +- add 0014-bindings-set-errno-in-pick_controller_from_path.patch +- add 0015-bindings-more-consistent-fs-behavior.patch +- add 0016-add-pld-linux-support.patch +- add 0017-don-t-use-argv-0-in-usage-output.patch +- add 0018-bindings-revert-cgroup-check.patch +- add 0019-bindings-improve-returned-errnos.patch +- add 0020-bindings-make-rmdir-behave-more-consistently.patch +- add 0021-libtool-do-not-link-lxcfs-against-liblxcfs.patch +- add 0022-bindings-lxcfs-improve-debugging.patch +- add 0023-bindings-fix-debug-macro.patch +- add 0024-bindings-restore-original-working-directory.patch + +------------------------------------------------------------------- +Wed Aug 31 11:37:18 UTC 2016 - [email protected] + +- remove 0001-skip-empty-entries-under-proc-self-cgroup.patch + +------------------------------------------------------------------- Old: ---- 0001-skip-empty-entries-under-proc-self-cgroup.patch lxcfs-2.0.2.tar.gz New: ---- 0001-Fix-test_reload-for-lxcfs-chroot.patch 0002-Virtualize-more-of-the-meminfo-fields.patch 0003-pam-fix-race-in-cgroup-creation.patch 0004-meminfo-don-t-show-negative-swapfree.patch 0005-bindings-improve-debugging.patch 0006-bindings-use-openat-fd-for-fstatat-unlinkat.patch 0007-bindings-close-open-fds-on-error.patch 0008-bindings-grant-access-to-var-lib-lxcfs.patch 0009-bindings-enable-access-to-var-lib-lxcfs-cgroup.patch 0010-bindings-allow-access-to-var-lib-lxcfs-proc.patch 0011-lxcfs-bindings-show-.-and-.-dir-entries.patch 0012-lxcfs-better-fs-behavior-on-var-lib-lxcfs.patch 0013-bindings-non-functional-changes.patch 0014-bindings-set-errno-in-pick_controller_from_path.patch 0015-bindings-more-consistent-fs-behavior.patch 0016-add-pld-linux-support.patch 0017-don-t-use-argv-0-in-usage-output.patch 0018-bindings-revert-cgroup-check.patch 0019-bindings-improve-returned-errnos.patch 0020-bindings-make-rmdir-behave-more-consistently.patch 0021-libtool-do-not-link-lxcfs-against-liblxcfs.patch 0022-bindings-lxcfs-improve-debugging.patch 0023-bindings-fix-debug-macro.patch 0024-bindings-restore-original-working-directory.patch lxcfs-2.0.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ lxcfs.spec ++++++ --- /var/tmp/diff_new_pack.a6dM7z/_old 2016-09-05 21:23:15.000000000 +0200 +++ /var/tmp/diff_new_pack.a6dM7z/_new 2016-09-05 21:23:15.000000000 +0200 @@ -15,19 +15,46 @@ # Please submit bugfixes or comments via http://bugs.opensuse.org/ # + Name: lxcfs -Version: 2.0.2 +Version: 2.0.3 Release: 0 -License: Apache-2.0 Summary: FUSE filesystem for LXC -Url: http://linuxcontainers.org +License: Apache-2.0 Group: System/Management +Url: http://linuxcontainers.org Source: https://linuxcontainers.org/downloads/%{name}/%{name}-%{version}.tar.gz -Patch: 0001-skip-empty-entries-under-proc-self-cgroup.patch +Patch0001: 0001-Fix-test_reload-for-lxcfs-chroot.patch +Patch0002: 0002-Virtualize-more-of-the-meminfo-fields.patch +Patch0003: 0003-pam-fix-race-in-cgroup-creation.patch +Patch0004: 0004-meminfo-don-t-show-negative-swapfree.patch +Patch0005: 0005-bindings-improve-debugging.patch +Patch0006: 0006-bindings-use-openat-fd-for-fstatat-unlinkat.patch +Patch0007: 0007-bindings-close-open-fds-on-error.patch +Patch0008: 0008-bindings-grant-access-to-var-lib-lxcfs.patch +Patch0009: 0009-bindings-enable-access-to-var-lib-lxcfs-cgroup.patch +Patch0010: 0010-bindings-allow-access-to-var-lib-lxcfs-proc.patch +Patch0011: 0011-lxcfs-bindings-show-.-and-.-dir-entries.patch +Patch0012: 0012-lxcfs-better-fs-behavior-on-var-lib-lxcfs.patch +Patch0013: 0013-bindings-non-functional-changes.patch +Patch0014: 0014-bindings-set-errno-in-pick_controller_from_path.patch +Patch0015: 0015-bindings-more-consistent-fs-behavior.patch +Patch0016: 0016-add-pld-linux-support.patch +Patch0017: 0017-don-t-use-argv-0-in-usage-output.patch +Patch0018: 0018-bindings-revert-cgroup-check.patch +Patch0019: 0019-bindings-improve-returned-errnos.patch +Patch0020: 0020-bindings-make-rmdir-behave-more-consistently.patch +Patch0021: 0021-libtool-do-not-link-lxcfs-against-liblxcfs.patch +Patch0022: 0022-bindings-lxcfs-improve-debugging.patch +Patch0023: 0023-bindings-fix-debug-macro.patch +Patch0024: 0024-bindings-restore-original-working-directory.patch +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: help2man +BuildRequires: libtool +BuildRequires: pam-devel BuildRequires: pkg-config BuildRequires: pkgconfig(fuse) -BuildRequires: pam-devel -BuildRequires: help2man BuildRoot: %{_tmppath}/%{name}-%{version}-build %description @@ -57,10 +84,34 @@ command line. %prep -%setup -q -%patch -p1 +%setup +%patch0001 -p1 +%patch0002 -p1 +%patch0003 -p1 +%patch0004 -p1 +%patch0005 -p1 +%patch0006 -p1 +%patch0007 -p1 +%patch0008 -p1 +%patch0009 -p1 +%patch0010 -p1 +%patch0011 -p1 +%patch0012 -p1 +%patch0013 -p1 +%patch0014 -p1 +%patch0015 -p1 +%patch0016 -p1 +%patch0017 -p1 +%patch0018 -p1 +%patch0019 -p1 +%patch0020 -p1 +%patch0021 -p1 +%patch0022 -p1 +%patch0023 -p1 +%patch0024 -p1 %build +autoreconf --force --install %configure --with-distro=suse make %{?_smp_mflags} @@ -117,3 +168,5 @@ %files -n pam_cgfs %defattr(-,root,root) /%{_lib}/security/pam_cgfs.so + +%changelog ++++++ 0001-Fix-test_reload-for-lxcfs-chroot.patch ++++++ >From ec2b5e7c6297a82914f59d7b49714beb5f8afeef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <[email protected]> Date: Tue, 16 Aug 2016 12:36:01 -0400 Subject: [PATCH 01/24] Fix test_reload for lxcfs chroot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <[email protected]> --- bindings.c | 10 +--------- tests/test_reload.sh | 8 ++++---- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/bindings.c b/bindings.c index 04f0b08..2fb4acf 100644 --- a/bindings.c +++ b/bindings.c @@ -3610,17 +3610,9 @@ out: #if RELOADTEST void iwashere(void) { - char *name, *cwd = get_current_dir_name(); - size_t len; int fd; - if (!cwd) - exit(1); - len = strlen(cwd) + strlen("/iwashere") + 1; - name = alloca(len); - snprintf(name, len, "%s/iwashere", cwd); - free(cwd); - fd = creat(name, 0755); + fd = creat("/tmp/lxcfs-iwashere", 0644); if (fd >= 0) close(fd); } diff --git a/tests/test_reload.sh b/tests/test_reload.sh index 5474cbb..5e37ace 100755 --- a/tests/test_reload.sh +++ b/tests/test_reload.sh @@ -26,7 +26,7 @@ cleanup() { umount -l ${testdir} fi rm -rf ${testdir} ${installdir} - rm -f iwashere + rm -f /tmp/lxcfs-iwashere rm -f ${pidfile} if [ ${FAILED} -eq 1 ]; then echo "liblxcfs.so reload test FAILED" @@ -50,9 +50,9 @@ while [ ! -d ${testdir}/proc ]; do count=$((count+1)) done -rm -f iwashere +rm -f /tmp/lxcfs-iwashere cat ${testdir}/proc/uptime -[ ! -f iwashere ] +[ ! -f /tmp/lxcfs-iwashere ] ( cd ${topdir}; make liblxcfstest.la @@ -65,5 +65,5 @@ cp ${libdir}/liblxcfstest.so ${libdir}/liblxcfs.so kill -USR1 ${lxcfspid} cat ${testdir}/proc/uptime -[ -f iwashere ] +[ -f /tmp/lxcfs-iwashere ] FAILED=0 -- 2.9.3 ++++++ 0002-Virtualize-more-of-the-meminfo-fields.patch ++++++ >From c6095b08bb3731f2b25fa2312e31da2d21b2b3eb Mon Sep 17 00:00:00 2001 From: Serge Hallyn <[email protected]> Date: Thu, 18 Aug 2016 00:03:51 -0500 Subject: [PATCH 02/24] Virtualize more of the meminfo fields The worst remaining offending line appears to be VmallocTotal. Suggestions for how to calculate that would be appreciated. Closes #119 Signed-off-by: Serge Hallyn <[email protected]> --- bindings.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/bindings.c b/bindings.c index 2fb4acf..1fa1027 100644 --- a/bindings.c +++ b/bindings.c @@ -2943,16 +2943,32 @@ static bool startswith(const char *line, const char *pref) return false; } -static void get_mem_cached(char *memstat, unsigned long *v) +static void parse_memstat(char *memstat, unsigned long *cached, + unsigned long *active_anon, unsigned long *inactive_anon, + unsigned long *active_file, unsigned long *inactive_file, + unsigned long *unevictable) { char *eol; - *v = 0; while (*memstat) { - if (startswith(memstat, "total_cache")) { - sscanf(memstat + 11, "%lu", v); - *v /= 1024; - return; + if (startswith(memstat, "cache")) { + sscanf(memstat + 11, "%lu", cached); + *cached /= 1024; + } else if (startswith(memstat, "active_anon")) { + sscanf(memstat + 11, "%lu", active_anon); + *active_anon /= 1024; + } else if (startswith(memstat, "inactive_anon")) { + sscanf(memstat + 11, "%lu", inactive_anon); + *inactive_anon /= 1024; + } else if (startswith(memstat, "active_file")) { + sscanf(memstat + 11, "%lu", active_file); + *active_file /= 1024; + } else if (startswith(memstat, "inactive_file")) { + sscanf(memstat + 11, "%lu", inactive_file); + *inactive_file /= 1024; + } else if (startswith(memstat, "unevictable")) { + sscanf(memstat + 11, "%lu", unevictable); + *unevictable /= 1024; } eol = strchr(memstat, '\n'); if (!eol) @@ -3069,7 +3085,8 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset, *memswlimit_str = NULL, *memswusage_str = NULL, *memswlimit_default_str = NULL, *memswusage_default_str = NULL; unsigned long memlimit = 0, memusage = 0, memswlimit = 0, memswusage = 0, - cached = 0, hosttotal = 0; + cached = 0, hosttotal = 0, active_anon = 0, inactive_anon = 0, + active_file = 0, inactive_file = 0, unevictable = 0; char *line = NULL; size_t linelen = 0, total_len = 0, rv = 0; char *cache = d->buf; @@ -3128,7 +3145,9 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset, memlimit /= 1024; memusage /= 1024; - get_mem_cached(memstat_str, &cached); + parse_memstat(memstat_str, &cached, &active_anon, + &inactive_anon, &active_file, &inactive_file, + &unevictable); f = fopen("/proc/meminfo", "r"); if (!f) @@ -3170,6 +3189,35 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset, } else if (startswith(line, "SwapCached:")) { snprintf(lbuf, 100, "SwapCached: %8lu kB\n", 0UL); printme = lbuf; + } else if (startswith(line, "Active")) { + snprintf(lbuf, 100, "Active: %8lu kB\n", + active_anon + active_file); + printme = lbuf; + } else if (startswith(line, "Inactive")) { + snprintf(lbuf, 100, "Inactive: %8lu kB\n", + inactive_anon + inactive_file); + printme = lbuf; + } else if (startswith(line, "Active(anon)")) { + snprintf(lbuf, 100, "Active(anon): %8lu kB\n", active_anon); + printme = lbuf; + } else if (startswith(line, "Inactive(anon)")) { + snprintf(lbuf, 100, "Inactive(anon): %8lu kB\n", inactive_anon); + printme = lbuf; + } else if (startswith(line, "Active(file)")) { + snprintf(lbuf, 100, "Active(file): %8lu kB\n", active_file); + printme = lbuf; + } else if (startswith(line, "Inactive(file)")) { + snprintf(lbuf, 100, "Inactive(file): %8lu kB\n", inactive_file); + printme = lbuf; + } else if (startswith(line, "Unevictable")) { + snprintf(lbuf, 100, "Unevictable: %8lu kB\n", unevictable); + printme = lbuf; + } else if (startswith(line, "SReclaimable")) { + snprintf(lbuf, 100, "SReclaimable: %8lu kB\n", 0UL); + printme = lbuf; + } else if (startswith(line, "SUnreclaim")) { + snprintf(lbuf, 100, "SUnreclaim: %8lu kB\n", 0UL); + printme = lbuf; } else printme = line; -- 2.9.3 ++++++ 0003-pam-fix-race-in-cgroup-creation.patch ++++++ >From 56ee748c3fd89752a6262471eb49d3b670bb3c09 Mon Sep 17 00:00:00 2001 From: Serge Hallyn <[email protected]> Date: Sun, 21 Aug 2016 13:26:42 -0500 Subject: [PATCH 03/24] pam: fix race in cgroup creation If we find that a cgroup already exists, we should 1. remove all the cgroups which we've created so far 2. set existed to true 3. return failure The caller should then detect that existed == true, and re-try with the next index. Signed-off-by: Serge Hallyn <[email protected]> --- pam/pam_cgfs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pam/pam_cgfs.c b/pam/pam_cgfs.c index 08f0694..24510e1 100644 --- a/pam/pam_cgfs.c +++ b/pam/pam_cgfs.c @@ -585,7 +585,7 @@ static bool cgfs_create_forone(struct controller *c, uid_t uid, gid_t gid, const #if DEBUG fprintf(stderr, "%s existed\n", path); #endif - return true; + return false; } bool pass = mkdir_p(c->mount_path, path); @@ -794,16 +794,16 @@ static int handle_login(const char *user) return PAM_SESSION_ERR; } + existed = false; if (!cgfs_create(cg, uid, gid, &existed)) { + if (existed) { + idx++; + continue; + } mysyslog(LOG_ERR, "Failed to create a cgroup for user %s\n", user); return PAM_SESSION_ERR; } - if (existed == 1) { - idx++; - continue; - } - if (!cgfs_enter(cg, false)) { mysyslog(LOG_ERR, "Failed to enter user cgroup %s for user %s\n", cg, user); return PAM_SESSION_ERR; -- 2.9.3 ++++++ 0004-meminfo-don-t-show-negative-swapfree.patch ++++++ >From b4665ce0c3b5bd6d2ceca843b52bd70ae5fb639a Mon Sep 17 00:00:00 2001 From: Serge Hallyn <[email protected]> Date: Sun, 21 Aug 2016 15:05:31 -0500 Subject: [PATCH 04/24] meminfo: don't show negative swapfree Also commonize some of the mem{,sw} free/used calculations. Closes #115 --- bindings.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bindings.c b/bindings.c index 2fb4acf..9bac10a 100644 --- a/bindings.c +++ b/bindings.c @@ -3155,8 +3155,10 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset, snprintf(lbuf, 100, "SwapTotal: %8lu kB\n", memswlimit - memlimit); printme = lbuf; } else if (startswith(line, "SwapFree:") && memswlimit > 0 && memswusage > 0) { - snprintf(lbuf, 100, "SwapFree: %8lu kB\n", - (memswlimit - memlimit) - (memswusage - memusage)); + unsigned long swaptotal = memswlimit - memlimit, + swapusage = memswusage - memusage, + swapfree = swapusage < swaptotal ? swaptotal - swapusage : 0; + snprintf(lbuf, 100, "SwapFree: %8lu kB\n", swapfree); printme = lbuf; } else if (startswith(line, "Slab:")) { snprintf(lbuf, 100, "Slab: %8lu kB\n", 0UL); @@ -3472,6 +3474,8 @@ static int proc_stat_read(char *buf, size_t size, off_t offset, char cpu_char[10]; /* That's a lot of cores */ char *c; + if (strlen(line) == 0) + continue; if (sscanf(line, "cpu%9[^ ]", cpu_char) != 1) { /* not a ^cpuN line containing a number N, just print it */ l = snprintf(cache, cache_size, "%s", line); -- 2.9.3 ++++++ 0005-bindings-improve-debugging.patch ++++++ >From 7dd6560a9b506c83c1a577e620ca0e81f0c6a9dd Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Wed, 24 Aug 2016 15:43:49 +0200 Subject: [PATCH 05/24] bindings: improve debugging - replace multiple DEBUG ifdefines with a single ifdefine at the top - ifdefine lxcfs_debug() macro function that expands to nothing when -DDEBUG is not given Signed-off-by: Christian Brauner <[email protected]> --- bindings.c | 62 ++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/bindings.c b/bindings.c index 916b43d..e3975cc 100644 --- a/bindings.c +++ b/bindings.c @@ -48,6 +48,16 @@ return -1; extern int pivot_root(const char * new_root, const char * put_old); #endif +#ifdef DEBUG +#define lxcfs_debug(format, ...) \ + do { \ + fprintf(stderr, "%s: %d: %s: " format, __FILE__, __LINE__, \ + __func__, __VA_ARGS__); \ + } while (false) +#else +#define lxcfs_debug(format, ...) +#endif /* DEBUG */ + enum { LXC_TYPE_CGDIR, LXC_TYPE_CGFILE, @@ -160,10 +170,10 @@ static bool initpid_still_valid(struct pidns_init_store *e, struct stat *nsfdsb) snprintf(fnam, 100, "/proc/%d", e->initpid); if (stat(fnam, &initsb) < 0) return false; -#if DEBUG - fprintf(stderr, "comparing ctime %ld %ld for pid %d\n", - e->ctime, initsb.st_ctime, e->initpid); -#endif + + lxcfs_debug("Comparing ctime %ld == %ld for pid %d.\n", e->ctime, + initsb.st_ctime, e->initpid); + if (e->ctime != initsb.st_ctime) return false; return true; @@ -175,9 +185,8 @@ static void remove_initpid(struct pidns_init_store *e) struct pidns_init_store *tmp; int h; -#if DEBUG - fprintf(stderr, "remove_initpid: removing entry for %d\n", e->initpid); -#endif + lxcfs_debug("Remove_initpid: removing entry for %d.\n", e->initpid); + h = HASH(e->ino); if (pidns_hash_table[h] == e) { pidns_hash_table[h] = e->next; @@ -212,18 +221,18 @@ static void prune_initpid_store(void) now = time(NULL); if (now < last_prune + PURGE_SECS) return; -#if DEBUG - fprintf(stderr, "pruning\n"); -#endif + + lxcfs_debug("%s\n", "Pruning."); + last_prune = now; threshold = now - 2 * PURGE_SECS; for (i = 0; i < PIDNS_HASH_SIZE; i++) { for (prev = NULL, e = pidns_hash_table[i]; e; ) { if (e->lastcheck < threshold) { -#if DEBUG - fprintf(stderr, "Removing cached entry for %d\n", e->initpid); -#endif + + lxcfs_debug("Removing cached entry for %d.\n", e->initpid); + delme = e; if (prev) prev->next = e->next; @@ -247,9 +256,8 @@ static void save_initpid(struct stat *sb, pid_t pid) struct stat procsb; int h; -#if DEBUG - fprintf(stderr, "save_initpid: adding entry for %d\n", pid); -#endif + lxcfs_debug("Save_initpid: adding entry for %d.\n", pid); + snprintf(fpath, 100, "/proc/%d", pid); if (stat(fpath, &procsb) < 0) return; @@ -577,9 +585,7 @@ static bool recursive_rmdir(const char *dirname, int fd) dir = fdopendir(dupfd); if (!dir) { -#if DEBUG - fprintf(stderr, "%s: failed to open %s: %s\n", __func__, dirname, strerror(errno)); -#endif + lxcfs_debug("Failed to open %s: %s.\n", dirname, strerror(errno)); return false; } @@ -602,18 +608,12 @@ static bool recursive_rmdir(const char *dirname, int fd) ret = fstatat(fd, pathname, &mystat, AT_SYMLINK_NOFOLLOW); if (ret) { -#if DEBUG - fprintf(stderr, "%s: failed to stat %s: %s\n", __func__, pathname, strerror(errno)); -#endif + lxcfs_debug("Failed to stat %s: %s.\n", pathname, strerror(errno)); continue; } - if (S_ISDIR(mystat.st_mode)) { - if (!recursive_rmdir(pathname, fd)) { -#if DEBUG - fprintf(stderr, "Error removing %s\n", pathname); -#endif - } - } + if (S_ISDIR(mystat.st_mode)) + if (!recursive_rmdir(pathname, fd)) + lxcfs_debug("Error removing %s.\n", pathname); } ret = true; @@ -623,9 +623,7 @@ static bool recursive_rmdir(const char *dirname, int fd) } if (unlinkat(fd, dirname, AT_REMOVEDIR) < 0) { -#if DEBUG - fprintf(stderr, "%s: failed to delete %s: %s\n", __func__, dirname, strerror(errno)); -#endif + lxcfs_debug("Failed to delete %s: %s.\n", dirname, strerror(errno)); ret = false; } close(fd); -- 2.9.3 ++++++ 0006-bindings-use-openat-fd-for-fstatat-unlinkat.patch ++++++ >From 2e81a5e3d8f70f395b83941e3a0277f995c27e08 Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Mon, 22 Aug 2016 02:47:27 +0200 Subject: [PATCH 06/24] bindings: use openat fd for fstatat(), unlinkat() Signed-off-by: Christian Brauner <[email protected]> --- bindings.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/bindings.c b/bindings.c index e3975cc..f0e7b80 100644 --- a/bindings.c +++ b/bindings.c @@ -571,7 +571,7 @@ int cgfs_create(const char *controller, const char *cg, uid_t uid, gid_t gid) return 0; } -static bool recursive_rmdir(const char *dirname, int fd) +static bool recursive_rmdir(const char *dirname, int fd, int cfd) { struct dirent *direntp; DIR *dir; @@ -593,9 +593,6 @@ static bool recursive_rmdir(const char *dirname, int fd) struct stat mystat; int rc; - if (!direntp) - break; - if (!strcmp(direntp->d_name, ".") || !strcmp(direntp->d_name, "..")) continue; @@ -606,13 +603,13 @@ static bool recursive_rmdir(const char *dirname, int fd) continue; } - ret = fstatat(fd, pathname, &mystat, AT_SYMLINK_NOFOLLOW); - if (ret) { + rc = fstatat(cfd, pathname, &mystat, AT_SYMLINK_NOFOLLOW); + if (rc) { lxcfs_debug("Failed to stat %s: %s.\n", pathname, strerror(errno)); continue; } if (S_ISDIR(mystat.st_mode)) - if (!recursive_rmdir(pathname, fd)) + if (!recursive_rmdir(pathname, fd, cfd)) lxcfs_debug("Error removing %s.\n", pathname); } @@ -622,7 +619,7 @@ static bool recursive_rmdir(const char *dirname, int fd) ret = false; } - if (unlinkat(fd, dirname, AT_REMOVEDIR) < 0) { + if (unlinkat(cfd, dirname, AT_REMOVEDIR) < 0) { lxcfs_debug("Failed to delete %s: %s.\n", dirname, strerror(errno)); ret = false; } @@ -652,7 +649,7 @@ bool cgfs_remove(const char *controller, const char *cg) if (fd < 0) return false; - return recursive_rmdir(dirnam, fd); + return recursive_rmdir(dirnam, fd, cfd); } bool cgfs_chmod_file(const char *controller, const char *file, mode_t mode) -- 2.9.3 ++++++ 0007-bindings-close-open-fds-on-error.patch ++++++ >From 7213ec5c20b91ff62d38c7b39f82c5e713aff08c Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Mon, 22 Aug 2016 17:48:12 +0200 Subject: [PATCH 07/24] bindings: close open fds on error Signed-off-by: Christian Brauner <[email protected]> --- bindings.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bindings.c b/bindings.c index f0e7b80..0cc926b 100644 --- a/bindings.c +++ b/bindings.c @@ -571,7 +571,7 @@ int cgfs_create(const char *controller, const char *cg, uid_t uid, gid_t gid) return 0; } -static bool recursive_rmdir(const char *dirname, int fd, int cfd) +static bool recursive_rmdir(const char *dirname, int fd, const int cfd) { struct dirent *direntp; DIR *dir; @@ -586,6 +586,7 @@ static bool recursive_rmdir(const char *dirname, int fd, int cfd) dir = fdopendir(dupfd); if (!dir) { lxcfs_debug("Failed to open %s: %s.\n", dirname, strerror(errno)); + close(dupfd); return false; } @@ -623,7 +624,8 @@ static bool recursive_rmdir(const char *dirname, int fd, int cfd) lxcfs_debug("Failed to delete %s: %s.\n", dirname, strerror(errno)); ret = false; } - close(fd); + + close(dupfd); return ret; } @@ -633,6 +635,7 @@ bool cgfs_remove(const char *controller, const char *cg) int fd, cfd; size_t len; char *dirnam, *tmpc; + bool bret; tmpc = find_mounted_controller(controller, &cfd); if (!tmpc) @@ -649,7 +652,9 @@ bool cgfs_remove(const char *controller, const char *cg) if (fd < 0) return false; - return recursive_rmdir(dirnam, fd, cfd); + bret = recursive_rmdir(dirnam, fd, cfd); + close(fd); + return bret; } bool cgfs_chmod_file(const char *controller, const char *file, mode_t mode) -- 2.9.3 ++++++ 0008-bindings-grant-access-to-var-lib-lxcfs.patch ++++++ >From 17e6e1e29fa875fbcae6e70c9580911f937d1cde Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Sun, 21 Aug 2016 00:22:38 +0200 Subject: [PATCH 08/24] bindings: grant access to /var/lib/lxcfs Signed-off-by: Christian Brauner <[email protected]> --- lxcfs.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lxcfs.c b/lxcfs.c index 47afe13..98b5d91 100644 --- a/lxcfs.c +++ b/lxcfs.c @@ -424,11 +424,19 @@ static int do_cg_releasedir(const char *path, struct fuse_file_info *fi) static int lxcfs_getattr(const char *path, struct stat *sb) { int ret; + struct timespec now; + if (strcmp(path, "/") == 0) { + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return -EINVAL; + sb->st_uid = sb->st_gid = 0; + sb->st_atim = sb->st_mtim = sb->st_ctim = now; + sb->st_size = 0; sb->st_mode = S_IFDIR | 00755; sb->st_nlink = 2; return 0; } + if (strncmp(path, "/cgroup", 7) == 0) { up_users(); ret = do_cg_getattr(path, sb); @@ -489,6 +497,10 @@ static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, of static int lxcfs_access(const char *path, int mode) { int ret; + + if (strcmp(path, "/") == 0 && access(path, R_OK) == 0) + return 0; + if (strncmp(path, "/cgroup", 7) == 0) { up_users(); ret = do_cg_access(path, mode); -- 2.9.3 ++++++ 0009-bindings-enable-access-to-var-lib-lxcfs-cgroup.patch ++++++ >From 6f0f6b832b5312e510add2fc4c571376184b59b8 Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Sun, 21 Aug 2016 00:02:32 +0200 Subject: [PATCH 09/24] bindings: enable access to /var/lib/lxcfs/cgroup Signed-off-by: Christian Brauner <[email protected]> --- bindings.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/bindings.c b/bindings.c index 0cc926b..6ae0c06 100644 --- a/bindings.c +++ b/bindings.c @@ -1909,11 +1909,18 @@ out: int cg_access(const char *path, int mode) { + int ret; const char *cgroup; - char *last = NULL, *path1, *path2, * cgdir = NULL, *controller; + char *path1, *path2, *controller; + char *last = NULL, *cgdir = NULL; struct cgfs_files *k = NULL; struct fuse_context *fc = fuse_get_context(); - int ret; + + if (strcmp(path, "/cgroup") == 0) { + if ((mode & W_OK) == 0) + return -EACCES; + return 0; + } if (!fc) return -EIO; -- 2.9.3 ++++++ 0010-bindings-allow-access-to-var-lib-lxcfs-proc.patch ++++++ >From e7849aa3f722c6ac7a16fd87147a295b708a2855 Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Sun, 21 Aug 2016 00:11:13 +0200 Subject: [PATCH 10/24] bindings: allow access to /var/lib/lxcfs/proc Signed-off-by: Christian Brauner <[email protected]> --- bindings.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bindings.c b/bindings.c index 6ae0c06..04b2a5f 100644 --- a/bindings.c +++ b/bindings.c @@ -4075,6 +4075,9 @@ int proc_open(const char *path, struct fuse_file_info *fi) int proc_access(const char *path, int mask) { + if (strcmp(path, "/proc") == 0 && access(path, R_OK) == 0) + return 0; + /* these are all read-only */ if ((mask & ~R_OK) != 0) return -EACCES; -- 2.9.3 ++++++ 0011-lxcfs-bindings-show-.-and-.-dir-entries.patch ++++++ >From d639f86341f7f07f0ade0c937fd576586bfb949e Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Sun, 21 Aug 2016 13:53:27 +0200 Subject: [PATCH 11/24] lxcfs, bindings: show "." and ".." dir entries Signed-off-by: Christian Brauner <[email protected]> --- bindings.c | 17 +++++++++++------ lxcfs.c | 6 ++++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/bindings.c b/bindings.c index 04b2a5f..997db7b 100644 --- a/bindings.c +++ b/bindings.c @@ -1742,6 +1742,9 @@ int cg_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset struct fuse_context *fc = fuse_get_context(); char **clist = NULL; + if (filler(buf, ".", NULL, 0) != 0 || filler(buf, "..", NULL, 0) != 0) + return -EIO; + if (d->type != LXC_TYPE_CGDIR) { fprintf(stderr, "Internal error: file cache info used in readdir\n"); return -EIO; @@ -4024,12 +4027,14 @@ int proc_getattr(const char *path, struct stat *sb) int proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { - if (filler(buf, "cpuinfo", NULL, 0) != 0 || - filler(buf, "meminfo", NULL, 0) != 0 || - filler(buf, "stat", NULL, 0) != 0 || - filler(buf, "uptime", NULL, 0) != 0 || - filler(buf, "diskstats", NULL, 0) != 0 || - filler(buf, "swaps", NULL, 0) != 0) + if (filler(buf, ".", NULL, 0) != 0 || + filler(buf, "..", NULL, 0) != 0 || + filler(buf, "cpuinfo", NULL, 0) != 0 || + filler(buf, "meminfo", NULL, 0) != 0 || + filler(buf, "stat", NULL, 0) != 0 || + filler(buf, "uptime", NULL, 0) != 0 || + filler(buf, "diskstats", NULL, 0) != 0 || + filler(buf, "swaps", NULL, 0) != 0) return -EINVAL; return 0; } diff --git a/lxcfs.c b/lxcfs.c index 98b5d91..0c695b7 100644 --- a/lxcfs.c +++ b/lxcfs.c @@ -474,8 +474,10 @@ static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, of { int ret; if (strcmp(path, "/") == 0) { - if (filler(buf, "proc", NULL, 0) != 0 || - filler(buf, "cgroup", NULL, 0) != 0) + if (filler(buf, ".", NULL, 0) != 0 || + filler(buf, "..", NULL, 0) != 0 || + filler(buf, "proc", NULL, 0) != 0 || + filler(buf, "cgroup", NULL, 0) != 0) return -EINVAL; return 0; } -- 2.9.3 ++++++ 0012-lxcfs-better-fs-behavior-on-var-lib-lxcfs.patch ++++++ >From f9b24a3e01e49dfa2b98c138f3d4f6f687c8d0b6 Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Mon, 22 Aug 2016 11:36:02 +0200 Subject: [PATCH 12/24] lxcfs: better fs behavior on /var/lib/lxcfs return -EPERM for mkdir(), rmdir(), chown(), chmod() on top directory /var/lib/lxcfs. Signed-off-by: Christian Brauner <[email protected]> --- lxcfs.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/lxcfs.c b/lxcfs.c index 0c695b7..a013033 100644 --- a/lxcfs.c +++ b/lxcfs.c @@ -449,7 +449,7 @@ static int lxcfs_getattr(const char *path, struct stat *sb) down_users(); return ret; } - return -EINVAL; + return -ENOENT; } static int lxcfs_opendir(const char *path, struct fuse_file_info *fi) @@ -478,7 +478,7 @@ static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, of filler(buf, "..", NULL, 0) != 0 || filler(buf, "proc", NULL, 0) != 0 || filler(buf, "cgroup", NULL, 0) != 0) - return -EINVAL; + return -ENOMEM; return 0; } if (strncmp(path, "/cgroup", 7) == 0) { @@ -493,14 +493,14 @@ static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, of down_users(); return ret; } - return -EINVAL; + return -ENOENT; } static int lxcfs_access(const char *path, int mode) { int ret; - if (strcmp(path, "/") == 0 && access(path, R_OK) == 0) + if (strcmp(path, "/") == 0 && (mode & W_OK) == 0) return 0; if (strncmp(path, "/cgroup", 7) == 0) { @@ -516,7 +516,7 @@ static int lxcfs_access(const char *path, int mode) return ret; } - return -EINVAL; + return -EACCES; } static int lxcfs_releasedir(const char *path, struct fuse_file_info *fi) @@ -551,7 +551,7 @@ static int lxcfs_open(const char *path, struct fuse_file_info *fi) return ret; } - return -EINVAL; + return -EACCES; } static int lxcfs_read(const char *path, char *buf, size_t size, off_t offset, @@ -627,7 +627,7 @@ int lxcfs_mkdir(const char *path, mode_t mode) return ret; } - return -EINVAL; + return -EPERM; } int lxcfs_chown(const char *path, uid_t uid, gid_t gid) @@ -640,7 +640,10 @@ int lxcfs_chown(const char *path, uid_t uid, gid_t gid) return ret; } - return -EINVAL; + if (strncmp(path, "/proc", 5) == 0) + return -EPERM; + + return -ENOENT; } /* @@ -652,7 +655,7 @@ int lxcfs_truncate(const char *path, off_t newsize) { if (strncmp(path, "/cgroup", 7) == 0) return 0; - return -EINVAL; + return -EPERM; } int lxcfs_rmdir(const char *path) @@ -664,7 +667,7 @@ int lxcfs_rmdir(const char *path) down_users(); return ret; } - return -EINVAL; + return -EPERM; } int lxcfs_chmod(const char *path, mode_t mode) @@ -676,7 +679,11 @@ int lxcfs_chmod(const char *path, mode_t mode) down_users(); return ret; } - return -EINVAL; + + if (strncmp(path, "/proc", 5) == 0) + return -EPERM; + + return -ENOENT; } const struct fuse_operations lxcfs_ops = { -- 2.9.3 ++++++ 0013-bindings-non-functional-changes.patch ++++++ >From 3adc421c2619aa43631493562d0adc60940346af Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Mon, 22 Aug 2016 11:56:46 +0200 Subject: [PATCH 13/24] bindings: non functional changes - whitespace fixes for pick_controller_from_path() Signed-off-by: Christian Brauner <[email protected]> --- bindings.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bindings.c b/bindings.c index 997db7b..cf56208 100644 --- a/bindings.c +++ b/bindings.c @@ -1508,9 +1508,9 @@ static char *pick_controller_from_path(struct fuse_context *fc, const char *path if (strlen(path) < 9) return NULL; - if (*(path+7) != '/') + if (*(path + 7) != '/') return NULL; - p1 = path+8; + p1 = path + 8; contr = strdupa(p1); if (!contr) return NULL; @@ -1519,7 +1519,7 @@ static char *pick_controller_from_path(struct fuse_context *fc, const char *path *slash = '\0'; int i; - for (i = 0; i < num_hierarchies; i++) { + for (i = 0; i < num_hierarchies; i++) { if (hierarchies[i] && strcmp(hierarchies[i], contr) == 0) return hierarchies[i]; } -- 2.9.3 ++++++ 0014-bindings-set-errno-in-pick_controller_from_path.patch ++++++ >From 99142521d202c1b626dd308e25c42eb95f613c21 Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Mon, 22 Aug 2016 12:00:25 +0200 Subject: [PATCH 14/24] bindings: set errno in pick_controller_from_path() This will allow us to provide better standard fs behavior. Signed-off-by: Christian Brauner <[email protected]> --- bindings.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/bindings.c b/bindings.c index cf56208..f3cd85d 100644 --- a/bindings.c +++ b/bindings.c @@ -1506,14 +1506,20 @@ static char *pick_controller_from_path(struct fuse_context *fc, const char *path const char *p1; char *contr, *slash; - if (strlen(path) < 9) + if (strlen(path) < 9) { + errno = EINVAL; return NULL; - if (*(path + 7) != '/') + } + if (*(path + 7) != '/') { + errno = EINVAL; return NULL; + } p1 = path + 8; contr = strdupa(p1); - if (!contr) + if (!contr) { + errno = ENOMEM; return NULL; + } slash = strstr(contr, "/"); if (slash) *slash = '\0'; @@ -1523,6 +1529,7 @@ static char *pick_controller_from_path(struct fuse_context *fc, const char *path if (hierarchies[i] && strcmp(hierarchies[i], contr) == 0) return hierarchies[i]; } + errno = ENOENT; return NULL; } -- 2.9.3 ++++++ 0015-bindings-more-consistent-fs-behavior.patch ++++++ >From 2f7036d08de5c60c72985b37f8ff5c01d248109a Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Mon, 22 Aug 2016 12:20:10 +0200 Subject: [PATCH 15/24] bindings: more consistent fs behavior - e.g. let cg_mkdir() return EPERM Signed-off-by: Christian Brauner <[email protected]> --- bindings.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bindings.c b/bindings.c index f3cd85d..281aad2 100644 --- a/bindings.c +++ b/bindings.c @@ -1605,7 +1605,7 @@ int cg_getattr(const char *path, struct stat *sb) controller = pick_controller_from_path(fc, path); if (!controller) - return -EIO; + return -errno; cgroup = find_cgroup_in_path(path); if (!cgroup) { /* this is just /cgroup/controller, return it as a dir */ @@ -1705,7 +1705,7 @@ int cg_opendir(const char *path, struct fuse_file_info *fi) // return list of keys for the controller, and list of child cgroups controller = pick_controller_from_path(fc, path); if (!controller) - return -EIO; + return -errno; cgroup = find_cgroup_in_path(path); if (!cgroup) { @@ -1863,7 +1863,7 @@ int cg_open(const char *path, struct fuse_file_info *fi) controller = pick_controller_from_path(fc, path); if (!controller) - return -EIO; + return -errno; cgroup = find_cgroup_in_path(path); if (!cgroup) return -EINVAL; @@ -1937,7 +1937,7 @@ int cg_access(const char *path, int mode) controller = pick_controller_from_path(fc, path); if (!controller) - return -EIO; + return -errno; cgroup = find_cgroup_in_path(path); if (!cgroup) { // access("/sys/fs/cgroup/systemd", mode) - rx allowed, w not @@ -2724,7 +2724,7 @@ int cg_chown(const char *path, uid_t uid, gid_t gid) controller = pick_controller_from_path(fc, path); if (!controller) - return -EINVAL; + return -errno; cgroup = find_cgroup_in_path(path); if (!cgroup) /* this is just /cgroup/controller */ @@ -2789,7 +2789,7 @@ int cg_chmod(const char *path, mode_t mode) controller = pick_controller_from_path(fc, path); if (!controller) - return -EINVAL; + return -errno; cgroup = find_cgroup_in_path(path); if (!cgroup) /* this is just /cgroup/controller */ @@ -2854,7 +2854,7 @@ int cg_mkdir(const char *path, mode_t mode) controller = pick_controller_from_path(fc, path); if (!controller) - return -EINVAL; + return errno == ENOENT ? -EPERM : -errno; cgroup = find_cgroup_in_path(path); if (!cgroup) @@ -2875,7 +2875,7 @@ int cg_mkdir(const char *path, mode_t mode) else if (last && strcmp(next, last) == 0) ret = -EEXIST; else - ret = -ENOENT; + ret = -EPERM; goto out; } @@ -2908,7 +2908,7 @@ int cg_rmdir(const char *path) controller = pick_controller_from_path(fc, path); if (!controller) - return -EINVAL; + return -errno; cgroup = find_cgroup_in_path(path); if (!cgroup) -- 2.9.3 ++++++ 0016-add-pld-linux-support.patch ++++++ >From 00d7fdd826af7afd37f18d99e371bd0aeb1afb79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <[email protected]> Date: Fri, 26 Aug 2016 00:18:46 +0300 Subject: [PATCH 16/24] add pld linux support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Elan Ruusamäe <[email protected]> --- configure.ac | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index dae4218..6c5c8be 100644 --- a/configure.ac +++ b/configure.ac @@ -66,6 +66,7 @@ if test "z$with_distro" = "z"; then AC_CHECK_FILE(/etc/mandrakelinux-release, with_distro="openmandriva") AC_CHECK_FILE(/etc/mandriva-release,with_distro="openmandriva") AC_CHECK_FILE(/etc/pardus-release,with_distro="pardus") + AC_CHECK_FILE(/etc/pld-release,with_distro="pld") fi with_distro=`echo ${with_distro} | tr '[[:upper:]]' '[[:lower:]]'` @@ -76,7 +77,7 @@ case $with_distro in ubuntu) distroconf=default.conf.ubuntu ;; - redhat|centos|fedora|oracle|oracleserver) + redhat|centos|fedora|oracle|oracleserver|pld) distroconf=default.conf.libvirt ;; *) @@ -108,6 +109,9 @@ case "$with_init_script" in ubuntu) init_script=upstart,systemd,sysvinit ;; + pld) + init_script=systemd,sysvinit + ;; slackware) echo -n "Warning: bsd init job not yet implemented" init_script= -- 2.9.3 ++++++ 0017-don-t-use-argv-0-in-usage-output.patch ++++++ >From c3fb7d7fbdc2d9cb2e9e818ac8fce52442583921 Mon Sep 17 00:00:00 2001 From: Evgeni Golov <[email protected]> Date: Fri, 26 Aug 2016 09:33:09 +0200 Subject: [PATCH 17/24] don't use argv[0] in usage output otherwise this generates "funny" manpages like /home/remote/egolov/Devel/lxcfs/.libs/lt-lxcfs [-p pidfile] mountpoint /home/remote/egolov/Devel/lxcfs/.libs/lt-lxcfs -h or /build/lxcfs-8lNGve/lxcfs-2.0/.1/.libs/lt-lxcfs [-p pidfile] mountpoint /build/lxcfs-8lNGve/lxcfs-2.0/.1/.libs/lt-lxcfs -h Signed-off-by: Evgeni Golov <[email protected]> --- lxcfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lxcfs.c b/lxcfs.c index 47afe13..e745ce5 100644 --- a/lxcfs.c +++ b/lxcfs.c @@ -708,13 +708,13 @@ const struct fuse_operations lxcfs_ops = { .fgetattr = NULL, }; -static void usage(const char *me) +static void usage() { fprintf(stderr, "Usage:\n"); fprintf(stderr, "\n"); - fprintf(stderr, "%s [-p pidfile] mountpoint\n", me); + fprintf(stderr, "lxcfs [-p pidfile] mountpoint\n"); fprintf(stderr, " Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH); - fprintf(stderr, "%s -h\n", me); + fprintf(stderr, "lxcfs -h\n"); exit(1); } @@ -838,7 +838,7 @@ int main(int argc, char *argv[]) exit(EXIT_SUCCESS); } if (argc != 2 || is_help(argv[1])) - usage(argv[0]); + usage(); do_reload(); if (signal(SIGUSR1, reload_handler) == SIG_ERR) { -- 2.9.3 ++++++ 0018-bindings-revert-cgroup-check.patch ++++++ >From 9873c5e858f9628435afa7ff6b6cc50afbb91e06 Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Thu, 25 Aug 2016 22:33:07 +0200 Subject: [PATCH 18/24] bindings: revert cgroup check We do not need to check whether mode & W_OK is passed in. Even if the cgroup root mount is writeable operations like cg_mkdir() et al. will fail with e.g. EPERM. Basically all operations will fail on the cgroup root mount point because the first operation they perform is pick_controller_from_path(). That is to say they try to e.g. pick "blkio" from /var/lib/lxcfs/cgroup/blkio/some/cgroups an similiar for all other controllers. If pick_controller_from_path() fails they all return an appropriate errno. For example, cg_mkdir() does: controller = pick_controller_from_path(fc, path); if (!controller) return errno == ENOENT ? -EPERM : -errno; This means, we do not need to return an errno already in cg_access when mode & W_OK is passed in. This has the advantage that users are still able to descend into /var/lib/lxcfs/cgroup via: cd /var/lib/lxcfs/cgroup but are still blocked from doing any write operations. Signed-off-by: Christian Brauner <[email protected]> --- bindings.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/bindings.c b/bindings.c index 281aad2..8a5909a 100644 --- a/bindings.c +++ b/bindings.c @@ -1926,11 +1926,8 @@ int cg_access(const char *path, int mode) struct cgfs_files *k = NULL; struct fuse_context *fc = fuse_get_context(); - if (strcmp(path, "/cgroup") == 0) { - if ((mode & W_OK) == 0) - return -EACCES; + if (strcmp(path, "/cgroup") == 0) return 0; - } if (!fc) return -EIO; -- 2.9.3 ++++++ 0019-bindings-improve-returned-errnos.patch ++++++ >From bc70ba9b492f1af79ce692471f3e300eaf4afe29 Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Fri, 26 Aug 2016 10:32:32 +0200 Subject: [PATCH 19/24] bindings: improve returned errnos Signed-off-by: Christian Brauner <[email protected]> --- bindings.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/bindings.c b/bindings.c index 8a5909a..aaba840 100644 --- a/bindings.c +++ b/bindings.c @@ -1541,12 +1541,17 @@ static const char *find_cgroup_in_path(const char *path) { const char *p1; - if (strlen(path) < 9) + if (strlen(path) < 9) { + errno = EINVAL; return NULL; - p1 = strstr(path+8, "/"); - if (!p1) + } + p1 = strstr(path + 8, "/"); + if (!p1) { + errno = EINVAL; return NULL; - return p1+1; + } + errno = 0; + return p1 + 1; } /* @@ -1866,7 +1871,7 @@ int cg_open(const char *path, struct fuse_file_info *fi) return -errno; cgroup = find_cgroup_in_path(path); if (!cgroup) - return -EINVAL; + return -errno; get_cgdir_and_path(cgroup, &cgdir, &last); if (!last) { @@ -2717,15 +2722,16 @@ int cg_chown(const char *path, uid_t uid, gid_t gid) return -EIO; if (strcmp(path, "/cgroup") == 0) - return -EINVAL; + return -EPERM; controller = pick_controller_from_path(fc, path); if (!controller) - return -errno; + return errno == ENOENT ? -EPERM : -errno; + cgroup = find_cgroup_in_path(path); if (!cgroup) /* this is just /cgroup/controller */ - return -EINVAL; + return -EPERM; get_cgdir_and_path(cgroup, &cgdir, &last); @@ -2782,15 +2788,16 @@ int cg_chmod(const char *path, mode_t mode) return -EIO; if (strcmp(path, "/cgroup") == 0) - return -EINVAL; + return -EPERM; controller = pick_controller_from_path(fc, path); if (!controller) - return -errno; + return errno == ENOENT ? -EPERM : -errno; + cgroup = find_cgroup_in_path(path); if (!cgroup) /* this is just /cgroup/controller */ - return -EINVAL; + return -EPERM; get_cgdir_and_path(cgroup, &cgdir, &last); @@ -2848,14 +2855,13 @@ int cg_mkdir(const char *path, mode_t mode) if (!fc) return -EIO; - controller = pick_controller_from_path(fc, path); if (!controller) return errno == ENOENT ? -EPERM : -errno; cgroup = find_cgroup_in_path(path); if (!cgroup) - return -EINVAL; + return -errno; get_cgdir_and_path(cgroup, &cgdir, &last); if (!last) @@ -2909,7 +2915,7 @@ int cg_rmdir(const char *path) cgroup = find_cgroup_in_path(path); if (!cgroup) - return -EINVAL; + return -errno; get_cgdir_and_path(cgroup, &cgdir, &last); if (!last) { -- 2.9.3 ++++++ 0020-bindings-make-rmdir-behave-more-consistently.patch ++++++ >From e254948fb93869c1a771cf5778161e703a422918 Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Fri, 26 Aug 2016 16:26:27 +0200 Subject: [PATCH 20/24] bindings: make rmdir behave more consistently We should be able to safely return -EPERM for: if (!pick_controller_from_path()) /* Someone's trying to delete "/cgroup". */ if (!find_cgroup_in_path()) /* Someone's trying to delete a controller e.g. "/blkio". */ if (!get_cgdir_and_path()) { /* Someone's trying to delete a cgroup on the same level as the * "/lxc" cgroup e.g. rmdir "/cgroup/blkio/lxc" or * rmdir "/cgroup/blkio/init.slice". */ } All other interesting cases are caught further down. Signed-off-by: Christian Brauner <[email protected]> --- bindings.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/bindings.c b/bindings.c index aaba840..4413a7d 100644 --- a/bindings.c +++ b/bindings.c @@ -1507,7 +1507,7 @@ static char *pick_controller_from_path(struct fuse_context *fc, const char *path char *contr, *slash; if (strlen(path) < 9) { - errno = EINVAL; + errno = EACCES; return NULL; } if (*(path + 7) != '/') { @@ -1542,7 +1542,7 @@ static const char *find_cgroup_in_path(const char *path) const char *p1; if (strlen(path) < 9) { - errno = EINVAL; + errno = EACCES; return NULL; } p1 = strstr(path + 8, "/"); @@ -2910,16 +2910,20 @@ int cg_rmdir(const char *path) return -EIO; controller = pick_controller_from_path(fc, path); - if (!controller) - return -errno; + if (!controller) /* Someone's trying to delete "/cgroup". */ + return -EPERM; cgroup = find_cgroup_in_path(path); - if (!cgroup) - return -errno; + if (!cgroup) /* Someone's trying to delete a controller e.g. "/blkio". */ + return -EPERM; get_cgdir_and_path(cgroup, &cgdir, &last); if (!last) { - ret = -EINVAL; + /* Someone's trying to delete a cgroup on the same level as the + * "/lxc" cgroup e.g. rmdir "/cgroup/blkio/lxc" or + * rmdir "/cgroup/blkio/init.slice". + */ + ret = -EPERM; goto out; } -- 2.9.3 ++++++ 0021-libtool-do-not-link-lxcfs-against-liblxcfs.patch ++++++ >From 23748216d35bc40c36bc5dd35199fd37f3d3152b Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Mon, 29 Aug 2016 10:12:27 +0200 Subject: [PATCH 21/24] libtool: do not link lxcfs against liblxcfs Make liblxcfs a libtool module. Also, stop linking lxcfs against liblxcfs. We do not really need this since we call dlopen() anyway. Furthermore, this allows us to make sure that functions marked with __attribute__(constructor) are not run before we call dlopen() in main() in lxcfs. This has the advantage that we can show help output without __attribute__(constructor) functions being run. Signed-off-by: Christian Brauner <[email protected]> --- Makefile.am | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index cb4abc1..444eaf5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,15 +9,15 @@ AM_CFLAGS += -DLIBDIR=\"$(LIBDIR)\" AM_LDFLAGS = $(FUSE_LIBS) -pthread #AM_CFLAGS += -DDEBUG -AM_CFLAGS += -DRUNTIME_PATH=\"$(RUNTIME_PATH)\" +AM_CFLAGS += -DRUNTIME_PATH=\"$(RUNTIME_PATH)\" liblxcfs_la_SOURCES = bindings.c cpuset.c bindings.h liblxcfs_la_CFLAGS = $(AM_CFLAGS) -liblxcfs_la_LDFLAGS = $(AM_CFLAGS) -shared +liblxcfs_la_LDFLAGS = $(AM_CFLAGS) -module -shared liblxcfstest_la_SOURCES = bindings.c cpuset.c bindings.h liblxcfstest_la_CFLAGS = $(AM_CFLAGS) -DRELOADTEST -liblxcfstest_la_LDFLAGS = $(AM_CFLAGS) -shared +liblxcfstest_la_LDFLAGS = $(AM_CFLAGS) -module -shared noinst_HEADERS = bindings.h @@ -26,7 +26,7 @@ lib_LTLIBRARIES = liblxcfs.la EXTRA_LTLIBRARIES = liblxcfstest.la lxcfs_SOURCES = lxcfs.c -lxcfs_LDADD = liblxcfs.la -ldl +lxcfs_LDADD = -ldl lxcfs_CFLAGS = $(AM_CFLAGS) lxcfs_LDFLAGS = $(AM_LDFLAGS) bin_PROGRAMS = lxcfs -- 2.9.3 ++++++ 0022-bindings-lxcfs-improve-debugging.patch ++++++ ++++ 943 lines (skipped) ++++++ 0023-bindings-fix-debug-macro.patch ++++++ >From 3b5a323346f95622d4b97d37a645b468d32a852c Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Tue, 30 Aug 2016 10:26:44 +0200 Subject: [PATCH 23/24] bindings: fix debug macro Signed-off-by: Christian Brauner <[email protected]> --- bindings.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bindings.h b/bindings.h index c295104..04d728c 100644 --- a/bindings.h +++ b/bindings.h @@ -1,10 +1,13 @@ +#ifndef __LXCFS_BINDINGS_H +#define __LXCFS_BINDINGS_H + /* directory under which we mount the controllers - /run/lxcfs/controllers */ #define BASEDIR RUNTIME_PATH "/lxcfs/controllers" #define ROOTDIR RUNTIME_PATH "/lxcfs/root" #define lxcfs_debug_stream(stream, format, ...) \ do { \ - fprintf(stderr, "%s: %d: %s: " format, __FILE__, __LINE__, \ + fprintf(stream, "%s: %d: %s: " format, __FILE__, __LINE__, \ __func__, __VA_ARGS__); \ } while (false) @@ -41,3 +44,5 @@ extern int proc_open(const char *path, struct fuse_file_info *fi); extern int proc_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi); extern int proc_access(const char *path, int mask); + +#endif /* __LXCFS__BINDINGS_H */ -- 2.9.3 ++++++ 0024-bindings-restore-original-working-directory.patch ++++++ >From e58dab009be0efbc2fbf60b4cff50d79d6ffbca8 Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Wed, 31 Aug 2016 02:20:09 +0200 Subject: [PATCH 24/24] bindings: restore original working directory Signed-off-by: Christian Brauner <[email protected]> --- bindings.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bindings.c b/bindings.c index b2d5553..ac88f48 100644 --- a/bindings.c +++ b/bindings.c @@ -4345,7 +4345,8 @@ static int preserve_ns(int pid) static void __attribute__((constructor)) collect_and_mount_subsystems(void) { FILE *f; - char *line = NULL; + char *cret, *line = NULL; + char cwd[MAXPATHLEN]; size_t len = 0; int i, init_ns = -1; @@ -4353,6 +4354,7 @@ static void __attribute__((constructor)) collect_and_mount_subsystems(void) lxcfs_error("Error opening /proc/self/cgroup: %s\n", strerror(errno)); return; } + while (getline(&line, &len, f) != -1) { char *p, *p2; @@ -4394,6 +4396,10 @@ static void __attribute__((constructor)) collect_and_mount_subsystems(void) for (i = 0; i < num_hierarchies; i++) fd_hierarchies[i] = -1; + cret = getcwd(cwd, MAXPATHLEN); + if (!cret) + lxcfs_debug("Could not retrieve current working directory: %s.\n", strerror(errno)); + /* This function calls unshare(CLONE_NEWNS) our initial mount namespace * to privately mount lxcfs cgroups. */ if (!cgfs_setup_controllers()) { @@ -4406,6 +4412,9 @@ static void __attribute__((constructor)) collect_and_mount_subsystems(void) goto out; } + if (!cret || chdir(cwd) < 0) + lxcfs_debug("Could not change back to original working directory: %s.\n", strerror(errno)); + print_subsystems(); out: -- 2.9.3 ++++++ lxcfs-2.0.2.tar.gz -> lxcfs-2.0.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-2.0.2/bindings.c new/lxcfs-2.0.3/bindings.c --- old/lxcfs-2.0.2/bindings.c 2016-06-28 20:27:44.000000000 +0200 +++ new/lxcfs-2.0.3/bindings.c 2016-08-16 04:36:32.000000000 +0200 @@ -8,30 +8,46 @@ #define FUSE_USE_VERSION 26 -#include <stdio.h> #include <dirent.h> +#include <errno.h> #include <fcntl.h> #include <fuse.h> -#include <unistd.h> -#include <errno.h> -#include <stdbool.h> -#include <time.h> -#include <string.h> -#include <stdlib.h> #include <libgen.h> -#include <sched.h> #include <pthread.h> +#include <sched.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <wait.h> #include <linux/sched.h> +#include <sys/epoll.h> +#include <sys/mman.h> +#include <sys/mount.h> #include <sys/param.h> #include <sys/socket.h> -#include <sys/mount.h> -#include <sys/epoll.h> -#include <wait.h> +#include <sys/syscall.h> #include "bindings.h" - #include "config.h" // for VERSION +/* Define pivot_root() if missing from the C library */ +#ifndef HAVE_PIVOT_ROOT +static int pivot_root(const char * new_root, const char * put_old) +{ +#ifdef __NR_pivot_root +return syscall(__NR_pivot_root, new_root, put_old); +#else +errno = ENOSYS; +return -1; +#endif +} +#else +extern int pivot_root(const char * new_root, const char * put_old); +#endif + enum { LXC_TYPE_CGDIR, LXC_TYPE_CGFILE, @@ -95,6 +111,26 @@ } } +/* READ-ONLY after __constructor__ collect_and_mount_subsystems() has run. + * Number of hierarchies mounted. */ +static int num_hierarchies; + +/* READ-ONLY after __constructor__ collect_and_mount_subsystems() has run. + * Hierachies mounted {cpuset, blkio, ...}: + * Initialized via __constructor__ collect_and_mount_subsystems(). */ +static char **hierarchies; + +/* READ-ONLY after __constructor__ collect_and_mount_subsystems() has run. + * Open file descriptors: + * @fd_hierarchies[i] refers to cgroup @hierarchies[i]. They are mounted in a + * private mount namespace. + * Initialized via __constructor__ collect_and_mount_subsystems(). + * @fd_hierarchies[i] can be used to perform file operations on the cgroup + * mounts and respective files in the private namespace even when located in + * another namespace using the *at() family of functions + * {openat(), fchownat(), ...}. */ +static int *fd_hierarchies; + static void unlock_mutex(pthread_mutex_t *l) { int ret; @@ -256,10 +292,10 @@ return NULL; } -static int is_dir(const char *path) +static int is_dir(const char *path, int fd) { struct stat statbuf; - int ret = stat(path, &statbuf); + int ret = fstatat(fd, path, &statbuf, fd); if (ret == 0 && S_ISDIR(statbuf.st_mode)) return 1; return 0; @@ -307,11 +343,11 @@ *len = newlen; } -static char *slurp_file(const char *from) +static char *slurp_file(const char *from, int fd) { char *line = NULL; char *contents = NULL; - FILE *f = fopen(from, "r"); + FILE *f = fdopen(fd, "r"); size_t len = 0, fulllen = 0; ssize_t linelen; @@ -329,12 +365,12 @@ return contents; } -static bool write_string(const char *fnam, const char *string) +static bool write_string(const char *fnam, const char *string, int fd) { FILE *f; size_t len, ret; - if (!(f = fopen(fnam, "w"))) + if (!(f = fdopen(fd, "w"))) return false; len = strlen(string); ret = fwrite(string, 1, len, f); @@ -350,12 +386,6 @@ return true; } -/* - * hierarchies, i.e. 'cpu,cpuacct' - */ -char **hierarchies; -int num_hierarchies; - struct cgfs_files { char *name; uint32_t uid, gid; @@ -384,7 +414,7 @@ { int i; - fprintf(stderr, "hierarchies:"); + fprintf(stderr, "hierarchies:\n"); for (i = 0; i < num_hierarchies; i++) { if (hierarchies[i]) fprintf(stderr, " %d: %s\n", i, hierarchies[i]); @@ -396,7 +426,7 @@ const char *s = haystack, *e; size_t nlen = strlen(needle); - while (*s && (e = index(s, ','))) { + while (*s && (e = strchr(s, ','))) { if (nlen != e - s) { s = e + 1; continue; @@ -411,17 +441,25 @@ } /* do we need to do any massaging here? I'm not sure... */ -static char *find_mounted_controller(const char *controller) +/* Return the mounted controller and store the corresponding open file descriptor + * referring to the controller mountpoint in the private lxcfs namespace in + * @cfd. + */ +static char *find_mounted_controller(const char *controller, int *cfd) { int i; for (i = 0; i < num_hierarchies; i++) { if (!hierarchies[i]) continue; - if (strcmp(hierarchies[i], controller) == 0) + if (strcmp(hierarchies[i], controller) == 0) { + *cfd = fd_hierarchies[i]; return hierarchies[i]; - if (in_comma_list(controller, hierarchies[i])) + } + if (in_comma_list(controller, hierarchies[i])) { + *cfd = fd_hierarchies[i]; return hierarchies[i]; + } } return NULL; @@ -430,28 +468,39 @@ bool cgfs_set_value(const char *controller, const char *cgroup, const char *file, const char *value) { + int ret, fd, cfd; size_t len; - char *fnam, *tmpc = find_mounted_controller(controller); + char *fnam, *tmpc; + tmpc = find_mounted_controller(controller, &cfd); if (!tmpc) return false; - /* basedir / tmpc / cgroup / file \0 */ - len = strlen(basedir) + strlen(tmpc) + strlen(cgroup) + strlen(file) + 4; + + /* Make sure we pass a relative path to *at() family of functions. + * . + /cgroup + / + file + \0 + */ + len = strlen(cgroup) + strlen(file) + 3; fnam = alloca(len); - snprintf(fnam, len, "%s/%s/%s/%s", basedir, tmpc, cgroup, file); + ret = snprintf(fnam, len, "%s%s/%s", *cgroup == '/' ? "." : "", cgroup, file); + if (ret < 0 || (size_t)ret >= len) + return false; + + fd = openat(cfd, fnam, O_WRONLY); + if (fd < 0) + return false; - return write_string(fnam, value); + return write_string(fnam, value, fd); } // Chown all the files in the cgroup directory. We do this when we create // a cgroup on behalf of a user. -static void chown_all_cgroup_files(const char *dirname, uid_t uid, gid_t gid) +static void chown_all_cgroup_files(const char *dirname, uid_t uid, gid_t gid, int fd) { - struct dirent dirent, *direntp; + struct dirent *direntp; char path[MAXPATHLEN]; size_t len; DIR *d; - int ret; + int fd1, ret; len = strlen(dirname); if (len >= MAXPATHLEN) { @@ -459,13 +508,17 @@ return; } - d = opendir(dirname); + fd1 = openat(fd, dirname, O_DIRECTORY); + if (fd1 < 0) + return; + + d = fdopendir(fd1); if (!d) { fprintf(stderr, "chown_all_cgroup_files: failed to open %s\n", dirname); return; } - while (readdir_r(d, &dirent, &direntp) == 0 && direntp) { + while ((direntp = readdir(d))) { if (!strcmp(direntp->d_name, ".") || !strcmp(direntp->d_name, "..")) continue; ret = snprintf(path, MAXPATHLEN, "%s/%s", dirname, direntp->d_name); @@ -473,7 +526,7 @@ fprintf(stderr, "chown_all_cgroup_files: pathname too long under %s\n", dirname); continue; } - if (chown(path, uid, gid) < 0) + if (fchownat(fd, path, uid, gid, 0) < 0) fprintf(stderr, "Failed to chown file %s to %u:%u", path, uid, gid); } closedir(d); @@ -481,38 +534,48 @@ int cgfs_create(const char *controller, const char *cg, uid_t uid, gid_t gid) { + int cfd; size_t len; - char *dirnam, *tmpc = find_mounted_controller(controller); + char *dirnam, *tmpc; + tmpc = find_mounted_controller(controller, &cfd); if (!tmpc) return -EINVAL; - /* basedir / tmpc / cg \0 */ - len = strlen(basedir) + strlen(tmpc) + strlen(cg) + 3; + + /* Make sure we pass a relative path to *at() family of functions. + * . + /cg + \0 + */ + len = strlen(cg) + 2; dirnam = alloca(len); - snprintf(dirnam, len, "%s/%s/%s", basedir,tmpc, cg); + snprintf(dirnam, len, "%s%s", *cg == '/' ? "." : "", cg); - if (mkdir(dirnam, 0755) < 0) + if (mkdirat(cfd, dirnam, 0755) < 0) return -errno; if (uid == 0 && gid == 0) return 0; - if (chown(dirnam, uid, gid) < 0) + if (fchownat(cfd, dirnam, uid, gid, 0) < 0) return -errno; - chown_all_cgroup_files(dirnam, uid, gid); + chown_all_cgroup_files(dirnam, uid, gid, cfd); return 0; } -static bool recursive_rmdir(const char *dirname) +static bool recursive_rmdir(const char *dirname, int fd) { - struct dirent dirent, *direntp; + struct dirent *direntp; DIR *dir; bool ret = false; char pathname[MAXPATHLEN]; + int dupfd; + + dupfd = dup(fd); // fdopendir() does bad things once it uses an fd. + if (dupfd < 0) + return false; - dir = opendir(dirname); + dir = fdopendir(dupfd); if (!dir) { #if DEBUG fprintf(stderr, "%s: failed to open %s: %s\n", __func__, dirname, strerror(errno)); @@ -520,7 +583,7 @@ return false; } - while (!readdir_r(dir, &dirent, &direntp)) { + while ((direntp = readdir(dir))) { struct stat mystat; int rc; @@ -537,7 +600,7 @@ continue; } - ret = lstat(pathname, &mystat); + ret = fstatat(fd, pathname, &mystat, AT_SYMLINK_NOFOLLOW); if (ret) { #if DEBUG fprintf(stderr, "%s: failed to stat %s: %s\n", __func__, pathname, strerror(errno)); @@ -545,7 +608,7 @@ continue; } if (S_ISDIR(mystat.st_mode)) { - if (!recursive_rmdir(pathname)) { + if (!recursive_rmdir(pathname, fd)) { #if DEBUG fprintf(stderr, "Error removing %s\n", pathname); #endif @@ -559,47 +622,63 @@ ret = false; } - if (rmdir(dirname) < 0) { + if (unlinkat(fd, dirname, AT_REMOVEDIR) < 0) { #if DEBUG fprintf(stderr, "%s: failed to delete %s: %s\n", __func__, dirname, strerror(errno)); #endif ret = false; } + close(fd); return ret; } bool cgfs_remove(const char *controller, const char *cg) { + int fd, cfd; size_t len; - char *dirnam, *tmpc = find_mounted_controller(controller); + char *dirnam, *tmpc; + tmpc = find_mounted_controller(controller, &cfd); if (!tmpc) return false; - /* basedir / tmpc / cg \0 */ - len = strlen(basedir) + strlen(tmpc) + strlen(cg) + 3; + + /* Make sure we pass a relative path to *at() family of functions. + * . + /cg + \0 + */ + len = strlen(cg) + 2; dirnam = alloca(len); - snprintf(dirnam, len, "%s/%s/%s", basedir,tmpc, cg); - return recursive_rmdir(dirnam); + snprintf(dirnam, len, "%s%s", *cg == '/' ? "." : "", cg); + + fd = openat(cfd, dirnam, O_DIRECTORY); + if (fd < 0) + return false; + + return recursive_rmdir(dirnam, fd); } bool cgfs_chmod_file(const char *controller, const char *file, mode_t mode) { + int cfd; size_t len; - char *pathname, *tmpc = find_mounted_controller(controller); + char *pathname, *tmpc; + tmpc = find_mounted_controller(controller, &cfd); if (!tmpc) return false; - /* basedir / tmpc / file \0 */ - len = strlen(basedir) + strlen(tmpc) + strlen(file) + 3; + + /* Make sure we pass a relative path to *at() family of functions. + * . + /file + \0 + */ + len = strlen(file) + 2; pathname = alloca(len); - snprintf(pathname, len, "%s/%s/%s", basedir, tmpc, file); - if (chmod(pathname, mode) < 0) + snprintf(pathname, len, "%s%s", *file == '/' ? "." : "", file); + if (fchmodat(cfd, pathname, mode, 0) < 0) return false; return true; } -static int chown_tasks_files(const char *dirname, uid_t uid, gid_t gid) +static int chown_tasks_files(const char *dirname, uid_t uid, gid_t gid, int fd) { size_t len; char *fname; @@ -607,92 +686,112 @@ len = strlen(dirname) + strlen("/cgroup.procs") + 1; fname = alloca(len); snprintf(fname, len, "%s/tasks", dirname); - if (chown(fname, uid, gid) != 0) + if (fchownat(fd, fname, uid, gid, 0) != 0) return -errno; snprintf(fname, len, "%s/cgroup.procs", dirname); - if (chown(fname, uid, gid) != 0) + if (fchownat(fd, fname, uid, gid, 0) != 0) return -errno; return 0; } int cgfs_chown_file(const char *controller, const char *file, uid_t uid, gid_t gid) { + int cfd; size_t len; - char *pathname, *tmpc = find_mounted_controller(controller); + char *pathname, *tmpc; + tmpc = find_mounted_controller(controller, &cfd); if (!tmpc) return -EINVAL; - /* basedir / tmpc / file \0 */ - len = strlen(basedir) + strlen(tmpc) + strlen(file) + 3; + + /* Make sure we pass a relative path to *at() family of functions. + * . + /file + \0 + */ + len = strlen(file) + 2; pathname = alloca(len); - snprintf(pathname, len, "%s/%s/%s", basedir, tmpc, file); - if (chown(pathname, uid, gid) < 0) + snprintf(pathname, len, "%s%s", *file == '/' ? "." : "", file); + if (fchownat(cfd, pathname, uid, gid, 0) < 0) return -errno; - if (is_dir(pathname)) + if (is_dir(pathname, cfd)) // like cgmanager did, we want to chown the tasks file as well - return chown_tasks_files(pathname, uid, gid); + return chown_tasks_files(pathname, uid, gid, cfd); return 0; } FILE *open_pids_file(const char *controller, const char *cgroup) { + int fd, cfd; size_t len; - char *pathname, *tmpc = find_mounted_controller(controller); + char *pathname, *tmpc; + tmpc = find_mounted_controller(controller, &cfd); if (!tmpc) return NULL; - /* basedir / tmpc / cgroup / "cgroup.procs" \0 */ - len = strlen(basedir) + strlen(tmpc) + strlen(cgroup) + 4 + strlen("cgroup.procs"); + + /* Make sure we pass a relative path to *at() family of functions. + * . + /cgroup + / "cgroup.procs" + \0 + */ + len = strlen(cgroup) + strlen("cgroup.procs") + 3; pathname = alloca(len); - snprintf(pathname, len, "%s/%s/%s/cgroup.procs", basedir, tmpc, cgroup); - return fopen(pathname, "w"); + snprintf(pathname, len, "%s%s/cgroup.procs", *cgroup == '/' ? "." : "", cgroup); + + fd = openat(cfd, pathname, O_WRONLY); + if (fd < 0) + return NULL; + + return fdopen(fd, "w"); } static bool cgfs_iterate_cgroup(const char *controller, const char *cgroup, bool directories, void ***list, size_t typesize, void* (*iterator)(const char*, const char*, const char*)) { + int cfd, fd, ret; size_t len; - char *dirname, *tmpc = find_mounted_controller(controller); + char *cg, *tmpc; char pathname[MAXPATHLEN]; size_t sz = 0, asz = 0; - struct dirent dirent, *direntp; + struct dirent *dirent; DIR *dir; - int ret; + tmpc = find_mounted_controller(controller, &cfd); *list = NULL; if (!tmpc) return false; - /* basedir / tmpc / cgroup \0 */ - len = strlen(basedir) + strlen(tmpc) + strlen(cgroup) + 3; - dirname = alloca(len); - snprintf(dirname, len, "%s/%s/%s", basedir, tmpc, cgroup); + /* Make sure we pass a relative path to *at() family of functions. */ + len = strlen(cgroup) + 1 /* . */ + 1 /* \0 */; + cg = alloca(len); + ret = snprintf(cg, len, "%s%s", *cgroup == '/' ? "." : "", cgroup); + if (ret < 0 || (size_t)ret >= len) { + fprintf(stderr, "%s: pathname too long under %s\n", __func__, cgroup); + return false; + } + + fd = openat(cfd, cg, O_DIRECTORY); + if (fd < 0) + return false; - dir = opendir(dirname); + dir = fdopendir(fd); if (!dir) return false; - while (!readdir_r(dir, &dirent, &direntp)) { + while ((dirent = readdir(dir))) { struct stat mystat; - int rc; - - if (!direntp) - break; - if (!strcmp(direntp->d_name, ".") || - !strcmp(direntp->d_name, "..")) + if (!strcmp(dirent->d_name, ".") || + !strcmp(dirent->d_name, "..")) continue; - rc = snprintf(pathname, MAXPATHLEN, "%s/%s", dirname, direntp->d_name); - if (rc < 0 || rc >= MAXPATHLEN) { - fprintf(stderr, "%s: pathname too long under %s\n", __func__, dirname); + ret = snprintf(pathname, MAXPATHLEN, "%s/%s", cg, dirent->d_name); + if (ret < 0 || ret >= MAXPATHLEN) { + fprintf(stderr, "%s: pathname too long under %s\n", __func__, cg); continue; } - ret = lstat(pathname, &mystat); + ret = fstatat(cfd, pathname, &mystat, AT_SYMLINK_NOFOLLOW); if (ret) { fprintf(stderr, "%s: failed to stat %s: %s\n", __func__, pathname, strerror(errno)); continue; @@ -709,12 +808,12 @@ } while (!tmp); *list = tmp; } - (*list)[sz] = (*iterator)(controller, cgroup, direntp->d_name); + (*list)[sz] = (*iterator)(controller, cg, dirent->d_name); (*list)[sz+1] = NULL; sz++; } if (closedir(dir) < 0) { - fprintf(stderr, "%s: failed closedir for %s: %s\n", __func__, dirname, strerror(errno)); + fprintf(stderr, "%s: failed closedir for %s: %s\n", __func__, cgroup, strerror(errno)); return false; } return true; @@ -756,46 +855,60 @@ bool cgfs_get_value(const char *controller, const char *cgroup, const char *file, char **value) { + int ret, fd, cfd; size_t len; - char *fnam, *tmpc = find_mounted_controller(controller); + char *fnam, *tmpc; + tmpc = find_mounted_controller(controller, &cfd); if (!tmpc) return false; - /* basedir / tmpc / cgroup / file \0 */ - len = strlen(basedir) + strlen(tmpc) + strlen(cgroup) + strlen(file) + 4; + + /* Make sure we pass a relative path to *at() family of functions. + * . + /cgroup + / + file + \0 + */ + len = strlen(cgroup) + strlen(file) + 3; fnam = alloca(len); - snprintf(fnam, len, "%s/%s/%s/%s", basedir, tmpc, cgroup, file); + ret = snprintf(fnam, len, "%s%s/%s", *cgroup == '/' ? "." : "", cgroup, file); + if (ret < 0 || (size_t)ret >= len) + return NULL; + + fd = openat(cfd, fnam, O_RDONLY); + if (fd < 0) + return NULL; - *value = slurp_file(fnam); + *value = slurp_file(fnam, fd); return *value != NULL; } struct cgfs_files *cgfs_get_key(const char *controller, const char *cgroup, const char *file) { + int ret, cfd; size_t len; - char *fnam, *tmpc = find_mounted_controller(controller); + char *fnam, *tmpc; struct stat sb; struct cgfs_files *newkey; - int ret; + tmpc = find_mounted_controller(controller, &cfd); if (!tmpc) return false; if (file && *file == '/') file++; - if (file && index(file, '/')) + if (file && strchr(file, '/')) return NULL; - /* basedir / tmpc / cgroup / file \0 */ - len = strlen(basedir) + strlen(tmpc) + strlen(cgroup) + 3; + /* Make sure we pass a relative path to *at() family of functions. + * . + /cgroup + / + file + \0 + */ + len = strlen(cgroup) + 3; if (file) len += strlen(file) + 1; fnam = alloca(len); - snprintf(fnam, len, "%s/%s/%s%s%s", basedir, tmpc, cgroup, - file ? "/" : "", file ? file : ""); + snprintf(fnam, len, "%s%s%s%s", *cgroup == '/' ? "." : "", cgroup, + file ? "/" : "", file ? file : ""); - ret = stat(fnam, &sb); + ret = fstatat(cfd, fnam, &sb, 0); if (ret < 0) return NULL; @@ -804,8 +917,8 @@ } while (!newkey); if (file) newkey->name = must_copy_string(file); - else if (rindex(cgroup, '/')) - newkey->name = must_copy_string(rindex(cgroup, '/')); + else if (strrchr(cgroup, '/')) + newkey->name = must_copy_string(strrchr(cgroup, '/')); else newkey->name = must_copy_string(cgroup); newkey->uid = sb.st_uid; @@ -831,21 +944,30 @@ } bool is_child_cgroup(const char *controller, const char *cgroup, const char *f) -{ size_t len; - char *fnam, *tmpc = find_mounted_controller(controller); +{ + int cfd; + size_t len; + char *fnam, *tmpc; int ret; struct stat sb; + tmpc = find_mounted_controller(controller, &cfd); if (!tmpc) return false; - /* basedir / tmpc / cgroup / f \0 */ - len = strlen(basedir) + strlen(tmpc) + strlen(cgroup) + strlen(f) + 4; + + /* Make sure we pass a relative path to *at() family of functions. + * . + /cgroup + / + f + \0 + */ + len = strlen(cgroup) + strlen(f) + 3; fnam = alloca(len); - snprintf(fnam, len, "%s/%s/%s/%s", basedir, tmpc, cgroup, f); + ret = snprintf(fnam, len, "%s%s/%s", *cgroup == '/' ? "." : "", cgroup, f); + if (ret < 0 || (size_t)ret >= len) + return false; - ret = stat(fnam, &sb); + ret = fstatat(cfd, fnam, &sb, 0); if (ret < 0 || !S_ISDIR(sb.st_mode)) return false; + return true; } @@ -1158,7 +1280,7 @@ return NULL; } - if (strcmp(querycg, "/") == 0) + if ((strcmp(querycg, "/") == 0) || (strcmp(querycg, "./") == 0)) start = strdup(taskcg + 1); else start = strdup(taskcg + strlen(querycg) + 1); @@ -1179,13 +1301,14 @@ static char *get_pid_cgroup(pid_t pid, const char *contrl) { + int cfd; char fnam[PROCLEN]; FILE *f; char *answer = NULL; char *line = NULL; size_t len = 0; int ret; - const char *h = find_mounted_controller(contrl); + const char *h = find_mounted_controller(contrl, &cfd); if (!h) return NULL; @@ -1298,10 +1421,18 @@ prune_init_slice(c2); /* - * callers pass in '/' for root cgroup, otherwise they pass - * in a cgroup without leading '/' + * callers pass in '/' or './' (openat()) for root cgroup, otherwise + * they pass in a cgroup without leading '/' + * + * The original line here was: + * linecmp = *cg == '/' ? c2 : c2+1; + * TODO: I'm not sure why you'd want to increment when *cg != '/'? + * Serge, do you know? */ - linecmp = *cg == '/' ? c2 : c2+1; + if (*cg == '/' || !strncmp(cg, "./", 2)) + linecmp = c2; + else + linecmp = c2 + 1; if (strncmp(linecmp, cg, strlen(linecmp)) != 0) { if (nextcg) { *nextcg = get_next_cgroup_dir(linecmp, cg); @@ -1324,7 +1455,7 @@ char *c2, *task_cg; size_t target_len, task_len; - if (strcmp(cg, "/") == 0) + if (strcmp(cg, "/") == 0 || strcmp(cg, "./") == 0) return true; c2 = get_pid_cgroup(pid, contrl); @@ -3928,11 +4059,242 @@ } } -static void __attribute__((constructor)) collect_subsystems(void) +/* + * Functions needed to setup cgroups in the __constructor__. + */ + +static bool mkdir_p(const char *dir, mode_t mode) +{ + const char *tmp = dir; + const char *orig = dir; + char *makeme; + + do { + dir = tmp + strspn(tmp, "/"); + tmp = dir + strcspn(dir, "/"); + makeme = strndup(orig, dir - orig); + if (!makeme) + return false; + if (mkdir(makeme, mode) && errno != EEXIST) { + fprintf(stderr, "failed to create directory '%s': %s", + makeme, strerror(errno)); + free(makeme); + return false; + } + free(makeme); + } while(tmp != dir); + + return true; +} + +static bool umount_if_mounted(void) +{ + if (umount2(BASEDIR, MNT_DETACH) < 0 && errno != EINVAL) { + fprintf(stderr, "failed to unmount %s: %s.\n", BASEDIR, strerror(errno)); + return false; + } + return true; +} + +static int pivot_enter(void) +{ + int ret = -1, oldroot = -1, newroot = -1; + + oldroot = open("/", O_DIRECTORY | O_RDONLY); + if (oldroot < 0) { + fprintf(stderr, "%s: Failed to open old root for fchdir.\n", __func__); + return ret; + } + + newroot = open(ROOTDIR, O_DIRECTORY | O_RDONLY); + if (newroot < 0) { + fprintf(stderr, "%s: Failed to open new root for fchdir.\n", __func__); + goto err; + } + + /* change into new root fs */ + if (fchdir(newroot) < 0) { + fprintf(stderr, "%s: Failed to change directory to new rootfs: %s.\n", __func__, ROOTDIR); + goto err; + } + + /* pivot_root into our new root fs */ + if (pivot_root(".", ".") < 0) { + fprintf(stderr, "%s: pivot_root() syscall failed: %s.\n", __func__, strerror(errno)); + goto err; + } + + /* + * At this point the old-root is mounted on top of our new-root. + * To unmounted it we must not be chdir'd into it, so escape back + * to the old-root. + */ + if (fchdir(oldroot) < 0) { + fprintf(stderr, "%s: Failed to enter old root.\n", __func__); + goto err; + } + if (umount2(".", MNT_DETACH) < 0) { + fprintf(stderr, "%s: Failed to detach old root.\n", __func__); + goto err; + } + + if (fchdir(newroot) < 0) { + fprintf(stderr, "%s: Failed to re-enter new root.\n", __func__); + goto err; + } + + ret = 0; + +err: + if (oldroot > 0) + close(oldroot); + if (newroot > 0) + close(newroot); + return ret; +} + +/* Prepare our new clean root. */ +static int pivot_prepare(void) +{ + if (mkdir(ROOTDIR, 0700) < 0 && errno != EEXIST) { + fprintf(stderr, "%s: Failed to create directory for new root.\n", __func__); + return -1; + } + + if (mount("/", ROOTDIR, NULL, MS_BIND, 0) < 0) { + fprintf(stderr, "%s: Failed to bind-mount / for new root: %s.\n", __func__, strerror(errno)); + return -1; + } + + if (mount(RUNTIME_PATH, ROOTDIR RUNTIME_PATH, NULL, MS_BIND, 0) < 0) { + fprintf(stderr, "%s: Failed to bind-mount /run into new root: %s.\n", __func__, strerror(errno)); + return -1; + } + + if (mount(BASEDIR, ROOTDIR BASEDIR, NULL, MS_REC | MS_MOVE, 0) < 0) { + printf("%s: failed to move " BASEDIR " into new root: %s.\n", __func__, strerror(errno)); + return -1; + } + + return 0; +} + +static bool pivot_new_root(void) +{ + /* Prepare new root. */ + if (pivot_prepare() < 0) + return false; + + /* Pivot into new root. */ + if (pivot_enter() < 0) + return false; + + return true; +} + +static bool setup_cgfs_dir(void) +{ + if (!mkdir_p(BASEDIR, 0700)) { + fprintf(stderr, "Failed to create lxcfs cgroup mountpoint.\n"); + return false; + } + + if (!umount_if_mounted()) { + fprintf(stderr, "Failed to clean up old lxcfs cgroup mountpoint.\n"); + return false; + } + + if (unshare(CLONE_NEWNS) < 0) { + fprintf(stderr, "%s: Failed to unshare mount namespace: %s.\n", __func__, strerror(errno)); + return false; + } + + if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0) < 0) { + fprintf(stderr, "%s: Failed to remount / private: %s.\n", __func__, strerror(errno)); + return false; + } + + if (mount("tmpfs", BASEDIR, "tmpfs", 0, "size=100000,mode=700") < 0) { + fprintf(stderr, "Failed to mount tmpfs over lxcfs cgroup mountpoint.\n"); + return false; + } + + return true; +} + +static bool do_mount_cgroups(void) +{ + char *target; + size_t clen, len; + int i, ret; + + for (i = 0; i < num_hierarchies; i++) { + char *controller = hierarchies[i]; + clen = strlen(controller); + len = strlen(BASEDIR) + clen + 2; + target = malloc(len); + if (!target) + return false; + ret = snprintf(target, len, "%s/%s", BASEDIR, controller); + if (ret < 0 || ret >= len) { + free(target); + return false; + } + if (mkdir(target, 0755) < 0 && errno != EEXIST) { + free(target); + return false; + } + if (mount(controller, target, "cgroup", 0, controller) < 0) { + fprintf(stderr, "Failed mounting cgroup %s\n", controller); + free(target); + return false; + } + + fd_hierarchies[i] = open(target, O_DIRECTORY); + if (fd_hierarchies[i] < 0) { + free(target); + return false; + } + free(target); + } + return true; +} + +static bool cgfs_setup_controllers(void) +{ + if (!setup_cgfs_dir()) + return false; + + if (!do_mount_cgroups()) { + fprintf(stderr, "Failed to set up private lxcfs cgroup mounts.\n"); + return false; + } + + if (!pivot_new_root()) + return false; + + return true; +} + +static int preserve_ns(int pid) +{ + int ret; + size_t len = 5 /* /proc */ + 21 /* /int_as_str */ + 7 /* /ns/mnt */ + 1 /* \0 */; + char path[len]; + + ret = snprintf(path, len, "/proc/%d/ns/mnt", pid); + if (ret < 0 || (size_t)ret >= len) + return -1; + + return open(path, O_RDONLY | O_CLOEXEC); +} + +static void __attribute__((constructor)) collect_and_mount_subsystems(void) { FILE *f; char *line = NULL; size_t len = 0; + int i, init_ns = -1; if ((f = fopen("/proc/self/cgroup", "r")) == NULL) { fprintf(stderr, "Error opening /proc/self/cgroup: %s\n", strerror(errno)); @@ -3951,23 +4313,57 @@ goto out; *p2 = '\0'; + /* With cgroupv2 /proc/self/cgroup can contain entries of the + * form: 0::/ This will cause lxcfs to fail the cgroup mounts + * because it parses out the empty string "" and later on passes + * it to mount(). Let's skip such entries. + */ + if (!strcmp(p, "")) + continue; + if (!store_hierarchy(line, p)) goto out; } + /* Preserve initial namespace. */ + init_ns = preserve_ns(getpid()); + if (init_ns < 0) + goto out; + + fd_hierarchies = malloc(sizeof(int *) * num_hierarchies); + if (!fd_hierarchies) + goto out; + + for (i = 0; i < num_hierarchies; i++) + fd_hierarchies[i] = -1; + + /* This function calls unshare(CLONE_NEWNS) our initial mount namespace + * to privately mount lxcfs cgroups. */ + if (!cgfs_setup_controllers()) + goto out; + + if (setns(init_ns, 0) < 0) + goto out; + print_subsystems(); out: free(line); fclose(f); + if (init_ns >= 0) + close(init_ns); } static void __attribute__((destructor)) free_subsystems(void) { int i; - for (i = 0; i < num_hierarchies; i++) + for (i = 0; i < num_hierarchies; i++) { if (hierarchies[i]) free(hierarchies[i]); + if (fd_hierarchies && fd_hierarchies[i] >= 0) + close(fd_hierarchies[i]); + } free(hierarchies); + free(fd_hierarchies); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-2.0.2/bindings.h new/lxcfs-2.0.3/bindings.h --- old/lxcfs-2.0.2/bindings.h 2016-06-28 20:27:44.000000000 +0200 +++ new/lxcfs-2.0.3/bindings.h 2016-08-16 04:36:32.000000000 +0200 @@ -1,5 +1,6 @@ /* directory under which we mount the controllers - /run/lxcfs/controllers */ -#define basedir RUNTIME_PATH "/lxcfs/controllers" +#define BASEDIR RUNTIME_PATH "/lxcfs/controllers" +#define ROOTDIR RUNTIME_PATH "/lxcfs/root" extern int cg_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-2.0.2/config/init/sysvinit/Makefile.in new/lxcfs-2.0.3/config/init/sysvinit/Makefile.in --- old/lxcfs-2.0.2/config/init/sysvinit/Makefile.in 2016-06-28 20:27:48.000000000 +0200 +++ new/lxcfs-2.0.3/config/init/sysvinit/Makefile.in 2016-08-16 04:36:38.000000000 +0200 @@ -361,8 +361,8 @@ maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -@INIT_SCRIPT_SYSV_FALSE@install-data-local: @INIT_SCRIPT_SYSV_FALSE@uninstall-local: +@INIT_SCRIPT_SYSV_FALSE@install-data-local: clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-2.0.2/config/init/upstart/Makefile.in new/lxcfs-2.0.3/config/init/upstart/Makefile.in --- old/lxcfs-2.0.2/config/init/upstart/Makefile.in 2016-06-28 20:27:48.000000000 +0200 +++ new/lxcfs-2.0.3/config/init/upstart/Makefile.in 2016-08-16 04:36:38.000000000 +0200 @@ -361,8 +361,8 @@ maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -@INIT_SCRIPT_UPSTART_FALSE@uninstall-local: @INIT_SCRIPT_UPSTART_FALSE@install-data-local: +@INIT_SCRIPT_UPSTART_FALSE@uninstall-local: clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-2.0.2/configure new/lxcfs-2.0.3/configure --- old/lxcfs-2.0.2/configure 2016-06-28 20:27:47.000000000 +0200 +++ new/lxcfs-2.0.3/configure 2016-08-16 04:36:37.000000000 +0200 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for lxcfs 2.0.2. +# Generated by GNU Autoconf 2.69 for lxcfs 2.0.3. # # Report bugs to <[email protected]>. # @@ -590,8 +590,8 @@ # Identity of this package. PACKAGE_NAME='lxcfs' PACKAGE_TARNAME='lxcfs' -PACKAGE_VERSION='2.0.2' -PACKAGE_STRING='lxcfs 2.0.2' +PACKAGE_VERSION='2.0.3' +PACKAGE_STRING='lxcfs 2.0.3' PACKAGE_BUGREPORT='[email protected]' PACKAGE_URL='' @@ -1368,7 +1368,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures lxcfs 2.0.2 to adapt to many kinds of systems. +\`configure' configures lxcfs 2.0.3 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1439,7 +1439,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of lxcfs 2.0.2:";; + short | recursive ) echo "Configuration of lxcfs 2.0.3:";; esac cat <<\_ACEOF @@ -1569,7 +1569,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -lxcfs configure 2.0.2 +lxcfs configure 2.0.3 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1938,7 +1938,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by lxcfs $as_me 2.0.2, which was +It was created by lxcfs $as_me 2.0.3, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2805,7 +2805,7 @@ # Define the identity of the package. PACKAGE='lxcfs' - VERSION='2.0.2' + VERSION='2.0.3' cat >>confdefs.h <<_ACEOF @@ -14497,7 +14497,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by lxcfs $as_me 2.0.2, which was +This file was extended by lxcfs $as_me 2.0.3, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14563,7 +14563,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -lxcfs config.status 2.0.2 +lxcfs config.status 2.0.3 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-2.0.2/configure.ac new/lxcfs-2.0.3/configure.ac --- old/lxcfs-2.0.2/configure.ac 2016-06-28 20:27:44.000000000 +0200 +++ new/lxcfs-2.0.3/configure.ac 2016-08-16 04:36:32.000000000 +0200 @@ -1,7 +1,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([lxcfs], [2.0.2], [[email protected]]) +AC_INIT([lxcfs], [2.0.3], [[email protected]]) AC_SUBST(ACLOCAL_AMFLAGS, "-I m4") AC_CONFIG_MACRO_DIR([m4]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-2.0.2/lxcfs.c new/lxcfs-2.0.3/lxcfs.c --- old/lxcfs-2.0.2/lxcfs.c 2016-06-28 20:27:44.000000000 +0200 +++ new/lxcfs-2.0.3/lxcfs.c 2016-08-16 04:36:32.000000000 +0200 @@ -8,28 +8,29 @@ #define FUSE_USE_VERSION 26 -#include <stdio.h> +#include <alloca.h> #include <dirent.h> +#include <dlfcn.h> +#include <errno.h> #include <fcntl.h> #include <fuse.h> -#include <unistd.h> -#include <errno.h> -#include <stdbool.h> -#include <time.h> -#include <string.h> -#include <stdlib.h> #include <libgen.h> -#include <sched.h> #include <pthread.h> -#include <dlfcn.h> +#include <sched.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <wait.h> #include <linux/sched.h> -#include <sys/socket.h> -#include <sys/mount.h> #include <sys/epoll.h> -#include <wait.h> +#include <sys/mount.h> +#include <sys/socket.h> -#include "config.h" // for VERSION #include "bindings.h" +#include "config.h" // for VERSION void *dlopen_handle; @@ -83,7 +84,7 @@ dlopen_handle = dlopen("/usr/lib/lxcfs/liblxcfs.so", RTLD_LAZY); if (!dlopen_handle) { - fprintf(stderr, "Failed to open liblxcfs\n"); + fprintf(stderr, "Failed to open liblxcfs: %s.\n", dlerror()); _exit(1); } @@ -763,127 +764,6 @@ return false; } -static bool mkdir_p(const char *dir, mode_t mode) -{ - const char *tmp = dir; - const char *orig = dir; - char *makeme; - - do { - dir = tmp + strspn(tmp, "/"); - tmp = dir + strcspn(dir, "/"); - makeme = strndup(orig, dir - orig); - if (!makeme) - return false; - if (mkdir(makeme, mode) && errno != EEXIST) { - fprintf(stderr, "failed to create directory '%s': %s", - makeme, strerror(errno)); - free(makeme); - return false; - } - free(makeme); - } while(tmp != dir); - - return true; -} - -static bool umount_if_mounted(void) -{ - if (umount2(basedir, MNT_DETACH) < 0 && errno != EINVAL) { - fprintf(stderr, "failed to umount %s: %s\n", basedir, - strerror(errno)); - return false; - } - return true; -} - -static bool setup_cgfs_dir(void) -{ - if (!mkdir_p(basedir, 0700)) { - fprintf(stderr, "Failed to create lxcfs cgdir\n"); - return false; - } - if (!umount_if_mounted()) { - fprintf(stderr, "Failed to clean up old lxcfs cgdir\n"); - return false; - } - if (mount("tmpfs", basedir, "tmpfs", 0, "size=100000,mode=700") < 0) { - fprintf(stderr, "Failed to mount tmpfs for private controllers\n"); - return false; - } - return true; -} - -static bool do_mount_cgroup(char *controller) -{ - char *target; - size_t len; - int ret; - - len = strlen(basedir) + strlen(controller) + 2; - target = alloca(len); - ret = snprintf(target, len, "%s/%s", basedir, controller); - if (ret < 0 || ret >= len) - return false; - if (mkdir(target, 0755) < 0 && errno != EEXIST) - return false; - if (mount(controller, target, "cgroup", 0, controller) < 0) { - fprintf(stderr, "Failed mounting cgroup %s\n", controller); - return false; - } - return true; -} - -static bool do_mount_cgroups(void) -{ - bool ret = false; - FILE *f; - char *line = NULL; - size_t len = 0; - - if ((f = fopen("/proc/self/cgroup", "r")) == NULL) { - fprintf(stderr, "Error opening /proc/self/cgroup: %s\n", strerror(errno)); - return false; - } - - while (getline(&line, &len, f) != -1) { - char *p, *p2; - - p = strchr(line, ':'); - if (!p) - goto out; - *(p++) = '\0'; - - p2 = strrchr(p, ':'); - if (!p2) - goto out; - *p2 = '\0'; - - if (!do_mount_cgroup(p)) - goto out; - } - ret = true; - -out: - free(line); - fclose(f); - return ret; -} - -static bool cgfs_setup_controllers(void) -{ - if (!setup_cgfs_dir()) { - return false; - } - - if (!do_mount_cgroups()) { - fprintf(stderr, "Failed to set up cgroup mounts\n"); - return false; - } - - return true; -} - static int set_pidfile(char *pidfile) { int fd; @@ -928,7 +808,8 @@ int main(int argc, char *argv[]) { - int ret = -1, pidfd; + int ret = EXIT_FAILURE; + int pidfd = -1; char *pidfile = NULL, *v = NULL; size_t pidfile_len; /* @@ -944,7 +825,7 @@ if (swallow_option(&argc, argv, "-o", &v)) { if (strcmp(v, "allow_other") != 0) { fprintf(stderr, "Warning: unexpected fuse option %s\n", v); - exit(1); + exit(EXIT_FAILURE); } free(v); v = NULL; @@ -954,7 +835,7 @@ if (argc == 2 && strcmp(argv[1], "--version") == 0) { fprintf(stderr, "%s\n", VERSION); - exit(0); + exit(EXIT_SUCCESS); } if (argc != 2 || is_help(argv[1])) usage(argv[0]); @@ -962,7 +843,7 @@ do_reload(); if (signal(SIGUSR1, reload_handler) == SIG_ERR) { fprintf(stderr, "Error setting USR1 signal handler: %m\n"); - exit(1); + goto out; } newargv[cnt++] = argv[0]; @@ -972,9 +853,6 @@ newargv[cnt++] = argv[1]; newargv[cnt++] = NULL; - if (!cgfs_setup_controllers()) - goto out; - if (!pidfile) { pidfile_len = strlen(RUNTIME_PATH) + strlen("/lxcfs.pid") + 1; pidfile = alloca(pidfile_len); @@ -983,12 +861,15 @@ if ((pidfd = set_pidfile(pidfile)) < 0) goto out; - ret = fuse_main(nargs, newargv, &lxcfs_ops, NULL); - - dlclose(dlopen_handle); - unlink(pidfile); - close(pidfd); + if (!fuse_main(nargs, newargv, &lxcfs_ops, NULL)) + ret = EXIT_SUCCESS; out: - return ret; + if (dlopen_handle) + dlclose(dlopen_handle); + if (pidfile) + unlink(pidfile); + if (pidfd > 0) + close(pidfd); + exit(ret); }
