df.c revision 1.12 1 /*
2 * Copyright (c) 1980, 1990 The Regents of the University of California.
3 * 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 char copyright[] =
41 "@(#) Copyright (c) 1980, 1990 The Regents of the University of California.\n\
42 All rights reserved.\n";
43 #endif /* not lint */
44
45 #ifndef lint
46 /*static char sccsid[] = "from: @(#)df.c 5.30 (Berkeley) 4/23/92";*/
47 static char rcsid[] = "$Id: df.c,v 1.12 1994/05/17 04:06:00 cgd Exp $";
48 #endif /* not lint */
49
50 #include <sys/param.h>
51 #include <sys/stat.h>
52 #include <sys/mount.h>
53 #include <errno.h>
54 #include <err.h>
55 #include <fcntl.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59
60 #include <unistd.h>
61
62 int bread __P((long, char *, int));
63 char *getmntpt __P((char *));
64 void prtstat __P((struct statfs *, long));
65 void ufs_df __P((char *, long));
66 void usage __P((void));
67
68 int iflag, kflag = 0, nflag, lflag;
69 long blocksize, mntsize;
70 struct statfs *mntbuf;
71 struct ufs_args mdev;
72
73 int
74 main(argc, argv)
75 int argc;
76 char *argv[];
77 {
78 struct stat stbuf;
79 struct statfs statfsbuf;
80 long width, maxwidth;
81 int ch, i;
82 char *mntpt;
83
84 while ((ch = getopt(argc, argv, "ikln")) != EOF)
85 switch(ch) {
86 case 'i':
87 iflag = 1;
88 break;
89 case 'k':
90 blocksize = 1024;
91 kflag = 1;
92 break;
93 case 'l':
94 lflag = 1;
95 break;
96 case 'n':
97 nflag = 1;
98 break;
99 case '?':
100 default:
101 usage();
102 }
103 argc -= optind;
104 argv += optind;
105
106 if (*argv && lflag)
107 errx(1, "-l does not make sense with list of mount points");
108
109 mntsize = getmntinfo(&mntbuf, (nflag ? MNT_NOWAIT : MNT_WAIT));
110 if (mntsize == 0)
111 err(1, "retrieving informaation on mounted file systems");
112 maxwidth = 0;
113 for (i = 0; i < mntsize; i++) {
114 width = strlen(mntbuf[i].f_mntfromname);
115 if (width > maxwidth)
116 maxwidth = width;
117 }
118 if (!*argv) {
119 for (i = 0; i < mntsize; i++)
120 if (!lflag || mntbuf[i].f_flags & MNT_LOCAL)
121 prtstat(&mntbuf[i], maxwidth);
122 exit(0);
123 }
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 ((stbuf.st_mode & S_IFMT) == S_IFCHR) {
131 ufs_df(*argv, maxwidth);
132 continue;
133 } else if ((stbuf.st_mode & S_IFMT) == S_IFBLK) {
134 if ((mntpt = getmntpt(*argv)) == 0) {
135 mntpt = mktemp(strdup("/tmp/df.XXXXXX"));
136 mdev.fspec = *argv;
137 if (mkdir(mntpt, DEFFILEMODE) != 0) {
138 warn("%s", mntpt);
139 continue;
140 }
141 if (mount(MOUNT_UFS, mntpt, MNT_RDONLY,
142 &mdev) != 0) {
143 ufs_df(*argv, maxwidth);
144 (void)rmdir(mntpt);
145 continue;
146 } else if (statfs(mntpt, &statfsbuf)) {
147 statfsbuf.f_mntonname[0] = '\0';
148 prtstat(&statfsbuf, maxwidth);
149 } else
150 warn("%s", *argv);
151 (void)unmount(mntpt, MNT_NOFORCE);
152 (void)rmdir(mntpt);
153 continue;
154 }
155 } else
156 mntpt = *argv;
157 /*
158 * Statfs does not take a `wait' flag, so we cannot
159 * implement nflag here.
160 */
161 if (statfs(mntpt, &statfsbuf) < 0) {
162 warn("%s", mntpt);
163 continue;
164 }
165 if (argc == 1)
166 maxwidth = strlen(statfsbuf.f_mntfromname) + 1;
167 prtstat(&statfsbuf, maxwidth);
168 }
169 return (0);
170 }
171
172 char *
173 getmntpt(name)
174 char *name;
175 {
176 long i;
177
178 for (i = 0; i < mntsize; i++) {
179 if (!strcmp(mntbuf[i].f_mntfromname, name))
180 return (mntbuf[i].f_mntonname);
181 }
182 return (0);
183 }
184
185 /*
186 * Print out status about a filesystem.
187 */
188 void
189 prtstat(sfsp, maxwidth)
190 register struct statfs *sfsp;
191 long maxwidth;
192 {
193 static int headerlen, timesthrough;
194 static char *header;
195 long used, availblks, inodes;
196
197 if (maxwidth < 11)
198 maxwidth = 11;
199 if (++timesthrough == 1) {
200 if (kflag) {
201 header = "1K-blocks";
202 headerlen = strlen(header);
203 } else
204 header = getbsize(&headerlen, &blocksize);
205 (void)printf("%-*.*s %s Used Avail Capacity",
206 maxwidth, maxwidth, "Filesystem", header);
207 if (iflag)
208 (void)printf(" iused ifree %%iused");
209 (void)printf(" Mounted on\n");
210 }
211 (void)printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname);
212 used = sfsp->f_blocks - sfsp->f_bfree;
213 availblks = sfsp->f_bavail + used;
214 (void)printf(" %*ld %7ld %7ld", headerlen,
215 sfsp->f_blocks * sfsp->f_bsize / blocksize,
216 used * sfsp->f_bsize / blocksize,
217 sfsp->f_bavail * sfsp->f_bsize / blocksize);
218 (void)printf(" %5.0f%%",
219 availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
220 if (iflag) {
221 inodes = sfsp->f_files;
222 used = inodes - sfsp->f_ffree;
223 (void)printf(" %7ld %7ld %5.0f%% ", used, sfsp->f_ffree,
224 inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0);
225 } else
226 (void)printf(" ");
227 (void)printf(" %s\n", sfsp->f_mntonname);
228 }
229
230 /*
231 * This code constitutes the old df code for extracting
232 * information from filesystem superblocks.
233 */
234 #include <ufs/fs.h>
235 #include <errno.h>
236 #include <fstab.h>
237
238 union {
239 struct fs iu_fs;
240 char dummy[SBSIZE];
241 } sb;
242 #define sblock sb.iu_fs
243
244 int fi;
245
246 void
247 ufs_df(file, maxwidth)
248 char *file;
249 long maxwidth;
250 {
251 struct statfs statfsbuf;
252 register struct statfs *sfsp;
253 char *mntpt;
254 static int synced;
255
256 if (synced++ == 0)
257 sync();
258
259 if ((fi = open(file, O_RDONLY)) < 0) {
260 warn("%s", file);
261 return;
262 }
263 if (bread((long)SBOFF, (char *)&sblock, SBSIZE) == 0) {
264 (void)close(fi);
265 return;
266 }
267 sfsp = &statfsbuf;
268 sfsp->f_type = 0;
269 sfsp->f_flags = 0;
270 sfsp->f_iosize = sblock.fs_fsize;
271 #ifdef notyet
272 sfsp->f_iosize = sblock.fs_bsize;
273 #endif
274 sfsp->f_blocks = sblock.fs_dsize;
275 sfsp->f_bfree = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag +
276 sblock.fs_cstotal.cs_nffree;
277 sfsp->f_bavail = (sblock.fs_dsize * (100 - sblock.fs_minfree) / 100) -
278 (sblock.fs_dsize - sfsp->f_bfree);
279 if (sfsp->f_bavail < 0)
280 sfsp->f_bavail = 0;
281 sfsp->f_files = sblock.fs_ncg * sblock.fs_ipg;
282 sfsp->f_ffree = sblock.fs_cstotal.cs_nifree;
283 sfsp->f_fsid.val[0] = 0;
284 sfsp->f_fsid.val[1] = 0;
285 if ((mntpt = getmntpt(file)) == 0)
286 mntpt = "";
287 bcopy((caddr_t)mntpt, (caddr_t)&sfsp->f_mntonname[0], MNAMELEN);
288 bcopy((caddr_t)file, (caddr_t)&sfsp->f_mntfromname[0], MNAMELEN);
289 strncpy(sfsp->f_fstypename, MOUNT_UFS, MFSNAMELEN);
290 sfsp->f_fstypename[MFSNAMELEN] = '\0';
291 prtstat(sfsp, maxwidth);
292 (void) close(fi);
293 }
294
295 int
296 bread(off, buf, cnt)
297 long off;
298 char *buf;
299 int cnt;
300 {
301 int n;
302
303 (void) lseek(fi, off, SEEK_SET);
304 if ((n=read(fi, buf, cnt)) != cnt) {
305 /* probably a dismounted disk if errno == EIO */
306 if (errno != EIO) {
307 (void)printf("\nread error off = %ld\n", off);
308 (void)printf("count = %d: %s\n", n, strerror(errno));
309 }
310 return (0);
311 }
312 return (1);
313 }
314
315 void
316 usage()
317 {
318
319 fprintf(stderr, "usage: df [-ikln] [file | file_system ...]\n");
320 exit(1);
321 }
322