df.c revision 1.15 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.15 1994/09/16 20:59:29 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 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 information 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
119 if (!*argv) {
120 for (i = 0; i < mntsize; i++)
121 if (!lflag || mntbuf[i].f_flags & MNT_LOCAL)
122 prtstat(&mntbuf[i], maxwidth);
123 exit(0);
124 }
125
126 for (; *argv; argv++) {
127 if (stat(*argv, &stbuf) < 0) {
128 if ((mntpt = getmntpt(*argv)) == 0) {
129 warn("%s", *argv);
130 continue;
131 }
132 } else if ((stbuf.st_mode & S_IFMT) == S_IFCHR) {
133 ufs_df(*argv, maxwidth);
134 continue;
135 } else if ((stbuf.st_mode & S_IFMT) == S_IFBLK) {
136 if ((mntpt = getmntpt(*argv)) == 0) {
137 mntpt = mktemp(strdup("/tmp/df.XXXXXX"));
138 mdev.fspec = *argv;
139 if (mkdir(mntpt, DEFFILEMODE) != 0) {
140 warn("%s", mntpt);
141 continue;
142 }
143 if (mount(MOUNT_UFS, mntpt, MNT_RDONLY,
144 &mdev) != 0) {
145 ufs_df(*argv, maxwidth);
146 (void)rmdir(mntpt);
147 continue;
148 } else if (statfs(mntpt, &statfsbuf)) {
149 statfsbuf.f_mntonname[0] = '\0';
150 prtstat(&statfsbuf, maxwidth);
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, &statfsbuf) < 0) {
164 warn("%s", mntpt);
165 continue;
166 }
167 if (argc == 1)
168 maxwidth = strlen(statfsbuf.f_mntfromname) + 1;
169 prtstat(&statfsbuf, maxwidth);
170 }
171 return (0);
172 }
173
174 char *
175 getmntpt(name)
176 char *name;
177 {
178 long i;
179
180 for (i = 0; i < mntsize; i++) {
181 if (!strcmp(mntbuf[i].f_mntfromname, name))
182 return (mntbuf[i].f_mntonname);
183 }
184 return (0);
185 }
186
187 /*
188 * Convert statfs returned filesystem size into BLOCKSIZE units.
189 * Attempts to avoid overflow for large filesystems.
190 */
191 #define fsbtoblk(num, fsbs, bs) \
192 (((fsbs) != 0 && (fsbs) < (bs)) ? \
193 (num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs)))
194
195 /*
196 * Print out status about a filesystem.
197 */
198 void
199 prtstat(sfsp, maxwidth)
200 struct statfs *sfsp;
201 int maxwidth;
202 {
203 static int headerlen, timesthrough;
204 static char *header;
205 long used, availblks, inodes;
206
207 if (maxwidth < 11)
208 maxwidth = 11;
209 if (++timesthrough == 1) {
210 if (kflag) {
211 header = "1K-blocks";
212 headerlen = strlen(header);
213 } else
214 header = getbsize(&headerlen, &blocksize);
215 (void)printf("%-*.*s %s Used Avail Capacity",
216 maxwidth, maxwidth, "Filesystem", header);
217 if (iflag)
218 (void)printf(" iused ifree %%iused");
219 (void)printf(" Mounted on\n");
220 }
221 (void)printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname);
222 used = sfsp->f_blocks - sfsp->f_bfree;
223 availblks = sfsp->f_bavail + used;
224 (void)printf(" %*ld %8ld %8ld", headerlen,
225 fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize),
226 fsbtoblk(used, sfsp->f_bsize, blocksize),
227 fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize));
228 (void)printf(" %5.0f%%",
229 availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
230 if (iflag) {
231 inodes = sfsp->f_files;
232 used = inodes - sfsp->f_ffree;
233 (void)printf(" %7ld %7ld %5.0f%% ", used, sfsp->f_ffree,
234 inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0);
235 } else
236 (void)printf(" ");
237 (void)printf(" %s\n", sfsp->f_mntonname);
238 }
239
240 /*
241 * This code constitutes the pre-system call Berkeley df code for extracting
242 * information from filesystem superblocks.
243 */
244 #include <ufs/ffs/fs.h>
245 #include <errno.h>
246 #include <fstab.h>
247
248 union {
249 struct fs iu_fs;
250 char dummy[SBSIZE];
251 } sb;
252 #define sblock sb.iu_fs
253
254 int rfd;
255
256 void
257 ufs_df(file, maxwidth)
258 char *file;
259 int maxwidth;
260 {
261 struct statfs statfsbuf;
262 struct statfs *sfsp;
263 char *mntpt;
264 static int synced;
265
266 if (synced++ == 0)
267 sync();
268
269 if ((rfd = open(file, O_RDONLY)) < 0) {
270 warn("%s", file);
271 return;
272 }
273 if (bread((off_t)SBOFF, &sblock, SBSIZE) == 0) {
274 (void)close(rfd);
275 return;
276 }
277 sfsp = &statfsbuf;
278 sfsp->f_type = 0;
279 sfsp->f_flags = 0;
280 sfsp->f_bsize = sblock.fs_fsize;
281 sfsp->f_iosize = sblock.fs_bsize;
282 sfsp->f_blocks = sblock.fs_dsize;
283 sfsp->f_bfree = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag +
284 sblock.fs_cstotal.cs_nffree;
285 sfsp->f_bavail = (sblock.fs_dsize * (100 - sblock.fs_minfree) / 100) -
286 (sblock.fs_dsize - sfsp->f_bfree);
287 if (sfsp->f_bavail < 0)
288 sfsp->f_bavail = 0;
289 sfsp->f_files = sblock.fs_ncg * sblock.fs_ipg;
290 sfsp->f_ffree = sblock.fs_cstotal.cs_nifree;
291 sfsp->f_fsid.val[0] = 0;
292 sfsp->f_fsid.val[1] = 0;
293 if ((mntpt = getmntpt(file)) == 0)
294 mntpt = "";
295 memmove(&sfsp->f_mntonname[0], mntpt, MNAMELEN);
296 memmove(&sfsp->f_mntfromname[0], file, MNAMELEN);
297 strncpy(sfsp->f_fstypename, MOUNT_UFS, MFSNAMELEN);
298 sfsp->f_fstypename[MFSNAMELEN] = '\0';
299 prtstat(sfsp, maxwidth);
300 (void)close(rfd);
301 }
302
303 int
304 bread(off, buf, cnt)
305 off_t off;
306 void *buf;
307 int cnt;
308 {
309 int nr;
310
311 (void)lseek(rfd, off, SEEK_SET);
312 if ((nr = read(rfd, buf, cnt)) != cnt) {
313 /* Probably a dismounted disk if errno == EIO. */
314 if (errno != EIO)
315 (void)fprintf(stderr, "\ndf: %qd: %s\n",
316 off, strerror(nr > 0 ? EIO : errno));
317 return (0);
318 }
319 return (1);
320 }
321
322 void
323 usage()
324 {
325 (void)fprintf(stderr, "usage: df [-ikln] [file | file_system ...]\n");
326 exit(1);
327 }
328