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