df.c revision 1.1.1.2 1 /*
2 * Copyright (c) 1980, 1990, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #ifndef lint
40 static char copyright[] =
41 "@(#) Copyright (c) 1980, 1990, 1993, 1994\n\
42 The Regents of the University of California. All rights reserved.\n";
43 #endif /* not lint */
44
45 #ifndef lint
46 static char sccsid[] = "@(#)df.c 8.9 (Berkeley) 5/8/95";
47 #endif /* not lint */
48
49 #include <sys/param.h>
50 #include <sys/stat.h>
51 #include <sys/mount.h>
52 #include <ufs/ufs/ufsmount.h>
53
54 #include <err.h>
55 #include <errno.h>
56 #include <fcntl.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61
62 int checkvfsname __P((const char *, char **));
63 char **makevfslist __P((char *));
64 long regetmntinfo __P((struct statfs **, long, char **));
65 int bread __P((off_t, void *, int));
66 char *getmntpt __P((char *));
67 void prtstat __P((struct statfs *, int));
68 void ufs_df __P((char *, int));
69 void usage __P((void));
70
71 int iflag, nflag;
72 struct ufs_args mdev;
73
74 int
75 main(argc, argv)
76 int argc;
77 char *argv[];
78 {
79 struct stat stbuf;
80 struct statfs statfsbuf, *mntbuf;
81 long mntsize;
82 int ch, err, i, maxwidth, width;
83 char *mntpt, **vfslist;
84
85 vfslist = NULL;
86 while ((ch = getopt(argc, argv, "int:")) != EOF)
87 switch (ch) {
88 case 'i':
89 iflag = 1;
90 break;
91 case 'n':
92 nflag = 1;
93 break;
94 case 't':
95 if (vfslist != NULL)
96 errx(1, "only one -t option may be specified.");
97 vfslist = makevfslist(optarg);
98 break;
99 case '?':
100 default:
101 usage();
102 }
103 argc -= optind;
104 argv += optind;
105
106 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
107 maxwidth = 0;
108 for (i = 0; i < mntsize; i++) {
109 width = strlen(mntbuf[i].f_mntfromname);
110 if (width > maxwidth)
111 maxwidth = width;
112 }
113
114 if (!*argv) {
115 mntsize = regetmntinfo(&mntbuf, mntsize, vfslist);
116 if (vfslist != NULL) {
117 maxwidth = 0;
118 for (i = 0; i < mntsize; i++) {
119 width = strlen(mntbuf[i].f_mntfromname);
120 if (width > maxwidth)
121 maxwidth = width;
122 }
123 }
124 for (i = 0; i < mntsize; i++)
125 prtstat(&mntbuf[i], maxwidth);
126 exit(0);
127 }
128
129 for (; *argv; argv++) {
130 if (stat(*argv, &stbuf) < 0) {
131 err = errno;
132 if ((mntpt = getmntpt(*argv)) == 0) {
133 warn("%s", *argv);
134 continue;
135 }
136 } else if ((stbuf.st_mode & S_IFMT) == S_IFCHR) {
137 ufs_df(*argv, maxwidth);
138 continue;
139 } else if ((stbuf.st_mode & S_IFMT) == S_IFBLK) {
140 if ((mntpt = getmntpt(*argv)) == 0) {
141 mntpt = mktemp(strdup("/tmp/df.XXXXXX"));
142 mdev.fspec = *argv;
143 if (mkdir(mntpt, DEFFILEMODE) != 0) {
144 warn("%s", mntpt);
145 continue;
146 }
147 if (mount("ufs", mntpt, MNT_RDONLY,
148 &mdev) != 0) {
149 ufs_df(*argv, maxwidth);
150 (void)rmdir(mntpt);
151 continue;
152 } else if (statfs(mntpt, &statfsbuf)) {
153 statfsbuf.f_mntonname[0] = '\0';
154 prtstat(&statfsbuf, maxwidth);
155 } else
156 warn("%s", *argv);
157 (void)unmount(mntpt, 0);
158 (void)rmdir(mntpt);
159 continue;
160 }
161 } else
162 mntpt = *argv;
163 /*
164 * Statfs does not take a `wait' flag, so we cannot
165 * implement nflag here.
166 */
167 if (statfs(mntpt, &statfsbuf) < 0) {
168 warn("%s", mntpt);
169 continue;
170 }
171 if (argc == 1)
172 maxwidth = strlen(statfsbuf.f_mntfromname) + 1;
173 prtstat(&statfsbuf, maxwidth);
174 }
175 return (0);
176 }
177
178 char *
179 getmntpt(name)
180 char *name;
181 {
182 long mntsize, i;
183 struct statfs *mntbuf;
184
185 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
186 for (i = 0; i < mntsize; i++) {
187 if (!strcmp(mntbuf[i].f_mntfromname, name))
188 return (mntbuf[i].f_mntonname);
189 }
190 return (0);
191 }
192
193 /*
194 * Make a pass over the filesystem info in ``mntbuf'' filtering out
195 * filesystem types not in vfslist and possibly re-stating to get
196 * current (not cached) info. Returns the new count of valid statfs bufs.
197 */
198 long
199 regetmntinfo(mntbufp, mntsize, vfslist)
200 struct statfs **mntbufp;
201 long mntsize;
202 char **vfslist;
203 {
204 int i, j;
205 struct statfs *mntbuf;
206
207 if (vfslist == NULL)
208 return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT));
209
210 mntbuf = *mntbufp;
211 for (j = 0, i = 0; i < mntsize; i++) {
212 if (checkvfsname(mntbuf[i].f_fstypename, vfslist))
213 continue;
214 if (!nflag)
215 (void)statfs(mntbuf[i].f_mntonname,&mntbuf[j]);
216 else if (i != j)
217 mntbuf[j] = mntbuf[i];
218 j++;
219 }
220 return (j);
221 }
222
223 /*
224 * Convert statfs returned filesystem size into BLOCKSIZE units.
225 * Attempts to avoid overflow for large filesystems.
226 */
227 #define fsbtoblk(num, fsbs, bs) \
228 (((fsbs) != 0 && (fsbs) < (bs)) ? \
229 (num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs)))
230
231 /*
232 * Print out status about a filesystem.
233 */
234 void
235 prtstat(sfsp, maxwidth)
236 struct statfs *sfsp;
237 int maxwidth;
238 {
239 static long blocksize;
240 static int headerlen, timesthrough;
241 static char *header;
242 long used, availblks, inodes;
243
244 if (maxwidth < 11)
245 maxwidth = 11;
246 if (++timesthrough == 1) {
247 header = getbsize(&headerlen, &blocksize);
248 (void)printf("%-*.*s %s Used Avail Capacity",
249 maxwidth, maxwidth, "Filesystem", header);
250 if (iflag)
251 (void)printf(" iused ifree %%iused");
252 (void)printf(" Mounted on\n");
253 }
254 (void)printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname);
255 used = sfsp->f_blocks - sfsp->f_bfree;
256 availblks = sfsp->f_bavail + used;
257 (void)printf(" %*ld %8ld %8ld", headerlen,
258 fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize),
259 fsbtoblk(used, sfsp->f_bsize, blocksize),
260 fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize));
261 (void)printf(" %5.0f%%",
262 availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
263 if (iflag) {
264 inodes = sfsp->f_files;
265 used = inodes - sfsp->f_ffree;
266 (void)printf(" %7ld %7ld %5.0f%% ", used, sfsp->f_ffree,
267 inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0);
268 } else
269 (void)printf(" ");
270 (void)printf(" %s\n", sfsp->f_mntonname);
271 }
272
273 /*
274 * This code constitutes the pre-system call Berkeley df code for extracting
275 * information from filesystem superblocks.
276 */
277 #include <ufs/ufs/dinode.h>
278 #include <ufs/ffs/fs.h>
279 #include <errno.h>
280 #include <fstab.h>
281
282 union {
283 struct fs iu_fs;
284 char dummy[SBSIZE];
285 } sb;
286 #define sblock sb.iu_fs
287
288 int rfd;
289
290 void
291 ufs_df(file, maxwidth)
292 char *file;
293 int maxwidth;
294 {
295 struct statfs statfsbuf;
296 struct statfs *sfsp;
297 char *mntpt;
298 static int synced;
299
300 if (synced++ == 0)
301 sync();
302
303 if ((rfd = open(file, O_RDONLY)) < 0) {
304 warn("%s", file);
305 return;
306 }
307 if (bread((off_t)SBOFF, &sblock, SBSIZE) == 0) {
308 (void)close(rfd);
309 return;
310 }
311 sfsp = &statfsbuf;
312 sfsp->f_type = 1;
313 strcpy(sfsp->f_fstypename, "ufs");
314 sfsp->f_flags = 0;
315 sfsp->f_bsize = sblock.fs_fsize;
316 sfsp->f_iosize = sblock.fs_bsize;
317 sfsp->f_blocks = sblock.fs_dsize;
318 sfsp->f_bfree = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag +
319 sblock.fs_cstotal.cs_nffree;
320 sfsp->f_bavail = (sblock.fs_dsize * (100 - sblock.fs_minfree) / 100) -
321 (sblock.fs_dsize - sfsp->f_bfree);
322 if (sfsp->f_bavail < 0)
323 sfsp->f_bavail = 0;
324 sfsp->f_files = sblock.fs_ncg * sblock.fs_ipg;
325 sfsp->f_ffree = sblock.fs_cstotal.cs_nifree;
326 sfsp->f_fsid.val[0] = 0;
327 sfsp->f_fsid.val[1] = 0;
328 if ((mntpt = getmntpt(file)) == 0)
329 mntpt = "";
330 memmove(&sfsp->f_mntonname[0], mntpt, MNAMELEN);
331 memmove(&sfsp->f_mntfromname[0], file, MNAMELEN);
332 prtstat(sfsp, maxwidth);
333 (void)close(rfd);
334 }
335
336 int
337 bread(off, buf, cnt)
338 off_t off;
339 void *buf;
340 int cnt;
341 {
342 int nr;
343
344 (void)lseek(rfd, off, SEEK_SET);
345 if ((nr = read(rfd, buf, cnt)) != cnt) {
346 /* Probably a dismounted disk if errno == EIO. */
347 if (errno != EIO)
348 (void)fprintf(stderr, "\ndf: %qd: %s\n",
349 off, strerror(nr > 0 ? EIO : errno));
350 return (0);
351 }
352 return (1);
353 }
354
355 void
356 usage()
357 {
358 (void)fprintf(stderr,
359 "usage: df [-in] [-t type] [file | file_system ...]\n");
360 exit(1);
361 }
362