Initial revision
[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 #include <sys/types.h>
19 #include "fsusage.h"
20
21 int statfs ();
22
23 #if defined(STAT_STATFS2_BSIZE) && !defined(_IBMR2) /* 4.3BSD, SunOS 4, HP-UX, AIX PS/2.  */
24 #include <sys/vfs.h>
25 #endif
26
27 #ifdef STAT_STATFS2_FSIZE       /* 4.4BSD.  */
28 #include <sys/mount.h>
29 #endif
30
31 #ifdef STAT_STATFS2_FS_DATA     /* Ultrix.  */
32 #include <sys/param.h>
33 #include <sys/mount.h>
34 #endif
35
36 #ifdef STAT_READ                /* SVR2.  */
37 #include <sys/param.h>
38 #include <sys/filsys.h>
39 #include <fcntl.h>
40 #endif
41
42 #if defined(STAT_STATFS4) || (defined(_AIX) && defined(_IBMR2)) /* SVR3, Dynix, Irix, AIX RS6000.  */
43 #include <sys/statfs.h>
44 #endif
45
46 #if defined(_AIX) && defined(_I386) /* AIX PS/2.  */
47 #include <sys/stat.h>
48 #include <sys/dustat.h>
49 #endif
50
51 #ifdef STAT_STATVFS             /* SVR4.  */
52 #include <sys/statvfs.h>
53 int statvfs ();
54 #endif
55
56 /* Return the number of TOSIZE-byte blocks used by
57    BLOCKS FROMSIZE-byte blocks, rounding up.  */
58
59 static long
60 adjust_blocks (blocks, fromsize, tosize)
61      long blocks;
62      int fromsize, tosize;
63 {
64   if (fromsize == tosize)       /* E.g., from 512 to 512.  */
65     return blocks;
66   else if (fromsize > tosize)   /* E.g., from 2048 to 512.  */
67     return blocks * (fromsize / tosize);
68   else                          /* E.g., from 256 to 512.  */
69     return (blocks + 1) / (tosize / fromsize);
70 }
71
72 /* Fill in the fields of FSP with information about space usage for
73    the filesystem on which PATH resides.
74    DISK is the device on which PATH is mounted, for space-getting
75    methods that need to know it.
76    Return 0 if successful, -1 if not. */
77
78 int
79 get_fs_usage (path, disk, fsp)
80      char *path, *disk;
81      struct fs_usage *fsp;
82 {
83 #ifdef STAT_STATFS2_FS_DATA     /* Ultrix.  */
84   struct fs_data fsd;
85
86   if (statfs (path, &fsd) != 1)
87     return -1;
88 #define convert_blocks(b) adjust_blocks ((b), 1024, 512)
89   fsp->fsu_blocks = convert_blocks (fsd.fd_req.btot);
90   fsp->fsu_bfree = convert_blocks (fsd.fd_req.bfree);
91   fsp->fsu_bavail = convert_blocks (fsd.fd_req.bfreen);
92   fsp->fsu_files = fsd.fd_req.gtot;
93   fsp->fsu_ffree = fsd.fd_req.gfree;
94 #endif
95
96 #ifdef STAT_READ                /* SVR2.  */
97 #ifndef SUPERBOFF
98 #define SUPERBOFF (SUPERB * 512)
99 #endif
100   struct filsys fsd;
101   int fd;
102
103   fd = open (disk, O_RDONLY);
104   if (fd < 0)
105     return -1;
106   lseek (fd, (long) SUPERBOFF, 0);
107   if (read (fd, (char *) &fsd, sizeof fsd) != sizeof fsd)
108     {
109       close (fd);
110       return -1;
111     }
112   close (fd);
113 #define convert_blocks(b) adjust_blocks ((b), (fsd.s_type == Fs2b ? 1024 : 512), 512)
114   fsp->fsu_blocks = convert_blocks (fsd.s_fsize);
115   fsp->fsu_bfree = convert_blocks (fsd.s_tfree);
116   fsp->fsu_bavail = convert_blocks (fsd.s_tfree);
117   fsp->fsu_files = (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1);
118   fsp->fsu_ffree = fsd.s_tinode;
119 #endif
120
121 #ifdef STAT_STATFS2_BSIZE       /* 4.3BSD, SunOS 4, HP-UX, AIX.  */
122   struct statfs fsd;
123
124   if (statfs (path, &fsd) < 0)
125     return -1;
126 #define convert_blocks(b) adjust_blocks ((b), fsd.f_bsize, 512)
127 #endif
128
129 #ifdef STAT_STATFS2_FSIZE       /* 4.4BSD.  */
130   struct statfs fsd;
131
132   if (statfs (path, &fsd) < 0)
133     return -1;
134 #define convert_blocks(b) adjust_blocks ((b), fsd.f_fsize, 512)
135 #endif
136
137 #ifdef STAT_STATFS4             /* SVR3, Dynix, Irix.  */
138   struct statfs fsd;
139
140   if (statfs (path, &fsd, sizeof fsd, 0) < 0)
141     return -1;
142   /* Empirically, the block counts on most SVR3 and SVR3-derived
143      systems seem to always be in terms of 512-byte blocks,
144      no matter what value f_bsize has.  */
145 #define convert_blocks(b) (b)
146 #ifndef _SEQUENT_               /* _SEQUENT_ is DYNIX/ptx.  */
147 #define f_bavail f_bfree
148 #endif
149 #endif
150
151 #ifdef STAT_STATVFS             /* SVR4.  */
152   struct statvfs fsd;
153
154   if (statvfs (path, &fsd) < 0)
155     return -1;
156   /* f_frsize isn't guaranteed to be supported.  */
157 #define convert_blocks(b) \
158   adjust_blocks ((b), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512)
159 #endif
160
161 #if !defined(STAT_STATFS2_FS_DATA) && !defined(STAT_READ) /* !Ultrix && !SVR2.  */
162   fsp->fsu_blocks = convert_blocks (fsd.f_blocks);
163   fsp->fsu_bfree = convert_blocks (fsd.f_bfree);
164   fsp->fsu_bavail = convert_blocks (fsd.f_bavail);
165   fsp->fsu_files = fsd.f_files;
166   fsp->fsu_ffree = fsd.f_ffree;
167 #endif
168
169   return 0;
170 }
171
172 #if defined(_AIX) && defined(_I386)
173 /* AIX PS/2 does not supply statfs.  */
174
175 int
176 statfs (path, fsb)
177      char *path;
178      struct statfs *fsb;
179 {
180   struct stat stats;
181   struct dustat fsd;
182
183   if (stat (path, &stats))
184     return -1;
185   if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
186     return -1;
187   fsb->f_type   = 0;
188   fsb->f_bsize  = fsd.du_bsize;
189   fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
190   fsb->f_bfree  = fsd.du_tfree;
191   fsb->f_bavail = fsd.du_tfree;
192   fsb->f_files  = (fsd.du_isize - 2) * fsd.du_inopb;
193   fsb->f_ffree  = fsd.du_tinode;
194   fsb->f_fsid.val[0] = fsd.du_site;
195   fsb->f_fsid.val[1] = fsd.du_pckno;
196   return 0;
197 }
198 #endif /* _AIX && _I386 */