| /* vi: set sw=4 ts=4: */ |
| /* |
| * df.c - report free disk space. |
| * |
| * Implemented roughly according to SUSv3: |
| * http://www.opengroup.org/onlinepubs/009695399/utilities/df.html |
| * |
| * usage: df [-k] [-P|-t] [file...] |
| */ |
| |
| #include "toys.h" |
| |
| static void show_mt(struct mtab_list *mt) |
| { |
| int len; |
| long size, used, avail, percent; |
| uint64_t block; |
| |
| // Return if it wasn't found (should never happen, but with /etc/mtab...) |
| if (!mt) return; |
| |
| // If we have -t, skip other filesystem types |
| if (toy.df.fstype) { |
| struct string_list *sl; |
| |
| for (sl = toy.df.fstype; sl; sl = sl->next) |
| if (!strcmp(mt->type, sl->str)) break; |
| if (!sl) return; |
| } |
| |
| // If we don't have -a, skip synthetic filesystems |
| if (!(toys.optflags & 1) && !mt->statvfs.f_blocks) return; |
| |
| // Figure out how much total/used/free space this filesystem has, |
| // forcing 64-bit math because filesystems are big now. |
| block = mt->statvfs.f_bsize ? : 1; |
| size = (long)((block * mt->statvfs.f_blocks) / toy.df.units); |
| used = (long)((block * (mt->statvfs.f_blocks-mt->statvfs.f_bfree)) |
| / toy.df.units); |
| avail = (long)((block |
| * (getuid() ? mt->statvfs.f_bavail : mt->statvfs.f_bfree)) |
| / toy.df.units); |
| percent = size ? 100-(long)((100*(uint64_t)avail)/size) : 0; |
| |
| // Figure out appropriate spacing |
| len = 25 - strlen(mt->device); |
| if (len < 1) len = 1; |
| if (CFG_DF_PEDANTIC && (toys.optflags & 8)) { |
| printf("%s %ld %ld %ld %ld%% %s\n", mt->device, size, used, avail, |
| percent, mt->dir); |
| } else { |
| printf("%s% *ld % 10ld % 9ld % 3ld%% %s\n",mt->device, len, |
| size, used, avail, percent, mt->dir); |
| } |
| } |
| |
| int df_main(void) |
| { |
| struct mtab_list *mt, *mt2, *mtlist; |
| |
| // Handle -P and -k |
| toy.df.units = 1024; |
| if (CFG_DF_PEDANTIC && (toys.optflags & 8)) { |
| // Units are 512 bytes if you select "pedantic" without "kilobytes". |
| if ((toys.optflags&3) == 1) toy.df.units = 512; |
| printf("Filesystem %ld-blocks Used Available Capacity Mounted on\n", |
| toy.df.units); |
| } else puts("Filesystem\t1K-blocks\tUsed Available Use% Mounted on"); |
| |
| mtlist = getmountlist(1); |
| |
| // If we have a list of filesystems on the command line, loop through them. |
| if (*toys.optargs) { |
| char **next; |
| |
| for(next = toys.optargs; *next; next++) { |
| struct stat st; |
| |
| // Stat it (complain if we can't). |
| if(!stat(*next, &st)) { |
| perror_msg("`%s'", next); |
| toys.exitval = 1; |
| continue; |
| } |
| |
| // Find and display this filesystem. Use _last_ hit in case of |
| // -- bind mounts. |
| mt2 = NULL; |
| for (mt = mtlist; mt; mt = mt->next) |
| if (st.st_dev == mt->stat.st_dev) mt2 = mt; |
| show_mt(mt2); |
| } |
| } else { |
| // Get and loop through mount list. |
| |
| for (mt = mtlist; mt; mt = mt->next) { |
| struct mtab_list *mt2, *mt3; |
| |
| if (!mt->stat.st_dev) continue; |
| |
| // Filter out overmounts. |
| mt3 = mt; |
| for (mt2 = mt->next; mt2; mt2 = mt2->next) { |
| if (mt->stat.st_dev == mt2->stat.st_dev) { |
| // For --bind mounts, take last match |
| if (!strcmp(mt->device, mt2->device)) mt3 = mt2; |
| // Filter out overmounts |
| mt2->stat.st_dev = 0; |
| } |
| } |
| show_mt(mt3); |
| } |
| } |
| |
| if (CFG_TOYS_FREE) llist_free(mtlist, NULL); |
| |
| return 0; |
| } |