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