df.c revision 1.16 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[] = "from: @(#)df.c 8.7 (Berkeley) 4/2/94";*/
47 static char rcsid[] = "$Id: df.c,v 1.16 1995/01/13 23:23:43 mycroft Exp $";
48 #endif /* not lint */
49
50 #include <sys/param.h>
51 #include <sys/stat.h>
52 #include <sys/mount.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 bread __P((off_t, void *, int));
63 char *getmntpt __P((char *));
64 void prtstat __P((struct statfs *, int));
65 void ufs_df __P((char *, int));
66 void add_fsmask __P((char *));
67 void usage __P((void));
68
69 struct fstype {
70 char *fs_name;
71 int fs_no;
72 };
73
74 int iflag, kflag, nflag, tflag;
75 long blocksize, mntsize;
76 struct statfs *mntbuf;
77 struct ufs_args mdev;
78 struct fstype *fstypes;
79 int numfstypes, defmatch = 1;
80 int posflags, negflags;
81
82 int
83 main(argc, argv)
84 int argc;
85 char *argv[];
86 {
87 struct stat stbuf;
88 struct statfs statfsbuf;
89 long width, maxwidth;
90 int ch, i;
91 char *mntpt;
92
93 while ((ch = getopt(argc, argv, "iklnt:")) != -1)
94 switch (ch) {
95 case 'i':
96 iflag = 1;
97 break;
98 case 'k':
99 blocksize = 1024;
100 kflag = 1;
101 break;
102 case 'l':
103 add_fsmask("local");
104 tflag = 1;
105 break;
106 case 'n':
107 nflag = 1;
108 break;
109 case 't':
110 add_fsmask(optarg);
111 tflag = 1;
112 break;
113 case '?':
114 default:
115 usage();
116 }
117 argc -= optind;
118 argv += optind;
119
120 if (*argv && tflag)
121 errx(1, "-l or -t does not make sense with list of mount points");
122
123 mntsize = getmntinfo(&mntbuf, (nflag ? MNT_NOWAIT : MNT_WAIT));
124 if (mntsize == 0)
125 err(1, "retrieving information on mounted file systems");
126 maxwidth = 0;
127 for (i = 0; i < mntsize; i++) {
128 width = strlen(mntbuf[i].f_mntfromname);
129 if (width > maxwidth)
130 maxwidth = width;
131 }
132
133 if (!*argv) {
134 for (i = 0; i < mntsize; i++)
135 prtstat(&mntbuf[i], maxwidth);
136 exit(0);
137 }
138
139 for (; *argv; argv++) {
140 if (stat(*argv, &stbuf) < 0) {
141 if ((mntpt = getmntpt(*argv)) == 0) {
142 warn("%s", *argv);
143 continue;
144 }
145 } else if ((stbuf.st_mode & S_IFMT) == S_IFCHR) {
146 ufs_df(*argv, maxwidth);
147 continue;
148 } else if ((stbuf.st_mode & S_IFMT) == S_IFBLK) {
149 if ((mntpt = getmntpt(*argv)) == 0) {
150 mntpt = mktemp(strdup("/tmp/df.XXXXXX"));
151 mdev.fspec = *argv;
152 if (mkdir(mntpt, DEFFILEMODE) != 0) {
153 warn("%s", mntpt);
154 continue;
155 }
156 if (mount(MOUNT_UFS, mntpt, MNT_RDONLY,
157 &mdev) != 0) {
158 ufs_df(*argv, maxwidth);
159 (void)rmdir(mntpt);
160 continue;
161 } else if (statfs(mntpt, &statfsbuf)) {
162 statfsbuf.f_mntonname[0] = '\0';
163 prtstat(&statfsbuf, maxwidth);
164 } else
165 warn("%s", *argv);
166 (void)unmount(mntpt, 0);
167 (void)rmdir(mntpt);
168 continue;
169 }
170 } else
171 mntpt = *argv;
172 /*
173 * Statfs does not take a `wait' flag, so we cannot
174 * implement nflag here.
175 */
176 if (statfs(mntpt, &statfsbuf) < 0) {
177 warn("%s", mntpt);
178 continue;
179 }
180 if (argc == 1)
181 maxwidth = strlen(statfsbuf.f_mntfromname) + 1;
182 prtstat(&statfsbuf, maxwidth);
183 }
184 return (0);
185 }
186
187 char *
188 getmntpt(name)
189 char *name;
190 {
191 long i;
192
193 for (i = 0; i < mntsize; i++) {
194 if (!strcmp(mntbuf[i].f_mntfromname, name))
195 return (mntbuf[i].f_mntonname);
196 }
197 return (0);
198 }
199
200 struct fsflags {
201 char *ff_name;
202 int ff_pos;
203 int ff_neg;
204 } fsflags[] = {
205 {"local", MNT_LOCAL, 0},
206 {"ro", MNT_RDONLY, 0},
207 {"rw", 0, MNT_RDONLY},
208 };
209
210 void
211 add_fsmask(fstype)
212 char *fstype;
213 {
214 int len, no, n;
215
216 len = strlen(fstype);
217
218 if (!bcmp(fstype, "no", 2)) {
219 no = 1;
220 defmatch = 1;
221 len -= 2;
222 fstype += 2;
223 } else {
224 no = 0;
225 defmatch = 0;
226 }
227
228 for (n = 0; n < sizeof(fsflags) / sizeof(fsflags[0]); n++) {
229 if (!bcmp(fstype, fsflags[n].ff_name, len+1)) {
230 if (!no) {
231 posflags |= fsflags[n].ff_pos;
232 posflags &= ~fsflags[n].ff_neg;
233 negflags |= fsflags[n].ff_neg;
234 negflags &= !fsflags[n].ff_pos;
235 } else {
236 posflags |= fsflags[n].ff_neg;
237 posflags &= ~fsflags[n].ff_pos;
238 negflags |= fsflags[n].ff_pos;
239 negflags &= ~fsflags[n].ff_neg;
240 }
241 return;
242 }
243 }
244
245 if (!bcmp(fstype, "all", len+1)) {
246 if (no) {
247 (void)fprintf(stderr, "I'm sorry. I can't do that, Dave.\n");
248 exit(1);
249 } else {
250 fstypes = NULL;
251 posflags = negflags = 0;
252 }
253 }
254
255 for (n = 0; n < numfstypes; n++) {
256 if (!bcmp(fstype, fstypes[n].fs_name, len+1)) {
257 fstypes[n].fs_no = no;
258 return;
259 }
260 }
261
262 numfstypes++;
263 fstypes = (struct fstype *) realloc(fstypes, sizeof(struct fstype) * numfstypes);
264 fstypes[numfstypes - 1].fs_name = strdup(fstype);
265 fstypes[numfstypes - 1].fs_no = no;
266 }
267
268 /*
269 * Convert statfs returned filesystem size into BLOCKSIZE units.
270 * Attempts to avoid overflow for large filesystems.
271 */
272 #define fsbtoblk(num, fsbs, bs) \
273 (((fsbs) != 0 && (fsbs) < (bs)) ? \
274 (num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs)))
275
276 /*
277 * Print out status about a filesystem.
278 */
279 void
280 prtstat(sfsp, maxwidth)
281 struct statfs *sfsp;
282 int maxwidth;
283 {
284 static int headerlen, timesthrough;
285 static char *header;
286 long used, availblks, inodes;
287 int i, gotmatch = defmatch;
288
289 if ((sfsp->f_flags & posflags) != posflags)
290 return;
291 if ((sfsp->f_flags & negflags) != 0)
292 return;
293 if (numfstypes) {
294 for (i = 0; i < numfstypes; i++)
295 if (!strcmp(sfsp->f_fstypename, fstypes[i].fs_name)) {
296 if (fstypes[i].fs_no)
297 return;
298 gotmatch = 1;
299 break;
300 }
301 if (!gotmatch)
302 return;
303 }
304 if (maxwidth < 11)
305 maxwidth = 11;
306 if (++timesthrough == 1) {
307 if (kflag) {
308 header = "1K-blocks";
309 headerlen = strlen(header);
310 } else
311 header = getbsize(&headerlen, &blocksize);
312 (void)printf("%-*.*s %s Used Avail Capacity",
313 maxwidth, maxwidth, "Filesystem", header);
314 if (iflag)
315 (void)printf(" iused ifree %%iused");
316 (void)printf(" Mounted on\n");
317 }
318 (void)printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname);
319 used = sfsp->f_blocks - sfsp->f_bfree;
320 availblks = sfsp->f_bavail + used;
321 (void)printf(" %*ld %8ld %8ld", headerlen,
322 fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize),
323 fsbtoblk(used, sfsp->f_bsize, blocksize),
324 fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize));
325 (void)printf(" %5.0f%%",
326 availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
327 if (iflag) {
328 inodes = sfsp->f_files;
329 used = inodes - sfsp->f_ffree;
330 (void)printf(" %7ld %7ld %5.0f%% ", used, sfsp->f_ffree,
331 inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0);
332 } else
333 (void)printf(" ");
334 (void)printf(" %s\n", sfsp->f_mntonname);
335 }
336
337 /*
338 * This code constitutes the pre-system call Berkeley df code for extracting
339 * information from filesystem superblocks.
340 */
341 #include <ufs/ffs/fs.h>
342 #include <errno.h>
343 #include <fstab.h>
344
345 union {
346 struct fs iu_fs;
347 char dummy[SBSIZE];
348 } sb;
349 #define sblock sb.iu_fs
350
351 int rfd;
352
353 void
354 ufs_df(file, maxwidth)
355 char *file;
356 int maxwidth;
357 {
358 struct statfs statfsbuf;
359 struct statfs *sfsp;
360 char *mntpt;
361 static int synced;
362
363 if (synced++ == 0)
364 sync();
365
366 if ((rfd = open(file, O_RDONLY)) < 0) {
367 warn("%s", file);
368 return;
369 }
370 if (bread((off_t)SBOFF, &sblock, SBSIZE) == 0) {
371 (void)close(rfd);
372 return;
373 }
374 sfsp = &statfsbuf;
375 sfsp->f_type = 0;
376 sfsp->f_flags = 0;
377 sfsp->f_bsize = sblock.fs_fsize;
378 sfsp->f_iosize = sblock.fs_bsize;
379 sfsp->f_blocks = sblock.fs_dsize;
380 sfsp->f_bfree = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag +
381 sblock.fs_cstotal.cs_nffree;
382 sfsp->f_bavail = (sblock.fs_dsize * (100 - sblock.fs_minfree) / 100) -
383 (sblock.fs_dsize - sfsp->f_bfree);
384 if (sfsp->f_bavail < 0)
385 sfsp->f_bavail = 0;
386 sfsp->f_files = sblock.fs_ncg * sblock.fs_ipg;
387 sfsp->f_ffree = sblock.fs_cstotal.cs_nifree;
388 sfsp->f_fsid.val[0] = 0;
389 sfsp->f_fsid.val[1] = 0;
390 if ((mntpt = getmntpt(file)) == 0)
391 mntpt = "";
392 memmove(&sfsp->f_mntonname[0], mntpt, MNAMELEN);
393 memmove(&sfsp->f_mntfromname[0], file, MNAMELEN);
394 strncpy(sfsp->f_fstypename, MOUNT_UFS, MFSNAMELEN);
395 sfsp->f_fstypename[MFSNAMELEN] = '\0';
396 prtstat(sfsp, maxwidth);
397 (void)close(rfd);
398 }
399
400 int
401 bread(off, buf, cnt)
402 off_t off;
403 void *buf;
404 int cnt;
405 {
406 int nr;
407
408 (void)lseek(rfd, off, SEEK_SET);
409 if ((nr = read(rfd, buf, cnt)) != cnt) {
410 /* Probably a dismounted disk if errno == EIO. */
411 if (errno != EIO)
412 (void)fprintf(stderr, "\ndf: %qd: %s\n",
413 off, strerror(nr > 0 ? EIO : errno));
414 return (0);
415 }
416 return (1);
417 }
418
419 void
420 usage()
421 {
422 (void)fprintf(stderr, "usage: df [-ikln] [-t type] [file | file_system ...]\n");
423 exit(1);
424 }
425