]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/base-filesystem.c
util-lib: split out fd-related operations into fd-util.[ch]
[thirdparty/systemd.git] / src / shared / base-filesystem.c
CommitLineData
3577de7a
KS
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Kay Sievers
7
8 systemd is free software; you can redistribute it and/or modify it
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
3577de7a 23#include <stdlib.h>
07630cea 24#include <sys/stat.h>
3577de7a
KS
25#include <unistd.h>
26
3577de7a
KS
27#include "log.h"
28#include "macro.h"
07630cea 29#include "string-util.h"
3577de7a 30#include "util.h"
07630cea 31#include "base-filesystem.h"
3ffd4af2 32#include "fd-util.h"
3577de7a
KS
33
34typedef struct BaseFilesystem {
35 const char *dir;
36 mode_t mode;
37 const char *target;
3fd165e5 38 const char *exists;
6404ecc8 39 bool ignore_failure;
3577de7a
KS
40} BaseFilesystem;
41
42static const BaseFilesystem table[] = {
30d7c9c4
HH
43 { "bin", 0, "usr/bin\0", NULL },
44 { "lib", 0, "usr/lib\0", NULL },
6404ecc8 45 { "root", 0755, NULL, NULL, true },
30d7c9c4 46 { "sbin", 0, "usr/sbin\0", NULL },
03cfe0d5
LP
47 { "usr", 0755, NULL, NULL },
48 { "var", 0755, NULL, NULL },
49 { "etc", 0755, NULL, NULL },
e1ae9755 50#if defined(__i386__) || defined(__x86_64__)
30d7c9c4
HH
51 { "lib64", 0, "usr/lib/x86_64-linux-gnu\0"
52 "usr/lib64\0", "ld-linux-x86-64.so.2" },
e1ae9755 53#endif
3577de7a
KS
54};
55
03cfe0d5 56int base_filesystem_create(const char *root, uid_t uid, gid_t gid) {
3577de7a
KS
57 _cleanup_close_ int fd = -1;
58 unsigned i;
a7f7d1bd 59 int r = 0;
3577de7a
KS
60
61 fd = open(root, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
4a62c710
MS
62 if (fd < 0)
63 return log_error_errno(errno, "Failed to open root file system: %m");
3577de7a
KS
64
65 for (i = 0; i < ELEMENTSOF(table); i ++) {
6f4f8056
HH
66 if (faccessat(fd, table[i].dir, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
67 continue;
68
3577de7a 69 if (table[i].target) {
6dc2852c 70 const char *target = NULL, *s;
e1ae9755
KS
71
72 /* check if one of the targets exists */
73 NULSTR_FOREACH(s, table[i].target) {
74 if (faccessat(fd, s, F_OK, AT_SYMLINK_NOFOLLOW) < 0)
75 continue;
76
3fd165e5
KS
77 /* check if a specific file exists at the target path */
78 if (table[i].exists) {
79 _cleanup_free_ char *p = NULL;
80
81 p = strjoin(s, "/", table[i].exists, NULL);
82 if (!p)
83 return log_oom();
84
85 if (faccessat(fd, p, F_OK, AT_SYMLINK_NOFOLLOW) < 0)
86 continue;
87 }
88
e1ae9755
KS
89 target = s;
90 break;
91 }
92
93 if (!target)
3577de7a
KS
94 continue;
95
e1ae9755 96 r = symlinkat(target, fd, table[i].dir);
4a62c710
MS
97 if (r < 0 && errno != EEXIST)
98 return log_error_errno(errno, "Failed to create symlink at %s/%s: %m", root, table[i].dir);
03cfe0d5
LP
99
100 if (uid != UID_INVALID || gid != UID_INVALID) {
101 if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
102 return log_error_errno(errno, "Failed to chown symlink at %s/%s: %m", root, table[i].dir);
103 }
104
3577de7a
KS
105 continue;
106 }
107
108 RUN_WITH_UMASK(0000)
109 r = mkdirat(fd, table[i].dir, table[i].mode);
6404ecc8
LP
110 if (r < 0 && errno != EEXIST) {
111 log_full_errno(table[i].ignore_failure ? LOG_DEBUG : LOG_ERR, errno,
112 "Failed to create directory at %s/%s: %m", root, table[i].dir);
113
114 if (!table[i].ignore_failure)
115 return -errno;
116 }
03cfe0d5
LP
117
118 if (uid != UID_INVALID || gid != UID_INVALID) {
119 if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
120 return log_error_errno(errno, "Failed to chown directory at %s/%s: %m", root, table[i].dir);
121 }
3577de7a
KS
122 }
123
124 return 0;
125}