]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/stat-util.c
tree-wide: drop 'This file is part of systemd' blurb
[thirdparty/systemd.git] / src / basic / stat-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
8fcde012 2/***
8fcde012 3 Copyright 2010-2012 Lennart Poettering
8fcde012
LP
4***/
5
11c3a366
TA
6#include <dirent.h>
7#include <errno.h>
8fcde012
LP
8#include <fcntl.h>
9#include <linux/magic.h>
dccca82b
LP
10#include <sched.h>
11#include <sys/stat.h>
8fcde012 12#include <sys/statvfs.h>
dccca82b 13#include <sys/types.h>
8fcde012
LP
14#include <unistd.h>
15
16#include "dirent-util.h"
17#include "fd-util.h"
7dcdb24e 18#include "fs-util.h"
8fcde012
LP
19#include "macro.h"
20#include "missing.h"
21#include "stat-util.h"
22#include "string-util.h"
23
24int is_symlink(const char *path) {
25 struct stat info;
26
27 assert(path);
28
29 if (lstat(path, &info) < 0)
30 return -errno;
31
32 return !!S_ISLNK(info.st_mode);
33}
34
35int is_dir(const char* path, bool follow) {
36 struct stat st;
37 int r;
38
39 assert(path);
40
41 if (follow)
42 r = stat(path, &st);
43 else
44 r = lstat(path, &st);
45 if (r < 0)
46 return -errno;
47
48 return !!S_ISDIR(st.st_mode);
49}
50
51int is_device_node(const char *path) {
52 struct stat info;
53
54 assert(path);
55
56 if (lstat(path, &info) < 0)
57 return -errno;
58
59 return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
60}
61
62int dir_is_empty(const char *path) {
63 _cleanup_closedir_ DIR *d;
64 struct dirent *de;
65
66 d = opendir(path);
67 if (!d)
68 return -errno;
69
70 FOREACH_DIRENT(de, d, return -errno)
71 return 0;
72
73 return 1;
74}
75
76bool null_or_empty(struct stat *st) {
77 assert(st);
78
79 if (S_ISREG(st->st_mode) && st->st_size <= 0)
80 return true;
81
82 /* We don't want to hardcode the major/minor of /dev/null,
83 * hence we do a simpler "is this a device node?" check. */
84
85 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
86 return true;
87
88 return false;
89}
90
91int null_or_empty_path(const char *fn) {
92 struct stat st;
93
94 assert(fn);
95
96 if (stat(fn, &st) < 0)
97 return -errno;
98
99 return null_or_empty(&st);
100}
101
102int null_or_empty_fd(int fd) {
103 struct stat st;
104
105 assert(fd >= 0);
106
107 if (fstat(fd, &st) < 0)
108 return -errno;
109
110 return null_or_empty(&st);
111}
112
113int path_is_read_only_fs(const char *path) {
114 struct statvfs st;
115
116 assert(path);
117
118 if (statvfs(path, &st) < 0)
119 return -errno;
120
121 if (st.f_flag & ST_RDONLY)
122 return true;
123
124 /* On NFS, statvfs() might not reflect whether we can actually
125 * write to the remote share. Let's try again with
126 * access(W_OK) which is more reliable, at least sometimes. */
127 if (access(path, W_OK) < 0 && errno == EROFS)
128 return true;
129
130 return false;
131}
132
e3f791a2 133int files_same(const char *filea, const char *fileb, int flags) {
8fcde012
LP
134 struct stat a, b;
135
136 assert(filea);
137 assert(fileb);
138
e3f791a2 139 if (fstatat(AT_FDCWD, filea, &a, flags) < 0)
8fcde012
LP
140 return -errno;
141
e3f791a2 142 if (fstatat(AT_FDCWD, fileb, &b, flags) < 0)
8fcde012
LP
143 return -errno;
144
145 return a.st_dev == b.st_dev &&
146 a.st_ino == b.st_ino;
147}
148
149bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
150 assert(s);
151 assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
152
153 return F_TYPE_EQUAL(s->f_type, magic_value);
154}
155
a66fee2e 156int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
8fcde012
LP
157 struct statfs s;
158
159 if (fstatfs(fd, &s) < 0)
160 return -errno;
161
162 return is_fs_type(&s, magic_value);
163}
164
40fd52f2 165int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
8fcde012
LP
166 _cleanup_close_ int fd = -1;
167
436e916e 168 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
8fcde012
LP
169 if (fd < 0)
170 return -errno;
171
a66fee2e 172 return fd_is_fs_type(fd, magic_value);
8fcde012
LP
173}
174
175bool is_temporary_fs(const struct statfs *s) {
77f9fa3b
LP
176 return is_fs_type(s, TMPFS_MAGIC) ||
177 is_fs_type(s, RAMFS_MAGIC);
178}
179
180bool is_network_fs(const struct statfs *s) {
181 return is_fs_type(s, CIFS_MAGIC_NUMBER) ||
182 is_fs_type(s, CODA_SUPER_MAGIC) ||
183 is_fs_type(s, NCP_SUPER_MAGIC) ||
184 is_fs_type(s, NFS_SUPER_MAGIC) ||
185 is_fs_type(s, SMB_SUPER_MAGIC) ||
186 is_fs_type(s, V9FS_MAGIC) ||
187 is_fs_type(s, AFS_SUPER_MAGIC) ||
188 is_fs_type(s, OCFS2_SUPER_MAGIC);
8fcde012
LP
189}
190
191int fd_is_temporary_fs(int fd) {
192 struct statfs s;
193
194 if (fstatfs(fd, &s) < 0)
195 return -errno;
196
197 return is_temporary_fs(&s);
198}
ffeb8285 199
77f9fa3b
LP
200int fd_is_network_fs(int fd) {
201 struct statfs s;
202
203 if (fstatfs(fd, &s) < 0)
204 return -errno;
205
206 return is_network_fs(&s);
207}
208
d7bea6b6
DP
209int fd_is_network_ns(int fd) {
210 int r;
211
212 r = fd_is_fs_type(fd, NSFS_MAGIC);
213 if (r <= 0)
214 return r;
77f9fa3b 215
29f74559
LP
216 r = ioctl(fd, NS_GET_NSTYPE);
217 if (r < 0)
d7bea6b6 218 return -errno;
77f9fa3b 219
d7bea6b6
DP
220 return r == CLONE_NEWNET;
221}
222
ffeb8285
LP
223int path_is_temporary_fs(const char *path) {
224 _cleanup_close_ int fd = -1;
225
436e916e 226 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
ffeb8285
LP
227 if (fd < 0)
228 return -errno;
229
230 return fd_is_temporary_fs(fd);
231}
3cc44114
LP
232
233int stat_verify_regular(const struct stat *st) {
234 assert(st);
235
236 /* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error
237 * code. */
238
239 if (S_ISDIR(st->st_mode))
240 return -EISDIR;
241
242 if (S_ISLNK(st->st_mode))
243 return -ELOOP;
244
245 if (!S_ISREG(st->st_mode))
246 return -EBADFD;
247
248 return 0;
249}
250
251int fd_verify_regular(int fd) {
252 struct stat st;
253
254 assert(fd >= 0);
255
256 if (fstat(fd, &st) < 0)
257 return -errno;
258
259 return stat_verify_regular(&st);
260}