Luigit
repositories / termux-janitor

termux-janitor

Interactive cleanup assistant for Termux: transparent, safe, confirmed disk reclamation.

owned by admin

spec/experiments/candidate_inactivity_and_namespace.md

Raw
Rendered preview

Candidate inactivity and namespace experiment

Question

Do old age, absence from a process file-descriptor table, or host-namespace symlink resolution establish that a filesystem object is disposable?

This tests the recommendation assumptions in PRODUCT.md and the treatment of installed proot-distro roots.

Environment

  • Date: 2026-09-13
  • Kernel: Linux 6.1.176 Android 14, AArch64
  • Compiler: Clang 21.1.8 targeting AArch64 Android
  • Fixtures: fresh private directories below Termux $TMPDIR

Closed but live temporary file

A native C probe synchronized parent and child processes with pipes, without sleeps. The child created a file, set its access and modification timestamps to the Unix epoch, mapped it, closed its file descriptor, and waited before reopening the path. The parent inspected the child's /proc/<pid>/fd entries and memory maps, then deleted the fixture path and allowed the child to continue.

parent: age_eligible=yes fd_reference_observed=no mapping_reference_observed=yes
child: mapping_still_valid=yes reopen_after_cleanup=failed errno=2
parent: cleanup_deleted_live_name=yes child_exit=0

The file was old and absent from the producer's file-descriptor table, but the producer still had a live mapping and required the pathname later. Scanning memory maps would detect this fixture, but would not prove that a closed pathname will not be reopened later. A negative observation is therefore not proof of inactivity.

Package-owned dangling links

The probe compared symlinks listed by the Termux dpkg database with target resolution from the host namespace. It found installed-package-owned links whose targets were currently absent, including:

openssh: $PREFIX/var/service/ssh-agent/log/run
openssh: $PREFIX/var/service/sshd/log/run
termux-x11-nightly: $PREFIX/var/service/tx11/log/run
util-linux-glibc: $PREFIX/glibc/share/bash-completion/completions/runuser

A generic broken-link rule would classify manager-owned configuration as a cleanup candidate. Ownership must therefore be established before generic filesystem eligibility, and unknown ownership must fail closed.

proot namespace resolution

Absolute symlink targets inside installed distro roots were unresolved in the Termux host namespace but present relative to their distro root:

debian/rootfs/etc/alternatives/awk -> /usr/bin/mawk
host target: absent
debian-root-relative target: present

ubuntu/rootfs/etc/alternatives/awk -> /usr/bin/mawk
host target: absent
ubuntu-root-relative target: present

Host-namespace resolution falsely labels these links broken. A symlink's target status is meaningful only in its owning namespace and root context.

Conclusion

Age, no observed open descriptor, and host-namespace target absence do not establish disposability. Generic stale temporary files, rotated logs, and dangling links cannot be safely pre-selected from those observations alone. Producer-specific disposal semantics are required for recommendation. Manager-controlled namespaces require adapter ownership handling, and symlink reports inside distro roots require namespace-aware resolution.

The experiment does not prove that every old temporary file or dangling link is live. It provides concrete counterexamples to treating weak negative evidence as a low-risk rule.

# Candidate inactivity and namespace experiment

## Question

Do old age, absence from a process file-descriptor table, or host-namespace symlink resolution establish that a filesystem object is disposable?

This tests the recommendation assumptions in [`PRODUCT.md`](../PRODUCT.md#62-safe-pre-selection) and the treatment of installed `proot-distro` roots.

## Environment

- Date: 2026-09-13
- Kernel: Linux 6.1.176 Android 14, AArch64
- Compiler: Clang 21.1.8 targeting AArch64 Android
- Fixtures: fresh private directories below Termux `$TMPDIR`

## Closed but live temporary file

A native C probe synchronized parent and child processes with pipes, without sleeps.
The child created a file, set its access and modification timestamps to the Unix epoch, mapped it, closed its file descriptor, and waited before reopening the path.
The parent inspected the child's `/proc/<pid>/fd` entries and memory maps, then deleted the fixture path and allowed the child to continue.

```text
parent: age_eligible=yes fd_reference_observed=no mapping_reference_observed=yes
child: mapping_still_valid=yes reopen_after_cleanup=failed errno=2
parent: cleanup_deleted_live_name=yes child_exit=0
```

The file was old and absent from the producer's file-descriptor table, but the producer still had a live mapping and required the pathname later.
Scanning memory maps would detect this fixture, but would not prove that a closed pathname will not be reopened later.
A negative observation is therefore not proof of inactivity.

## Package-owned dangling links

The probe compared symlinks listed by the Termux dpkg database with target resolution from the host namespace.
It found installed-package-owned links whose targets were currently absent, including:

```text
openssh: $PREFIX/var/service/ssh-agent/log/run
openssh: $PREFIX/var/service/sshd/log/run
termux-x11-nightly: $PREFIX/var/service/tx11/log/run
util-linux-glibc: $PREFIX/glibc/share/bash-completion/completions/runuser
```

A generic broken-link rule would classify manager-owned configuration as a cleanup candidate.
Ownership must therefore be established before generic filesystem eligibility, and unknown ownership must fail closed.

## proot namespace resolution

Absolute symlink targets inside installed distro roots were unresolved in the Termux host namespace but present relative to their distro root:

```text
debian/rootfs/etc/alternatives/awk -> /usr/bin/mawk
host target: absent
debian-root-relative target: present

ubuntu/rootfs/etc/alternatives/awk -> /usr/bin/mawk
host target: absent
ubuntu-root-relative target: present
```

Host-namespace resolution falsely labels these links broken.
A symlink's target status is meaningful only in its owning namespace and root context.

## Conclusion

**Age, no observed open descriptor, and host-namespace target absence do not establish disposability.**
Generic stale temporary files, rotated logs, and dangling links cannot be safely pre-selected from those observations alone.
Producer-specific disposal semantics are required for recommendation.
Manager-controlled namespaces require adapter ownership handling, and symlink reports inside distro roots require namespace-aware resolution.

The experiment does not prove that every old temporary file or dangling link is live.
It provides concrete counterexamples to treating weak negative evidence as a low-risk rule.