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