df.c revision 1.18 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.18 1995/01/30 19:30:13 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 int ufs_df __P((char *, struct statfs *));
66 int selected __P((const char *));
67 void maketypelist __P((char *));
68 long regetmntinfo __P((struct statfs **, long));
69 void usage __P((void));
70
71 int iflag, kflag, lflag, nflag;
72 char **typelist = NULL;
73 struct ufs_args mdev;
74
75 int
76 main(argc, argv)
77 int argc;
78 char *argv[];
79 {
80 struct stat stbuf;
81 struct statfs statfsbuf, *mntbuf;
82 long mntsize;
83 int ch, i, maxwidth, width;
84 char *mntpt;
85
86 while ((ch = getopt(argc, argv, "iklnt:")) != -1)
87 switch (ch) {
88 case 'i':
89 iflag = 1;
90 break;
91 case 'k':
92 kflag = 1;
93 break;
94 case 'l':
95 lflag = 1;
96 break;
97 case 'n':
98 nflag = 1;
99 break;
100 case 't':
101 if (typelist != NULL)
102 errx(1, "only one -t option may be specified.");
103 maketypelist(optarg);
104 break;
105 case '?':
106 default:
107 usage();
108 }
109 argc -= optind;
110 argv += optind;
111
112 if (*argv && (lflag || typelist != NULL))
113 errx(1, "-l or -t does not make sense with list of mount points");
114
115 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
116 if (mntsize == 0)
117 err(1, "retrieving information on mounted file systems");
118
119 if (!*argv) {
120 mntsize = regetmntinfo(&mntbuf, mntsize);
121 } else {
122 mntbuf = malloc(argc * sizeof(struct statfs));
123 mntsize = 0;
124 for (; *argv; argv++) {
125 if (stat(*argv, &stbuf) < 0) {
126 if ((mntpt = getmntpt(*argv)) == 0) {
127 warn("%s", *argv);
128 continue;
129 }
130 } else if (S_ISCHR(stbuf.st_mode)) {
131 if (!ufs_df(*argv, &mntbuf[mntsize]))
132 ++mntsize;
133 continue;
134 } else if (S_ISBLK(stbuf.st_mode)) {
135 if ((mntpt = getmntpt(*argv)) == 0) {
136 mntpt = mktemp(strdup("/tmp/df.XXXXXX"));
137 mdev.fspec = *argv;
138 if (mkdir(mntpt, DEFFILEMODE) != 0) {
139 warn("%s", mntpt);
140 continue;
141 }
142 if (mount(MOUNT_UFS, mntpt, MNT_RDONLY,
143 &mdev) != 0) {
144 (void)rmdir(mntpt);
145 if (!ufs_df(*argv, &mntbuf[mntsize]))
146 ++mntsize;
147 continue;
148 } else if (!statfs(mntpt, &mntbuf[mntsize])) {
149 mntbuf[mntsize].f_mntonname[0] = '\0';
150 ++mntsize;
151 } else
152 warn("%s", *argv);
153 (void)unmount(mntpt, 0);
154 (void)rmdir(mntpt);
155 continue;
156 }
157 } else
158 mntpt = *argv;
159 /*
160 * Statfs does not take a `wait' flag, so we cannot
161 * implement nflag here.
162 */
163 if (!statfs(mntpt, &mntbuf[mntsize]))
164 ++mntsize;
165 else
166 warn("%s", *argv);
167 }
168 }
169
170 maxwidth = 0;
171 for (i = 0; i < mntsize; i++) {
172 width = strlen(mntbuf[i].f_mntfromname);
173 if (width > maxwidth)
174 maxwidth = width;
175 }
176 for (i = 0; i < mntsize; i++)
177 prtstat(&mntbuf[i], maxwidth);
178 exit(0);
179 }
180
181 char *
182 getmntpt(name)
183 char *name;
184 {
185 long mntsize, i;
186 struct statfs *mntbuf;
187
188 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
189 for (i = 0; i < mntsize; i++) {
190 if (!strcmp(mntbuf[i].f_mntfromname, name))
191 return (mntbuf[i].f_mntonname);
192 }
193 return (0);
194 }
195
196 static enum { IN_LIST, NOT_IN_LIST } which;
197
198 int
199 selected(type)
200 const char *type;
201 {
202 char **av;
203
204 /* If no type specified, it's always selected. */
205 if (typelist == NULL)
206 return (1);
207 for (av = typelist; *av != NULL; ++av)
208 if (!strcmp(type, *av))
209 return (which == IN_LIST ? 1 : 0);
210 return (which == IN_LIST ? 0 : 1);
211 }
212
213 void
214 maketypelist(fslist)
215 char *fslist;
216 {
217 int i;
218 char *nextcp, **av;
219
220 if ((fslist == NULL) || (fslist[0] == '\0'))
221 errx(1, "empty type list");
222
223 /*
224 * XXX
225 * Note: the syntax is "noxxx,yyy" for no xxx's and
226 * no yyy's, not the more intuitive "noyyy,noyyy".
227 */
228 if (fslist[0] == 'n' && fslist[1] == 'o') {
229 fslist += 2;
230 which = NOT_IN_LIST;
231 } else
232 which = IN_LIST;
233
234 /* Count the number of types. */
235 for (i = 1, nextcp = fslist; nextcp = strchr(nextcp, ','); i++)
236 ++nextcp;
237
238 /* Build an array of that many types. */
239 if ((av = typelist = malloc((i + 1) * sizeof(char *))) == NULL)
240 err(1, NULL);
241 av[0] = fslist;
242 for (i = 1, nextcp = fslist; nextcp = strchr(nextcp, ','); i++) {
243 *nextcp = '\0';
244 av[i] = ++nextcp;
245 }
246 /* Terminate the array. */
247 av[i] = NULL;
248 }
249
250 /*
251 * Make a pass over the filesystem info in ``mntbuf'' filtering out
252 * filesystem types not in ``fsmask'' and possibly re-stating to get
253 * current (not cached) info. Returns the new count of valid statfs bufs.
254 */
255 long
256 regetmntinfo(mntbufp, mntsize)
257 struct statfs **mntbufp;
258 long mntsize;
259 {
260 int i, j;
261 struct statfs *mntbuf;
262
263 if (!lflag && typelist == NULL)
264 return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT));
265
266 mntbuf = *mntbufp;
267 j = 0;
268 for (i = 0; i < mntsize; i++) {
269 if (lflag && (mntbuf[i].f_flags & MNT_LOCAL) == 0)
270 continue;
271 if (!selected(mntbuf[i].f_fstypename))
272 continue;
273 if (nflag)
274 mntbuf[j] = mntbuf[i];
275 else
276 (void)statfs(mntbuf[i].f_mntonname, &mntbuf[j]);
277 j++;
278 }
279 return (j);
280 }
281
282 /*
283 * Convert statfs returned filesystem size into BLOCKSIZE units.
284 * Attempts to avoid overflow for large filesystems.
285 */
286 #define fsbtoblk(num, fsbs, bs) \
287 (((fsbs) != 0 && (fsbs) < (bs)) ? \
288 (num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs)))
289
290 /*
291 * Print out status about a filesystem.
292 */
293 void
294 prtstat(sfsp, maxwidth)
295 struct statfs *sfsp;
296 int maxwidth;
297 {
298 static long blocksize;
299 static int headerlen, timesthrough;
300 static char *header;
301 long used, availblks, inodes;
302
303 if (maxwidth < 11)
304 maxwidth = 11;
305 if (++timesthrough == 1) {
306 if (kflag) {
307 blocksize = 1024;
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 int
354 ufs_df(file, sfsp)
355 char *file;
356 struct statfs *sfsp;
357 {
358 char *mntpt;
359 static int synced;
360
361 if (synced++ == 0)
362 sync();
363
364 if ((rfd = open(file, O_RDONLY)) < 0) {
365 warn("%s", file);
366 return (-1);
367 }
368 if (bread((off_t)SBOFF, &sblock, SBSIZE) == 0) {
369 (void)close(rfd);
370 return (-1);
371 }
372 sfsp->f_type = 0;
373 sfsp->f_flags = 0;
374 sfsp->f_bsize = sblock.fs_fsize;
375 sfsp->f_iosize = sblock.fs_bsize;
376 sfsp->f_blocks = sblock.fs_dsize;
377 sfsp->f_bfree = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag +
378 sblock.fs_cstotal.cs_nffree;
379 sfsp->f_bavail = (sblock.fs_dsize * (100 - sblock.fs_minfree) / 100) -
380 (sblock.fs_dsize - sfsp->f_bfree);
381 if (sfsp->f_bavail < 0)
382 sfsp->f_bavail = 0;
383 sfsp->f_files = sblock.fs_ncg * sblock.fs_ipg;
384 sfsp->f_ffree = sblock.fs_cstotal.cs_nifree;
385 sfsp->f_fsid.val[0] = 0;
386 sfsp->f_fsid.val[1] = 0;
387 if ((mntpt = getmntpt(file)) == 0)
388 mntpt = "";
389 memmove(&sfsp->f_mntonname[0], mntpt, MNAMELEN);
390 memmove(&sfsp->f_mntfromname[0], file, MNAMELEN);
391 strncpy(sfsp->f_fstypename, MOUNT_UFS, MFSNAMELEN);
392 sfsp->f_fstypename[MFSNAMELEN] = '\0';
393 (void)close(rfd);
394 return (0);
395 }
396
397 int
398 bread(off, buf, cnt)
399 off_t off;
400 void *buf;
401 int cnt;
402 {
403 int nr;
404
405 (void)lseek(rfd, off, SEEK_SET);
406 if ((nr = read(rfd, buf, cnt)) != cnt) {
407 /* Probably a dismounted disk if errno == EIO. */
408 if (errno != EIO)
409 (void)fprintf(stderr, "\ndf: %qd: %s\n",
410 off, strerror(nr > 0 ? EIO : errno));
411 return (0);
412 }
413 return (1);
414 }
415
416 void
417 usage()
418 {
419 (void)fprintf(stderr, "usage: df [-ikln] [-t type] [file | file_system ...]\n");
420 exit(1);
421 }
422