Line data Source code
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 3 of the License, or
9 : (at your option) 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, see <http://www.gnu.org/licenses/>. */
18 :
19 : #include <config.h>
20 :
21 : #include "fsusage.h"
22 :
23 : #include <limits.h>
24 : #include <sys/types.h>
25 :
26 : #if STAT_STATVFS /* POSIX 1003.1-2001 (and later) with XSI */
27 : # include <sys/statvfs.h>
28 : #else
29 : /* Don't include backward-compatibility files unless they're needed.
30 : Eventually we'd like to remove all this cruft. */
31 : # include <fcntl.h>
32 : # include <unistd.h>
33 : # include <sys/stat.h>
34 : # if HAVE_SYS_PARAM_H
35 : # include <sys/param.h>
36 : # endif
37 : # if HAVE_SYS_MOUNT_H
38 : # include <sys/mount.h>
39 : # endif
40 : # if HAVE_SYS_VFS_H
41 : # include <sys/vfs.h>
42 : # endif
43 : # if HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */
44 : # include <sys/fs/s5param.h>
45 : # endif
46 : # if defined HAVE_SYS_FILSYS_H && !defined _CRAY
47 : # include <sys/filsys.h> /* SVR2 */
48 : # endif
49 : # if HAVE_SYS_STATFS_H
50 : # include <sys/statfs.h>
51 : # endif
52 : # if HAVE_DUSTAT_H /* AIX PS/2 */
53 : # include <sys/dustat.h>
54 : # endif
55 : # include "full-read.h"
56 : #endif
57 :
58 : /* The results of open() in this file are not used with fchdir,
59 : therefore save some unnecessary work in fchdir.c. */
60 : #undef open
61 : #undef close
62 :
63 : /* Many space usage primitives use all 1 bits to denote a value that is
64 : not applicable or unknown. Propagate this information by returning
65 : a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
66 : is unsigned and narrower than uintmax_t. */
67 : #define PROPAGATE_ALL_ONES(x) \
68 : ((sizeof (x) < sizeof (uintmax_t) \
69 : && (~ (x) == (sizeof (x) < sizeof (int) \
70 : ? - (1 << (sizeof (x) * CHAR_BIT)) \
71 : : 0))) \
72 : ? UINTMAX_MAX : (uintmax_t) (x))
73 :
74 : /* Extract the top bit of X as an uintmax_t value. */
75 : #define EXTRACT_TOP_BIT(x) ((x) \
76 : & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
77 :
78 : /* If a value is negative, many space usage primitives store it into an
79 : integer variable by assignment, even if the variable's type is unsigned.
80 : So, if a space usage variable X's top bit is set, convert X to the
81 : uintmax_t value V such that (- (uintmax_t) V) is the negative of
82 : the original value. If X's top bit is clear, just yield X.
83 : Use PROPAGATE_TOP_BIT if the original value might be negative;
84 : otherwise, use PROPAGATE_ALL_ONES. */
85 : #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
86 :
87 : /* Fill in the fields of FSP with information about space usage for
88 : the file system on which FILE resides.
89 : DISK is the device on which FILE is mounted, for space-getting
90 : methods that need to know it.
91 : Return 0 if successful, -1 if not. When returning -1, ensure that
92 : ERRNO is either a system error value, or zero if DISK is NULL
93 : on a system that requires a non-NULL value. */
94 : int
95 758 : get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
96 : {
97 : #if defined STAT_STATVFS /* POSIX */
98 :
99 : struct statvfs fsd;
100 :
101 : if (statvfs (file, &fsd) < 0)
102 : return -1;
103 :
104 : /* f_frsize isn't guaranteed to be supported. */
105 : fsp->fsu_blocksize = (fsd.f_frsize
106 : ? PROPAGATE_ALL_ONES (fsd.f_frsize)
107 : : PROPAGATE_ALL_ONES (fsd.f_bsize));
108 :
109 : #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
110 :
111 : struct fs_data fsd;
112 :
113 : if (statfs (file, &fsd) != 1)
114 : return -1;
115 :
116 : fsp->fsu_blocksize = 1024;
117 : fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot);
118 : fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree);
119 : fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen);
120 : fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0;
121 : fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot);
122 : fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree);
123 :
124 : #elif defined STAT_READ_FILSYS /* SVR2 */
125 : # ifndef SUPERBOFF
126 : # define SUPERBOFF (SUPERB * 512)
127 : # endif
128 :
129 : struct filsys fsd;
130 : int fd;
131 :
132 : if (! disk)
133 : {
134 : errno = 0;
135 : return -1;
136 : }
137 :
138 : fd = open (disk, O_RDONLY);
139 : if (fd < 0)
140 : return -1;
141 : lseek (fd, (off_t) SUPERBOFF, 0);
142 : if (full_read (fd, (char *) &fsd, sizeof fsd) != sizeof fsd)
143 : {
144 : close (fd);
145 : return -1;
146 : }
147 : close (fd);
148 :
149 : fsp->fsu_blocksize = (fsd.s_type == Fs2b ? 1024 : 512);
150 : fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.s_fsize);
151 : fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.s_tfree);
152 : fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.s_tfree);
153 : fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.s_tfree) != 0;
154 : fsp->fsu_files = (fsd.s_isize == -1
155 : ? UINTMAX_MAX
156 : : (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1));
157 : fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.s_tinode);
158 :
159 : #elif defined STAT_STATFS3_OSF1
160 :
161 : struct statfs fsd;
162 :
163 : if (statfs (file, &fsd, sizeof (struct statfs)) != 0)
164 : return -1;
165 :
166 : fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
167 :
168 : #elif defined STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX */
169 :
170 : struct statfs fsd;
171 :
172 758 : if (statfs (file, &fsd) < 0)
173 0 : return -1;
174 :
175 758 : fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
176 :
177 : # ifdef STATFS_TRUNCATES_BLOCK_COUNTS
178 :
179 : /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
180 : struct statfs are truncated to 2GB. These conditions detect that
181 : truncation, presumably without botching the 4.1.1 case, in which
182 : the values are not truncated. The correct counts are stored in
183 : undocumented spare fields. */
184 : if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0)
185 : {
186 : fsd.f_blocks = fsd.f_spare[0];
187 : fsd.f_bfree = fsd.f_spare[1];
188 : fsd.f_bavail = fsd.f_spare[2];
189 : }
190 : # endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
191 :
192 : #elif defined STAT_STATFS2_FSIZE /* 4.4BSD */
193 :
194 : struct statfs fsd;
195 :
196 : if (statfs (file, &fsd) < 0)
197 : return -1;
198 :
199 : fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
200 :
201 : #elif defined STAT_STATFS4 /* SVR3, Dynix, Irix, AIX */
202 :
203 : # if !_AIX && !defined _SEQUENT_ && !defined DOLPHIN
204 : # define f_bavail f_bfree
205 : # endif
206 :
207 : struct statfs fsd;
208 :
209 : if (statfs (file, &fsd, sizeof fsd, 0) < 0)
210 : return -1;
211 :
212 : /* Empirically, the block counts on most SVR3 and SVR3-derived
213 : systems seem to always be in terms of 512-byte blocks,
214 : no matter what value f_bsize has. */
215 : # if _AIX || defined _CRAY
216 : fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
217 : # else
218 : fsp->fsu_blocksize = 512;
219 : # endif
220 :
221 : #endif
222 :
223 : #if (defined STAT_STATVFS \
224 : || (!defined STAT_STATFS2_FS_DATA && !defined STAT_READ_FILSYS))
225 :
226 758 : fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks);
227 758 : fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree);
228 758 : fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail);
229 758 : fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0;
230 758 : fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files);
231 758 : fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree);
232 :
233 : #endif
234 :
235 758 : return 0;
236 : }
237 :
238 : #if defined _AIX && defined _I386
239 : /* AIX PS/2 does not supply statfs. */
240 :
241 : int
242 : statfs (char *file, struct statfs *fsb)
243 : {
244 : struct stat stats;
245 : struct dustat fsd;
246 :
247 : if (stat (file, &stats) != 0)
248 : return -1;
249 : if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
250 : return -1;
251 : fsb->f_type = 0;
252 : fsb->f_bsize = fsd.du_bsize;
253 : fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
254 : fsb->f_bfree = fsd.du_tfree;
255 : fsb->f_bavail = fsd.du_tfree;
256 : fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb;
257 : fsb->f_ffree = fsd.du_tinode;
258 : fsb->f_fsid.val[0] = fsd.du_site;
259 : fsb->f_fsid.val[1] = fsd.du_pckno;
260 : return 0;
261 : }
262 :
263 : #endif /* _AIX && _I386 */
|