waseigo

waseigo

DiskSpace

Hi everyone, I needed this for a project I’ve been working on, and couldn’t find a simple solution that would work. The solutions in Check disk space inside elixir didn’t work for me.

Looking at how Exqlite deals with NIFs, I wrote a Makefile and then used Grok 3 with numerous rounds to generate the C file for a NIF. I then had GPT-5 and Gemini 2.5 Flash review it, then back to Grok 3 for implementing the suggested improvements, as Grok’s license permits licensing generated code permissively. Back and forth, again and again.

It should work on everything POSIX and on Windows, though I have only tested it on Debian 12. I don’t have Apple computers, and currently don’t run FreeBSD or NetBSD anywhere to try it out there.

What it does

It returns information about total, used, free, and available disk space, using native system calls for accuracy and performance. Optionally converts the results into human-readable strings with kibibytes etc. or kilobytes etc.

Returns disk space metrics as a map with keys:

  • :total — total size of the filesystem
  • :used — bytes currently used
  • :free — bytes free on the filesystem
  • :available — bytes available to the current user (may be less than free due to permissions)

Provides both safe (stat/2) and bang (stat!/2) variants (with opts keyword-list options for human-readable output), the latter raising on errors.

Provides a humanize/2 function to which you can pipe the output of stat/2 and stat!/2 to generate human-readable output, if you don’t want to pass opts to those functions.

Usage example

iex(1)> DiskSpace.stat!("/tmp")
%{
  available: 32389640192,
  free: 43895349248,
  total: 225035927552,
  used: 181140578304
}
iex(2)> DiskSpace.stat("/tmp")
{:ok,
 %{
   available: 32389599232,
   free: 43895308288,
   total: 225035927552,
   used: 181140619264
 }}
iex(3)> DiskSpace.stat("/tmp", humanize: true)
{:ok,
 %{
   available: "30.17 GiB",
   free: "40.88 GiB",
   total: "209.58 GiB",
   used: "168.70 GiB"
 }}
iex(4)> DiskSpace.stat("/tmp", humanize: true, base: :decimal)
{:ok,
 %{
   available: "32.39 GB",
   free: "43.90 GB",
   total: "225.04 GB",
   used: "181.14 GB"
 }}
iex(5)> DiskSpace.stat!("/yolo/swag")
** (DiskSpace.Error) DiskSpace error: :realpath_failed
    (disk_space 0.1.0) lib/disk_space.ex:86: DiskSpace.stat!/2
    iex:5: (file)

Error-handling

  • stat/2 returns {:ok, stats_map} or {:error, reason}
  • stat!/2 returns stats_map or raises DiskSpace.Error

Reporting issues and opening PRs welcome.

https://github.com/waseigo/disk_space

Showing Posts 1 to 8

hauleth

hauleth

Why not use os_mon’s disksup? How does your solution differs?

waseigo

waseigo OP

I couldn’t get os_mon/disksup to start!

waseigo

waseigo OP

Actually, I just got disksup working. I had to add :os_mon to the :extra_applications in mix.exs… Oh well, live and learn!

To answer your question:

Criterion :disksup.get_disk_info/1 disk_space.stat/2 and stat!/2
What it is Function of a supervised process (:os_mon’s :disksup) Function relying on a NIF
Runtime requirements :os_mon in :extra_applications in mix.exs Nothing
Need to compile? No, part of Erlang Yes
Returns Returns total space, available space, and capacity (% of disk space used) Returns total space, used space, free space, available to the current user
Return value type 4-element tuple in list; first element: path as charlist; other elements: integers {:ok, stats_map} or {:error, reason} (stat/2), stats_map or raises exception (stat!/2), where stats_map is a plain Elixir map with atom keys with: integer values (bytes) if option :humanize is false (default), string values (KiB, kB, etc.) if :humanize is true
Return units kibibytes, percentage (as integers) bytes (integers) or human-readable strings with humanize: true, either as KiB etc. (base: :binary, default) or kB etc. (base: :decimal)
Interval 30 minutes (default), configurable with disk_space_check_interval N/A - checks upon invocation
Optional conversion to KiB, kB, etc. No Yes, with DiskSpace.humanize/2
Works with UNCs on Windows? Maybe not (“On WIN32 - All logical drives of type “FIXED_DISK” are checked.”) Should work (not tested / cannot test)
Can alert you? Yes, with :alarm_handler, signal :disk_almost_full, via :os_mon No, use it for “spot checks”
Well tested? Yes No (not yet)
waseigo

waseigo OP

Just published v0.2.1 and deprecated v0.1.0 and v0.2.0.

v0.2.0 reshapes {:error, reason} and {:error, reason, info} tuples coming from the NIF to {:error, %{reason: reason, info: info} for easier pattern-matching on always 2-element error tuples.

v0.2.1 actually works as a dependency… I had forgotten to include c_src in the package :person_facepalming:

Also added the earlier comparison table to README.md, as it was a great question, thanks @hauleth!

NobbZ

NobbZ

Of course there is a runtime requirement… You have to add an entry to the applications deps list, and unless you set runtime: false your app will be loaded and started at runtime.

Please be aware that this is implicit, and compare it to the explicit adding to applications back before elixir 1.5.

waseigo

waseigo OP

Aha, I was not aware of that, thanks!

waseigo

waseigo OP

Version 0.3.0 is up on Hex.pm.

  • Tests now do not rely on mocking
  • Requires OTP 27 on Windows
  • Requires OTP 26 and above on recent Linux and on macOS
  • Works on NetBSD 10.1, FreeBSD 14.3 and OpenBSD 7.7
  • Does not work on DragonFlyBSD 6.4.1 due to OTP 25
  • GitHub Actions workflow added for Linux, macOS, Windows

Supported Elixir and OTP versions

OS Arch. Elixir OTP Builds and mix test passes?
Linux (Ubuntu/Debian) amd64 1.14 25 :cross_mark: errors with Erlang headers
Linux (Ubuntu/Debian) amd64 1.15 26 :white_check_mark:
Linux (Ubuntu/Debian) amd64 1.16 26 :white_check_mark:
Linux (Ubuntu/Debian) amd64 1.17 27 :white_check_mark:
Linux (Ubuntu/Debian) amd64 1.18 27 :white_check_mark:
Linux (Ubuntu/Debian) amd64 1.18.4 28 :white_question_mark: Unknown / not tested
macOS arm64 1.14 25 :cross_mark: errors with Erlang headers
macOS arm64 1.15 26 :white_check_mark:
macOS arm64 1.16 26 :white_check_mark:
macOS arm64 1.17 27 :white_check_mark:
macOS arm64 1.18 27 :white_check_mark:
macOS arm64 1.18.4 28 :white_question_mark: Unknown / not tested
Windows amd64 1.14 25 :cross_mark: errors with Erlang headers
Windows amd64 1.15 26 :cross_mark: errors with Erlang headers
Windows amd64 1.16 26 :cross_mark: errors with Erlang headers
Windows amd64 1.17 27 :white_check_mark:
Windows amd64 1.18 27 :white_check_mark:
Windows amd64 1.18.4 28 :white_question_mark: Unknown / not tested
NetBSD 10.1 amd64 1.17.2 27 :white_check_mark:
FreeBSD 14.3 amd64 1.17.3 26 :white_check_mark:
OpenBSD 7.7 amd64 1.18.3 27 :white_check_mark:
DragonFlyBSD 6.4.2 amd64 1.16.3 25 :cross_mark: errors with Erlang headers

Apologies to those behind the 40+ downloads of the prior versions, for whom it was only working on Linux. First time I’m dealing with a NIF (or GitHub Actions, for that matter)!

waseigo

waseigo OP

v0.4.0 is on Hex.pm, I bumped the minimum Elixir version to 1.15, though it’s really the OTP version that determines things, and using DiskSpace on Windows requires OTP 27 and above, therefore Elixir 1.17.

I deprecated the previous versions.

Also, I wrote down my experience with having Grok 3 write the C source and Makefile (and the build.yml for GitHub Actions) with code reviews by Gemini 2.5 Flash and GPT-5 in a blog post:

— All posts loaded —

Where Next? Top

Trending in Announcing Top

wojtekmach
Hey everyone! Req is an HTTP client for Elixir that I’ve been working on for quite some time. There is already a lot of HTTP clients out...
New
handnot2
Samly can be used to enable SAML 2.0 Single Sign On in a Plug/Phoenix application. This library uses Erlang esaml to provide plug enabl...
New
woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New
MRdotB
I needed to reuse React components from my Chrome extension in my Phoenix/LiveView backend. I noticed that for Svelte/Vue, there are live...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
fuelen
Hi all! I want to present a small library which provides a mix task for generating an Entity-Relationship Diagram for Ecto schemas. You...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
AstonJ
This showed up on my feed.. anyone heard of it? Just hype? Ox Alpha is a reasoning model designed for coding, sustained ag...
New
sergio
It’s not that it’s vocabulary is too advanced. It’s something worse. I get lost trying to follow even a paragraph written by Claude. It’...
New
sorenone
Today we’re releasing Oban for Python. Not an Oban client in Python. Not a pythonx wrapper embedded in Elixir. Nope, it’s a fully operati...
New
akoutmos
@hugobarauna, Dr. Dimitrios Koutmos (my brother) and I (Alex Koutmos) have been hard at work on writing a book on how you can use Elixir ...
New
pferriby
Introductory paragraph I’ll be looking for a keen junior or someone that has a couple of years experience in the real world (so you’ve be...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews