*** empty log message ***
[gnulib.git] / lib / fsusage.c
1 /* fsusage.c -- return space usage of mounted filesystems
2    Copyright (C) 1991, 1992, 1996 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 Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 #if HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #if HAVE_INTTYPES_H
23 # include <inttypes.h>
24 #endif
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include "fsusage.h"
28
29 int statfs ();
30
31 #if HAVE_SYS_PARAM_H
32 # include <sys/param.h>
33 #endif
34
35 #if HAVE_SYS_MOUNT_H
36 # include <sys/mount.h>
37 #endif
38
39 #if HAVE_SYS_VFS_H
40 # include <sys/vfs.h>
41 #endif
42
43 #if HAVE_SYS_FS_S5PARAM_H       /* Fujitsu UXP/V */
44 # include <sys/fs/s5param.h>
45 #endif
46
47 #if defined (HAVE_SYS_FILSYS_H) && !defined (_CRAY)
48 # include <sys/filsys.h>        /* SVR2 */
49 #endif
50
51 #if HAVE_FCNTL_H
52 # include <fcntl.h>
53 #endif
54
55 #if HAVE_SYS_STATFS_H
56 # include <sys/statfs.h>
57 #endif
58
59 #if HAVE_DUSTAT_H               /* AIX PS/2 */
60 # include <sys/dustat.h>
61 #endif
62
63 #if HAVE_SYS_STATVFS_H          /* SVR4 */
64 # include <sys/statvfs.h>
65 int statvfs ();
66 #endif
67
68 int safe_read ();
69
70 /* Fill in the fields of FSP with information about space usage for
71    the filesystem on which PATH resides.
72    DISK is the device on which PATH is mounted, for space-getting
73    methods that need to know it.
74    Return 0 if successful, -1 if not.  When returning -1, ensure that
75    ERRNO is either a system error value, or zero if DISK is NULL
76    on a system that requires a non-NULL value.  */
77 int
78 get_fs_usage (path, disk, fsp)
79      const char *path;
80      const char *disk;
81      struct fs_usage *fsp;
82 {
83 #ifdef STAT_STATFS3_OSF1
84
85   struct statfs fsd;
86
87   if (statfs (path, &fsd, sizeof (struct statfs)) != 0)
88     return -1;
89
90   fsp->fsu_blocksize = fsd.f_fsize;
91
92 #endif /* STAT_STATFS3_OSF1 */
93
94 #ifdef STAT_STATFS2_FS_DATA     /* Ultrix */
95
96   struct fs_data fsd;
97
98   if (statfs (path, &fsd) != 1)
99     return -1;
100
101   fsp->fsu_blocksize = 1024;
102   fsp->fsu_blocks = fsd.fd_req.btot;
103   fsp->fsu_bfree = fsd.fd_req.bfree;
104   fsp->fsu_bavail = fsd.fd_req.bfreen;
105   fsp->fsu_files = fsd.fd_req.gtot;
106   fsp->fsu_ffree = fsd.fd_req.gfree;
107
108 #endif /* STAT_STATFS2_FS_DATA */
109
110 #ifdef STAT_READ_FILSYS         /* SVR2 */
111 # ifndef SUPERBOFF
112 #  define SUPERBOFF (SUPERB * 512)
113 # endif
114
115   struct filsys fsd;
116   int fd;
117
118   if (! disk)
119     {
120       errno = 0;
121       return -1;
122     }
123
124   fd = open (disk, O_RDONLY);
125   if (fd < 0)
126     return -1;
127   lseek (fd, (off_t) SUPERBOFF, 0);
128   if (safe_read (fd, (char *) &fsd, sizeof fsd) != sizeof fsd)
129     {
130       close (fd);
131       return -1;
132     }
133   close (fd);
134
135   fsp->fsu_blocksize = fsd.s_type == Fs2b ? 1024 : 512;
136   fsp->fsu_blocks = fsd.s_fsize;
137   fsp->fsu_bfree = fsd.s_tfree;
138   fsp->fsu_bavail = fsd.s_tfree;
139   fsp->fsu_files = (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1);
140   fsp->fsu_ffree = fsd.s_tinode;
141
142 #endif /* STAT_READ_FILSYS */
143
144 #ifdef STAT_STATFS2_BSIZE       /* 4.3BSD, SunOS 4, HP-UX, AIX */
145
146   struct statfs fsd;
147
148   if (statfs (path, &fsd) < 0)
149     return -1;
150
151   fsp->fsu_blocksize = fsd.f_bsize;
152
153 # ifdef STATFS_TRUNCATES_BLOCK_COUNTS
154
155   /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
156      struct statfs are truncated to 2GB.  These conditions detect that
157      truncation, presumably without botching the 4.1.1 case, in which
158      the values are not truncated.  The correct counts are stored in
159      undocumented spare fields.  */
160   if (fsd.f_blocks == 0x1fffff && fsd.f_spare[0] > 0)
161     {
162       fsd.f_blocks = fsd.f_spare[0];
163       fsd.f_bfree = fsd.f_spare[1];
164       fsd.f_bavail = fsd.f_spare[2];
165     }
166 # endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
167
168 #endif /* STAT_STATFS2_BSIZE */
169
170 #ifdef STAT_STATFS2_FSIZE       /* 4.4BSD */
171
172   struct statfs fsd;
173
174   if (statfs (path, &fsd) < 0)
175     return -1;
176
177   fsp->fsu_blocksize = fsd.f_fsize;
178
179 #endif /* STAT_STATFS2_FSIZE */
180
181 #ifdef STAT_STATFS4             /* SVR3, Dynix, Irix, AIX */
182
183 # if !_AIX && !defined _SEQUENT_ && !defined DOLPHIN
184 #  define f_bavail f_bfree
185 # endif
186
187   struct statfs fsd;
188
189   if (statfs (path, &fsd, sizeof fsd, 0) < 0)
190     return -1;
191
192   /* Empirically, the block counts on most SVR3 and SVR3-derived
193      systems seem to always be in terms of 512-byte blocks,
194      no matter what value f_bsize has.  */
195 # if _AIX || defined(_CRAY)
196    fsp->fsu_blocksize = fsd.f_bsize;
197 # else
198    fsp->fsu_blocksize = 512;
199 # endif
200
201 #endif /* STAT_STATFS4 */
202
203 #ifdef STAT_STATVFS             /* SVR4 */
204
205   struct statvfs fsd;
206
207   if (statvfs (path, &fsd) < 0)
208     return -1;
209
210   /* f_frsize isn't guaranteed to be supported.  */
211   fsp->fsu_blocksize = fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize;
212
213 #endif /* STAT_STATVFS */
214
215 #if !defined(STAT_STATFS2_FS_DATA) && !defined(STAT_READ_FILSYS)
216                                 /* !Ultrix && !SVR2 */
217
218   fsp->fsu_blocks = fsd.f_blocks;
219   fsp->fsu_bfree = fsd.f_bfree;
220   fsp->fsu_bavail = fsd.f_bavail;
221   fsp->fsu_files = fsd.f_files;
222   fsp->fsu_ffree = fsd.f_ffree;
223
224 #endif /* not STAT_STATFS2_FS_DATA && not STAT_READ_FILSYS */
225
226   return 0;
227 }
228
229 #if defined(_AIX) && defined(_I386)
230 /* AIX PS/2 does not supply statfs.  */
231
232 int
233 statfs (path, fsb)
234      char *path;
235      struct statfs *fsb;
236 {
237   struct stat stats;
238   struct dustat fsd;
239
240   if (stat (path, &stats))
241     return -1;
242   if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
243     return -1;
244   fsb->f_type   = 0;
245   fsb->f_bsize  = fsd.du_bsize;
246   fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
247   fsb->f_bfree  = fsd.du_tfree;
248   fsb->f_bavail = fsd.du_tfree;
249   fsb->f_files  = (fsd.du_isize - 2) * fsd.du_inopb;
250   fsb->f_ffree  = fsd.du_tinode;
251   fsb->f_fsid.val[0] = fsd.du_site;
252   fsb->f_fsid.val[1] = fsd.du_pckno;
253   return 0;
254 }
255
256 #endif /* _AIX && _I386 */