.
[gnulib.git] / lib / fsusage.c
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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
17
18 #ifdef HAVE_CONFIG_H
19 #if defined (CONFIG_BROKETS)
20 /* We use <config.h> instead of "config.h" so that a compilation
21    using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
22    (which it would do because it found this file in $srcdir).  */
23 #include <config.h>
24 #else
25 #include "config.h"
26 #endif
27 #endif
28
29 #include <sys/types.h>
30 #include "fsusage.h"
31
32 int statfs ();
33
34 #if defined (STAT_STATFS3_OSF1) /* DEC Alpha running OSF/1 */
35 #  include <sys/mount.h>
36 #endif
37
38 #if defined(STAT_STATFS2_BSIZE) && !defined(_IBMR2) /* 4.3BSD, SunOS 4, HP-UX, AIX PS/2.  */
39 #include <sys/vfs.h>
40 #endif
41
42 #ifdef STAT_STATFS2_FSIZE       /* 4.4BSD.  */
43 #include <sys/mount.h>
44 #endif
45
46 #ifdef STAT_STATFS2_FS_DATA     /* Ultrix.  */
47 #include <sys/param.h>
48 #include <sys/mount.h>
49 #endif
50
51 #ifdef STAT_READ                /* SVR2.  */
52 #include <sys/param.h>
53 #include <sys/filsys.h>
54 #include <fcntl.h>
55 #endif
56
57 #if defined(STAT_STATFS4) || (defined(_AIX) && defined(_IBMR2)) /* SVR3, Dynix, Irix, AIX RS6000.  */
58 #include <sys/statfs.h>
59 #endif
60
61 #if defined(_AIX) && defined(_I386) /* AIX PS/2.  */
62 #include <sys/stat.h>
63 #include <sys/dustat.h>
64 #endif
65
66 #ifdef STAT_STATVFS             /* SVR4.  */
67 #include <sys/statvfs.h>
68 int statvfs ();
69 #endif
70
71 /* Set B_NEW to the number of TOSIZE-byte blocks used by B FROMSIZE-byte
72    blocks, rounding away from zero.  TOSIZE must be positive.  Return -1
73    from invoking function if FROMSIZE is not positive.  */
74
75 #define ADJUST_BLOCKS(b_new, b, fromsize, tosize)                       \
76   do                                                                    \
77     {                                                                   \
78       if ((tosize) <= 0)                                                \
79         abort ();                                                       \
80       if ((fromsize) <= 0)                                              \
81         return -1;                                                      \
82                                                                         \
83       if ((fromsize) == (tosize))       /* E.g., from 512 to 512.  */   \
84         (b_new) = (b);                                                  \
85       else if ((fromsize) > (tosize))   /* E.g., from 2048 to 512.  */  \
86         (b_new) = (b) * ((fromsize) / (tosize));                        \
87       else                              /* E.g., from 256 to 512.  */   \
88         (b_new) = ((b) + ((b) < 0 ? -1 : 1)) / ((tosize) / (fromsize)); \
89     }                                                                   \
90   while (0)
91
92 /* Fill in the fields of FSP with information about space usage for
93    the filesystem on which PATH resides.
94    DISK is the device on which PATH is mounted, for space-getting
95    methods that need to know it.
96    Return 0 if successful, -1 if not. */
97
98 int
99 get_fs_usage (path, disk, fsp)
100      char *path, *disk;
101      struct fs_usage *fsp;
102 {
103 #if defined (STAT_STATFS3_OSF1)
104   struct statfs fsd;
105
106   if (statfs (path, &fsd, sizeof (struct statfs)) != 0)
107     return -1;
108 #define CONVERT_BLOCKS(bnew, b) ADJUST_BLOCKS ((bnew), (b), fsd.f_fsize, 512)
109 #endif /* STAT_STATFS3_OSF1 */
110
111 #ifdef STAT_STATFS2_FS_DATA     /* Ultrix.  */
112   struct fs_data fsd;
113
114   if (statfs (path, &fsd) != 1)
115     return -1;
116 #define CONVERT_BLOCKS(bnew, b) ADJUST_BLOCKS ((bnew), (b), 1024, 512)
117   CONVERT_BLOCKS (fsp->fsu_blocks, fsd.fd_req.btot);
118   CONVERT_BLOCKS (fsp->fsu_bfree, fsd.fd_req.bfree);
119   CONVERT_BLOCKS (fsp->fsu_bavail, fsd.fd_req.bfreen);
120   fsp->fsu_files = fsd.fd_req.gtot;
121   fsp->fsu_ffree = fsd.fd_req.gfree;
122 #endif
123
124 #ifdef STAT_READ                /* SVR2.  */
125 #ifndef SUPERBOFF
126 #define SUPERBOFF (SUPERB * 512)
127 #endif
128   struct filsys fsd;
129   int fd;
130
131   fd = open (disk, O_RDONLY);
132   if (fd < 0)
133     return -1;
134   lseek (fd, (long) SUPERBOFF, 0);
135   if (read (fd, (char *) &fsd, sizeof fsd) != sizeof fsd)
136     {
137       close (fd);
138       return -1;
139     }
140   close (fd);
141 #define CONVERT_BLOCKS(bnew, b) \
142     ADJUST_BLOCKS ((bnew), (b), (fsd.s_type == Fs2b ? 1024 : 512), 512)
143   CONVERT_BLOCKS (fsp->fsu_blocks, fsd.s_fsize);
144   CONVERT_BLOCKS (fsp->fsu_bfree, fsd.s_tfree);
145   CONVERT_BLOCKS (fsp->fsu_bavail, fsd.s_tfree);
146   fsp->fsu_files = (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1);
147   fsp->fsu_ffree = fsd.s_tinode;
148 #endif
149
150 #ifdef STAT_STATFS2_BSIZE       /* 4.3BSD, SunOS 4, HP-UX, AIX.  */
151   struct statfs fsd;
152
153   if (statfs (path, &fsd) < 0)
154     return -1;
155 #define CONVERT_BLOCKS(bnew, b) ADJUST_BLOCKS ((bnew), (b), fsd.f_bsize, 512)
156 #endif
157
158 #ifdef STAT_STATFS2_FSIZE       /* 4.4BSD.  */
159   struct statfs fsd;
160
161   if (statfs (path, &fsd) < 0)
162     return -1;
163 #define CONVERT_BLOCKS(bnew, b) ADJUST_BLOCKS ((bnew), (b), fsd.f_fsize, 512)
164 #endif
165
166 #ifdef STAT_STATFS4             /* SVR3, Dynix, Irix.  */
167   struct statfs fsd;
168
169   if (statfs (path, &fsd, sizeof fsd, 0) < 0)
170     return -1;
171   /* Empirically, the block counts on most SVR3 and SVR3-derived
172      systems seem to always be in terms of 512-byte blocks,
173      no matter what value f_bsize has.  */
174 #define CONVERT_BLOCKS(bnew, b)                                         \
175   do                                                                    \
176     {                                                                   \
177       (bnew) = (b);                                                     \
178     }                                                                   \
179   while (0)
180
181 #ifndef _SEQUENT_               /* _SEQUENT_ is DYNIX/ptx.  */
182 #ifndef DOLPHIN                 /* DOLPHIN 3.8.alfa/7.18 has f_bavail */
183 #define f_bavail f_bfree
184 #endif
185 #endif
186 #endif
187
188 #ifdef STAT_STATVFS             /* SVR4.  */
189   struct statvfs fsd;
190
191   if (statvfs (path, &fsd) < 0)
192     return -1;
193   /* f_frsize isn't guaranteed to be supported.  */
194 #define CONVERT_BLOCKS(bnew, b) \
195   ADJUST_BLOCKS ((bnew), (b), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512)
196 #endif
197
198 #if !defined(STAT_STATFS2_FS_DATA) && !defined(STAT_READ) /* !Ultrix && !SVR2.  */
199   CONVERT_BLOCKS (fsp->fsu_blocks, fsd.f_blocks);
200   CONVERT_BLOCKS (fsp->fsu_bfree, fsd.f_bfree);
201   CONVERT_BLOCKS (fsp->fsu_bavail, fsd.f_bavail);
202   fsp->fsu_files = fsd.f_files;
203   fsp->fsu_ffree = fsd.f_ffree;
204 #endif
205
206   return 0;
207 }
208
209 #if defined(_AIX) && defined(_I386)
210 /* AIX PS/2 does not supply statfs.  */
211
212 int
213 statfs (path, fsb)
214      char *path;
215      struct statfs *fsb;
216 {
217   struct stat stats;
218   struct dustat fsd;
219
220   if (stat (path, &stats))
221     return -1;
222   if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
223     return -1;
224   fsb->f_type   = 0;
225   fsb->f_bsize  = fsd.du_bsize;
226   fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
227   fsb->f_bfree  = fsd.du_tfree;
228   fsb->f_bavail = fsd.du_tfree;
229   fsb->f_files  = (fsd.du_isize - 2) * fsd.du_inopb;
230   fsb->f_ffree  = fsd.du_tinode;
231   fsb->f_fsid.val[0] = fsd.du_site;
232   fsb->f_fsid.val[1] = fsd.du_pckno;
233   return 0;
234 }
235 #endif /* _AIX && _I386 */