]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/stat-util.c
os-util: add helpers for finding /etc/os-release
[thirdparty/systemd.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 int is_symlink(const char *path) {
27 struct stat info;
28
29 assert(path);
30
31 if (lstat(path, &info) < 0)
32 return -errno;
33
34 return !!S_ISLNK(info.st_mode);
35 }
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 int is_device_node(const char *path) {
54 struct stat info;
55
56 assert(path);
57
58 if (lstat(path, &info) < 0)
59 return -errno;
60
61 return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
62 }
63
64 int dir_is_empty(const char *path) {
65 _cleanup_closedir_ DIR *d;
66 struct dirent *de;
67
68 d = opendir(path);
69 if (!d)
70 return -errno;
71
72 FOREACH_DIRENT(de, d, return -errno)
73 return 0;
74
75 return 1;
76 }
77
78 bool null_or_empty(struct stat *st) {
79 assert(st);
80
81 if (S_ISREG(st->st_mode) && st->st_size <= 0)
82 return true;
83
84 /* We don't want to hardcode the major/minor of /dev/null,
85 * hence we do a simpler "is this a device node?" check. */
86
87 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
88 return true;
89
90 return false;
91 }
92
93 int null_or_empty_path(const char *fn) {
94 struct stat st;
95
96 assert(fn);
97
98 if (stat(fn, &st) < 0)
99 return -errno;
100
101 return null_or_empty(&st);
102 }
103
104 int null_or_empty_fd(int fd) {
105 struct stat st;
106
107 assert(fd >= 0);
108
109 if (fstat(fd, &st) < 0)
110 return -errno;
111
112 return null_or_empty(&st);
113 }
114
115 int path_is_read_only_fs(const char *path) {
116 struct statvfs st;
117
118 assert(path);
119
120 if (statvfs(path, &st) < 0)
121 return -errno;
122
123 if (st.f_flag & ST_RDONLY)
124 return true;
125
126 /* On NFS, statvfs() might not reflect whether we can actually
127 * write to the remote share. Let's try again with
128 * access(W_OK) which is more reliable, at least sometimes. */
129 if (access(path, W_OK) < 0 && errno == EROFS)
130 return true;
131
132 return false;
133 }
134
135 int files_same(const char *filea, const char *fileb, int flags) {
136 struct stat a, b;
137
138 assert(filea);
139 assert(fileb);
140
141 if (fstatat(AT_FDCWD, filea, &a, flags) < 0)
142 return -errno;
143
144 if (fstatat(AT_FDCWD, fileb, &b, flags) < 0)
145 return -errno;
146
147 return a.st_dev == b.st_dev &&
148 a.st_ino == b.st_ino;
149 }
150
151 bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
152 assert(s);
153 assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
154
155 return F_TYPE_EQUAL(s->f_type, magic_value);
156 }
157
158 int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
159 struct statfs s;
160
161 if (fstatfs(fd, &s) < 0)
162 return -errno;
163
164 return is_fs_type(&s, magic_value);
165 }
166
167 int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
168 _cleanup_close_ int fd = -1;
169
170 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
171 if (fd < 0)
172 return -errno;
173
174 return fd_is_fs_type(fd, magic_value);
175 }
176
177 bool is_temporary_fs(const struct statfs *s) {
178 return is_fs_type(s, TMPFS_MAGIC) ||
179 is_fs_type(s, RAMFS_MAGIC);
180 }
181
182 bool is_network_fs(const struct statfs *s) {
183 return is_fs_type(s, CIFS_MAGIC_NUMBER) ||
184 is_fs_type(s, CODA_SUPER_MAGIC) ||
185 is_fs_type(s, NCP_SUPER_MAGIC) ||
186 is_fs_type(s, NFS_SUPER_MAGIC) ||
187 is_fs_type(s, SMB_SUPER_MAGIC) ||
188 is_fs_type(s, V9FS_MAGIC) ||
189 is_fs_type(s, AFS_SUPER_MAGIC) ||
190 is_fs_type(s, OCFS2_SUPER_MAGIC);
191 }
192
193 int fd_is_temporary_fs(int fd) {
194 struct statfs s;
195
196 if (fstatfs(fd, &s) < 0)
197 return -errno;
198
199 return is_temporary_fs(&s);
200 }
201
202 int fd_is_network_fs(int fd) {
203 struct statfs s;
204
205 if (fstatfs(fd, &s) < 0)
206 return -errno;
207
208 return is_network_fs(&s);
209 }
210
211 int fd_is_network_ns(int fd) {
212 int r;
213
214 r = fd_is_fs_type(fd, NSFS_MAGIC);
215 if (r <= 0)
216 return r;
217
218 r = ioctl(fd, NS_GET_NSTYPE);
219 if (r < 0)
220 return -errno;
221
222 return r == CLONE_NEWNET;
223 }
224
225 int path_is_temporary_fs(const char *path) {
226 _cleanup_close_ int fd = -1;
227
228 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
229 if (fd < 0)
230 return -errno;
231
232 return fd_is_temporary_fs(fd);
233 }
234
235 int stat_verify_regular(const struct stat *st) {
236 assert(st);
237
238 /* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error
239 * code. */
240
241 if (S_ISDIR(st->st_mode))
242 return -EISDIR;
243
244 if (S_ISLNK(st->st_mode))
245 return -ELOOP;
246
247 if (!S_ISREG(st->st_mode))
248 return -EBADFD;
249
250 return 0;
251 }
252
253 int fd_verify_regular(int fd) {
254 struct stat st;
255
256 assert(fd >= 0);
257
258 if (fstat(fd, &st) < 0)
259 return -errno;
260
261 return stat_verify_regular(&st);
262 }