* 2 of the License, or (at your option) any later version.
*/
+#include <sys/statvfs.h>
#include <fcntl.h>
#include <dirent.h>
+#include <limits.h>
#include "utils.h"
#include "namespace.h"
static void bind_etc(const char *name)
{
- char etc_netns_path[MAXPATHLEN];
- char netns_name[MAXPATHLEN];
- char etc_name[MAXPATHLEN];
+ char etc_netns_path[sizeof(NETNS_ETC_DIR) + NAME_MAX];
+ char netns_name[PATH_MAX];
+ char etc_name[PATH_MAX];
struct dirent *entry;
DIR *dir;
+ if (strlen(name) >= NAME_MAX)
+ return;
+
snprintf(etc_netns_path, sizeof(etc_netns_path), "%s/%s", NETNS_ETC_DIR, name);
dir = opendir(etc_netns_path);
if (!dir)
int netns_switch(char *name)
{
- char net_path[MAXPATHLEN];
+ char net_path[PATH_MAX];
int netns;
+ unsigned long mountflags = 0;
+ struct statvfs fsstat;
snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
netns = open(net_path, O_RDONLY | O_CLOEXEC);
if (setns(netns, CLONE_NEWNET) < 0) {
fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n",
name, strerror(errno));
+ close(netns);
return -1;
}
+ close(netns);
if (unshare(CLONE_NEWNS) < 0) {
fprintf(stderr, "unshare failed: %s\n", strerror(errno));
strerror(errno));
return -1;
}
+
/* Mount a version of /sys that describes the network namespace */
+
if (umount2("/sys", MNT_DETACH) < 0) {
- fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno));
- return -1;
+ /* If this fails, perhaps there wasn't a sysfs instance mounted. Good. */
+ if (statvfs("/sys", &fsstat) == 0) {
+ /* We couldn't umount the sysfs, we'll attempt to overlay it.
+ * A read-only instance can't be shadowed with a read-write one. */
+ if (fsstat.f_flag & ST_RDONLY)
+ mountflags = MS_RDONLY;
+ }
}
- if (mount(name, "/sys", "sysfs", 0, NULL) < 0) {
+ if (mount(name, "/sys", "sysfs", mountflags, NULL) < 0) {
fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno));
return -1;
}
int netns_get_fd(const char *name)
{
- char pathbuf[MAXPATHLEN];
+ char pathbuf[PATH_MAX];
const char *path, *ptr;
path = name;