README.md

# DiskSpace

A small Elixir library that provides functions to retrieve disk usage statistics for a given filesystem path.

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.

## Features

- 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)
- Optional conversion of results from bytes into human-readable strings
- Supports Linux, macOS, BSD, and Windows (via native NIFs)
- Provides both safe (`stat/2`) and bang (`stat!/2`) variants (with `opts` keyword-list options for human-readable output), the latter raising on errors

## Installation

Add [`disk_space`](https://hex.pm/packages/disk_space) to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:disk_space, "~> 0.2.1"}
  ]
end
```

## Build requirements

Since DiskSpace includes native code, you need the following build tools and development headers depending on your operating system:

### Linux

- `build-essential` (for `gcc`, `make`, etc.)
- `erlang-dev` or `erlang-erts-dev` (Erlang development headers)
- `libc` development headers (usually installed by default)

Example on Debian and its derivatives:

> `sudo apt-get install build-essential erlang-dev`

### macOS

- Xcode Command Line Tools (for gcc and make)
- Erlang installed via [Homebrew](https://brew.sh/) or other means

> `xcode-select --install`

### FreeBSD, NetBSD, DragonflyBSD, OpenBSD

- Appropriate compiler and make tools (usually available by default)
- Erlang development headers (install via `ports` or pkg manager)

### Windows

- Visual Studio with C++ build tools
- Erlang installed with development headers
- `nmake` or `mingw32-make` as your make tool

## Usage example

```elixir
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("/home/tisaak") |> DiskSpace.humanize(:decimal)
{:ok,
 %{
   free: "43.86 GB",
   total: "225.04 GB",
   used: "181.18 GB",
   available: "32.35 GB"
 }}
iex(6)> DiskSpace.stat("/yolo/swag")
{:error,
 %{
   info: %{errno: 2, errstr: ~c"No such file or directory"},
   reason: :not_directory
 }}
iex(7)> DiskSpace.stat!("/yolo/swag")
** (DiskSpace.Error) DiskSpace error: {:error, %{info: nil, reason: %{info: %{errno: 2, errstr: ~c"No such file or directory"}, reason: :not_directory}}}
    (disk_space 0.1.1) lib/disk_space.ex:85: DiskSpace.stat!/2
    iex:7: (file)
```

## Error-handling

- `stat/2` returns `{:ok, stats_map}` or `{:error, info}`, where `info` is a map with populated `:reason` (atom) and `:info` (map or `nil`) with more information, if provided by the NIF.
- `stat!/2` returns `stats_map` or raises `DiskSpace.Error` with `stat/2`'s `{:error, info}` as the message.

## Alternatives

Add [`:os_mon`](https://erlang.org/documentation/doc-16-rc2/lib/os_mon-2.11/doc/html/os_mon_app.html) in `:extra_applications` in `mix.exs`, then use [get_disk_info/1](https://erlang.org/documentation/doc-16-rc2/lib/os_mon-2.11/doc/html/disksup.html#get_disk_info/1) of [`disksup`](https://erlang.org/documentation/doc-16-rc2/lib/os_mon-2.11/doc/html/disksup.html) service.

## Comparison to using `:os_mon`/`disksup`

| 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?          | Probably 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)                                                                                                                                                                                                                                                                        |

## Use of GenAI

`c_src/disk_space.c` was incrementally generated/adapted by xAI's Grok 3 model over multiple rounds of prompting for reviews and improvements that were suggested by Grok 3, GPT-5 and Gemini 2.5 Flash.

## Caveats

- Only tested on Debian Linux 12.
- _Should_ work on all POSIX systems, including the BSDs, but haven't tested it.
- _Should_ work on macOS, but I have no Apple PCs anymore to test it out.
- _Should_ work on Windows, but I have no Windows machines to test it with.
- The tests do not cover multiplatform compatibility.

Improvements, fixes and suggestions about potential issues welcome. Kindly submit a PR.

## License

Apache-2.0

## Documentation

For more details, see the documentation at https://hexdocs.pm/disk_space.

## Discussion thread

[ElixirForum: DiskSpace - retrieve disk usage statistics for a given filesystem path](https://elixirforum.com/t/diskspace-retrieve-disk-usage-statistics-for-a-given-filesystem-path/72064)