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