Skip to content

Commit

Permalink
ccon: Create mount target files/directories based on source stat
Browse files Browse the repository at this point in the history
Avoid:

  mount("/some/source/file", "/some/target/file", NULL, MS_BIND, NULL) = -1 ENOTDIR (Not a directory)

by creating target *files* (instead of directories) in those cases.
  • Loading branch information
wking committed Feb 27, 2018
1 parent 766d926 commit ce2d4a4
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 6 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,9 +348,12 @@ processes inside a user namespace.

If they don't start with a slash, **`source`** and **`target`** are
interpreted as paths relative to ccon's [current working
directory][getcwd.3]. If **`target`** does not exist, ccon will
attempt to create it by calling [`mkdir`][mkdir.3p], making multiple
calls if necessary.
directory][getcwd.3].

If **`target`** does not exist, ccon will attempt to create it by
calling [`mkdir`][mkdir.3p], making multiple calls if necessary. If
**`source`** is set to a non-directory and **`target`** does not exit,
ccon will create an empty file at **`target`** to mount over.

In addition to the usual types supported by [`mount`][mount.2], ccon
supports a `pivot-root` **`type`** that invokes the
Expand Down
54 changes: 51 additions & 3 deletions ccon.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ static char **json_array_of_strings_value(json_t * array);
static int close_pipe(int pipe_fd[]);
static int splice_pseudoterminal_master(int *master, int *slave);
static int mkdir_all(const char *path, mode_t mode);
static int mkfile_all(const char *path, mode_t dir_mode, mode_t file_mode);

int main(int argc, char **argv)
{
Expand Down Expand Up @@ -2137,12 +2138,13 @@ static int get_mount_flag(const char *name, unsigned long *flag)

static int handle_mounts(json_t * config)
{
struct stat buf;
json_t *namespaces, *mt_ns, *mounts, *mt, *v1, *v2;
const char *source, *target, *type, *data, *flag;
char cwd[MAX_PATH], full_source[MAX_PATH], full_target[MAX_PATH];
unsigned long flags, f;
size_t i, j;
int size;
int size, mkdir;

namespaces = json_object_get(config, "namespaces");
if (!namespaces) {
Expand Down Expand Up @@ -2253,7 +2255,19 @@ static int handle_mounts(json_t * config)
return 1;
}
} else {
if (mkdir_all(target, 0777) == -1) {
mkdir = 1;
if (source) {
if (stat(source, &buf) == -1) {
PERROR("stat");
return 1;
}
mkdir = S_ISDIR(buf.st_mode);
}
if (mkdir) {
if (mkdir_all(target, 0777) == -1) {
return 1;
}
} else if (mkfile_all(target, 0777, 0666) == -1) {
return 1;
}

Expand Down Expand Up @@ -2620,7 +2634,7 @@ static int mkdir_all(const char *path, mode_t mode)
err = -1;
goto cleanup;
}
LOG("create directory %s\n", path);;
LOG("create directory %s\n", path);
if (mkdir(path, mode) == -1) {
PERROR("mkdir");
err = -1;
Expand All @@ -2639,3 +2653,37 @@ static int mkdir_all(const char *path, mode_t mode)
}
return err;
}

static int mkfile_all(const char *path, mode_t dir_mode, mode_t file_mode)
{
char *path_copy = NULL, *dir = NULL;
int fd = -1, err = 0;

path_copy = strdup(path);
if (path_copy == NULL) {
PERROR("strdup");
err = -1;
goto cleanup;
}
dir = dirname(path_copy);
if (mkdir_all(dir, dir_mode) == -1) {
err = -1;
goto cleanup;
}
LOG("create file %s\n", path);
fd = open(path, O_CREAT | O_RDONLY, file_mode);
if (fd == -1) {
PERROR("mkdir_all open");
}

cleanup:
if (fd >= 0) {
if (close(fd) == -1) {
PERROR("close mkdir_all descriptor");
}
}
if (path_copy != NULL) {
free(path_copy);
}
return err;
}
47 changes: 47 additions & 0 deletions test/t2002-mount-namespace.t
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,51 @@ test_expect_success BUSYBOX,ID 'Test mount namespace creates destination directo
test_cmp expected actual
"

test_expect_success BUSYBOX,ID 'Test mount namespace creates destination files' "
mkdir -p rootfs &&
ccon --verbose --config-string '{
\"version\": \"0.5.0\",
\"namespaces\": {
\"user\": {
\"setgroups\": false,
\"uidMappings\": [
{
\"containerID\": 0,
\"hostID\": $(id -u),
\"size\": 1
}
],
\"gidMappings\": [
{
\"containerID\": 0,
\"hostID\": $(id -u),
\"size\": 1
}
]
},
\"mount\": {
\"mounts\": [
{
\"target\": \"/tmp/\",
\"type\": \"tmpfs\"
},
{
\"source\": \"/bin/busybox\",
\"target\": \"/tmp/a/b/c\",
\"flags\": [
\"MS_BIND\"
]
}
]
}
},
\"process\": {
\"args\": [\"/bin/busybox\", \"ls\", \"/tmp/a/b\"],
\"host\": true
}
}' >actual &&
echo c >expected &&
test_cmp expected actual
"

test_done

0 comments on commit ce2d4a4

Please sign in to comment.