]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/stat-util.c
Merge pull request #2495 from heftig/master
[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 "macro.h"
32 #include "missing.h"
33 #include "stat-util.h"
34 #include "string-util.h"
35
36 int is_symlink(const char *path) {
37 struct stat info;
38
39 assert(path);
40
41 if (lstat(path, &info) < 0)
42 return -errno;
43
44 return !!S_ISLNK(info.st_mode);
45 }
46
47 int is_dir(const char* path, bool follow) {
48 struct stat st;
49 int r;
50
51 assert(path);
52
53 if (follow)
54 r = stat(path, &st);
55 else
56 r = lstat(path, &st);
57 if (r < 0)
58 return -errno;
59
60 return !!S_ISDIR(st.st_mode);
61 }
62
63 int is_device_node(const char *path) {
64 struct stat info;
65
66 assert(path);
67
68 if (lstat(path, &info) < 0)
69 return -errno;
70
71 return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
72 }
73
74 int dir_is_empty(const char *path) {
75 _cleanup_closedir_ DIR *d;
76 struct dirent *de;
77
78 d = opendir(path);
79 if (!d)
80 return -errno;
81
82 FOREACH_DIRENT(de, d, return -errno)
83 return 0;
84
85 return 1;
86 }
87
88 bool null_or_empty(struct stat *st) {
89 assert(st);
90
91 if (S_ISREG(st->st_mode) && st->st_size <= 0)
92 return true;
93
94 /* We don't want to hardcode the major/minor of /dev/null,
95 * hence we do a simpler "is this a device node?" check. */
96
97 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
98 return true;
99
100 return false;
101 }
102
103 int null_or_empty_path(const char *fn) {
104 struct stat st;
105
106 assert(fn);
107
108 if (stat(fn, &st) < 0)
109 return -errno;
110
111 return null_or_empty(&st);
112 }
113
114 int null_or_empty_fd(int fd) {
115 struct stat st;
116
117 assert(fd >= 0);
118
119 if (fstat(fd, &st) < 0)
120 return -errno;
121
122 return null_or_empty(&st);
123 }
124
125 int path_is_read_only_fs(const char *path) {
126 struct statvfs st;
127
128 assert(path);
129
130 if (statvfs(path, &st) < 0)
131 return -errno;
132
133 if (st.f_flag & ST_RDONLY)
134 return true;
135
136 /* On NFS, statvfs() might not reflect whether we can actually
137 * write to the remote share. Let's try again with
138 * access(W_OK) which is more reliable, at least sometimes. */
139 if (access(path, W_OK) < 0 && errno == EROFS)
140 return true;
141
142 return false;
143 }
144
145 int path_is_os_tree(const char *path) {
146 char *p;
147 int r;
148
149 assert(path);
150
151 /* We use /usr/lib/os-release as flag file if something is an OS */
152 p = strjoina(path, "/usr/lib/os-release");
153 r = access(p, F_OK);
154 if (r >= 0)
155 return 1;
156
157 /* Also check for the old location in /etc, just in case. */
158 p = strjoina(path, "/etc/os-release");
159 r = access(p, F_OK);
160
161 return r >= 0;
162 }
163
164 int files_same(const char *filea, const char *fileb) {
165 struct stat a, b;
166
167 assert(filea);
168 assert(fileb);
169
170 if (stat(filea, &a) < 0)
171 return -errno;
172
173 if (stat(fileb, &b) < 0)
174 return -errno;
175
176 return a.st_dev == b.st_dev &&
177 a.st_ino == b.st_ino;
178 }
179
180 bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
181 assert(s);
182 assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
183
184 return F_TYPE_EQUAL(s->f_type, magic_value);
185 }
186
187 int fd_check_fstype(int fd, statfs_f_type_t magic_value) {
188 struct statfs s;
189
190 if (fstatfs(fd, &s) < 0)
191 return -errno;
192
193 return is_fs_type(&s, magic_value);
194 }
195
196 int path_check_fstype(const char *path, statfs_f_type_t magic_value) {
197 _cleanup_close_ int fd = -1;
198
199 fd = open(path, O_RDONLY);
200 if (fd < 0)
201 return -errno;
202
203 return fd_check_fstype(fd, magic_value);
204 }
205
206 bool is_temporary_fs(const struct statfs *s) {
207 return is_fs_type(s, TMPFS_MAGIC) ||
208 is_fs_type(s, RAMFS_MAGIC);
209 }
210
211 int fd_is_temporary_fs(int fd) {
212 struct statfs s;
213
214 if (fstatfs(fd, &s) < 0)
215 return -errno;
216
217 return is_temporary_fs(&s);
218 }