├── COPYING ├── INSTALL ├── attic └── gs.py ├── .github └── workflows │ └── smoke-tests.yml ├── README ├── pydf.1 ├── pydfrc ├── CHANGES └── pydf /COPYING: -------------------------------------------------------------------------------- 1 | This package was written by Radovan Garabík 2 | 3 | Copyright: 4 | 5 | Public domain. Do whatever you want to do with this program. 6 | 7 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | You must have Python 3 installed (at least version 3.1). 2 | 3 | edit first line of pydf to point to your python interpreter, 4 | copy pydf somewhere into your path, 5 | copy pydf.1 where your manpages reside (e.g. /usr/local/man/man1) 6 | and copy pydfrc into /etc/pydfrc, or ~/.pydfrc 7 | 8 | Modify /etc/pydfrc according to your taste. 9 | -------------------------------------------------------------------------------- /attic/gs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # get terminal size 4 | # from resize(1) 5 | # it does not work quite properly and there is a simpler way 6 | # 7 | # do not use 8 | 9 | import os, sys, time, termios 10 | from termios import ICRNL, IUCLC, ICANON, ECHO, CS8, VMIN, VTIME, TCSANOW, TCSADRAIN, TCSAFLUSH 11 | 12 | getsize = b"\0337\033[r\033[999;999H\0336n\033[18t" 13 | restoreemu = b"\0338" 14 | ttyfd = os.open('/dev/tty', os.O_RDWR) 15 | 16 | tioorig = termios.tcgetattr(ttyfd) 17 | tio = tioorig[:] 18 | 19 | tio[0] &= ~(ICRNL | IUCLC) # iflag 20 | tio[3] &= ~(ICANON | ECHO) # lflag 21 | tio[2] |= CS8 # cflag 22 | tio[6][VMIN] = 6 # cc 23 | tio[6][VTIME] = 1 # cc 24 | termios.tcsetattr(ttyfd, TCSAFLUSH, tio) 25 | os.write(ttyfd, getsize) 26 | x = os.read(ttyfd, len(getsize)) 27 | os.write(ttyfd, restoreemu) 28 | termios.tcsetattr(ttyfd, TCSADRAIN, tioorig) 29 | sys.stdout.buffer.write(x) 30 | -------------------------------------------------------------------------------- /.github/workflows/smoke-tests.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025 Sebastian Pipping 2 | # SPDX-License-Identifier: 0BSD 3 | 4 | name: Smoke Tests 5 | 6 | # Drop permissions to minimum for security 7 | permissions: 8 | contents: read 9 | 10 | on: 11 | pull_request: 12 | push: 13 | schedule: 14 | - cron: '0 16 * * 5' # Every Friday 4pm 15 | workflow_dispatch: 16 | 17 | jobs: 18 | smoke-tests: 19 | name: Smoke Tests 20 | 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | python-version: ["3.10", 3.14] # oldest and most recent version supported 25 | 26 | runs-on: ubuntu-24.04 27 | 28 | steps: 29 | 30 | - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 31 | 32 | - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 33 | with: 34 | python-version: ${{ matrix.python-version }} 35 | 36 | - name: Run smoke tests 37 | run: | 38 | export PS4=$'\n# ' 39 | set -x 40 | ./pydf 41 | ./pydf --help 42 | ./pydf --version 43 | ./pydf --all 44 | ./pydf --human-readable 45 | ./pydf --si 46 | ./pydf --block-size=1 47 | ./pydf --local 48 | ./pydf --kilobytes 49 | ./pydf --megabytes 50 | ./pydf --gigabytes 51 | ./pydf --blocks 52 | ./pydf --bw 53 | ./pydf --scale-bars 54 | ./pydf --mounts=/etc/mtab 55 | ./pydf --show-binds 56 | ./pydf --inodes 57 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | pydf is all-singing, all-dancing, fully colourised df(1)-clone 2 | written in python. 3 | 4 | Requirements: 5 | pydf was written for linux, using specific linux features. 6 | The fact it runs on other systems is pure coincidence, 7 | but neverthless it happens to work on wide range of modern 8 | unix systems. 9 | 10 | System-wide configuration is in /etc/pydfrc, per-user 11 | configuration in ~/.pydfrc (format of these files is the same) 12 | 13 | Colours are one of: 14 | none, default, bold, underline, blink, reverse, concealed, 15 | black, green, yellow, blue, magenta, cyan, white, 16 | on_black, on_green, on_yellow, on_blue, on_magenta, on_cyan, on_white 17 | beep 18 | on_red means that the background (instead of foreground) is painted 19 | with red etc... 20 | 21 | 22 | pydf recognizes following parameters: 23 | 24 | --help show this help message 25 | -v, --version show version 26 | -a, --all include filesystems having 0 blocks 27 | -h, --human-readable print sizes in human readable format (e.g. 1K 234M 2G) 28 | -H, --si likewise, but use powers of 1000 not 1024 29 | -b BLOCKSIZE, --block-size=BLOCKSIZE 30 | use BLOCKSIZE-byte blocks 31 | -l, --local limit listing to local filesystems 32 | -k, --kilobytes like --block-size=1024 33 | -m, --megabytes like --block-size=1048576 34 | -g, --gigabytes like --block-size=1073741824 35 | --blocks use filesystem native block size 36 | --bw do not use colours 37 | --mounts=MOUNTS_FILE File to get mount information from. On normal Linux 38 | systems only /etc/mtab or /proc/mounts make sense. 39 | Some other Unices use /etc/mnttab. Use /proc/mounts 40 | when /etc/mtab is corrupted or inaccessible (the 41 | output looks a bit weird in this case). 42 | -B, --show-binds show 'mount --bind' mounts 43 | -i, --inodes show inode instead of block usage 44 | -S, --scale-bars show bar sizes scaled to the largest filesystem size 45 | 46 | Written by Radovan Garabík . 47 | For new versions, look at https://kassiopeia.juls.savba.sk/~garabik/software/pydf.html 48 | 49 | 50 | Similar utilities: 51 | * dysk - advanced utility to display disk space usage, written in Rust: https://dystroy.org/dysk/ 52 | * di - disk information utility: https://diskinfo-di.sourceforge.io/ 53 | * dfc - colorful df clone written in C: https://github.com/rolinh/dfc 54 | 55 | -------------------------------------------------------------------------------- /pydf.1: -------------------------------------------------------------------------------- 1 | .TH PYDF 1 2 | .SH NAME 3 | pydf \- report colourised filesystem disk space usage 4 | .SH SYNOPSIS 5 | .B pydf 6 | .I "[options]" 7 | .I "[file]" 8 | .SH "DESCRIPTION" 9 | .B pydf 10 | is a python script that displays the amount of disk space available 11 | on the mounted filesystems, using different colours for different 12 | types of filesystems. Output format is completely customizable. 13 | .TP 14 | If an optional 15 | .I "file" 16 | argument is given, pydf displays just information about filesystem 17 | containing the file(s), otherwise it displays information about all 18 | mounted filesystems. 19 | 20 | .SH OPTIONS 21 | .TP 22 | .B \-\-help 23 | Show summary of options. 24 | .TP 25 | .B \-v, \-\-version 26 | Show version of program. 27 | .TP 28 | .B \-a, \-\-all 29 | include filesystems having 0 blocks 30 | .TP 31 | .B \-h, \-\-human-readable 32 | print sizes in human readable format (e.g., 133K 2341M 2448G) 33 | .TP 34 | .B \-H, \-\-si 35 | likewise, but use powers of 1000 not 1024 36 | .TP 37 | .B \-\-block-size=SIZE 38 | use SIZE-byte blocks 39 | .TP 40 | .B \-k, \-\-kilobytes 41 | like --block-size=1024 42 | .TP 43 | .B \-i, \-\-inodes 44 | show information about inodes instead of blocks 45 | .TP 46 | .B \-l, \-\-local 47 | limit listing to local filesystems 48 | .TP 49 | .B \-m, \-\-megabytes 50 | like --block-size=1048576 51 | .TP 52 | .B \-g, \-\-gigabytes 53 | like --block-size=1073741824 54 | .TP 55 | .B \-\-blocks 56 | use filesystem native block size 57 | .TP 58 | .B \-\-bw 59 | do not use colours 60 | .TP 61 | .B \-\-mounts=FILE 62 | file to get mount information from. 63 | On normal linux system, only /etc/mtab or /proc/mounts make sense. 64 | Use /proc/mounts when /etc/mtab is corrupted or inaccessible 65 | (the output looks a bit weird in this case though) 66 | .TP 67 | .B \-B, \-\-show\-binds 68 | Show also mount --bind mounted filesystems. 69 | .TP 70 | .B \-S, \-\-scale\-bars 71 | Show bar sizes scaled to the largest filesystem size 72 | .SH "BUGS" 73 | POSIX mandates to have f_blocks and f_bfree to be the number in units of f_frsize. However, 74 | many programs are buggy, including df(1) from coreutils, and Linux kernel often lies and reports 75 | f_frsize == f_bsize. Some filesystem and some other operating systems don't, and then the size 76 | reported by pydf is incorrect. As a stopgap measure, there is a parameter 77 | .I statvfs_block 78 | in 79 | .B /etc/pydfrc 80 | where you can force f_frsize or f_bsize. 81 | .SH "FILES" 82 | .TP 83 | .B /etc/pydfrc 84 | main configuration file 85 | .TP 86 | .B ~/.pydfrc 87 | per-user configuration file 88 | .SH "SEE ALSO" 89 | .BR df "(1) 90 | .SH AUTHOR 91 | Radovan Garab\('ik 92 | -------------------------------------------------------------------------------- /pydfrc: -------------------------------------------------------------------------------- 1 | # Configuration file for pydf 2 | # 3 | # 4 | # colours can be: 5 | # 'none' - no change from previous colour 6 | # 'default' - default system colour 7 | # 8 | # special attributes: 9 | # 'bold' 10 | # 'underline' 11 | # 'blink' 12 | # 'reverse' 13 | # 'concealed' 14 | # 15 | # foreground: 16 | # 'black' 17 | # 'red' 18 | # 'green' 19 | # 'yellow' 20 | # 'blue' 21 | # 'magenta' 22 | # 'cyan' 23 | # 'white' 24 | # 25 | # background: 26 | # 'on_black' 27 | # 'on_red' 28 | # 'on_green' 29 | # 'on_yellow' 30 | # 'on_blue' 31 | # 'on_magenta' 32 | # 'on_cyan' 33 | # 'on_white' 34 | # 35 | # beep: 36 | # 'beep' 37 | # 38 | # 39 | # or any combination of these, separated with commas 40 | 41 | 42 | # normal text colour - used to switch to after one row is displayed 43 | normal_colour = 'default' 44 | 45 | # colour of the header 46 | header_colour = 'yellow' 47 | 48 | # colour for local filesystems 49 | local_fs_colour = 'default' 50 | 51 | # colour for remote filesystems (such as nfs, samba, afs....) 52 | remote_fs_colour = 'green' 53 | 54 | # colour for special filesystems (such as proc, pty) 55 | special_fs_colour = 'blue' 56 | 57 | # colour for readonly mounted filesystems 58 | readonly_fs_colour = 'cyan' 59 | 60 | # colour for filesystems with usage > FILL_THRESH 61 | filled_fs_colour = 'red' 62 | 63 | # colour for filesystems with usage > FULL_THRESH 64 | full_fs_colour = 'on_red', 'green', 'blink' 65 | 66 | # custom device names - not implemented yet 67 | #custom_devices_colour = { 68 | # '/dev/loop' : ('green', 'blink') 69 | #} 70 | 71 | 72 | # default format for displaying sizes "-h" or "-H" or "-m" or "-k" or "--blocks" 73 | sizeformat = "-h" 74 | 75 | # string used to separace columns in the table 76 | column_separator = ' ' 77 | 78 | # colour of the string 79 | column_separator_colour = 'none' 80 | 81 | # if the screen is wider than necessary, stretch the bar: 82 | # 0 - do not stretch 83 | # 1 - stretch to fill the whole screen 84 | # real number in between - stretch by this ratio of free space 85 | stretch_screen = 0.3 86 | 87 | # filesystem filled up over this limit (in percents) is displayed 88 | # with filled_fs_colour (to show it is dangerously filled up) 89 | FILL_THRESH = 95.0 90 | 91 | # filesystem filled up over this limit is displayed with 92 | # full_fs_colour (to show it is FULL) 93 | FULL_THRESH = 99.0 94 | 95 | # Format used to display information: (keyword, size, justify). 96 | # keyword - one of 'fs' 'fstype' 'size' 'used' 'avail' 'perc' 'bar' 'on'. 97 | # size - if 'size' is integer, it is a minimal possible column width of the entry 98 | # if 'size' is float, it is a minimal column width in percent of screen width 99 | # 100 | # justify is either "l" for left justify, "r" for right justify or "c" for 101 | # center. 102 | # You can use any order and any combination of keywords, but 103 | # be careful not to exceed the size of your screen 104 | 105 | 106 | #format = [ 107 | # ('fs', 15, "l"), ('size', 9, "r"), 108 | # ('used', 9, "r"), ('avail', 9, "r"), ('perc', 5, "r"), 109 | # ('bar', 8, "l"), ('on', 16, "l") 110 | # ] 111 | 112 | # this is somewhat conservative 113 | # use fixed width for everything, since you want it readable 114 | # only the bar is specified by percentage, because you want it dynamic 115 | format = [ 116 | ('fs', 10, "l"), ('fstype', 6, "l"), ('size', 5, "r"), 117 | ('used', 5, "r"), ('avail', 5, "r"), ('perc', 5, "r"), 118 | ('bar', 0.1, "l"), ('on', 11, "l") 119 | ] 120 | 121 | 122 | # character to display filesystem size bar 123 | barchar = '#' 124 | 125 | # fill the empty space of the size bar with this character 126 | bar_fillchar = '.' 127 | 128 | # hide 'mount --bind' binds? 129 | hidebinds = True 130 | 131 | # list of files to try to get mount information from 132 | # on normal linux systems only /etc/mtab or /proc/mounts make sense 133 | mountfile = ['/etc/mtab', '/etc/mnttab', '/proc/mounts'] 134 | 135 | # use f_bsize or f_frsize 136 | # possible values: bsize, frsize, auto 137 | # auto means frsize if running on Linux, otherwise bsize 138 | statvfs_block = 'auto' 139 | 140 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | pydf (15) 2 | * split debian/changelog (will be used for debian-only changes) and the main changelog (this file) 3 | * add -S, --scale-bars option to scale bars to correspond to the device size 4 | * modify bind mounts logic to follow new kernel behaviour 5 | * add several special (i.e. not shown by default) filesystems 6 | * add support for COLUMNS and NO_COLOR environmental variables 7 | * this is the last version supporting Python 2 8 | 9 | pydf (14) unstable; urgency=medium 10 | 11 | * do not colour readonly filesystem in b&w mode, thanks to Dave Vehrs 12 | (closes: #851904) 13 | 14 | -- Radovan Garabík Mon, 20 Mar 2017 10:42:03 +0100 15 | 16 | pydf (13) unstable; urgency=low 17 | 18 | * added statvfs_block configuration option, to select between 19 | statvfs.F_BSIZE and statvfs.F_FRSIZE 20 | 21 | -- Radovan Garabík Sat, 10 Jan 2015 19:35:34 +0100 22 | 23 | pydf (12) unstable; urgency=low 24 | 25 | * better python3 compatibility; escape control and invalid characters in 26 | mountpoint names 27 | 28 | -- Radovan Garabík Fri, 26 Dec 2014 22:35:40 +0100 29 | 30 | pydf (11) unstable; urgency=low 31 | 32 | * add nfs4 to the list of remote filesystems (thanks to Markus Hauschild) 33 | * add fallback if resize does not work (closes: #577454) 34 | * somewhat better dealing with possible errors in 'resize' fallback 35 | * add several Debian/kFreeBSD special filesystems 36 | 37 | -- Radovan Garabík Sun, 27 Jan 2013 20:42:24 +0200 38 | 39 | pydf (10) unstable; urgency=low 40 | 41 | * normal_colour was not interpreting colour codes properly 42 | (thanks to Juhapekka Tolvanen and Norman Rasmussen for 43 | pointing this out) 44 | (closes: #577595, #582462) 45 | * if termios reports zero for terminal width, use fallback 46 | (closes: #577454) 47 | * added devtmpfs to the list of special filesystems 48 | (closes: #577453), both bugreports thanks to Romain Francoise 49 | * use subprocess or commands depending on major python version 50 | (closes: #579936), patch thanks to Emmanuel Bouthenot 51 | * remove parentheses in class definition, to enable 52 | python2.4 compatibility (thanks to Clint Savage) 53 | * add patch for /dev/mapper links, thanks to Ernest Beinrohr 54 | 55 | -- Radovan Garabík Sun, 11 Dec 2011 15:06:41 +0200 56 | 57 | pydf (9) unstable; urgency=low 58 | 59 | * remove stray ANSI escape sequence when using --bw mode 60 | * convert to run with python3 (thanks to Dror Levin) 61 | 62 | -- Radovan Garabík Mon, 29 Mar 2010 23:06:15 +0200 63 | 64 | pydf (8) unstable; urgency=low 65 | 66 | * run pylint & pychecker -- fix some previously unnoticed bugs 67 | * treat "special" filesystems and those with 0 blocks the same 68 | (i.e. do not display them unless -a option is given) 69 | * add fuse.sshfs to the list of networked filesystems 70 | 71 | -- Radovan Garabík Sat, 24 Oct 2009 17:40:14 +0200 72 | 73 | pydf (7) unstable; urgency=low 74 | 75 | * add 'inodes' option (closes: #51044), patch thanks to Thomas Rösner 76 | * change 'blocks-size' option into 'block-size', as originally intended 77 | * if the used percentage is meaningless, display '-' instead of 0 78 | * minor documentation updates 79 | 80 | -- Radovan Garabík Fri, 10 Apr 2009 14:40:00 +0200 81 | 82 | pydf (6) unstable; urgency=low 83 | 84 | * add the 'hidebinds' options (thanks to Martin von Wittich) 85 | 86 | -- Radovan Garabík Thu, 17 Apr 2008 22:24:03 +0200 87 | 88 | pydf (5) unstable; urgency=low 89 | 90 | * make the bar stretchable, to fill the whole screen width 91 | 92 | -- Radovan Garabík Fri, 10 Aug 2007 13:53:49 +0200 93 | 94 | pydf (4) unstable; urgency=low 95 | 96 | * fix scrolling artefacts at the bottom of terminal 97 | * fix accidentally removed possibility to use colour sequences 98 | 99 | -- Radovan Garabík Thu, 19 Jul 2007 14:54:15 +0200 100 | 101 | pydf (3) unstable; urgency=low 102 | 103 | * completely rewrited formatting code, now utilizes better 104 | screen width (closes: #421118) 105 | * display special filesystems with block_size != 0 in different colour 106 | 107 | -- Radovan Garabík Sun, 15 Jul 2007 19:36:05 +0200 108 | 109 | pydf (2) unstable; urgency=low 110 | 111 | * use termios to get terminal size, does not need resize(1) anymore 112 | (thanks to Josip Rodin for the idea) 113 | 114 | -- Radovan Garabík Sun, 13 May 2007 10:14:45 +0200 115 | 116 | pydf (1) unstable; urgency=low 117 | 118 | * show read only mounted filesystems in different colour (thanks 119 | to Michał J. Gajda and Bastian Kleineidam) 120 | * add binary-arch target to debian/rules (closes: #395633) 121 | * work around python statvfs 32-bit overflow (closes: #396298) 122 | 123 | -- Radovan Garabík Wed, 1 Nov 2006 17:09:52 +0200 124 | 125 | pydf (0.9.9) unstable; urgency=low 126 | 127 | * find automatically mountpoints for arguments (closes: #140483), 128 | thanks to Jürgen A. Erhard 129 | 130 | -- Radovan Garabík Thu, 30 Mar 2006 18:34:49 +0200 131 | 132 | pydf (0.9.8.5) unstable; urgency=low 133 | 134 | * added sshfs to the list of remote filesystems 135 | * added udf to the list of filesystem that are always full 136 | (thanks to Benoît Dejean) 137 | 138 | -- Radovan Garabík Fri, 2 Sep 2005 23:12:41 +0200 139 | 140 | pydf (0.9.8.4) unstable; urgency=low 141 | 142 | * mountfile can be a list now, pydf will try each of them 143 | * fallback to parsing mount(1) output if no mountfile is available 144 | (this adds support for many different operating systems, e.g. MacOSX) 145 | 146 | -- Radovan Garabík Mon, 22 Aug 2005 11:01:01 +0200 147 | 148 | pydf (0.9.8.3) unstable; urgency=low 149 | 150 | * failback to default size when 'resize' is not present (closes: #320564) 151 | * Suggest xutils (for 'resize') 152 | * better barsize rounding 153 | 154 | -- Radovan Garabík Wed, 3 Aug 2005 10:24:40 +0200 155 | 156 | pydf (0.9.8.2) unstable; urgency=low 157 | 158 | * use F_BSIZE instead of F_FRSIZE (closes: #289527) 159 | 160 | -- Radovan Garabík Tue, 2 Aug 2005 12:54:30 +0200 161 | 162 | pydf (0.9.8.1) unstable; urgency=low 163 | 164 | * change forgotten FILL_THRESH value from ridiculously low value back 165 | to 0.95, thanks to Lasse Pommerenke for noticing (closes: #318968) 166 | 167 | -- Radovan Garabík Tue, 19 Jul 2005 09:34:41 +0200 168 | 169 | pydf (0.9.8) unstable; urgency=low 170 | 171 | * try to detect terminal size 172 | * round values to nearest number (closes: #278683, #315273), note that df(1) 173 | sometimes rounds the values incorrectly 174 | 175 | -- Radovan Garabík Sat, 30 Apr 2005 16:05:11 +0200 176 | 177 | pydf (0.9.7) unstable; urgency=low 178 | 179 | * overall reworking, brought up in sync with newer python versions 180 | * accepts mountpoints as arguments (closes: #140483), thanks to Josip Rodin 181 | * only necessary filesystems are queried (closes: #280907) 182 | 183 | -- Radovan Garabik Wed, 5 Jan 2005 20:28:28 +0100 184 | 185 | pydf (0.9.6) unstable; urgency=low 186 | 187 | * modified dependencies for new python numbering scheme (closes: #118248) 188 | * mention /etc/pydfrc in manpage (closes: #108167) 189 | 190 | -- Radovan Garabik Mon, 5 Nov 2001 10:47:10 +0100 191 | 192 | pydf (0.9.5) unstable; urgency=low 193 | 194 | * corercted typo in manpage (closes #99878). 195 | 196 | -- Radovan Garabik Mon, 4 Jun 2001 13:07:06 +0200 197 | 198 | pydf (0.9.4) unstable; urgency=low 199 | 200 | * move Build-Depends where it belongs. 201 | * depends on python | python2 202 | 203 | -- Radovan Garabik Fri, 23 Feb 2001 21:41:04 +0100 204 | 205 | pydf (0.9.3) unstable; urgency=low 206 | 207 | * rebuilt with a new GPG key 208 | 209 | -- Radovan Garabik Fri, 1 Sep 2000 08:27:58 +0200 210 | 211 | pydf (0.9.2) unstable; urgency=low 212 | 213 | * added debhelper to Build-Depends 214 | 215 | -- Radovan Garabik Wed, 16 Feb 2000 16:08:24 +0100 216 | 217 | pydf (0.9.1) unstable; urgency=low 218 | 219 | * Fixed stupid bug affecting those with broken python on RedHat. 220 | Thanks to Keith M. Briggs for pointing this out. 221 | 222 | -- Radovan Garabik Fri, 14 Jan 2000 13:09:13 +0100 223 | 224 | pydf (0.9) unstable; urgency=low 225 | 226 | * More colour definitions 227 | * Upgraded Standards-Version 228 | * Corrected typo in the manpage 229 | * Included pointer to stat(1) in README 230 | 231 | -- Radovan Garabik Thu, 6 Jan 2000 17:24:32 +0100 232 | 233 | pydf (0.8.1) unstable; urgency=low 234 | 235 | * NMU (sponsored). 236 | * Set control file so Radovan is listed properly as the maintainer. 237 | 238 | -- Chris Lawrence Tue, 4 Jan 2000 02:11:01 -0600 239 | 240 | pydf (0.8) unstable; urgency=low 241 | 242 | * statvfs checks for errors - e.g., if you do not have rights to statfs 243 | the filesystem, pydf would not crash 244 | * use getopt for argument parsing 245 | * added --block-size, --local, --all options 246 | * Radovan Garabik is the person 247 | responsible for this package; I am his sponsor and uploading it on his 248 | behalf. 249 | 250 | -- Chris Lawrence Tue, 5 Oct 1999 20:25:25 +0200 251 | 252 | pydf (0.7) unstable; urgency=low 253 | 254 | * build with new debhelper - FHS compliant 255 | * a couple of spelling errors in README fixed 256 | 257 | -- Radovan Garabik Sat, 18 Sep 1999 10:34:28 +0200 258 | 259 | pydf (0.6) unstable; urgency=low 260 | 261 | * now displays size correctly for filesystem with FRSIZE != BSIZE, 262 | workaround for some broked pythons (see 0.3) still valid 263 | * documentation update 264 | * increased version number from 0.4 :-) 265 | 266 | -- Radovan Garabik Wed, 15 Sep 1999 20:52:21 +0200 267 | 268 | pydf (0.5) unstable; urgency=low 269 | 270 | * fixed typo preventing correct display of small sizes 271 | 272 | -- Radovan Garabik Wed, 1 Sep 1999 13:19:38 +0200 273 | 274 | pydf (0.4) unstable; urgency=low 275 | 276 | * network filesystems with block size 0 are now recognized as network 277 | filesystems, not as special filesystems 278 | * workaround for older python interpreter without os.statvfs function 279 | 280 | -- Radovan Garabik Mon, 30 Aug 1999 19:53:50 +0200 281 | 282 | pydf (0.3) unstable; urgency=low 283 | 284 | * Restore original colour after itself 285 | * Should work on RedHat 6.0 now 286 | * Improved colour scheme 287 | * Added --mounts option 288 | 289 | -- Radovan Garabik Fri, 27 Aug 1999 17:24:45 +0200 290 | 291 | pydf (0.2) unstable; urgency=low 292 | 293 | * Initial Release. 294 | 295 | -- Radovan Garabik Thu, 26 Aug 1999 19:16:29 +0200 296 | 297 | Local variables: 298 | mode: debian-changelog 299 | End: 300 | -------------------------------------------------------------------------------- /pydf: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | 3 | import sys, os, re, string, struct, unicodedata 4 | from optparse import OptionParser 5 | 6 | from math import log 7 | 8 | import subprocess 9 | 10 | 11 | class Bar: 12 | def __init__(self, percentage=0, width=2, header=False, psize=0.0): 13 | self.percentage = percentage 14 | self.width = width 15 | self.header = header 16 | self.psize = psize 17 | 18 | def __len__(self): 19 | return self.width 20 | 21 | def __str__(self): 22 | return self.format(self, 'l') 23 | 24 | def format(self, pos, max_psize=None): 25 | if self.header: 26 | return ' '*self.width 27 | if max_psize: 28 | # scale relative to max physical size 29 | # .---self.width---------------. 30 | # .---bar_w----------. | 31 | # |.--used_w--. | | 32 | # "[############......] " 33 | bar_w = int(((self.psize*self.width)/max_psize)) 34 | used_w = int(round(self.percentage*(bar_w-2))) 35 | bar = '['+manglestring(used_w*barchar, bar_w-2, pos, bar_fillchar)+']' 36 | spaces = ' '*(self.width - len(bar)) 37 | return bar + spaces 38 | else: 39 | # scale each to screen width 40 | size = int(round(self.percentage*(self.width-2))) 41 | return '['+manglestring(size*barchar, self.width-2, pos, bar_fillchar)+']' 42 | 43 | 44 | def get_terminal_width_termios(): 45 | try: 46 | import fcntl, termios 47 | except ImportError: 48 | return None 49 | s = struct.pack("HHHH", 0, 0, 0, 0) 50 | try: 51 | lines, cols, xpixels, ypixels = \ 52 | struct.unpack( 53 | "HHHH", 54 | fcntl.ioctl(sys.stdout.fileno(), 55 | termios.TIOCGWINSZ, s) 56 | ) 57 | except (IOError, AttributeError): 58 | return None 59 | return cols 60 | 61 | def get_terminal_width_resize(): 62 | status, output = subprocess.getstatusoutput('resize') 63 | if status!=0: # error in running resize 64 | return None 65 | c = output.split('\n') 66 | c = [x for x in c if x.startswith('COLUMNS=')] 67 | if c: 68 | c = c[0] 69 | dummy, c = c.split('=', 1) 70 | if c[-1] == ';': 71 | c = c[:-1] 72 | if c: 73 | return int(c) 74 | else: 75 | return None 76 | 77 | def get_terminal_width_columns(): 78 | width_str = os.environ.get('COLUMNS', '80') 79 | try: 80 | width = int(width_str) 81 | except ValueError: 82 | return None 83 | 84 | if not 60 <= width <= 1000: # a simple sanity check 85 | return None 86 | 87 | return width 88 | 89 | def get_terminal_width_dumb(): 90 | return 80 91 | 92 | def get_terminal_width(): 93 | handlers = [get_terminal_width_termios, get_terminal_width_resize, get_terminal_width_columns, get_terminal_width_dumb] 94 | for handler in handlers: 95 | width = handler() 96 | if width: 97 | return width 98 | return 80 # fallback, should not happen 99 | 100 | 101 | def find_mountpoint(path): 102 | if not os.path.lexists(path): 103 | sys.stderr.write('pydf: %s: No such file or directory\n' % repr(path)) 104 | return None 105 | while not os.path.ismount(path): 106 | path = os.path.dirname(path) 107 | return path 108 | 109 | 110 | #some default definitions 111 | colours = { 112 | 'none' : "", 113 | 'default' : "\033[0m", 114 | 'bold' : "\033[1m", 115 | 'underline' : "\033[4m", 116 | 'blink' : "\033[5m", 117 | 'reverse' : "\033[7m", 118 | 'concealed' : "\033[8m", 119 | 120 | 'black' : "\033[30m", 121 | 'red' : "\033[31m", 122 | 'green' : "\033[32m", 123 | 'yellow' : "\033[33m", 124 | 'blue' : "\033[34m", 125 | 'magenta' : "\033[35m", 126 | 'cyan' : "\033[36m", 127 | 'white' : "\033[37m", 128 | 129 | 'on_black' : "\033[40m", 130 | 'on_red' : "\033[41m", 131 | 'on_green' : "\033[42m", 132 | 'on_yellow' : "\033[43m", 133 | 'on_blue' : "\033[44m", 134 | 'on_magenta' : "\033[45m", 135 | 'on_cyan' : "\033[46m", 136 | 'on_white' : "\033[47m", 137 | 138 | 'beep' : "\007" 139 | } 140 | 141 | 142 | normal_colour = 'default' 143 | header_colour = 'yellow' 144 | local_fs_colour = 'default' 145 | remote_fs_colour = 'green' 146 | special_fs_colour = 'blue' 147 | readonly_fs_colour = 'cyan' 148 | filled_fs_colour = 'red' 149 | full_fs_colour = 'on_red' 150 | custom_device_colour = {} #TODO 151 | 152 | sizeformat = "-h" 153 | column_separator = ' ' 154 | column_separator_colour = 'none' 155 | row_separator = '' 156 | hidebinds = True 157 | 158 | stretch_screen = 0.3 159 | 160 | do_total_sum = False 161 | 162 | FILL_THRESH = 95.0 163 | FULL_THRESH = 99.0 164 | 165 | 166 | format = [ 167 | ('fs', 10, "l"), ('size', 5, "r"), 168 | ('used', 5, "r"), ('avail', 5, "r"), ('perc', 4, "r"), 169 | ('bar', 0.1, "l"), ('on', 11, "l") 170 | ] 171 | 172 | 173 | barchar = '#' 174 | bar_fillchar = '.' 175 | 176 | mountfile = ['/etc/mtab', '/etc/mnttab', '/proc/mounts'] 177 | 178 | statvfs_block = 'auto' 179 | 180 | #end of default definitions 181 | 182 | # read configuration file 183 | for conffile in ["/etc/pydfrc", os.environ['HOME']+"/.pydfrc"]: 184 | if os.path.isfile(conffile): 185 | exec(compile(open(conffile).read(), conffile, 'exec')) 186 | 187 | 188 | header = { 189 | 'fs' : "Filesystem", 190 | 'size' : "Size", 191 | 'used' : "Used", 192 | 'avail' : "Avail", 193 | 'on' : "Mounted on", 194 | 'fstype' : "Type", 195 | 'perc' : "Use%", 196 | 'bar' : Bar(header=True), 197 | } 198 | 199 | def sanitize_output(s): 200 | "sanitize nonprintable characters for printing" 201 | r = '' 202 | for c in s: 203 | if ord(c)<32: 204 | r += r'\x%02x' % ord(c) 205 | # surrogate characters encoding non-decodable bytes in the names of mountpoints 206 | elif 0xdc80 <= ord(c) <= 0xdcff: 207 | r += r'\x%02x' % (ord(c)-0xdc00) 208 | # test for strange unicode characters 209 | elif unicodedata.category(c)[0]=='C' or unicodedata.category(c) in ('Zl', 'Zp'): 210 | if ord(c) <= 0xffff: 211 | r += r'\u%04X' % ord(c) 212 | else: 213 | r += r'\U%08X' % ord(c) 214 | else: 215 | r += c 216 | return r 217 | 218 | def out(s): 219 | try: 220 | sys.stdout.write(s) 221 | except UnicodeEncodeError: 222 | sys.stdout.write(s.encode('ascii', 'ignore').decode()) 223 | 224 | class DumbStatus: 225 | "emulates statvfs results with only zero values" 226 | f_bsize = f_frsize = f_blocks = f_bfree = f_bavail = f_files = f_ffree = f_favail = f_flag = f_namemax = 0 227 | 228 | def hfnum(size, base): 229 | "human readable number" 230 | if size == 0: 231 | return "0" 232 | if size < 0: 233 | return "?" 234 | if inodes: 235 | units = [""] 236 | else: 237 | units = ["B"] 238 | units += ["k", "M", "G", "T", "P", "Z", "Y"] 239 | power = int(log(size)/log(base)) 240 | if power < 0: 241 | power = 0 242 | if power >= len(units): 243 | power = len(units)-1 244 | nsize = int(round(1.*size/(base**power))) 245 | if nsize < 10 and power >= 1: 246 | power -= 1 247 | nsize = int(round(1.*size/(base**power))) 248 | r = str(nsize) + units[power] 249 | return r 250 | 251 | def myformat(number, sizeformat, fs_blocksize): 252 | "format number as file size. fs_blocksize here is a filesysem blocksize" 253 | size = int(number)*fs_blocksize 254 | if blocksize: # that is, blocksize was explicitly set up 255 | sn = round(1.*size/blocksize) 256 | sn = int(sn) 257 | return str(sn) 258 | if sizeformat == "-k": 259 | sn = round(size/1024.) 260 | sn = int(sn) 261 | return str(sn) 262 | elif sizeformat == "-m": 263 | sn = round(size/(1024.*1024)) 264 | sn = int(sn) 265 | return str(sn) 266 | elif sizeformat == "-g": 267 | sn = round(size/(1024.*1024*1024)) 268 | sn = int(sn) 269 | return str(sn) 270 | elif sizeformat == "-h": 271 | return hfnum(size, 1024) 272 | elif sizeformat == "-H": 273 | return hfnum(size, 1000) 274 | elif sizeformat == "--blocks": 275 | return str(number) 276 | else: # this should not happen 277 | raise ValueError("Impossible error, contact the author, sizeformat="+repr(sizeformat)) 278 | 279 | def manglestring(s, l, pos, fillchar=' '): 280 | "cut string to fit exactly into l chars" 281 | if pos == "r": 282 | ns = s.rjust(l, fillchar) 283 | elif pos == "l": 284 | ns = s.ljust(l, fillchar) 285 | elif pos == "c": 286 | ns = s.center(l, fillchar) 287 | else: 288 | raise ValueError('Error in manglestring') 289 | if len(ns) > l: 290 | ns = ns[:int(l/2)] + "~" + ns[-int(l/2)+1:] 291 | return ns 292 | 293 | def makecolour(clist): 294 | "take list (or tuple or just one name) of colour names and return string of ANSI definitions" 295 | s = "" 296 | if type(clist) == str: 297 | lclist = [clist] 298 | else: 299 | lclist = clist 300 | for i in lclist: 301 | s = s + colours[i] 302 | return s 303 | 304 | def version(): 305 | return '15' 306 | 307 | def get_all_mountpoints(): 308 | "return all mountpoints in fs" 309 | 310 | # fallback when nothing else works 311 | dummy_result = {'/': ('/', '')} 312 | 313 | if isinstance(mountfile, str): 314 | f = open(mountfile,"rb") 315 | else: 316 | for i in mountfile: 317 | if os.path.exists(i): 318 | f = open(i,"rb") 319 | break 320 | else: 321 | # fallback, first try to parse mount output 322 | status, mout = subprocess.getstatusoutput('mount') 323 | if status !=0: 324 | return dummy_result 325 | mlines = mout.split('\n') 326 | r = {} 327 | for line in mlines: 328 | if not ' on ' in line: 329 | continue 330 | device, on = line.split(' on ', 1) 331 | device = device.split()[0] 332 | onparts = on.split() 333 | on = onparts[0] 334 | # option format: (a,b,..) 335 | opts = onparts[-1][1:-1].split(',') 336 | r[on] = (device, '', opts) 337 | 338 | if r: 339 | return r 340 | else: 341 | return dummy_result 342 | 343 | mountlines = f.readlines() # bytes! 344 | 345 | # convert to representable strings 346 | errhandler = 'surrogateescape' 347 | mountlines = [x.decode(sys.stdin.encoding, errhandler) for x in mountlines] 348 | r = {} 349 | for l in mountlines: 350 | spl = l.split() 351 | if len(spl)<4: 352 | print("Error in", mountfile) 353 | print(repr(l)) 354 | continue 355 | device, mp, typ, opts = spl[0:4] 356 | opts = opts.split(',') 357 | r[mp] = (device, typ, opts) 358 | return r 359 | 360 | def niceprint_fs(fs): 361 | "print LVM as nice symlink" 362 | matchObj = re.search( r'^\/dev\/mapper\/(.*)-(.*)', str(fs)) # will fail if fs cannot be converted to unicode 363 | if matchObj: 364 | return "/dev/" + matchObj.group(1) + "/" + matchObj.group(2) 365 | else: 366 | return fs 367 | 368 | def identify_bind_mounts(mountpoints): 369 | by_dev = {} 370 | for mp, (device, typ, opts) in mountpoints.items(): 371 | if device not in by_dev or mp.count('/') < by_dev[device].count('/'): 372 | by_dev[device] = mp 373 | r = {} 374 | for mp, (device, typ, opts) in mountpoints.items(): 375 | if mp != by_dev[device] and 'bind' not in opts: 376 | opts = ['bind'] + opts 377 | r[mp] = (device, typ, opts) 378 | return r 379 | 380 | def get_row_mp(mp): 381 | if mp: 382 | if mp in mountpoints: 383 | device, fstype, opts = mountpoints[mp] 384 | device = niceprint_fs(device) 385 | else: 386 | # oops, the mountpoint is not in /etc/mtab or equivalent 387 | # return dummy values 388 | device, fstype, opts = '-', '-', '-' 389 | rdonly = 'ro' in opts or fstype in ("iso9660", "udf") 390 | bind = 'bind' in opts or 'rbind' in opts 391 | 392 | try: 393 | status = os.statvfs(mp) 394 | except (OSError, IOError): 395 | status = DumbStatus() 396 | if statvfs_block == 'bsize': 397 | fs_blocksize = status.f_bsize or status.f_frsize 398 | elif statvfs_block == 'frsize': 399 | fs_blocksize = status.f_frsize or status.f_bsize 400 | elif statvfs_block == 'auto': 401 | if sys.platform == 'linux2': 402 | fs_blocksize = status.f_bsize or status.f_frsize 403 | else: 404 | fs_blocksize = status.f_frsize or status.f_bsize 405 | else: 406 | # bad value in configuration 407 | raise ValueError('bad configuration: statvfs_block') 408 | free = status.f_bfree 409 | size = status.f_blocks 410 | avail = status.f_bavail 411 | inodes_free = status.f_ffree 412 | inodes_size = status.f_files 413 | inodes_avail = status.f_favail 414 | if (size==0 or is_special_fs(fstype)) and not allfss: 415 | return 416 | if bind and hidebinds: 417 | return 418 | used = size-free 419 | inodes_used = inodes_size - inodes_free 420 | 421 | if inodes: 422 | psize = inodes_size 423 | size_f = myformat(inodes_size, sizeformat, 1) 424 | used_f = myformat(inodes_used, sizeformat, 1) 425 | avail_f = myformat(inodes_avail, sizeformat, 1) 426 | try: 427 | perc = int(round(100.*inodes_used/inodes_size)) 428 | perc_f = str(perc) 429 | except ZeroDivisionError: 430 | perc = 0 431 | perc_f = '-' 432 | 433 | # Do not show 100% when not full and not 0% when not empty 434 | if perc == 100 and inodes_used < inodes_size: 435 | perc_f = '>99' 436 | elif perc == 0 and inodes_used > 0: 437 | perc_f = '<1' 438 | 439 | else: 440 | psize = size 441 | size_f = myformat(size, sizeformat, fs_blocksize) 442 | used_f = myformat(used, sizeformat, fs_blocksize) 443 | avail_f = myformat(avail, sizeformat, fs_blocksize) 444 | try: 445 | perc = int(round(100.*used/size)) 446 | perc_f = str(perc) 447 | except ZeroDivisionError: 448 | perc = 0 449 | perc_f = '-' 450 | 451 | # Do not show 100% when not full and not 0% when not empty 452 | if perc == 100 and used < size: 453 | perc_f = '>99' 454 | elif perc == 0 and used > 0: 455 | perc_f = '<1' 456 | 457 | info = { 458 | 'fs' : device, 459 | 'size' : size_f, 460 | 'used' : used_f, 461 | 'avail' : avail_f, 462 | 'on' : mp, 463 | 'fstype' : fstype, 464 | 'perc' : perc_f, 465 | 'bar' : None, 466 | } 467 | 468 | current_colour = local_fs_colour 469 | if is_remote_fs(fstype): 470 | current_colour = remote_fs_colour 471 | elif size == 0 or is_special_fs(fstype): 472 | current_colour = special_fs_colour 473 | else: # header 474 | current_colour = header_colour 475 | 476 | row = [] 477 | 478 | for j in format: 479 | 480 | if j[0]=='bar': 481 | width = j[1] 482 | if 0 FULL_THRESH: 490 | current_colour = full_fs_colour 491 | elif perc > FILL_THRESH: 492 | current_colour = filled_fs_colour 493 | if j[0]=='bar': 494 | info['bar'] = Bar(perc/100., width, psize=psize) 495 | 496 | text = info[j[0]] 497 | # if there are control or invalid unicode characters in mountpoint names 498 | if not isinstance(text, Bar): 499 | text = sanitize_output(text) 500 | 501 | else: 502 | text = header[j[0]] 503 | if j[0]=='bar': 504 | text.width = width 505 | 506 | column = [current_colour, text] 507 | row.append(column) 508 | 509 | return row 510 | 511 | 512 | def is_remote_fs(fs): 513 | "test if fs (as type) is a remote one" 514 | fs = fs.lower() 515 | 516 | return fs in [ "nfs", "smbfs", "cifs", "ncpfs", "afs", "coda", 517 | "ftpfs", "mfs", "sshfs", "fuse.sshfs", "nfs4" ] 518 | 519 | def is_special_fs(fs): 520 | "test if fs (as type) is a special one" 521 | "in addition, a filesystem is special if it has number of blocks equal to 0" 522 | fs = fs.lower() 523 | return fs in [ 524 | "tmpfs", 525 | "devpts", 526 | "devtmpfs", 527 | "proc", 528 | "sysfs", 529 | "usbfs", 530 | "devfs", 531 | "fdescfs", 532 | "linprocfs", 533 | "squashfs", 534 | "ecryptfs", 535 | "overlay", 536 | "efivarfs", 537 | "fuse.encfs", 538 | ] 539 | 540 | def get_table(mps): 541 | "table is a list of rows" 542 | "row is a list of columns" 543 | "column is a list of [colour code, content]" 544 | "content is a string, unless it is a Bar() instance" 545 | rows = [get_row_mp(None)] 546 | for mp in mps: 547 | row = get_row_mp(mp) 548 | if row is not None: 549 | rows.append(row) 550 | return rows 551 | 552 | 553 | def squeeze_table(table, desired_width, scale_bars): 554 | "squeeze table to fit into width characters" 555 | 556 | cols = len(table[0]) 557 | 558 | # build a row of minimal (possible, from format) cell sizes 559 | minrow = [] 560 | for j in format: 561 | width = j[1] 562 | if 0 < width < 1: # i.e. percentage 563 | width = int(width*terminal_width)-1 564 | minrow.append(width) 565 | 566 | # row of maximal cell sizes 567 | maxrow = [0]*cols 568 | 569 | for row in table: 570 | for col in range(cols): 571 | colsize = len(row[col][1]) 572 | maxrow[col] = max(maxrow[col], colsize) 573 | 574 | # maximal differences between (real cell size - minimal possible cell size) 575 | deltarow = [maxrow[i]-minrow[i] for i in range(cols)] 576 | 577 | deltas = list(zip(deltarow, list(range(cols)))) 578 | deltas.sort() 579 | deltas.reverse() 580 | 581 | # how many characters we need to cut off from table width 582 | to_reduce = sum(maxrow) + (cols-1)*len(column_separator) - desired_width 583 | 584 | to_stretch = 0 585 | # if there is free space 586 | if to_reduce < 0 and stretch_screen: 587 | # -to_reduce is now number of spare characters 588 | to_stretch = int(-to_reduce * stretch_screen) 589 | 590 | new_maxrow = maxrow[:] # new sizes 591 | for delta, i in deltas: 592 | if to_reduce < 0: 593 | # we have finished 594 | break 595 | if delta >= to_reduce: 596 | new_maxrow[i] -= to_reduce 597 | # and we finished 598 | to_reduce = 0 599 | break 600 | else: 601 | new_maxrow[i] -= delta # now it contains the minimal possible width 602 | to_reduce -= delta 603 | 604 | if to_reduce > 0: 605 | # we were not able to reduce the size enough 606 | # since it will wrap anywway, we might as well display 607 | # complete long lines 608 | new_maxrow = maxrow 609 | max_psize = None 610 | if scale_bars: 611 | # get the max psize when scaling 612 | max_psize = 0.0 613 | for row in table: 614 | for col in range(cols): 615 | cell_content = row[col][1] 616 | if isinstance(cell_content, Bar): 617 | max_psize = max(max_psize, cell_content.psize) 618 | for row in table: 619 | for col in range(cols): 620 | cell_content = row[col][1] 621 | if isinstance(cell_content, Bar): 622 | cell_content.width += to_stretch 623 | formatted_cell_content = cell_content.format(format[col][2],max_psize) 624 | else: 625 | formatted_cell_content = manglestring(cell_content, new_maxrow[col], format[col][2]) 626 | row[col][1] = formatted_cell_content 627 | 628 | 629 | def display_table(table, terminal_width, scale_bars): 630 | "display our internal output table" 631 | 632 | squeeze_table(table, terminal_width-1, scale_bars) 633 | 634 | colsepcol = makecolour(column_separator_colour) 635 | for row in table: 636 | firstcol = True 637 | for colourcode, text in row: 638 | if firstcol: 639 | firstcol = False 640 | else: 641 | out(colsepcol) 642 | out(column_separator) 643 | out(makecolour(colourcode)) 644 | out(text) 645 | out(row_separator) 646 | out(makecolour(normal_colour)) 647 | out('\n') 648 | 649 | 650 | 651 | # the fun begins here 652 | 653 | parser = OptionParser(usage="usage: %prog [options] arg", add_help_option=False) 654 | 655 | parser.version = '%prog version ' + version() 656 | 657 | parser.add_option("", "--help", action="help", help="show this help message") 658 | parser.add_option("-v", "--version", action="version", help="show version") 659 | 660 | parser.add_option("-a", "--all", 661 | action="store_true", dest="show_all", default=False, 662 | help="include filesystems having 0 blocks") 663 | parser.add_option("-h", "--human-readable", 664 | action="store_const", const='-h', dest="sizeformat", 665 | help="print sizes in human readable format (e.g., 1K 234M 2G)") 666 | parser.add_option("-H", "--si", 667 | action="store_const", const='-H', dest="sizeformat", 668 | help="likewise, but use powers of 1000 not 1024") 669 | parser.add_option("-b", "--block-size", 670 | action="store", dest="blocksize", default=0, type="int", 671 | help="use BLOCKSIZE-byte blocks") 672 | parser.add_option("-l", "--local", 673 | action="store_true", dest="local_only", default=False, 674 | help="limit listing to local filesystems") 675 | parser.add_option("-k", "--kilobytes", 676 | action="store_const", const='-k', dest="sizeformat", 677 | help="like --block-size=1024") 678 | parser.add_option("-m", "--megabytes", 679 | action="store_const", const='-m', dest="sizeformat", 680 | help="like --block-size=1048576") 681 | parser.add_option("-g", "--gigabytes", 682 | action="store_const", const='-g', dest="sizeformat", 683 | help="like --block-size=1073741824") 684 | parser.add_option("", "--blocks", 685 | action="store_const", const='--blocks', dest="sizeformat", 686 | help="use filesystem native block size") 687 | parser.add_option("", "--bw", 688 | action="store_true", dest="b_w", default=False, 689 | help="do not use colours") 690 | #parser.add_option("", "--sum", 691 | # action="store_true", dest="do_total_sum", default=False, 692 | # help="display sum of all the displayed sizes") 693 | parser.add_option("-S", "--scale-bars", 694 | action="store_const", const='-P', dest="scale_bars", 695 | help="scale bars to largest disk size") 696 | parser.add_option("", "--mounts", 697 | action="store", dest="mounts_file", type="string", 698 | help="""File to get mount information from. 699 | On normal Linux systems only /etc/mtab or /proc/mounts make sense. 700 | Some other Unices use /etc/mnttab. 701 | Use /proc/mounts when /etc/mtab is corrupted or inaccessible 702 | (the output looks a bit weird in this case).""") 703 | parser.add_option("-B", "--show-binds", 704 | action="store_false", dest="hidebinds", default=hidebinds, 705 | help="show 'mount --bind' mounts") 706 | parser.add_option("-i", "--inodes", 707 | action="store_true", dest="inodes", default=False, 708 | help="show inode instead of block usage") 709 | 710 | (options, args) = parser.parse_args() 711 | 712 | blocksize = options.blocksize 713 | allfss = options.show_all 714 | localonly = options.local_only 715 | hidebinds = options.hidebinds 716 | inodes = options.inodes 717 | if inodes: 718 | header["size"] = "Nodes" 719 | 720 | if options.sizeformat: 721 | sizeformat = options.sizeformat 722 | 723 | #if options.do_total_sum: 724 | # do_total_sum = True 725 | 726 | if options.b_w or os.environ.get('NO_COLOR'): 727 | normal_colour = header_colour = local_fs_colour = remote_fs_colour = readonly_fs_colour = special_fs_colour = filled_fs_colour = full_fs_colour = 'none' 728 | if options.mounts_file: 729 | mountfile = options.mounts_file 730 | 731 | terminal_width = get_terminal_width() 732 | 733 | mountpoints = get_all_mountpoints() 734 | mountpoints = identify_bind_mounts(mountpoints) 735 | 736 | if args: 737 | mp_to_display = [find_mountpoint(os.path.realpath(x)) for x in args] 738 | mp_to_display = [x for x in mp_to_display if x is not None] 739 | else: 740 | mp_to_display = list(mountpoints.keys()) 741 | if localonly: 742 | mp_to_display = [x for x in mp_to_display if not is_remote_fs(mountpoints[x][1])] 743 | mp_to_display.sort() 744 | 745 | table = get_table(mp_to_display) 746 | display_table(table, terminal_width, options.scale_bars) 747 | 748 | --------------------------------------------------------------------------------