]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/stat-util.c
Add SPDX license identifiers to source files under the LGPL
[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 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <dirent.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <linux/magic.h>
27 #include <sys/statvfs.h>
28 #include <unistd.h>
29
30 #include "dirent-util.h"
31 #include "fd-util.h"
32 #include "fs-util.h"
33 #include "macro.h"
34 #include "missing.h"
35 #include "stat-util.h"
36 #include "string-util.h"
37
38 int is_symlink(const char *path) {
39 struct stat info;
40
41 assert(path);
42
43 if (lstat(path, &info) < 0)
44 return -errno;
45
46 return !!S_ISLNK(info.st_mode);
47 }
48
49 int is_dir(const char* path, bool follow) {
50 struct stat st;
51 int r;
52
53 assert(path);
54
55 if (follow)
56 r = stat(path, &st);
57 else
58 r = lstat(path, &st);
59 if (r < 0)
60 return -errno;
61
62 return !!S_ISDIR(st.st_mode);
63 }
64
65 int is_device_node(const char *path) {
66 struct stat info;
67
68 assert(path);
69
70 if (lstat(path, &info) < 0)
71 return -errno;
72
73 return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
74 }
75
76 int dir_is_empty(const char *path) {
77 _cleanup_closedir_ DIR *d;
78 struct dirent *de;
79
80 d = opendir(path);
81 if (!d)
82 return -errno;
83
84 FOREACH_DIRENT(de, d, return -errno)
85 return 0;
86
87 return 1;
88 }
89
90 bool null_or_empty(struct stat *st) {
91 assert(st);
92
93 if (S_ISREG(st->st_mode) && st->st_size <= 0)
94 return true;
95
96 /* We don't want to hardcode the major/minor of /dev/null,
97 * hence we do a simpler "is this a device node?" check. */
98
99 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
100 return true;
101
102 return false;
103 }
104
105 int null_or_empty_path(const char *fn) {
106 struct stat st;
107
108 assert(fn);
109
110 if (stat(fn, &st) < 0)
111 return -errno;
112
113 return null_or_empty(&st);
114 }
115
116 int null_or_empty_fd(int fd) {
117 struct stat st;
118
119 assert(fd >= 0);
120
121 if (fstat(fd, &st) < 0)
122 return -errno;
123
124 return null_or_empty(&st);
125 }
126
127 int path_is_read_only_fs(const char *path) {
128 struct statvfs st;
129
130 assert(path);
131
132 if (statvfs(path, &st) < 0)
133 return -errno;
134
135 if (st.f_flag & ST_RDONLY)
136 return true;
137
138 /* On NFS, statvfs() might not reflect whether we can actually
139 * write to the remote share. Let's try again with
140 * access(W_OK) which is more reliable, at least sometimes. */
141 if (access(path, W_OK) < 0 && errno == EROFS)
142 return true;
143
144 return false;
145 }
146
147 int path_is_os_tree(const char *path) {
148 int r;
149
150 assert(path);
151
152 /* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir
153 * always results in -ENOENT, and we can properly distuingish the case where the whole root doesn't exist from
154 * the case where just the os-release file is missing. */
155 if (laccess(path, F_OK) < 0)
156 return -errno;
157
158 /* We use /usr/lib/os-release as flag file if something is an OS */
159 r = chase_symlinks("/usr/lib/os-release", path, CHASE_PREFIX_ROOT, NULL);
160 if (r == -ENOENT) {
161
162 /* Also check for the old location in /etc, just in case. */
163 r = chase_symlinks("/etc/os-release", path, CHASE_PREFIX_ROOT, NULL);
164 if (r == -ENOENT)
165 return 0; /* We got nothing */
166 }
167 if (r < 0)
168 return r;
169
170 return 1;
171 }
172
173 int files_same(const char *filea, const char *fileb, int flags) {
174 struct stat a, b;
175
176 assert(filea);
177 assert(fileb);
178
179 if (fstatat(AT_FDCWD, filea, &a, flags) < 0)
180 return -errno;
181
182 if (fstatat(AT_FDCWD, fileb, &b, flags) < 0)
183 return -errno;
184
185 return a.st_dev == b.st_dev &&
186 a.st_ino == b.st_ino;
187 }
188
189 bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
190 assert(s);
191 assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
192
193 return F_TYPE_EQUAL(s->f_type, magic_value);
194 }
195
196 int fd_check_fstype(int fd, statfs_f_type_t magic_value) {
197 struct statfs s;
198
199 if (fstatfs(fd, &s) < 0)
200 return -errno;
201
202 return is_fs_type(&s, magic_value);
203 }
204
205 int path_check_fstype(const char *path, statfs_f_type_t magic_value) {
206 _cleanup_close_ int fd = -1;
207
208 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
209 if (fd < 0)
210 return -errno;
211
212 return fd_check_fstype(fd, magic_value);
213 }
214
215 bool is_temporary_fs(const struct statfs *s) {
216 return is_fs_type(s, TMPFS_MAGIC) ||
217 is_fs_type(s, RAMFS_MAGIC);
218 }
219
220 int fd_is_temporary_fs(int fd) {
221 struct statfs s;
222
223 if (fstatfs(fd, &s) < 0)
224 return -errno;
225
226 return is_temporary_fs(&s);
227 }
228
229 int path_is_temporary_fs(const char *path) {
230 _cleanup_close_ int fd = -1;
231
232 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
233 if (fd < 0)
234 return -errno;
235
236 return fd_is_temporary_fs(fd);
237 }