chiark / gitweb /
0c3fbc8e1b3bf56300fa20422cb62cd556b67e98
[elogind.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 "macro.h"
32 #include "missing.h"
33 #include "stat-util.h"
34 #include "string-util.h"
35
36 #if 0 /// UNNEEDED by elogind
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 #endif // 0
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 #if 0 /// UNNEEDED by elogind
66 int is_device_node(const char *path) {
67         struct stat info;
68
69         assert(path);
70
71         if (lstat(path, &info) < 0)
72                 return -errno;
73
74         return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
75 }
76
77 int dir_is_empty(const char *path) {
78         _cleanup_closedir_ DIR *d;
79         struct dirent *de;
80
81         d = opendir(path);
82         if (!d)
83                 return -errno;
84
85         FOREACH_DIRENT(de, d, return -errno)
86                 return 0;
87
88         return 1;
89 }
90 #endif // 0
91
92 bool null_or_empty(struct stat *st) {
93         assert(st);
94
95         if (S_ISREG(st->st_mode) && st->st_size <= 0)
96                 return true;
97
98         /* We don't want to hardcode the major/minor of /dev/null,
99          * hence we do a simpler "is this a device node?" check. */
100
101         if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
102                 return true;
103
104         return false;
105 }
106
107 int null_or_empty_path(const char *fn) {
108         struct stat st;
109
110         assert(fn);
111
112         if (stat(fn, &st) < 0)
113                 return -errno;
114
115         return null_or_empty(&st);
116 }
117
118 #if 0 /// UNNEEDED by elogind
119 int null_or_empty_fd(int fd) {
120         struct stat st;
121
122         assert(fd >= 0);
123
124         if (fstat(fd, &st) < 0)
125                 return -errno;
126
127         return null_or_empty(&st);
128 }
129 #endif // 0
130
131 int path_is_read_only_fs(const char *path) {
132         struct statvfs st;
133
134         assert(path);
135
136         if (statvfs(path, &st) < 0)
137                 return -errno;
138
139         if (st.f_flag & ST_RDONLY)
140                 return true;
141
142         /* On NFS, statvfs() might not reflect whether we can actually
143          * write to the remote share. Let's try again with
144          * access(W_OK) which is more reliable, at least sometimes. */
145         if (access(path, W_OK) < 0 && errno == EROFS)
146                 return true;
147
148         return false;
149 }
150
151 #if 0 /// UNNEEDED by elogind
152 int path_is_os_tree(const char *path) {
153         int r;
154
155         assert(path);
156
157         /* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir
158          * always results in -ENOENT, and we can properly distuingish the case where the whole root doesn't exist from
159          * the case where just the os-release file is missing. */
160         if (laccess(path, F_OK) < 0)
161                 return -errno;
162
163         /* We use /usr/lib/os-release as flag file if something is an OS */
164         r = chase_symlinks("/usr/lib/os-release", path, CHASE_PREFIX_ROOT, NULL);
165         if (r == -ENOENT) {
166
167                 /* Also check for the old location in /etc, just in case. */
168                 r = chase_symlinks("/etc/os-release", path, CHASE_PREFIX_ROOT, NULL);
169                 if (r == -ENOENT)
170                         return 0; /* We got nothing */
171         }
172         if (r < 0)
173                 return r;
174
175         return 1;
176 }
177 #endif // 0
178
179 int files_same(const char *filea, const char *fileb) {
180         struct stat a, b;
181
182         assert(filea);
183         assert(fileb);
184
185         if (stat(filea, &a) < 0)
186                 return -errno;
187
188         if (stat(fileb, &b) < 0)
189                 return -errno;
190
191         return a.st_dev == b.st_dev &&
192                a.st_ino == b.st_ino;
193 }
194
195 bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
196         assert(s);
197         assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
198
199         return F_TYPE_EQUAL(s->f_type, magic_value);
200 }
201
202 #if 0 /// UNNEEDED by elogind
203 int fd_check_fstype(int fd, statfs_f_type_t magic_value) {
204         struct statfs s;
205
206         if (fstatfs(fd, &s) < 0)
207                 return -errno;
208
209         return is_fs_type(&s, magic_value);
210 }
211
212 int path_check_fstype(const char *path, statfs_f_type_t magic_value) {
213         _cleanup_close_ int fd = -1;
214
215         fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
216         if (fd < 0)
217                 return -errno;
218
219         return fd_check_fstype(fd, magic_value);
220 }
221 #endif // 0
222
223 bool is_temporary_fs(const struct statfs *s) {
224     return is_fs_type(s, TMPFS_MAGIC) ||
225            is_fs_type(s, RAMFS_MAGIC);
226 }
227
228 int fd_is_temporary_fs(int fd) {
229         struct statfs s;
230
231         if (fstatfs(fd, &s) < 0)
232                 return -errno;
233
234         return is_temporary_fs(&s);
235 }
236
237 int path_is_temporary_fs(const char *path) {
238         _cleanup_close_ int fd = -1;
239
240         fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
241         if (fd < 0)
242                 return -errno;
243
244         return fd_is_temporary_fs(fd);
245 }