1 /* fsusage.c -- return space usage of mounted filesystems
2 Copyright (C) 1991, 1992 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
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
17
18 This file was modified slightly by Ian Lance Taylor, December 1992,
19 and again July 1995, for use with Taylor UUCP. */
20
21 #include "uucp.h"
22 #include "uudefs.h"
23 #include "sysdep.h"
24 #include "fsusg.h"
25
26 int statfs ();
27
28 #if HAVE_SYS_PARAM_H
29 #include <sys/param.h>
30 #endif
31
32 #if HAVE_SYS_MOUNT_H
33 #include <sys/mount.h>
34 #endif
35
36 #if HAVE_SYS_VFS_H
37 #include <sys/vfs.h>
38 #endif
39
40 #if HAVE_SYS_FILSYS_H
41 #include <sys/filsys.h> /* SVR2. */
42 #endif
43
44 #if HAVE_FCNTL_H
45 #include <fcntl.h>
46 #endif
47
48 #if HAVE_SYS_STATFS_H
49 #include <sys/statfs.h>
50 #endif
51
52 #if HAVE_SYS_DUSTAT_H /* AIX PS/2. */
53 #include <sys/dustat.h>
54 #endif
55
56 #if HAVE_SYS_STATVFS_H /* SVR4. */
57 #include <sys/statvfs.h>
58 int statvfs ();
59 #endif
60
61 #if HAVE_USTAT_H /* SVR2 and others. */
62 #include <ustat.h>
63 #endif
64
65 #if STAT_DISK_SPACE /* QNX. */
66 #include <sys/disk.h>
67 #include <errno.h>
68 #endif
69
70 #define STAT_NONE 0
71
72 #if ! STAT_STATFS3_OSF1
73 #if ! STAT_STATFS2_FS_DATA
74 #if ! STAT_STATFS2_BSIZE
75 #if ! STAT_STATFS2_FSIZE
76 #if ! STAT_STATFS4
77 #if ! STAT_STATVFS
78 #if ! STAT_DISK_SPACE
79 #if ! STAT_USTAT
80 #undef STAT_NONE
81 #define STAT_NONE 1
82 #endif
83 #endif
84 #endif
85 #endif
86 #endif
87 #endif
88 #endif
89 #endif
90
91 #if ! STAT_NONE
92
93 static long adjust_blocks P((long blocks, int fromsize, int tosize));
94
95 /* Return the number of TOSIZE-byte blocks used by
96 BLOCKS FROMSIZE-byte blocks, rounding away from zero.
97 TOSIZE must be positive. Return -1 if FROMSIZE is not positive. */
98
99 static long
adjust_blocks(blocks,fromsize,tosize)100 adjust_blocks (blocks, fromsize, tosize)
101 long blocks;
102 int fromsize, tosize;
103 {
104 if (tosize <= 0)
105 abort ();
106 if (fromsize <= 0)
107 return -1;
108
109 if (fromsize == tosize) /* E.g., from 512 to 512. */
110 return blocks;
111 else if (fromsize > tosize) /* E.g., from 2048 to 512. */
112 return blocks * (fromsize / tosize);
113 else /* E.g., from 256 to 512. */
114 return (blocks + (blocks < 0 ? -1 : 1)) / (tosize / fromsize);
115 }
116
117 #endif
118
119 /* Fill in the fields of FSP with information about space usage for
120 the filesystem on which PATH resides.
121 DISK is the device on which PATH is mounted, for space-getting
122 methods that need to know it.
123 Return 0 if successful, -1 if not. */
124
125 int
get_fs_usage(path,disk,fsp)126 get_fs_usage (path, disk, fsp)
127 char *path, *disk ATTRIBUTE_UNUSED;
128 struct fs_usage *fsp;
129 {
130 #if STAT_NONE
131 return -1;
132 #endif
133
134 #if STAT_STATFS3_OSF1
135 struct statfs fsd;
136
137 if (statfs (path, &fsd, sizeof (struct statfs)) != 0)
138 return -1;
139 #define CONVERT_BLOCKS(b) adjust_blocks ((b), fsd.f_fsize, 512)
140 #endif /* STAT_STATFS3_OSF1 */
141
142 #if STAT_STATFS2_FS_DATA /* Ultrix. */
143 struct fs_data fsd;
144
145 if (statfs (path, &fsd) != 1)
146 return -1;
147 #define CONVERT_BLOCKS(b) adjust_blocks ((long) (b), 1024, 512)
148 fsp->fsu_blocks = CONVERT_BLOCKS (fsd.fd_req.btot);
149 fsp->fsu_bfree = CONVERT_BLOCKS (fsd.fd_req.bfree);
150 fsp->fsu_bavail = CONVERT_BLOCKS (fsd.fd_req.bfreen);
151 fsp->fsu_files = fsd.fd_req.gtot;
152 fsp->fsu_ffree = fsd.fd_req.gfree;
153 #endif
154
155 #if STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX. */
156 struct statfs fsd;
157
158 if (statfs (path, &fsd) < 0)
159 return -1;
160 #define CONVERT_BLOCKS(b) adjust_blocks ((b), fsd.f_bsize, 512)
161 #endif
162
163 #if STAT_STATFS2_FSIZE /* 4.4BSD. */
164 struct statfs fsd;
165
166 if (statfs (path, &fsd) < 0)
167 return -1;
168 #define CONVERT_BLOCKS(b) adjust_blocks ((b), fsd.f_fsize, 512)
169 #endif
170
171 #if STAT_STATFS4 /* SVR3, Dynix, Irix. */
172 struct statfs fsd;
173
174 if (statfs (path, &fsd, sizeof fsd, 0) < 0)
175 return -1;
176 /* Empirically, the block counts on most SVR3 and SVR3-derived
177 systems seem to always be in terms of 512-byte blocks,
178 no matter what value f_bsize has. */
179 # if _AIX
180 # define CONVERT_BLOCKS(b) adjust_blocks ((b), fsd.f_bsize, 512)
181 # else
182 # define CONVERT_BLOCKS(b) (b)
183 # ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx. */
184 # ifndef DOLPHIN /* DOLPHIN 3.8.alfa/7.18 has f_bavail */
185 # define f_bavail f_bfree
186 # endif
187 # endif
188 # endif
189 #endif
190
191 #if STAT_STATVFS /* SVR4. */
192 struct statvfs fsd;
193
194 if (statvfs (path, &fsd) < 0)
195 return -1;
196 /* f_frsize isn't guaranteed to be supported. */
197 #define CONVERT_BLOCKS(b) \
198 adjust_blocks ((b), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512)
199 #endif
200
201 #if STAT_DISK_SPACE /* QNX. */
202 int o;
203 int iret;
204 long cfree_blocks, ctotal_blocks;
205 char *zpath;
206 char *zslash;
207
208 zpath = zbufcpy (path);
209 while ((o = open (zpath, O_RDONLY, 0)) == -1
210 && errno == ENOENT)
211 {
212 /* The named file doesn't exist, so we can't open it. Try the
213 directory containing it. */
214 if ((strcmp ("/", zpath) == 0)
215 || (strcmp (zpath, ".") == 0)
216 || (strcmp (zpath, "") == 0)
217 /* QNX peculiarity: "//2" means root on node 2 */
218 || ((strncmp (zpath, "//", 2) == 0)
219 && (strchr (zpath + 2, '/') == NULL)))
220 {
221 /* We can't shorten this! */
222 break;
223 }
224
225 /* Shorten the pathname by one component and try again. */
226 zslash = strrchr (zpath, '/');
227 if (zslash == NULL)
228 {
229 /* Try the current directory. We can open directories. */
230 zpath[0] = '.';
231 zpath[1] = '\0';
232 }
233 else if (zslash == zpath)
234 {
235 /* Try the root directory. */
236 zpath[0] = '/';
237 zpath[1] = '\0';
238 }
239 else
240 {
241 /* Chop off last path component. */
242 zslash[0] = '\0';
243 }
244 }
245 if (o == -1)
246 {
247 ulog (LOG_ERROR, "get_fs_usage: open (%s) failed: %s", zpath,
248 strerror (errno));
249 ubuffree (zpath);
250 return -1;
251 }
252 ubuffree (zpath);
253
254 iret = disk_space (o, &cfree_blocks, &ctotal_blocks);
255 (void) close (o);
256 if (iret == -1)
257 {
258 ulog (LOG_ERROR, "get_fs_usage: disk_space failed: %s",
259 strerror (errno));
260 return -1;
261 }
262
263 fsp->fsu_blocks = ctotal_blocks;
264 fsp->fsu_bfree = cfree_blocks;
265 fsp->fsu_bavail = cfree_blocks;
266
267 /* QNX has no limit on the number of inodes. Most inodes are stored
268 directly in the directory entry. */
269 fsp->fsu_files = -1;
270 fsp->fsu_ffree = -1;
271 #endif /* STAT_DISK_SPACE */
272
273 #if STAT_USTAT
274 struct stat sstat;
275 struct ustat s;
276
277 if (stat (path, &sstat) < 0
278 || ustat (sstat.st_dev, &s) < 0)
279 return -1;
280 fsp->fsu_blocks = -1;
281 fsp->fsu_bfree = s.f_tfree;
282 fsp->fsu_bavail = s.f_tfree;
283 fsp->fsu_files = -1;
284 fsp->fsu_ffree = -1;
285 #endif
286
287 #if ! STAT_STATFS2_FS_DATA /* ! Ultrix */
288 #if ! STAT_DISK_SPACE
289 #if ! STAT_USTAT
290 #if ! STAT_NONE
291 fsp->fsu_blocks = CONVERT_BLOCKS (fsd.f_blocks);
292 fsp->fsu_bfree = CONVERT_BLOCKS (fsd.f_bfree);
293 fsp->fsu_bavail = CONVERT_BLOCKS (fsd.f_bavail);
294 fsp->fsu_files = fsd.f_files;
295 fsp->fsu_ffree = fsd.f_ffree;
296 #endif
297 #endif
298 #endif
299 #endif
300
301 return 0;
302 }
303
304 #ifdef _AIX
305 #ifdef _I386
306 /* AIX PS/2 does not supply statfs. */
307
308 int
statfs(path,fsb)309 statfs (path, fsb)
310 char *path;
311 struct statfs *fsb;
312 {
313 struct stat stats;
314 struct dustat fsd;
315
316 if (stat (path, &stats))
317 return -1;
318 if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
319 return -1;
320 fsb->f_type = 0;
321 fsb->f_bsize = fsd.du_bsize;
322 fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
323 fsb->f_bfree = fsd.du_tfree;
324 fsb->f_bavail = fsd.du_tfree;
325 fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb;
326 fsb->f_ffree = fsd.du_tinode;
327 fsb->f_fsid.val[0] = fsd.du_site;
328 fsb->f_fsid.val[1] = fsd.du_pckno;
329 return 0;
330 }
331 #endif /* _I386 */
332 #endif /* _AIX */
333