{"id":18151307,"url":"https://github.com/msantos/libenospace","last_synced_at":"2025-04-28T17:48:47.257Z","repository":{"id":136621434,"uuid":"174348505","full_name":"msantos/libenospace","owner":"msantos","description":"Process-based disk usage limits","archived":false,"fork":false,"pushed_at":"2023-09-24T11:48:12.000Z","size":12,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-30T11:41:39.937Z","etag":null,"topics":["disk-space","ld-preload","ldpreload"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/msantos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2019-03-07T13:25:16.000Z","updated_at":"2024-03-21T05:54:02.000Z","dependencies_parsed_at":"2023-09-29T10:49:52.304Z","dependency_job_id":null,"html_url":"https://github.com/msantos/libenospace","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msantos%2Flibenospace","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msantos%2Flibenospace/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msantos%2Flibenospace/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msantos%2Flibenospace/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/msantos","download_url":"https://codeload.github.com/msantos/libenospace/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251359847,"owners_count":21577174,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["disk-space","ld-preload","ldpreload"],"created_at":"2024-11-02T01:07:18.110Z","updated_at":"2025-04-28T17:48:47.214Z","avatar_url":"https://github.com/msantos.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# libenospace\n\nlibenospace: set disk usage limits for a process\n\nlibenospace works by intercepting calls to `write(2)` using `LD_PRELOAD`.\n\n## Build\n\n```\nmake\n```\n\n## Example\n\n```\n# simulate a full disk\nLD_PRELOAD=libenospace.so LIBENOSPACE_AVAIL=-1 sh -c \"yes \u003e test\"\n\n# limit free space to 10Gb\nLD_PRELOAD=libenospace.so LIBENOSPACE_OPT=bytes \\\n    LIBENOSPACE_AVAIL=$((10*1024*1024*1024)) vim\n```\n\n## Environment Variables\n\n`LIBENOSPACE_OPT`\n: Specify whether the minimum available free disk space is calculated\nas a percentage or in bytes:\n\n```\n    percent: percentage of free disk space (default)\n    bytes: free disk space in bytes\n```\n\n`LIBENOSPACE_AVAIL`\n: Set the minimum free disk space.\n\n```\n    0: never enforce disk space limits\n    -1: always enforce disk space limits\n    \u003e0: disk usage limit as percentage (default) or in bytes\n        (see `LIBENOSPACE_OPT`)\n```\n\n`LIBENOSPACE_ERRNO`\n: Sets the value to return on write failures (default: ENOSPC).\n\n`LIBENOSPACE_DEBUG`\n: Write errors and informational messages to stderr.\n\n## Limitations\n\n* libenospace requires the program to be dynamically linked\n\n  libenospace will not work with statically linked programs or programs\n  directly making syscalls.\n\n* currently libenospace only enforces usage limits on:\n\n  * extfs (ext2, ext3, ext4)\n  * ecryptfs\n  * btrfs\n\n* usage limits apply to all filesystems the program accesses\n\n  For example, a program writing to /home and /opt may have writes to\n  /opt succeed while writes to /home fail, if /home does not have the\n  minimum available space.\n\n* overhead: for regular files, libenospace makes 2 additional syscalls\n  per write(2)\n\n  For all file descriptors (sockets, pipes, char devices), libenospace\n  calls `fstat(2)`.\n\n* disk usage limits do not check the number of inodes\n\n* disk usage limits apply to the following syscalls:\n\n  ```\n    write(2)\n    writev(2)\n    pwrite(2)\n    pwritev(2)\n  ```\n\n## Rationale\n\nDisk space is a shared resource. If multiple processes share disk space,\nany process can monopolize usage.\n\nProcesses may be otherwise isolated using Linux containers: running in\nseparate namespaces, under unique UIDs, bind mounting directories on a\ncommon disk.\n\nIsolating disk usage usually requires administrative intervention and\ndedicating space to each process.\n\nlibenospace lets processes opt into disk usage limits without requiring\nany special privileges.\n\n## Alternatives\n\n### Bind Mounts\n\nBind mounts do not support disk usage limits.\n\n### Partitions\n\nNew partitions can be created for each process:\n\n* requires root privileges\n\n* a new partition must be created for each process\n\n* depending on the underlying file system and volume management, may be\n  inflexible and may require interruption of service\n\n### Loopback Mounts\n\nCreate a sparse file on the disk and mount within the container:\n\n* requires root privileges\n\n* since loopback mounts are sparse files, no disk space is used\n\n  The disk image is sparse. If it is not used, actual disk usage is\n  minimal. If the disk is used at all, e.g., writing and deleting files,\n  the full disk image will eventually be used.\n\n  Since the loop device is created on an existing partition, care must\n  be taken to leave appropriate space for other processes.\n\n### Disk Quota\n\n* requires root privileges\n\n* quotas are per user not per process\n\n* accounting overhead\n\n* the quota system is designed for administrators setting limits for\n  human users, not for services running under a dedicated UID\n\n### fuse\n\n* requires root privileges or setuid executables\n\n[fusequota](https://github.com/floriandejonckheere/fusequota)\n\n### Resource Limits\n\nProcesses can restrict the maximum writable size of a file by calling\n`setrlimit(RLIMIT_FSIZE)`.\n\nIf the file size exceeds the limit, the process will be sent a `SIGXFSZ`\nsignal. By default, the signal will cause the process to exit but the\nsignal can be ignored:\n\n```shell\n#!/bin/bash\n\nset -o errexit\nset -o nounset\nset -o pipefail\n\n# ignore the signal\n# write will return -1\ntrap '' XFSZ\n\n# disable file writes\nulimit -f 0\n\n# test: File too large\nyes \u003e test\n```\n\n* no special privileges required\n\n* can be set per process\n\n* only effective if the program writes to one file, e.g., a log\n\n  The process can write many files of the maximum file size\n  until the disk space is full or the inode limit is reached.\n\n* if the maximum file size is set to 0, the process can still create 0\n  byte files and truncate existing files\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmsantos%2Flibenospace","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmsantos%2Flibenospace","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmsantos%2Flibenospace/lists"}