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