diff options
Diffstat (limited to 'lib/fsusage.c')
-rw-r--r-- | lib/fsusage.c | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/lib/fsusage.c b/lib/fsusage.c new file mode 100644 index 00000000..5a864bf2 --- /dev/null +++ b/lib/fsusage.c | |||
@@ -0,0 +1,281 @@ | |||
1 | /* fsusage.c -- return space usage of mounted filesystems | ||
2 | Copyright (C) 1991, 1992, 1996, 1998, 1999 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
17 | |||
18 | #include "../plugins/config.h" | ||
19 | |||
20 | #if HAVE_INTTYPES_H | ||
21 | # include <inttypes.h> | ||
22 | #endif | ||
23 | #include <sys/types.h> | ||
24 | #include <sys/stat.h> | ||
25 | #include "fsusage.h" | ||
26 | |||
27 | #if HAVE_LIMITS_H | ||
28 | # include <limits.h> | ||
29 | #endif | ||
30 | #ifndef CHAR_BIT | ||
31 | # define CHAR_BIT 8 | ||
32 | #endif | ||
33 | |||
34 | int statfs (); | ||
35 | |||
36 | #if HAVE_SYS_PARAM_H | ||
37 | # include <sys/param.h> | ||
38 | #endif | ||
39 | |||
40 | #if HAVE_SYS_MOUNT_H | ||
41 | # include <sys/mount.h> | ||
42 | #endif | ||
43 | |||
44 | #if HAVE_SYS_VFS_H | ||
45 | # include <sys/vfs.h> | ||
46 | #endif | ||
47 | |||
48 | #if HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */ | ||
49 | # include <sys/fs/s5param.h> | ||
50 | #endif | ||
51 | |||
52 | #if defined (HAVE_SYS_FILSYS_H) && !defined (_CRAY) | ||
53 | # include <sys/filsys.h> /* SVR2 */ | ||
54 | #endif | ||
55 | |||
56 | #if HAVE_FCNTL_H | ||
57 | # include <fcntl.h> | ||
58 | #endif | ||
59 | |||
60 | #if HAVE_SYS_STATFS_H | ||
61 | # include <sys/statfs.h> | ||
62 | #endif | ||
63 | |||
64 | #if HAVE_DUSTAT_H /* AIX PS/2 */ | ||
65 | # include <sys/dustat.h> | ||
66 | #endif | ||
67 | |||
68 | #if HAVE_SYS_STATVFS_H /* SVR4 */ | ||
69 | # include <sys/statvfs.h> | ||
70 | int statvfs (); | ||
71 | #endif | ||
72 | |||
73 | /* Many space usage primitives use all 1 bits to denote a value that is | ||
74 | not applicable or unknown. Propagate this information by returning | ||
75 | a uintmax_t value that is all 1 bits if the argument is all 1 bits, | ||
76 | even if the argument is unsigned and smaller than uintmax_t. */ | ||
77 | #define PROPAGATE_ALL_ONES(x) ((x) == -1 ? (uintmax_t) -1 : (uintmax_t) (x)) | ||
78 | |||
79 | /* Extract the top bit of X as an uintmax_t value. */ | ||
80 | #define EXTRACT_TOP_BIT(x) ((x) \ | ||
81 | & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1))) | ||
82 | |||
83 | /* If a value is negative, many space usage primitives store it into an | ||
84 | integer variable by assignment, even if the variable's type is unsigned. | ||
85 | So, if a space usage variable X's top bit is set, convert X to the | ||
86 | uintmax_t value V such that (- (uintmax_t) V) is the negative of | ||
87 | the original value. If X's top bit is clear, just yield X. | ||
88 | Use PROPAGATE_TOP_BIT if the original value might be negative; | ||
89 | otherwise, use PROPAGATE_ALL_ONES. */ | ||
90 | #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1)) | ||
91 | |||
92 | int safe_read (); | ||
93 | |||
94 | /* Fill in the fields of FSP with information about space usage for | ||
95 | the filesystem on which PATH resides. | ||
96 | DISK is the device on which PATH is mounted, for space-getting | ||
97 | methods that need to know it. | ||
98 | Return 0 if successful, -1 if not. When returning -1, ensure that | ||
99 | ERRNO is either a system error value, or zero if DISK is NULL | ||
100 | on a system that requires a non-NULL value. */ | ||
101 | int | ||
102 | get_fs_usage (const char *path, const char *disk, struct fs_usage *fsp) | ||
103 | { | ||
104 | #ifdef STAT_STATFS3_OSF1 | ||
105 | |||
106 | struct statfs fsd; | ||
107 | |||
108 | if (statfs (path, &fsd, sizeof (struct statfs)) != 0) | ||
109 | return -1; | ||
110 | |||
111 | fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize); | ||
112 | |||
113 | #endif /* STAT_STATFS3_OSF1 */ | ||
114 | |||
115 | #ifdef STAT_STATFS2_FS_DATA /* Ultrix */ | ||
116 | |||
117 | struct fs_data fsd; | ||
118 | |||
119 | if (statfs (path, &fsd) != 1) | ||
120 | return -1; | ||
121 | |||
122 | fsp->fsu_blocksize = 1024; | ||
123 | fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot); | ||
124 | fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree); | ||
125 | fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen); | ||
126 | fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0; | ||
127 | fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot); | ||
128 | fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree); | ||
129 | |||
130 | #endif /* STAT_STATFS2_FS_DATA */ | ||
131 | |||
132 | #ifdef STAT_READ_FILSYS /* SVR2 */ | ||
133 | # ifndef SUPERBOFF | ||
134 | # define SUPERBOFF (SUPERB * 512) | ||
135 | # endif | ||
136 | |||
137 | struct filsys fsd; | ||
138 | int fd; | ||
139 | |||
140 | if (! disk) | ||
141 | { | ||
142 | errno = 0; | ||
143 | return -1; | ||
144 | } | ||
145 | |||
146 | fd = open (disk, O_RDONLY); | ||
147 | if (fd < 0) | ||
148 | return -1; | ||
149 | lseek (fd, (off_t) SUPERBOFF, 0); | ||
150 | if (safe_read (fd, (char *) &fsd, sizeof fsd) != sizeof fsd) | ||
151 | { | ||
152 | close (fd); | ||
153 | return -1; | ||
154 | } | ||
155 | close (fd); | ||
156 | |||
157 | fsp->fsu_blocksize = (fsd.s_type == Fs2b ? 1024 : 512); | ||
158 | fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.s_fsize); | ||
159 | fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.s_tfree); | ||
160 | fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.s_tfree); | ||
161 | fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.s_tfree) != 0; | ||
162 | fsp->fsu_files = (fsd.s_isize == -1 | ||
163 | ? (uintmax_t) -1 | ||
164 | : (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1)); | ||
165 | fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.s_tinode); | ||
166 | |||
167 | #endif /* STAT_READ_FILSYS */ | ||
168 | |||
169 | #ifdef STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX */ | ||
170 | |||
171 | struct statfs fsd; | ||
172 | |||
173 | if (statfs (path, &fsd) < 0) | ||
174 | return -1; | ||
175 | |||
176 | fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize); | ||
177 | |||
178 | # ifdef STATFS_TRUNCATES_BLOCK_COUNTS | ||
179 | |||
180 | /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the | ||
181 | struct statfs are truncated to 2GB. These conditions detect that | ||
182 | truncation, presumably without botching the 4.1.1 case, in which | ||
183 | the values are not truncated. The correct counts are stored in | ||
184 | undocumented spare fields. */ | ||
185 | if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0) | ||
186 | { | ||
187 | fsd.f_blocks = fsd.f_spare[0]; | ||
188 | fsd.f_bfree = fsd.f_spare[1]; | ||
189 | fsd.f_bavail = fsd.f_spare[2]; | ||
190 | } | ||
191 | # endif /* STATFS_TRUNCATES_BLOCK_COUNTS */ | ||
192 | |||
193 | #endif /* STAT_STATFS2_BSIZE */ | ||
194 | |||
195 | #ifdef STAT_STATFS2_FSIZE /* 4.4BSD */ | ||
196 | |||
197 | struct statfs fsd; | ||
198 | |||
199 | if (statfs (path, &fsd) < 0) | ||
200 | return -1; | ||
201 | |||
202 | fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize); | ||
203 | |||
204 | #endif /* STAT_STATFS2_FSIZE */ | ||
205 | |||
206 | #ifdef STAT_STATFS4 /* SVR3, Dynix, Irix, AIX */ | ||
207 | |||
208 | # if !_AIX && !defined _SEQUENT_ && !defined DOLPHIN | ||
209 | # define f_bavail f_bfree | ||
210 | # endif | ||
211 | |||
212 | struct statfs fsd; | ||
213 | |||
214 | if (statfs (path, &fsd, sizeof fsd, 0) < 0) | ||
215 | return -1; | ||
216 | |||
217 | /* Empirically, the block counts on most SVR3 and SVR3-derived | ||
218 | systems seem to always be in terms of 512-byte blocks, | ||
219 | no matter what value f_bsize has. */ | ||
220 | # if _AIX || defined(_CRAY) | ||
221 | fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize); | ||
222 | # else | ||
223 | fsp->fsu_blocksize = 512; | ||
224 | # endif | ||
225 | |||
226 | #endif /* STAT_STATFS4 */ | ||
227 | |||
228 | #ifdef STAT_STATVFS /* SVR4 */ | ||
229 | |||
230 | struct statvfs fsd; | ||
231 | |||
232 | if (statvfs (path, &fsd) < 0) | ||
233 | return -1; | ||
234 | |||
235 | /* f_frsize isn't guaranteed to be supported. */ | ||
236 | fsp->fsu_blocksize = | ||
237 | PROPAGATE_ALL_ONES (fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize); | ||
238 | |||
239 | #endif /* STAT_STATVFS */ | ||
240 | |||
241 | #if !defined(STAT_STATFS2_FS_DATA) && !defined(STAT_READ_FILSYS) | ||
242 | /* !Ultrix && !SVR2 */ | ||
243 | |||
244 | fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks); | ||
245 | fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree); | ||
246 | fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail); | ||
247 | fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0; | ||
248 | fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files); | ||
249 | fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree); | ||
250 | |||
251 | #endif /* not STAT_STATFS2_FS_DATA && not STAT_READ_FILSYS */ | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | #if defined(_AIX) && defined(_I386) | ||
257 | /* AIX PS/2 does not supply statfs. */ | ||
258 | |||
259 | int | ||
260 | statfs (char *path, struct statfs *fsb) | ||
261 | { | ||
262 | struct stat stats; | ||
263 | struct dustat fsd; | ||
264 | |||
265 | if (stat (path, &stats)) | ||
266 | return -1; | ||
267 | if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd))) | ||
268 | return -1; | ||
269 | fsb->f_type = 0; | ||
270 | fsb->f_bsize = fsd.du_bsize; | ||
271 | fsb->f_blocks = fsd.du_fsize - fsd.du_isize; | ||
272 | fsb->f_bfree = fsd.du_tfree; | ||
273 | fsb->f_bavail = fsd.du_tfree; | ||
274 | fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb; | ||
275 | fsb->f_ffree = fsd.du_tinode; | ||
276 | fsb->f_fsid.val[0] = fsd.du_site; | ||
277 | fsb->f_fsid.val[1] = fsd.du_pckno; | ||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | #endif /* _AIX && _I386 */ | ||