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