Search code examples
rakudiskspacelinux-disk-free

Raku-native disk space usage


Purpose:

  • Save a program that writes data to disk from vain attempts of writing to a full filesystem;
  • Save bandwidth (don't download if nowhere to store);
  • Save user's and programmer's time and nerves (notify them of the problem instead of having them tearing out their hair with reading misleading error messages and "why the heck this software is not working!").

The question comes in 2 parts:

  1. Reporting storage space statistics (available, used, total etc.), either of all filesystems or of the filesystem that path in question belongs to.
  2. Reporting a filesystem error on running out of space.

Part 1

Share please NATIVE Raku alternative(s) (TIMTOWTDIBSCINABTE "Tim Toady Bicarbonate") to:

raku -e 'qqx{ df -P $*CWD }.print'

Here, raku -executes df (disk free) external program via shell quoting with interpolation qqx{}, feeding -Portable-format argument and $*CWD Current Working Directory, then .prints the df's output.


The snippet initially had been written as raku -e 'qqx{ df -hP $*CWD }.print' — with both -human-readable and -Portable — but it turned out that it is not a ubiquitously valid command. In OpenBSD 7.0, it exits with an error: df: -h and -i are incompatible with -P.
For adding human-readability, you may consider Number::Bytes::Human module


Solution

  • Part 1 — Reporting storage space statistics

    There's no built in function for reporting storage space statistics. Options include:

    • Write Raku code (a few lines) that uses NativeCall to invoke a platform / filesystem specific system call (such as statvfs()) and uses the information returned by that call.

    • Use a suitable Raku library. FileSystem::Capacity picks and runs an external program for you, and then makes its resulting data available in a portable form.

    • Use run (or similar1) to invoke a specific external program such as df.

    • Use an Inline::* foreign language adaptor to enable invoking of a foreign PL's solution for reporting storage space statistics, and use the info it provides.2

    Part 2 — Reporting running out of space

    Raku seems to neatly report No space left on device:

    > spurt '/tmp/failwrite', 'filesystem is full!'
    Failed to write bytes to filehandle: No space left on device
      in block <unit> at <unknown file> line 1
    
    > mkdir '/tmp/failmkdir'
    Failed to create directory '/tmp/failmkdir' with mode '0o777': Failed to mkdir: No space left on device
      in block <unit> at <unknown file> line 1
    

    (Programmers will need to avoid throwing away these exceptions.)

    Footnotes

    1 run runs an external command without involving a shell. This guarantees that the risks attendant with involving a shell are eliminated. That said, Raku also supports use of a shell (because that can be convenient and appropriate in some scenarios). See the exchange of comments under the question (eg this one) for some brief discussion of this, and the shell doc for a summary of the risk:

    All shell metacharacters are interpreted by the shell, including pipes, redirects, environment variable substitutions and so on. Shell escapes are a severe security concern and can cause confusion with unusual file names. Use run if you want to be safe.

    2 Foreign language adaptors for Raku (Raku modules in the Inline:: namespace) allow Raku code to use code written in other languages. These adaptors are not part of the Raku language standard, and most are barely experimental status, if that, but, conversely, the best are in great shape and allow Raku code to use foreign libraries as if they were written for Raku. (As of 2021 Inline::Perl5 is the most polished.)