]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/namespace.c
shared: add path_compare(), an ordering path comparison
[thirdparty/systemd.git] / src / core / namespace.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
15ae422b
LP
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
15ae422b
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
15ae422b 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
15ae422b
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <sys/mount.h>
24#include <string.h>
25#include <stdio.h>
26#include <unistd.h>
27#include <sys/stat.h>
15ae422b 28#include <sched.h>
25e870b5 29#include <linux/fs.h>
15ae422b
LP
30
31#include "strv.h"
32#include "util.h"
9eb977db 33#include "path-util.h"
15ae422b 34#include "missing.h"
613b411c 35#include "loopback-setup.h"
7f112f50 36#include "dev-setup.h"
d7b8eec7
LP
37#include "selinux-util.h"
38#include "namespace.h"
15ae422b 39
c17ec25e 40typedef enum MountMode {
15ae422b
LP
41 /* This is ordered by priority! */
42 INACCESSIBLE,
43 READONLY,
ac0930c8
LP
44 PRIVATE_TMP,
45 PRIVATE_VAR_TMP,
7f112f50 46 PRIVATE_DEV,
a610cc4f 47 PRIVATE_BUS_ENDPOINT,
15ae422b 48 READWRITE
c17ec25e 49} MountMode;
15ae422b 50
c17ec25e 51typedef struct BindMount {
15ae422b 52 const char *path;
c17ec25e 53 MountMode mode;
ac0930c8 54 bool done;
ea92ae33 55 bool ignore;
c17ec25e 56} BindMount;
15ae422b 57
c17ec25e 58static int append_mounts(BindMount **p, char **strv, MountMode mode) {
15ae422b
LP
59 char **i;
60
613b411c
LP
61 assert(p);
62
15ae422b
LP
63 STRV_FOREACH(i, strv) {
64
ea92ae33 65 (*p)->ignore = false;
002b2268 66 (*p)->done = false;
ea92ae33 67
94828d2d 68 if ((mode == INACCESSIBLE || mode == READONLY || mode == READWRITE) && (*i)[0] == '-') {
ea92ae33
MW
69 (*p)->ignore = true;
70 (*i)++;
71 }
72
15ae422b
LP
73 if (!path_is_absolute(*i))
74 return -EINVAL;
75
76 (*p)->path = *i;
77 (*p)->mode = mode;
78 (*p)++;
79 }
80
81 return 0;
82}
83
c17ec25e
MS
84static int mount_path_compare(const void *a, const void *b) {
85 const BindMount *p = a, *q = b;
15ae422b
LP
86
87 if (path_equal(p->path, q->path)) {
88
89 /* If the paths are equal, check the mode */
90 if (p->mode < q->mode)
91 return -1;
92
93 if (p->mode > q->mode)
94 return 1;
95
96 return 0;
97 }
98
99 /* If the paths are not equal, then order prefixes first */
100 if (path_startswith(p->path, q->path))
101 return 1;
102
103 if (path_startswith(q->path, p->path))
104 return -1;
105
106 return 0;
107}
108
c17ec25e
MS
109static void drop_duplicates(BindMount *m, unsigned *n) {
110 BindMount *f, *t, *previous;
15ae422b 111
c17ec25e 112 assert(m);
15ae422b 113 assert(n);
15ae422b 114
c17ec25e 115 for (f = m, t = m, previous = NULL; f < m+*n; f++) {
15ae422b 116
ac0930c8 117 /* The first one wins */
15ae422b
LP
118 if (previous && path_equal(f->path, previous->path))
119 continue;
120
e2d7c1a0 121 *t = *f;
15ae422b 122
15ae422b
LP
123 previous = t;
124
125 t++;
126 }
127
c17ec25e 128 *n = t - m;
15ae422b
LP
129}
130
7f112f50
LP
131static int mount_dev(BindMount *m) {
132 static const char devnodes[] =
133 "/dev/null\0"
134 "/dev/zero\0"
135 "/dev/full\0"
136 "/dev/random\0"
137 "/dev/urandom\0"
138 "/dev/tty\0";
139
2b85f4e1 140 char temporary_mount[] = "/tmp/namespace-dev-XXXXXX";
63cc4c31 141 const char *d, *dev = NULL, *devpts = NULL, *devshm = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL;
7f112f50
LP
142 _cleanup_umask_ mode_t u;
143 int r;
144
145 assert(m);
146
147 u = umask(0000);
148
2b85f4e1
LP
149 if (!mkdtemp(temporary_mount))
150 return -errno;
151
63c372cb 152 dev = strjoina(temporary_mount, "/dev");
dc751688 153 (void) mkdir(dev, 0755);
2b85f4e1
LP
154 if (mount("tmpfs", dev, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=755") < 0) {
155 r = -errno;
156 goto fail;
157 }
158
63c372cb 159 devpts = strjoina(temporary_mount, "/dev/pts");
dc751688 160 (void) mkdir(devpts, 0755);
2b85f4e1
LP
161 if (mount("/dev/pts", devpts, NULL, MS_BIND, NULL) < 0) {
162 r = -errno;
163 goto fail;
164 }
165
63c372cb 166 devptmx = strjoina(temporary_mount, "/dev/ptmx");
3164e3cb
ZJS
167 if (symlink("pts/ptmx", devptmx) < 0) {
168 r = -errno;
169 goto fail;
170 }
e06b6479 171
63c372cb 172 devshm = strjoina(temporary_mount, "/dev/shm");
dc751688 173 (void) mkdir(devshm, 01777);
2b85f4e1
LP
174 r = mount("/dev/shm", devshm, NULL, MS_BIND, NULL);
175 if (r < 0) {
176 r = -errno;
177 goto fail;
178 }
179
63c372cb 180 devmqueue = strjoina(temporary_mount, "/dev/mqueue");
dc751688 181 (void) mkdir(devmqueue, 0755);
3164e3cb 182 (void) mount("/dev/mqueue", devmqueue, NULL, MS_BIND, NULL);
2b85f4e1 183
63c372cb 184 devhugepages = strjoina(temporary_mount, "/dev/hugepages");
dc751688 185 (void) mkdir(devhugepages, 0755);
3164e3cb 186 (void) mount("/dev/hugepages", devhugepages, NULL, MS_BIND, NULL);
2b85f4e1 187
63c372cb 188 devlog = strjoina(temporary_mount, "/dev/log");
3164e3cb 189 (void) symlink("/run/systemd/journal/dev-log", devlog);
82d25240 190
7f112f50 191 NULSTR_FOREACH(d, devnodes) {
2b85f4e1
LP
192 _cleanup_free_ char *dn = NULL;
193 struct stat st;
194
195 r = stat(d, &st);
7f112f50 196 if (r < 0) {
2b85f4e1
LP
197
198 if (errno == ENOENT)
199 continue;
200
201 r = -errno;
202 goto fail;
7f112f50
LP
203 }
204
2b85f4e1
LP
205 if (!S_ISBLK(st.st_mode) &&
206 !S_ISCHR(st.st_mode)) {
207 r = -EINVAL;
208 goto fail;
209 }
210
211 if (st.st_rdev == 0)
212 continue;
213
214 dn = strappend(temporary_mount, d);
215 if (!dn) {
216 r = -ENOMEM;
217 goto fail;
218 }
219
ecabcf8b 220 mac_selinux_create_file_prepare(d, st.st_mode);
2b85f4e1 221 r = mknod(dn, st.st_mode, st.st_rdev);
ecabcf8b 222 mac_selinux_create_file_clear();
dd078a1e 223
2b85f4e1
LP
224 if (r < 0) {
225 r = -errno;
226 goto fail;
227 }
7f112f50
LP
228 }
229
2b85f4e1 230 dev_setup(temporary_mount);
7f112f50 231
2b85f4e1
LP
232 if (mount(dev, "/dev/", NULL, MS_MOVE, NULL) < 0) {
233 r = -errno;
234 goto fail;
235 }
7f112f50 236
2b85f4e1
LP
237 rmdir(dev);
238 rmdir(temporary_mount);
7f112f50 239
2b85f4e1 240 return 0;
7f112f50 241
2b85f4e1
LP
242fail:
243 if (devpts)
244 umount(devpts);
7f112f50 245
2b85f4e1
LP
246 if (devshm)
247 umount(devshm);
7f112f50 248
2b85f4e1
LP
249 if (devhugepages)
250 umount(devhugepages);
7f112f50 251
2b85f4e1
LP
252 if (devmqueue)
253 umount(devmqueue);
7f112f50 254
d267c5aa
ZJS
255 umount(dev);
256 rmdir(dev);
2b85f4e1 257 rmdir(temporary_mount);
7f112f50 258
2b85f4e1 259 return r;
7f112f50
LP
260}
261
a610cc4f
DM
262static int mount_kdbus(BindMount *m) {
263
264 char temporary_mount[] = "/tmp/kdbus-dev-XXXXXX";
265 _cleanup_free_ char *basepath = NULL;
266 _cleanup_umask_ mode_t u;
120d578e 267 char *busnode = NULL, *root;
a610cc4f
DM
268 struct stat st;
269 int r;
270
271 assert(m);
272
273 u = umask(0000);
274
4a62c710
MS
275 if (!mkdtemp(temporary_mount))
276 return log_error_errno(errno, "Failed create temp dir: %m");
a610cc4f 277
63c372cb 278 root = strjoina(temporary_mount, "/kdbus");
dc751688 279 (void) mkdir(root, 0755);
a610cc4f
DM
280 if (mount("tmpfs", root, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=777") < 0) {
281 r = -errno;
282 goto fail;
283 }
284
285 /* create a new /dev/null dev node copy so we have some fodder to
286 * bind-mount the custom endpoint over. */
287 if (stat("/dev/null", &st) < 0) {
56f64d95 288 log_error_errno(errno, "Failed to stat /dev/null: %m");
a610cc4f
DM
289 r = -errno;
290 goto fail;
291 }
292
63c372cb 293 busnode = strjoina(root, "/bus");
a610cc4f 294 if (mknod(busnode, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0) {
56f64d95 295 log_error_errno(errno, "mknod() for %s failed: %m", busnode);
a610cc4f
DM
296 r = -errno;
297 goto fail;
298 }
299
300 r = mount(m->path, busnode, "bind", MS_BIND, NULL);
301 if (r < 0) {
56f64d95 302 log_error_errno(errno, "bind mount of %s failed: %m", m->path);
a610cc4f
DM
303 r = -errno;
304 goto fail;
305 }
306
307 basepath = dirname_malloc(m->path);
308 if (!basepath) {
309 r = -ENOMEM;
310 goto fail;
311 }
312
313 if (mount(root, basepath, NULL, MS_MOVE, NULL) < 0) {
56f64d95 314 log_error_errno(errno, "bind mount of %s failed: %m", basepath);
a610cc4f
DM
315 r = -errno;
316 goto fail;
317 }
318
319 rmdir(temporary_mount);
320 return 0;
321
322fail:
323 if (busnode) {
324 umount(busnode);
325 unlink(busnode);
326 }
327
1775f1eb
ZJS
328 umount(root);
329 rmdir(root);
a610cc4f
DM
330 rmdir(temporary_mount);
331
332 return r;
333}
334
ac0930c8 335static int apply_mount(
c17ec25e 336 BindMount *m,
ac0930c8 337 const char *tmp_dir,
c17ec25e 338 const char *var_tmp_dir) {
ac0930c8 339
15ae422b 340 const char *what;
15ae422b 341 int r;
15ae422b 342
c17ec25e 343 assert(m);
15ae422b 344
c17ec25e 345 switch (m->mode) {
15ae422b
LP
346
347 case INACCESSIBLE:
6d313367
LP
348
349 /* First, get rid of everything that is below if there
350 * is anything... Then, overmount it with an
351 * inaccessible directory. */
352 umount_recursive(m->path, 0);
353
c17ec25e 354 what = "/run/systemd/inaccessible";
15ae422b
LP
355 break;
356
357 case READONLY:
15ae422b 358 case READWRITE:
d6797c92
LP
359 /* Nothing to mount here, we just later toggle the
360 * MS_RDONLY bit for the mount point */
361 return 0;
15ae422b 362
ac0930c8
LP
363 case PRIVATE_TMP:
364 what = tmp_dir;
365 break;
366
367 case PRIVATE_VAR_TMP:
368 what = var_tmp_dir;
15ae422b 369 break;
e364ad06 370
d6797c92
LP
371 case PRIVATE_DEV:
372 return mount_dev(m);
373
a610cc4f
DM
374 case PRIVATE_BUS_ENDPOINT:
375 return mount_kdbus(m);
376
e364ad06
LP
377 default:
378 assert_not_reached("Unknown mode");
15ae422b
LP
379 }
380
ac0930c8 381 assert(what);
15ae422b 382
c17ec25e 383 r = mount(what, m->path, NULL, MS_BIND|MS_REC, NULL);
ac0930c8 384 if (r >= 0)
c17ec25e 385 log_debug("Successfully mounted %s to %s", what, m->path);
ea92ae33 386 else if (m->ignore && errno == ENOENT)
d6797c92 387 return 0;
15ae422b 388
ac0930c8
LP
389 return r;
390}
15ae422b 391
c17ec25e 392static int make_read_only(BindMount *m) {
ac0930c8 393 int r;
15ae422b 394
c17ec25e 395 assert(m);
ac0930c8 396
d6797c92
LP
397 if (IN_SET(m->mode, INACCESSIBLE, READONLY))
398 r = bind_remount_recursive(m->path, true);
664064d6 399 else if (IN_SET(m->mode, READWRITE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV))
d6797c92
LP
400 r = bind_remount_recursive(m->path, false);
401 else
402 r = 0;
ac0930c8 403
d6797c92
LP
404 if (m->ignore && r == -ENOENT)
405 return 0;
ac0930c8 406
d6797c92 407 return r;
15ae422b
LP
408}
409
613b411c
LP
410int setup_namespace(
411 char** read_write_dirs,
412 char** read_only_dirs,
413 char** inaccessible_dirs,
a004cb4c
LP
414 const char* tmp_dir,
415 const char* var_tmp_dir,
416 const char* bus_endpoint_path,
7f112f50 417 bool private_dev,
1b8689f9
LP
418 ProtectHome protect_home,
419 ProtectSystem protect_system,
e6547662 420 unsigned long mount_flags) {
15ae422b 421
7ff7394d 422 BindMount *m, *mounts = NULL;
613b411c 423 unsigned n;
c17ec25e 424 int r = 0;
15ae422b 425
613b411c 426 if (mount_flags == 0)
c17ec25e 427 mount_flags = MS_SHARED;
ac0930c8 428
d5a3f0ea
ZJS
429 if (unshare(CLONE_NEWNS) < 0)
430 return -errno;
15ae422b 431
a610cc4f 432 n = !!tmp_dir + !!var_tmp_dir + !!bus_endpoint_path +
613b411c
LP
433 strv_length(read_write_dirs) +
434 strv_length(read_only_dirs) +
7f112f50 435 strv_length(inaccessible_dirs) +
417116f2 436 private_dev +
c8835999 437 (protect_home != PROTECT_HOME_NO ? 3 : 0) +
051be1f7 438 (protect_system != PROTECT_SYSTEM_NO ? 2 : 0) +
1b8689f9 439 (protect_system == PROTECT_SYSTEM_FULL ? 1 : 0);
613b411c
LP
440
441 if (n > 0) {
002b2268 442 m = mounts = (BindMount *) alloca0(n * sizeof(BindMount));
613b411c
LP
443 r = append_mounts(&m, read_write_dirs, READWRITE);
444 if (r < 0)
445 return r;
446
447 r = append_mounts(&m, read_only_dirs, READONLY);
448 if (r < 0)
449 return r;
450
451 r = append_mounts(&m, inaccessible_dirs, INACCESSIBLE);
452 if (r < 0)
7ff7394d
ZJS
453 return r;
454
613b411c 455 if (tmp_dir) {
7ff7394d
ZJS
456 m->path = "/tmp";
457 m->mode = PRIVATE_TMP;
458 m++;
613b411c 459 }
7ff7394d 460
613b411c 461 if (var_tmp_dir) {
7ff7394d
ZJS
462 m->path = "/var/tmp";
463 m->mode = PRIVATE_VAR_TMP;
464 m++;
465 }
ac0930c8 466
7f112f50
LP
467 if (private_dev) {
468 m->path = "/dev";
469 m->mode = PRIVATE_DEV;
470 m++;
471 }
472
a610cc4f
DM
473 if (bus_endpoint_path) {
474 m->path = bus_endpoint_path;
475 m->mode = PRIVATE_BUS_ENDPOINT;
476 m++;
477 }
478
1b8689f9 479 if (protect_home != PROTECT_HOME_NO) {
c8835999 480 r = append_mounts(&m, STRV_MAKE("-/home", "-/run/user", "-/root"), protect_home == PROTECT_HOME_READ_ONLY ? READONLY : INACCESSIBLE);
417116f2
LP
481 if (r < 0)
482 return r;
483 }
484
1b8689f9 485 if (protect_system != PROTECT_SYSTEM_NO) {
051be1f7 486 r = append_mounts(&m, protect_system == PROTECT_SYSTEM_FULL ? STRV_MAKE("/usr", "-/boot", "/etc") : STRV_MAKE("/usr", "-/boot"), READONLY);
417116f2
LP
487 if (r < 0)
488 return r;
489 }
490
7ff7394d 491 assert(mounts + n == m);
ac0930c8 492
7ff7394d
ZJS
493 qsort(mounts, n, sizeof(BindMount), mount_path_compare);
494 drop_duplicates(mounts, &n);
15ae422b
LP
495 }
496
c2c13f2d
LP
497 if (n > 0) {
498 /* Remount / as SLAVE so that nothing now mounted in the namespace
499 shows up in the parent */
500 if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
501 return -errno;
502
503 for (m = mounts; m < mounts + n; ++m) {
504 r = apply_mount(m, tmp_dir, var_tmp_dir);
505 if (r < 0)
506 goto fail;
507 }
15ae422b 508
c2c13f2d
LP
509 for (m = mounts; m < mounts + n; ++m) {
510 r = make_read_only(m);
511 if (r < 0)
512 goto fail;
513 }
15ae422b
LP
514 }
515
c2c13f2d
LP
516 /* Remount / as the desired mode. Not that this will not
517 * reestablish propagation from our side to the host, since
518 * what's disconnected is disconnected. */
c17ec25e 519 if (mount(NULL, "/", NULL, mount_flags | MS_REC, NULL) < 0) {
15ae422b 520 r = -errno;
613b411c 521 goto fail;
15ae422b
LP
522 }
523
15ae422b
LP
524 return 0;
525
613b411c 526fail:
c2c13f2d
LP
527 if (n > 0) {
528 for (m = mounts; m < mounts + n; ++m)
529 if (m->done)
42b1b990 530 (void) umount2(m->path, MNT_DETACH);
c2c13f2d 531 }
613b411c
LP
532
533 return r;
534}
535
536static int setup_one_tmp_dir(const char *id, const char *prefix, char **path) {
537 _cleanup_free_ char *x = NULL;
6b46ea73
LP
538 char bid[SD_ID128_STRING_MAX];
539 sd_id128_t boot_id;
540 int r;
613b411c
LP
541
542 assert(id);
543 assert(prefix);
544 assert(path);
545
6b46ea73
LP
546 /* We include the boot id in the directory so that after a
547 * reboot we can easily identify obsolete directories. */
548
549 r = sd_id128_get_boot(&boot_id);
550 if (r < 0)
551 return r;
552
553 x = strjoin(prefix, "/systemd-private-", sd_id128_to_string(boot_id, bid), "-", id, "-XXXXXX", NULL);
613b411c
LP
554 if (!x)
555 return -ENOMEM;
556
557 RUN_WITH_UMASK(0077)
558 if (!mkdtemp(x))
559 return -errno;
560
561 RUN_WITH_UMASK(0000) {
562 char *y;
563
63c372cb 564 y = strjoina(x, "/tmp");
613b411c
LP
565
566 if (mkdir(y, 0777 | S_ISVTX) < 0)
567 return -errno;
c17ec25e 568 }
15ae422b 569
613b411c
LP
570 *path = x;
571 x = NULL;
572
573 return 0;
574}
575
576int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) {
577 char *a, *b;
578 int r;
579
580 assert(id);
581 assert(tmp_dir);
582 assert(var_tmp_dir);
583
584 r = setup_one_tmp_dir(id, "/tmp", &a);
585 if (r < 0)
586 return r;
587
588 r = setup_one_tmp_dir(id, "/var/tmp", &b);
589 if (r < 0) {
590 char *t;
591
63c372cb 592 t = strjoina(a, "/tmp");
613b411c
LP
593 rmdir(t);
594 rmdir(a);
595
596 free(a);
597 return r;
598 }
599
600 *tmp_dir = a;
601 *var_tmp_dir = b;
602
603 return 0;
604}
605
606int setup_netns(int netns_storage_socket[2]) {
607 _cleanup_close_ int netns = -1;
608 union {
609 struct cmsghdr cmsghdr;
610 uint8_t buf[CMSG_SPACE(sizeof(int))];
611 } control = {};
612 struct msghdr mh = {
613 .msg_control = &control,
614 .msg_controllen = sizeof(control),
615 };
616 struct cmsghdr *cmsg;
617 int r;
618
619 assert(netns_storage_socket);
620 assert(netns_storage_socket[0] >= 0);
621 assert(netns_storage_socket[1] >= 0);
622
623 /* We use the passed socketpair as a storage buffer for our
76cd584b
LP
624 * namespace reference fd. Whatever process runs this first
625 * shall create a new namespace, all others should just join
626 * it. To serialize that we use a file lock on the socket
627 * pair.
613b411c
LP
628 *
629 * It's a bit crazy, but hey, works great! */
630
631 if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0)
632 return -errno;
633
634 if (recvmsg(netns_storage_socket[0], &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC) < 0) {
635 if (errno != EAGAIN) {
636 r = -errno;
637 goto fail;
638 }
639
640 /* Nothing stored yet, so let's create a new namespace */
641
642 if (unshare(CLONE_NEWNET) < 0) {
643 r = -errno;
644 goto fail;
645 }
646
647 loopback_setup();
648
649 netns = open("/proc/self/ns/net", O_RDONLY|O_CLOEXEC|O_NOCTTY);
650 if (netns < 0) {
651 r = -errno;
652 goto fail;
653 }
654
655 r = 1;
656 } else {
657 /* Yay, found something, so let's join the namespace */
658
659 for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
660 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
661 assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int)));
662 netns = *(int*) CMSG_DATA(cmsg);
663 }
664 }
665
666 if (setns(netns, CLONE_NEWNET) < 0) {
667 r = -errno;
668 goto fail;
669 }
670
671 r = 0;
672 }
673
674 cmsg = CMSG_FIRSTHDR(&mh);
675 cmsg->cmsg_level = SOL_SOCKET;
676 cmsg->cmsg_type = SCM_RIGHTS;
677 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
678 memcpy(CMSG_DATA(cmsg), &netns, sizeof(int));
679 mh.msg_controllen = cmsg->cmsg_len;
680
681 if (sendmsg(netns_storage_socket[1], &mh, MSG_DONTWAIT|MSG_NOSIGNAL) < 0) {
682 r = -errno;
683 goto fail;
684 }
685
686fail:
687 lockf(netns_storage_socket[0], F_ULOCK, 0);
688
15ae422b
LP
689 return r;
690}
417116f2 691
1b8689f9
LP
692static const char *const protect_home_table[_PROTECT_HOME_MAX] = {
693 [PROTECT_HOME_NO] = "no",
694 [PROTECT_HOME_YES] = "yes",
695 [PROTECT_HOME_READ_ONLY] = "read-only",
417116f2
LP
696};
697
1b8689f9
LP
698DEFINE_STRING_TABLE_LOOKUP(protect_home, ProtectHome);
699
700static const char *const protect_system_table[_PROTECT_SYSTEM_MAX] = {
701 [PROTECT_SYSTEM_NO] = "no",
702 [PROTECT_SYSTEM_YES] = "yes",
703 [PROTECT_SYSTEM_FULL] = "full",
704};
705
706DEFINE_STRING_TABLE_LOOKUP(protect_system, ProtectSystem);