]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/base-filesystem.c
util-lib: split our string related calls from util.[ch] into its own file string...
[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"
3577de7a
KS
32
33typedef struct BaseFilesystem {
34 const char *dir;
35 mode_t mode;
36 const char *target;
3fd165e5 37 const char *exists;
6404ecc8 38 bool ignore_failure;
3577de7a
KS
39} BaseFilesystem;
40
41static const BaseFilesystem table[] = {
30d7c9c4
HH
42 { "bin", 0, "usr/bin\0", NULL },
43 { "lib", 0, "usr/lib\0", NULL },
6404ecc8 44 { "root", 0755, NULL, NULL, true },
30d7c9c4 45 { "sbin", 0, "usr/sbin\0", NULL },
03cfe0d5
LP
46 { "usr", 0755, NULL, NULL },
47 { "var", 0755, NULL, NULL },
48 { "etc", 0755, NULL, NULL },
e1ae9755 49#if defined(__i386__) || defined(__x86_64__)
30d7c9c4
HH
50 { "lib64", 0, "usr/lib/x86_64-linux-gnu\0"
51 "usr/lib64\0", "ld-linux-x86-64.so.2" },
e1ae9755 52#endif
3577de7a
KS
53};
54
03cfe0d5 55int base_filesystem_create(const char *root, uid_t uid, gid_t gid) {
3577de7a
KS
56 _cleanup_close_ int fd = -1;
57 unsigned i;
a7f7d1bd 58 int r = 0;
3577de7a
KS
59
60 fd = open(root, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
4a62c710
MS
61 if (fd < 0)
62 return log_error_errno(errno, "Failed to open root file system: %m");
3577de7a
KS
63
64 for (i = 0; i < ELEMENTSOF(table); i ++) {
6f4f8056
HH
65 if (faccessat(fd, table[i].dir, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
66 continue;
67
3577de7a 68 if (table[i].target) {
6dc2852c 69 const char *target = NULL, *s;
e1ae9755
KS
70
71 /* check if one of the targets exists */
72 NULSTR_FOREACH(s, table[i].target) {
73 if (faccessat(fd, s, F_OK, AT_SYMLINK_NOFOLLOW) < 0)
74 continue;
75
3fd165e5
KS
76 /* check if a specific file exists at the target path */
77 if (table[i].exists) {
78 _cleanup_free_ char *p = NULL;
79
80 p = strjoin(s, "/", table[i].exists, NULL);
81 if (!p)
82 return log_oom();
83
84 if (faccessat(fd, p, F_OK, AT_SYMLINK_NOFOLLOW) < 0)
85 continue;
86 }
87
e1ae9755
KS
88 target = s;
89 break;
90 }
91
92 if (!target)
3577de7a
KS
93 continue;
94
e1ae9755 95 r = symlinkat(target, fd, table[i].dir);
4a62c710
MS
96 if (r < 0 && errno != EEXIST)
97 return log_error_errno(errno, "Failed to create symlink at %s/%s: %m", root, table[i].dir);
03cfe0d5
LP
98
99 if (uid != UID_INVALID || gid != UID_INVALID) {
100 if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
101 return log_error_errno(errno, "Failed to chown symlink at %s/%s: %m", root, table[i].dir);
102 }
103
3577de7a
KS
104 continue;
105 }
106
107 RUN_WITH_UMASK(0000)
108 r = mkdirat(fd, table[i].dir, table[i].mode);
6404ecc8
LP
109 if (r < 0 && errno != EEXIST) {
110 log_full_errno(table[i].ignore_failure ? LOG_DEBUG : LOG_ERR, errno,
111 "Failed to create directory at %s/%s: %m", root, table[i].dir);
112
113 if (!table[i].ignore_failure)
114 return -errno;
115 }
03cfe0d5
LP
116
117 if (uid != UID_INVALID || gid != UID_INVALID) {
118 if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
119 return log_error_errno(errno, "Failed to chown directory at %s/%s: %m", root, table[i].dir);
120 }
3577de7a
KS
121 }
122
123 return 0;
124}