10f66f451Sopenharmony_ci/* df.c - report free disk space. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2006 Rob Landley <rob@landley.net> 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * See http://opengroup.org/onlinepubs/9699919799/utilities/df.html 60f66f451Sopenharmony_ci 70f66f451Sopenharmony_ciUSE_DF(NEWTOY(df, "HPkhit*a[-HPkh]", TOYFLAG_SBIN)) 80f66f451Sopenharmony_ci 90f66f451Sopenharmony_ciconfig DF 100f66f451Sopenharmony_ci bool "df" 110f66f451Sopenharmony_ci default y 120f66f451Sopenharmony_ci help 130f66f451Sopenharmony_ci usage: df [-HPkhi] [-t type] [FILESYSTEM ...] 140f66f451Sopenharmony_ci 150f66f451Sopenharmony_ci The "disk free" command shows total/used/available disk space for 160f66f451Sopenharmony_ci each filesystem listed on the command line, or all currently mounted 170f66f451Sopenharmony_ci filesystems. 180f66f451Sopenharmony_ci 190f66f451Sopenharmony_ci -a Show all (including /proc and friends) 200f66f451Sopenharmony_ci -P The SUSv3 "Pedantic" option 210f66f451Sopenharmony_ci -k Sets units back to 1024 bytes (the default without -P) 220f66f451Sopenharmony_ci -h Human readable (K=1024) 230f66f451Sopenharmony_ci -H Human readable (k=1000) 240f66f451Sopenharmony_ci -i Show inodes instead of blocks 250f66f451Sopenharmony_ci -t type Display only filesystems of this type 260f66f451Sopenharmony_ci 270f66f451Sopenharmony_ci Pedantic provides a slightly less useful output format dictated by Posix, 280f66f451Sopenharmony_ci and sets the units to 512 bytes instead of the default 1024 bytes. 290f66f451Sopenharmony_ci*/ 300f66f451Sopenharmony_ci 310f66f451Sopenharmony_ci#define FOR_df 320f66f451Sopenharmony_ci#include "toys.h" 330f66f451Sopenharmony_ci 340f66f451Sopenharmony_ciGLOBALS( 350f66f451Sopenharmony_ci struct arg_list *t; 360f66f451Sopenharmony_ci 370f66f451Sopenharmony_ci long units; 380f66f451Sopenharmony_ci int column_widths[5]; 390f66f451Sopenharmony_ci int header_shown; 400f66f451Sopenharmony_ci) 410f66f451Sopenharmony_ci 420f66f451Sopenharmony_cistatic void measure_column(int col, const char *s) 430f66f451Sopenharmony_ci{ 440f66f451Sopenharmony_ci size_t len = strlen(s); 450f66f451Sopenharmony_ci 460f66f451Sopenharmony_ci if (TT.column_widths[col] < len) TT.column_widths[col] = len; 470f66f451Sopenharmony_ci} 480f66f451Sopenharmony_ci 490f66f451Sopenharmony_cistatic void measure_numeric_column(int col, long long n) 500f66f451Sopenharmony_ci{ 510f66f451Sopenharmony_ci snprintf(toybuf, sizeof(toybuf), "%llu", n); 520f66f451Sopenharmony_ci return measure_column(col, toybuf); 530f66f451Sopenharmony_ci} 540f66f451Sopenharmony_ci 550f66f451Sopenharmony_cistatic void show_header() 560f66f451Sopenharmony_ci{ 570f66f451Sopenharmony_ci TT.header_shown = 1; 580f66f451Sopenharmony_ci 590f66f451Sopenharmony_ci // The filesystem column is always at least this wide. 600f66f451Sopenharmony_ci if (TT.column_widths[0] < 14) TT.column_widths[0] = 14; 610f66f451Sopenharmony_ci 620f66f451Sopenharmony_ci if ((toys.optflags & (FLAG_H|FLAG_h))) { 630f66f451Sopenharmony_ci xprintf((toys.optflags&FLAG_i) ? 640f66f451Sopenharmony_ci "%-*sInodes IUsed IFree IUse%% Mounted on\n" : 650f66f451Sopenharmony_ci "%-*s Size Used Avail Use%% Mounted on\n", 660f66f451Sopenharmony_ci TT.column_widths[0], "Filesystem"); 670f66f451Sopenharmony_ci } else { 680f66f451Sopenharmony_ci const char *item_label, *used_label, *free_label, *use_label; 690f66f451Sopenharmony_ci 700f66f451Sopenharmony_ci if (toys.optflags & FLAG_i) { 710f66f451Sopenharmony_ci item_label = "Inodes"; 720f66f451Sopenharmony_ci used_label = "IUsed"; 730f66f451Sopenharmony_ci free_label = "IFree"; 740f66f451Sopenharmony_ci use_label = "IUse%"; 750f66f451Sopenharmony_ci } else { 760f66f451Sopenharmony_ci item_label = TT.units == 512 ? "512-blocks" : "1K-blocks"; 770f66f451Sopenharmony_ci used_label = "Used"; 780f66f451Sopenharmony_ci free_label = "Available"; 790f66f451Sopenharmony_ci use_label = toys.optflags & FLAG_P ? "Capacity" : "Use%"; 800f66f451Sopenharmony_ci } 810f66f451Sopenharmony_ci 820f66f451Sopenharmony_ci measure_column(1, item_label); 830f66f451Sopenharmony_ci measure_column(2, used_label); 840f66f451Sopenharmony_ci measure_column(3, free_label); 850f66f451Sopenharmony_ci measure_column(4, use_label); 860f66f451Sopenharmony_ci xprintf("%-*s %*s %*s %*s %*s Mounted on\n", 870f66f451Sopenharmony_ci TT.column_widths[0], "Filesystem", 880f66f451Sopenharmony_ci TT.column_widths[1], item_label, 890f66f451Sopenharmony_ci TT.column_widths[2], used_label, 900f66f451Sopenharmony_ci TT.column_widths[3], free_label, 910f66f451Sopenharmony_ci TT.column_widths[4], use_label); 920f66f451Sopenharmony_ci 930f66f451Sopenharmony_ci // For the "Use%" column, the trailing % should be inside the column. 940f66f451Sopenharmony_ci TT.column_widths[4]--; 950f66f451Sopenharmony_ci } 960f66f451Sopenharmony_ci} 970f66f451Sopenharmony_ci 980f66f451Sopenharmony_cistatic void show_mt(struct mtab_list *mt, int measuring) 990f66f451Sopenharmony_ci{ 1000f66f451Sopenharmony_ci unsigned long long size, used, avail, percent, block; 1010f66f451Sopenharmony_ci char *device; 1020f66f451Sopenharmony_ci 1030f66f451Sopenharmony_ci // Return if it wasn't found (should never happen, but with /etc/mtab...) 1040f66f451Sopenharmony_ci if (!mt) return; 1050f66f451Sopenharmony_ci 1060f66f451Sopenharmony_ci // If we have -t, skip other filesystem types 1070f66f451Sopenharmony_ci if (TT.t) { 1080f66f451Sopenharmony_ci struct arg_list *al; 1090f66f451Sopenharmony_ci 1100f66f451Sopenharmony_ci for (al = TT.t; al; al = al->next) 1110f66f451Sopenharmony_ci if (!strcmp(mt->type, al->arg)) break; 1120f66f451Sopenharmony_ci 1130f66f451Sopenharmony_ci if (!al) return; 1140f66f451Sopenharmony_ci } 1150f66f451Sopenharmony_ci 1160f66f451Sopenharmony_ci // If we don't have -a, skip synthetic filesystems 1170f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_a) && !mt->statvfs.f_blocks) return; 1180f66f451Sopenharmony_ci 1190f66f451Sopenharmony_ci // Figure out how much total/used/free space this filesystem has, 1200f66f451Sopenharmony_ci // forcing 64-bit math because filesystems are big now. 1210f66f451Sopenharmony_ci if (toys.optflags & FLAG_i) { 1220f66f451Sopenharmony_ci size = mt->statvfs.f_files; 1230f66f451Sopenharmony_ci used = mt->statvfs.f_files - mt->statvfs.f_ffree; 1240f66f451Sopenharmony_ci avail = getuid() ? mt->statvfs.f_favail : mt->statvfs.f_ffree; 1250f66f451Sopenharmony_ci } else { 1260f66f451Sopenharmony_ci block = mt->statvfs.f_bsize ? mt->statvfs.f_bsize : 1; 1270f66f451Sopenharmony_ci size = (block * mt->statvfs.f_blocks) / TT.units; 1280f66f451Sopenharmony_ci used = (block * (mt->statvfs.f_blocks-mt->statvfs.f_bfree)) / TT.units; 1290f66f451Sopenharmony_ci avail= (block*(getuid()?mt->statvfs.f_bavail:mt->statvfs.f_bfree))/TT.units; 1300f66f451Sopenharmony_ci } 1310f66f451Sopenharmony_ci if (!(used+avail)) percent = 0; 1320f66f451Sopenharmony_ci else { 1330f66f451Sopenharmony_ci percent = (used*100)/(used+avail); 1340f66f451Sopenharmony_ci if (used*100 != percent*(used+avail)) percent++; 1350f66f451Sopenharmony_ci } 1360f66f451Sopenharmony_ci 1370f66f451Sopenharmony_ci device = *mt->device == '/' ? realpath(mt->device, NULL) : NULL; 1380f66f451Sopenharmony_ci if (!device) device = mt->device; 1390f66f451Sopenharmony_ci 1400f66f451Sopenharmony_ci if (measuring) { 1410f66f451Sopenharmony_ci measure_column(0, device); 1420f66f451Sopenharmony_ci measure_numeric_column(1, size); 1430f66f451Sopenharmony_ci measure_numeric_column(2, used); 1440f66f451Sopenharmony_ci measure_numeric_column(3, avail); 1450f66f451Sopenharmony_ci } else { 1460f66f451Sopenharmony_ci if (!TT.header_shown) show_header(); 1470f66f451Sopenharmony_ci 1480f66f451Sopenharmony_ci if (toys.optflags & (FLAG_H|FLAG_h)) { 1490f66f451Sopenharmony_ci char *size_str = toybuf, *used_str = toybuf+64, *avail_str = toybuf+128; 1500f66f451Sopenharmony_ci int hr_flags = (toys.optflags & FLAG_H) ? HR_1000 : 0; 1510f66f451Sopenharmony_ci int w = 4 + !!(toys.optflags & FLAG_i); 1520f66f451Sopenharmony_ci 1530f66f451Sopenharmony_ci human_readable(size_str, size, hr_flags); 1540f66f451Sopenharmony_ci human_readable(used_str, used, hr_flags); 1550f66f451Sopenharmony_ci human_readable(avail_str, avail, hr_flags); 1560f66f451Sopenharmony_ci xprintf("%-*s %*s %*s %*s %*llu%% %s\n", 1570f66f451Sopenharmony_ci TT.column_widths[0], device, 1580f66f451Sopenharmony_ci w, size_str, w, used_str, w, avail_str, w-1, percent, mt->dir); 1590f66f451Sopenharmony_ci } else xprintf("%-*s %*llu %*llu %*llu %*llu%% %s\n", 1600f66f451Sopenharmony_ci TT.column_widths[0], device, 1610f66f451Sopenharmony_ci TT.column_widths[1], size, 1620f66f451Sopenharmony_ci TT.column_widths[2], used, 1630f66f451Sopenharmony_ci TT.column_widths[3], avail, 1640f66f451Sopenharmony_ci TT.column_widths[4], percent, 1650f66f451Sopenharmony_ci mt->dir); 1660f66f451Sopenharmony_ci } 1670f66f451Sopenharmony_ci 1680f66f451Sopenharmony_ci if (device != mt->device) free(device); 1690f66f451Sopenharmony_ci} 1700f66f451Sopenharmony_ci 1710f66f451Sopenharmony_civoid df_main(void) 1720f66f451Sopenharmony_ci{ 1730f66f451Sopenharmony_ci struct mtab_list *mt, *mtstart, *mtend; 1740f66f451Sopenharmony_ci int measuring; 1750f66f451Sopenharmony_ci 1760f66f451Sopenharmony_ci if (toys.optflags & (FLAG_H|FLAG_h)) { 1770f66f451Sopenharmony_ci TT.units = 1; 1780f66f451Sopenharmony_ci } else { 1790f66f451Sopenharmony_ci // Units are 512 bytes if you select "pedantic" without "kilobytes". 1800f66f451Sopenharmony_ci TT.units = toys.optflags & FLAG_P ? 512 : 1024; 1810f66f451Sopenharmony_ci } 1820f66f451Sopenharmony_ci 1830f66f451Sopenharmony_ci if (!(mtstart = xgetmountlist(0))) return; 1840f66f451Sopenharmony_ci mtend = dlist_terminate(mtstart); 1850f66f451Sopenharmony_ci 1860f66f451Sopenharmony_ci // If we have a list of filesystems on the command line, loop through them. 1870f66f451Sopenharmony_ci if (*toys.optargs) { 1880f66f451Sopenharmony_ci // Measure the names then output the table. 1890f66f451Sopenharmony_ci for (measuring = 1; measuring >= 0; --measuring) { 1900f66f451Sopenharmony_ci char **next; 1910f66f451Sopenharmony_ci 1920f66f451Sopenharmony_ci for (next = toys.optargs; *next; next++) { 1930f66f451Sopenharmony_ci struct stat st; 1940f66f451Sopenharmony_ci 1950f66f451Sopenharmony_ci // Stat it (complain if we can't). 1960f66f451Sopenharmony_ci if (stat(*next, &st)) { 1970f66f451Sopenharmony_ci perror_msg("'%s'", *next); 1980f66f451Sopenharmony_ci continue; 1990f66f451Sopenharmony_ci } 2000f66f451Sopenharmony_ci 2010f66f451Sopenharmony_ci // Find and display this filesystem. Use _last_ hit in case of 2020f66f451Sopenharmony_ci // overmounts (which is first hit in the reversed list). 2030f66f451Sopenharmony_ci for (mt = mtend; mt; mt = mt->prev) { 2040f66f451Sopenharmony_ci if (st.st_dev == mt->stat.st_dev 2050f66f451Sopenharmony_ci || (st.st_rdev && (st.st_rdev == mt->stat.st_dev))) 2060f66f451Sopenharmony_ci { 2070f66f451Sopenharmony_ci show_mt(mt, measuring); 2080f66f451Sopenharmony_ci break; 2090f66f451Sopenharmony_ci } 2100f66f451Sopenharmony_ci } 2110f66f451Sopenharmony_ci } 2120f66f451Sopenharmony_ci } 2130f66f451Sopenharmony_ci } else { 2140f66f451Sopenharmony_ci // Loop through mount list to filter out overmounts. 2150f66f451Sopenharmony_ci for (mt = mtend; mt; mt = mt->prev) { 2160f66f451Sopenharmony_ci struct mtab_list *mt2, *mt3; 2170f66f451Sopenharmony_ci 2180f66f451Sopenharmony_ci // 0:0 is LANANA null device 2190f66f451Sopenharmony_ci if (!mt->stat.st_dev) continue; 2200f66f451Sopenharmony_ci 2210f66f451Sopenharmony_ci // Filter out overmounts. 2220f66f451Sopenharmony_ci mt3 = mt; 2230f66f451Sopenharmony_ci for (mt2 = mt->prev; mt2; mt2 = mt2->prev) { 2240f66f451Sopenharmony_ci if (mt->stat.st_dev == mt2->stat.st_dev) { 2250f66f451Sopenharmony_ci // For --bind mounts, show earliest mount 2260f66f451Sopenharmony_ci if (!strcmp(mt->device, mt2->device)) { 2270f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_a)) mt3->stat.st_dev = 0; 2280f66f451Sopenharmony_ci mt3 = mt2; 2290f66f451Sopenharmony_ci } else mt2->stat.st_dev = 0; 2300f66f451Sopenharmony_ci } 2310f66f451Sopenharmony_ci } 2320f66f451Sopenharmony_ci } 2330f66f451Sopenharmony_ci 2340f66f451Sopenharmony_ci // Measure the names then output the table. 2350f66f451Sopenharmony_ci for (measuring = 1; measuring >= 0; --measuring) { 2360f66f451Sopenharmony_ci // Cosmetic: show filesystems in creation order. 2370f66f451Sopenharmony_ci for (mt = mtstart; mt; mt = mt->next) { 2380f66f451Sopenharmony_ci if (mt->stat.st_dev) show_mt(mt, measuring); 2390f66f451Sopenharmony_ci } 2400f66f451Sopenharmony_ci } 2410f66f451Sopenharmony_ci } 2420f66f451Sopenharmony_ci 2430f66f451Sopenharmony_ci if (CFG_TOYBOX_FREE) llist_traverse(mtstart, free); 2440f66f451Sopenharmony_ci} 245