]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/stat-util.c
core: delay adding target dependencies until all units are loaded and aliases resolve...
[thirdparty/systemd.git] / src / basic / stat-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
8fcde012
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2010-2012 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
11c3a366
TA
21#include <dirent.h>
22#include <errno.h>
8fcde012
LP
23#include <fcntl.h>
24#include <linux/magic.h>
dccca82b
LP
25#include <sched.h>
26#include <sys/stat.h>
8fcde012 27#include <sys/statvfs.h>
dccca82b 28#include <sys/types.h>
8fcde012
LP
29#include <unistd.h>
30
31#include "dirent-util.h"
32#include "fd-util.h"
7dcdb24e 33#include "fs-util.h"
8fcde012
LP
34#include "macro.h"
35#include "missing.h"
36#include "stat-util.h"
37#include "string-util.h"
38
39int is_symlink(const char *path) {
40 struct stat info;
41
42 assert(path);
43
44 if (lstat(path, &info) < 0)
45 return -errno;
46
47 return !!S_ISLNK(info.st_mode);
48}
49
50int is_dir(const char* path, bool follow) {
51 struct stat st;
52 int r;
53
54 assert(path);
55
56 if (follow)
57 r = stat(path, &st);
58 else
59 r = lstat(path, &st);
60 if (r < 0)
61 return -errno;
62
63 return !!S_ISDIR(st.st_mode);
64}
65
66int is_device_node(const char *path) {
67 struct stat info;
68
69 assert(path);
70
71 if (lstat(path, &info) < 0)
72 return -errno;
73
74 return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
75}
76
77int dir_is_empty(const char *path) {
78 _cleanup_closedir_ DIR *d;
79 struct dirent *de;
80
81 d = opendir(path);
82 if (!d)
83 return -errno;
84
85 FOREACH_DIRENT(de, d, return -errno)
86 return 0;
87
88 return 1;
89}
90
91bool null_or_empty(struct stat *st) {
92 assert(st);
93
94 if (S_ISREG(st->st_mode) && st->st_size <= 0)
95 return true;
96
97 /* We don't want to hardcode the major/minor of /dev/null,
98 * hence we do a simpler "is this a device node?" check. */
99
100 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
101 return true;
102
103 return false;
104}
105
106int null_or_empty_path(const char *fn) {
107 struct stat st;
108
109 assert(fn);
110
111 if (stat(fn, &st) < 0)
112 return -errno;
113
114 return null_or_empty(&st);
115}
116
117int null_or_empty_fd(int fd) {
118 struct stat st;
119
120 assert(fd >= 0);
121
122 if (fstat(fd, &st) < 0)
123 return -errno;
124
125 return null_or_empty(&st);
126}
127
128int path_is_read_only_fs(const char *path) {
129 struct statvfs st;
130
131 assert(path);
132
133 if (statvfs(path, &st) < 0)
134 return -errno;
135
136 if (st.f_flag & ST_RDONLY)
137 return true;
138
139 /* On NFS, statvfs() might not reflect whether we can actually
140 * write to the remote share. Let's try again with
141 * access(W_OK) which is more reliable, at least sometimes. */
142 if (access(path, W_OK) < 0 && errno == EROFS)
143 return true;
144
145 return false;
146}
147
148int path_is_os_tree(const char *path) {
8fcde012
LP
149 int r;
150
151 assert(path);
152
7dcdb24e
LP
153 /* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir
154 * always results in -ENOENT, and we can properly distuingish the case where the whole root doesn't exist from
155 * the case where just the os-release file is missing. */
156 if (laccess(path, F_OK) < 0)
157 return -errno;
8fcde012 158
7dcdb24e
LP
159 /* We use /usr/lib/os-release as flag file if something is an OS */
160 r = chase_symlinks("/usr/lib/os-release", path, CHASE_PREFIX_ROOT, NULL);
161 if (r == -ENOENT) {
162
163 /* Also check for the old location in /etc, just in case. */
164 r = chase_symlinks("/etc/os-release", path, CHASE_PREFIX_ROOT, NULL);
165 if (r == -ENOENT)
166 return 0; /* We got nothing */
167 }
168 if (r < 0)
169 return r;
8fcde012 170
7dcdb24e 171 return 1;
8fcde012
LP
172}
173
e3f791a2 174int files_same(const char *filea, const char *fileb, int flags) {
8fcde012
LP
175 struct stat a, b;
176
177 assert(filea);
178 assert(fileb);
179
e3f791a2 180 if (fstatat(AT_FDCWD, filea, &a, flags) < 0)
8fcde012
LP
181 return -errno;
182
e3f791a2 183 if (fstatat(AT_FDCWD, fileb, &b, flags) < 0)
8fcde012
LP
184 return -errno;
185
186 return a.st_dev == b.st_dev &&
187 a.st_ino == b.st_ino;
188}
189
190bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
191 assert(s);
192 assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
193
194 return F_TYPE_EQUAL(s->f_type, magic_value);
195}
196
a66fee2e 197int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
8fcde012
LP
198 struct statfs s;
199
200 if (fstatfs(fd, &s) < 0)
201 return -errno;
202
203 return is_fs_type(&s, magic_value);
204}
205
40fd52f2 206int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
8fcde012
LP
207 _cleanup_close_ int fd = -1;
208
436e916e 209 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
8fcde012
LP
210 if (fd < 0)
211 return -errno;
212
a66fee2e 213 return fd_is_fs_type(fd, magic_value);
8fcde012
LP
214}
215
216bool is_temporary_fs(const struct statfs *s) {
77f9fa3b
LP
217 return is_fs_type(s, TMPFS_MAGIC) ||
218 is_fs_type(s, RAMFS_MAGIC);
219}
220
221bool is_network_fs(const struct statfs *s) {
222 return is_fs_type(s, CIFS_MAGIC_NUMBER) ||
223 is_fs_type(s, CODA_SUPER_MAGIC) ||
224 is_fs_type(s, NCP_SUPER_MAGIC) ||
225 is_fs_type(s, NFS_SUPER_MAGIC) ||
226 is_fs_type(s, SMB_SUPER_MAGIC) ||
227 is_fs_type(s, V9FS_MAGIC) ||
228 is_fs_type(s, AFS_SUPER_MAGIC) ||
229 is_fs_type(s, OCFS2_SUPER_MAGIC);
8fcde012
LP
230}
231
232int fd_is_temporary_fs(int fd) {
233 struct statfs s;
234
235 if (fstatfs(fd, &s) < 0)
236 return -errno;
237
238 return is_temporary_fs(&s);
239}
ffeb8285 240
77f9fa3b
LP
241int fd_is_network_fs(int fd) {
242 struct statfs s;
243
244 if (fstatfs(fd, &s) < 0)
245 return -errno;
246
247 return is_network_fs(&s);
248}
249
d7bea6b6
DP
250int fd_is_network_ns(int fd) {
251 int r;
252
253 r = fd_is_fs_type(fd, NSFS_MAGIC);
254 if (r <= 0)
255 return r;
77f9fa3b
LP
256
257 if (ioctl(fd, NS_GET_NSTYPE) < 0)
d7bea6b6 258 return -errno;
77f9fa3b 259
d7bea6b6
DP
260 return r == CLONE_NEWNET;
261}
262
ffeb8285
LP
263int path_is_temporary_fs(const char *path) {
264 _cleanup_close_ int fd = -1;
265
436e916e 266 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
ffeb8285
LP
267 if (fd < 0)
268 return -errno;
269
270 return fd_is_temporary_fs(fd);
271}
3cc44114
LP
272
273int stat_verify_regular(const struct stat *st) {
274 assert(st);
275
276 /* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error
277 * code. */
278
279 if (S_ISDIR(st->st_mode))
280 return -EISDIR;
281
282 if (S_ISLNK(st->st_mode))
283 return -ELOOP;
284
285 if (!S_ISREG(st->st_mode))
286 return -EBADFD;
287
288 return 0;
289}
290
291int fd_verify_regular(int fd) {
292 struct stat st;
293
294 assert(fd >= 0);
295
296 if (fstat(fd, &st) < 0)
297 return -errno;
298
299 return stat_verify_regular(&st);
300}