Skip to content

Commit aaebdae

Browse files
committed
ccon: Recursively mkdir for missing mount targets
This makes it possible to mount content inside a tmpfs. For example, systemd wants a tmpfs at /dev [1] and you may want to also mount /dev/pts, /dev/shm, etc. Or you may want to put a tmpfs at /sys/fs/cgroup and a cgroup filesystem at /sys/fs/cgroup/systemd. There's also some background discussion in [2]. [1]: https://www.freedesktop.org/wiki/Software/systemd/ContainerInterface/ [2]: opencontainers/runtime-spec#591 Subject: Require the mount destination to be created before hand
1 parent e4a62da commit aaebdae

File tree

3 files changed

+89
-1
lines changed

3 files changed

+89
-1
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,9 @@ processes inside a user namespace.
264264

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

269271
In addition to the usual types supported by [`mount`][mount.2], ccon
270272
supports a `pivot-root` **`type`** that invokes the
@@ -837,6 +839,7 @@ be distributed under the GPLv3+.
837839
[exec.3]: http://man7.org/linux/man-pages/man3/exec.3.html
838840
[getcwd.3]: http://man7.org/linux/man-pages/man3/getcwd.3.html
839841
[grantpt.3p]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/grantpt.html
842+
[mkdir.3p]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html
840843
[posix_openpt.3p]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html
841844
[stdin.3]: http://man7.org/linux/man-pages/man3/stdin.3.html
842845
[pts.4]: http://man7.org/linux/man-pages/man4/pty.4.html

ccon.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ static int close_pipe(int pipe_fd[]);
124124
static int sendfd(int socket, int *fd);
125125
static int recvfd(int socket, int *fd);
126126
static int splice_pseudoterminal_master(int *master);
127+
static int mkdir_all(const char *path, mode_t mode);
127128

128129
int main(int argc, char **argv)
129130
{
@@ -1889,6 +1890,10 @@ static int handle_mounts(json_t * config)
18891890
return 1;
18901891
}
18911892
} else {
1893+
if (mkdir_all(target, 0777) == -1) {
1894+
return 1;
1895+
}
1896+
18921897
LOG("mount %lu: %s to %s (type: %s, flags: %lu, data %s)\n", (unsigned long int)i, source, target, type, flags, data);
18931898
if (mount(source, target, type, flags, data) == -1) {
18941899
PERROR("mount");
@@ -2366,3 +2371,37 @@ static int splice_pseudoterminal_master(int *master)
23662371

23672372
return err;
23682373
}
2374+
2375+
static int mkdir_all(const char *path, mode_t mode)
2376+
{
2377+
struct stat buf;
2378+
char *path_copy = NULL, *dir = NULL;
2379+
int err = 0;
2380+
2381+
if (stat(path, &buf) == -1) {
2382+
if (errno == ENOENT) {
2383+
path_copy = strdup(path);
2384+
dir = dirname(path_copy);
2385+
if (mkdir_all(dir, mode) == -1) {
2386+
err = -1;
2387+
goto cleanup;
2388+
}
2389+
LOG("create directory %s\n", path);;
2390+
if (mkdir(path, mode) == -1) {
2391+
PERROR("mkdir");
2392+
err = -1;
2393+
goto cleanup;
2394+
}
2395+
} else {
2396+
PERROR("stat");
2397+
err = -1;
2398+
goto cleanup;
2399+
}
2400+
}
2401+
2402+
cleanup:
2403+
if (path_copy != NULL) {
2404+
free(path_copy);
2405+
}
2406+
return err;
2407+
}

test/t2002-mount-namespace.t

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,50 @@ test_expect_success BUSYBOX,ID 'Test mount namespace pivot root' "
110110
test_cmp expected actual
111111
"
112112

113+
test_expect_success BUSYBOX,ID 'Test mount namespace creates destination directories' "
114+
mkdir -p rootfs &&
115+
ccon --verbose --config-string '{
116+
\"version\": \"0.4.0\",
117+
\"namespaces\": {
118+
\"user\": {
119+
\"setgroups\": false,
120+
\"uidMappings\": [
121+
{
122+
\"containerID\": 0,
123+
\"hostID\": $(id -u),
124+
\"size\": 1
125+
}
126+
],
127+
\"gidMappings\": [
128+
{
129+
\"containerID\": 0,
130+
\"hostID\": $(id -u),
131+
\"size\": 1
132+
}
133+
]
134+
},
135+
\"mount\": {
136+
\"mounts\": [
137+
{
138+
\"target\": \"/tmp/\",
139+
\"type\": \"tmpfs\"
140+
},
141+
{
142+
\"target\": \"/tmp/foo/bar\",
143+
\"type\": \"tmpfs\"
144+
}
145+
]
146+
}
147+
},
148+
\"process\": {
149+
\"args\": [\"/bin/busybox\", \"ls\", \"/tmp/foo\"],
150+
\"host\": true
151+
}
152+
}' >actual &&
153+
cat <<-EOF >expected &&
154+
bar
155+
EOF
156+
test_cmp expected actual
157+
"
158+
113159
test_done

0 commit comments

Comments
 (0)