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