chroot-distro 2.3.2__tar.gz → 2.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.github/workflows/ci.yml +2 -2
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.github/workflows/codeql.yml +1 -1
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/PKG-INFO +39 -17
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/README.md +38 -16
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/pyproject.toml +1 -1
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/help/pages.py +36 -18
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/info.py +100 -14
- chroot_distro-2.4.0/src/chroot_distro/commands/kernel_config.py +323 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/kill.py +18 -1
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/login/__init__.py +315 -22
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/login/bindings.py +104 -21
- chroot_distro-2.4.0/src/chroot_distro/commands/ps.py +132 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/completions/_chroot-distro +3 -3
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/completions/chroot-distro.bash +1 -1
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/completions/chroot-distro.fish +4 -4
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/constants.py +1 -0
- chroot_distro-2.4.0/src/chroot_distro/helpers/max_iso_holder.py +167 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/mount_manager.py +127 -44
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/namespace.py +195 -17
- chroot_distro-2.4.0/src/chroot_distro/helpers/session_registry.py +212 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/parser.py +9 -3
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/paths.py +13 -1
- chroot_distro-2.4.0/tests/unit/test_kernel_config.py +186 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_kill.py +87 -8
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_login_helpers.py +283 -2
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_namespace.py +5 -1
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_parser.py +25 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_paths.py +9 -0
- chroot_distro-2.4.0/tests/unit/test_session.py +264 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/uv.lock +1 -1
- chroot_distro-2.3.2/check-config.sh +0 -429
- chroot_distro-2.3.2/src/chroot_distro/commands/ps.py +0 -56
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.editorconfig +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.github/codeql/codeql-config.yml +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.github/dependabot.yml +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.github/workflows/publish.yml +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.gitignore +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.python-version +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/LICENSE +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/check-before-commit.sh +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/__init__.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/arch.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/atomic.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/cli.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/backup.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/build.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/clear_cache.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/copy.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/diff.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/help/__init__.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/help/render.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/install.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/install_local.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/list_cmd.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/login/chroot_cmd.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/login/env.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/login/passwd.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/push.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/remove.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/rename.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/reset.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/restore.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/run.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/search.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/sync.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/unmount.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/elevate.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/exceptions.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/__init__.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/android.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_cache.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/__init__.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/constants.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/copy_step.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/dockerignore.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/engine.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/errors.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/handlers.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/parsing.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/run_step.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/stage.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/users.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/display.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/__init__.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/cache.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/layers.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/media.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/pull.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/push.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/refs.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/transport.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/dockerfile.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/download.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/gpu.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/layer_diff.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/nvidia.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/oci_writer.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/rootfs.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/session.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/sound.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/tar_extract.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/wayland.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/x11.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/locking.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/message.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/names.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/progress.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/py.typed +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/rate_limit.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/conftest.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_android.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_arch.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_backup_restore.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_bind_options.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_cli.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_constants.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_diff_baseline_cache.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_display.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_display_sockets.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_docker_refs.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_dockerfile.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_download_algorithms.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_download_blob_multi.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_download_multi.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_elevate.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_gpu.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_info.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_install.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_install_local.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_layer_diff.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_list.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_locking.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_message.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_mount_manager_ns.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_names.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_progress.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_push_chunked.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_remove.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_rootfs.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_sound.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_tar_extract.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_unmount.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_wayland.py +0 -0
- {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_x11.py +0 -0
|
@@ -13,7 +13,7 @@ jobs:
|
|
|
13
13
|
|
|
14
14
|
steps:
|
|
15
15
|
- name: Checkout Code
|
|
16
|
-
uses: actions/checkout@
|
|
16
|
+
uses: actions/checkout@v7
|
|
17
17
|
|
|
18
18
|
- name: Set up Python
|
|
19
19
|
uses: actions/setup-python@v6
|
|
@@ -47,7 +47,7 @@ jobs:
|
|
|
47
47
|
|
|
48
48
|
steps:
|
|
49
49
|
- name: Checkout Code
|
|
50
|
-
uses: actions/checkout@
|
|
50
|
+
uses: actions/checkout@v7
|
|
51
51
|
|
|
52
52
|
- name: Set up Python ${{ matrix.python-version }}
|
|
53
53
|
uses: actions/setup-python@v6
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chroot-distro
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: chroot-distro is a lightweight Linux container management utility built around chroot.
|
|
5
5
|
Project-URL: Homepage, https://github.com/sabamdarif/chroot-distro
|
|
6
6
|
Project-URL: Repository, https://github.com/sabamdarif/chroot-distro
|
|
@@ -65,7 +65,7 @@ when needed (see [First-run check](#first-run-check)).
|
|
|
65
65
|
* [`login`](#login--start-a-shell-inside-a-container)
|
|
66
66
|
* [`run`](#run--run-the-image-defined-entrypoint)
|
|
67
67
|
* [`list`](#list--list-installed-containers)
|
|
68
|
-
* [`ps`](#ps--list-
|
|
68
|
+
* [`ps`](#ps--list-active-sessions)
|
|
69
69
|
* [`search`](#search--search-docker-hub)
|
|
70
70
|
* [`diff`](#diff--inspect-filesystem-changes)
|
|
71
71
|
* [`remove`](#remove--delete-a-container)
|
|
@@ -192,7 +192,7 @@ chroot-distro push myuser/myapp:1.0
|
|
|
192
192
|
# Rebuild from scratch (loses all in-container data)
|
|
193
193
|
chroot-distro reset ubuntu
|
|
194
194
|
|
|
195
|
-
# List
|
|
195
|
+
# List active sessions (PID, container, type, user, uptime, command)
|
|
196
196
|
chroot-distro ps
|
|
197
197
|
|
|
198
198
|
# Search Docker Hub for an image
|
|
@@ -207,8 +207,9 @@ chroot-distro diff ubuntu
|
|
|
207
207
|
# Unmount bindings and end active sessions
|
|
208
208
|
chroot-distro unmount ubuntu
|
|
209
209
|
|
|
210
|
-
# Forcibly stop a running container (SIGKILL + unmount)
|
|
210
|
+
# Forcibly stop a running container (SIGKILL + unmount), by name or session PID
|
|
211
211
|
chroot-distro kill ubuntu
|
|
212
|
+
chroot-distro kill 12345
|
|
212
213
|
|
|
213
214
|
# Permanently remove a container (unmounts active sessions first)
|
|
214
215
|
chroot-distro remove ubuntu
|
|
@@ -733,20 +734,41 @@ printed.
|
|
|
733
734
|
|
|
734
735
|
---
|
|
735
736
|
|
|
736
|
-
### `ps` — List
|
|
737
|
+
### `ps` — List active sessions
|
|
737
738
|
|
|
738
739
|
```
|
|
739
740
|
chroot-distro ps [OPTIONS]
|
|
740
741
|
```
|
|
741
742
|
|
|
742
|
-
List
|
|
743
|
-
|
|
744
|
-
|
|
743
|
+
List every active container session — one row per live `login` or `run`.
|
|
744
|
+
Each session is tracked by a per-PID JSON file under
|
|
745
|
+
`$RUNTIME_DIR/sessions/` with flock-based liveness detection (immune to
|
|
746
|
+
PID recycling and crash-safe). Does not require root.
|
|
747
|
+
|
|
748
|
+
Output columns:
|
|
749
|
+
|
|
750
|
+
| Column | Description |
|
|
751
|
+
|---|---|
|
|
752
|
+
| `PID` | Host PID of the session's chroot process. |
|
|
753
|
+
| `CONTAINER` | Container name. |
|
|
754
|
+
| `TYPE` | `login` or `run` (recorded at session start). |
|
|
755
|
+
| `USER` | User the session runs as. |
|
|
756
|
+
| `UPTIME` | Elapsed time since session start (e.g. `3m12s`, `1h04m`). |
|
|
757
|
+
| `COMMAND` | Inner command line (shell-quoted, truncated to terminal width). |
|
|
758
|
+
|
|
759
|
+
Example output:
|
|
760
|
+
|
|
761
|
+
```
|
|
762
|
+
PID CONTAINER TYPE USER UPTIME COMMAND
|
|
763
|
+
12345 ubuntu login root 3m12s /bin/bash -l
|
|
764
|
+
12388 debian run* root 0m44s nginx -g 'daemon off;'
|
|
765
|
+
|
|
766
|
+
* detached session
|
|
767
|
+
```
|
|
745
768
|
|
|
746
769
|
| Option | Description |
|
|
747
770
|
|---|---|
|
|
748
|
-
| `-
|
|
749
|
-
| `-q`, `--quiet` | Print only container names, one per line. |
|
|
771
|
+
| `-q`, `--quiet` | Print only PIDs, one per line (for scripting). |
|
|
750
772
|
|
|
751
773
|
---
|
|
752
774
|
|
|
@@ -839,14 +861,12 @@ fallback.
|
|
|
839
861
|
### `kill` — Forcibly stop a running container
|
|
840
862
|
|
|
841
863
|
```
|
|
842
|
-
chroot-distro kill CONTAINER
|
|
843
|
-
Aliases: k, stop
|
|
864
|
+
chroot-distro kill (CONTAINER | PID)
|
|
844
865
|
```
|
|
845
866
|
|
|
846
|
-
Forcibly stop a running container
|
|
847
|
-
|
|
848
|
-
mounts are unmounted, and the namespace holder (if any) is released. This
|
|
849
|
-
is the abrupt counterpart to `unmount` (equivalent to `docker kill`).
|
|
867
|
+
Forcibly stop a running container. The argument may be a container name or a session PID shown in `chroot-distro ps`. When a session PID is provided, the entire container that the session belongs to is stopped. Only PIDs from active chroot-distro sessions are accepted; random host PIDs are rejected.
|
|
868
|
+
|
|
869
|
+
All processes inside the container's chroot are sent `SIGTERM` and then `SIGKILL` after a short grace period, the bind mounts are unmounted, and the namespace holder (if any) is released. This is the abrupt counterpart to `unmount` (equivalent to `docker kill`).
|
|
850
870
|
|
|
851
871
|
---
|
|
852
872
|
|
|
@@ -1114,7 +1134,9 @@ Unlike `proot`, which rewrites paths via `ptrace`, Chroot-Distro uses
|
|
|
1114
1134
|
real kernel features:
|
|
1115
1135
|
|
|
1116
1136
|
- **Bind mounts** (`mount --bind`) for host directories inside the guest.
|
|
1117
|
-
- **Session tracking** under `$RUNTIME_DIR/data/<name>/sessions
|
|
1137
|
+
- **Session tracking** under `$RUNTIME_DIR/data/<name>/sessions` (counter)
|
|
1138
|
+
and `$RUNTIME_DIR/sessions/<pid>.json` (per-session registry for `ps`,
|
|
1139
|
+
with `flock`-based liveness detection).
|
|
1118
1140
|
- **Automatic mount/unmount**: the first session mounts; the last session
|
|
1119
1141
|
exiting unmounts everything.
|
|
1120
1142
|
- **Lazy unmount fallback** (`umount -l`) when a target is busy.
|
|
@@ -36,7 +36,7 @@ when needed (see [First-run check](#first-run-check)).
|
|
|
36
36
|
* [`login`](#login--start-a-shell-inside-a-container)
|
|
37
37
|
* [`run`](#run--run-the-image-defined-entrypoint)
|
|
38
38
|
* [`list`](#list--list-installed-containers)
|
|
39
|
-
* [`ps`](#ps--list-
|
|
39
|
+
* [`ps`](#ps--list-active-sessions)
|
|
40
40
|
* [`search`](#search--search-docker-hub)
|
|
41
41
|
* [`diff`](#diff--inspect-filesystem-changes)
|
|
42
42
|
* [`remove`](#remove--delete-a-container)
|
|
@@ -163,7 +163,7 @@ chroot-distro push myuser/myapp:1.0
|
|
|
163
163
|
# Rebuild from scratch (loses all in-container data)
|
|
164
164
|
chroot-distro reset ubuntu
|
|
165
165
|
|
|
166
|
-
# List
|
|
166
|
+
# List active sessions (PID, container, type, user, uptime, command)
|
|
167
167
|
chroot-distro ps
|
|
168
168
|
|
|
169
169
|
# Search Docker Hub for an image
|
|
@@ -178,8 +178,9 @@ chroot-distro diff ubuntu
|
|
|
178
178
|
# Unmount bindings and end active sessions
|
|
179
179
|
chroot-distro unmount ubuntu
|
|
180
180
|
|
|
181
|
-
# Forcibly stop a running container (SIGKILL + unmount)
|
|
181
|
+
# Forcibly stop a running container (SIGKILL + unmount), by name or session PID
|
|
182
182
|
chroot-distro kill ubuntu
|
|
183
|
+
chroot-distro kill 12345
|
|
183
184
|
|
|
184
185
|
# Permanently remove a container (unmounts active sessions first)
|
|
185
186
|
chroot-distro remove ubuntu
|
|
@@ -704,20 +705,41 @@ printed.
|
|
|
704
705
|
|
|
705
706
|
---
|
|
706
707
|
|
|
707
|
-
### `ps` — List
|
|
708
|
+
### `ps` — List active sessions
|
|
708
709
|
|
|
709
710
|
```
|
|
710
711
|
chroot-distro ps [OPTIONS]
|
|
711
712
|
```
|
|
712
713
|
|
|
713
|
-
List
|
|
714
|
-
|
|
715
|
-
|
|
714
|
+
List every active container session — one row per live `login` or `run`.
|
|
715
|
+
Each session is tracked by a per-PID JSON file under
|
|
716
|
+
`$RUNTIME_DIR/sessions/` with flock-based liveness detection (immune to
|
|
717
|
+
PID recycling and crash-safe). Does not require root.
|
|
718
|
+
|
|
719
|
+
Output columns:
|
|
720
|
+
|
|
721
|
+
| Column | Description |
|
|
722
|
+
|---|---|
|
|
723
|
+
| `PID` | Host PID of the session's chroot process. |
|
|
724
|
+
| `CONTAINER` | Container name. |
|
|
725
|
+
| `TYPE` | `login` or `run` (recorded at session start). |
|
|
726
|
+
| `USER` | User the session runs as. |
|
|
727
|
+
| `UPTIME` | Elapsed time since session start (e.g. `3m12s`, `1h04m`). |
|
|
728
|
+
| `COMMAND` | Inner command line (shell-quoted, truncated to terminal width). |
|
|
729
|
+
|
|
730
|
+
Example output:
|
|
731
|
+
|
|
732
|
+
```
|
|
733
|
+
PID CONTAINER TYPE USER UPTIME COMMAND
|
|
734
|
+
12345 ubuntu login root 3m12s /bin/bash -l
|
|
735
|
+
12388 debian run* root 0m44s nginx -g 'daemon off;'
|
|
736
|
+
|
|
737
|
+
* detached session
|
|
738
|
+
```
|
|
716
739
|
|
|
717
740
|
| Option | Description |
|
|
718
741
|
|---|---|
|
|
719
|
-
| `-
|
|
720
|
-
| `-q`, `--quiet` | Print only container names, one per line. |
|
|
742
|
+
| `-q`, `--quiet` | Print only PIDs, one per line (for scripting). |
|
|
721
743
|
|
|
722
744
|
---
|
|
723
745
|
|
|
@@ -810,14 +832,12 @@ fallback.
|
|
|
810
832
|
### `kill` — Forcibly stop a running container
|
|
811
833
|
|
|
812
834
|
```
|
|
813
|
-
chroot-distro kill CONTAINER
|
|
814
|
-
Aliases: k, stop
|
|
835
|
+
chroot-distro kill (CONTAINER | PID)
|
|
815
836
|
```
|
|
816
837
|
|
|
817
|
-
Forcibly stop a running container
|
|
818
|
-
|
|
819
|
-
mounts are unmounted, and the namespace holder (if any) is released. This
|
|
820
|
-
is the abrupt counterpart to `unmount` (equivalent to `docker kill`).
|
|
838
|
+
Forcibly stop a running container. The argument may be a container name or a session PID shown in `chroot-distro ps`. When a session PID is provided, the entire container that the session belongs to is stopped. Only PIDs from active chroot-distro sessions are accepted; random host PIDs are rejected.
|
|
839
|
+
|
|
840
|
+
All processes inside the container's chroot are sent `SIGTERM` and then `SIGKILL` after a short grace period, the bind mounts are unmounted, and the namespace holder (if any) is released. This is the abrupt counterpart to `unmount` (equivalent to `docker kill`).
|
|
821
841
|
|
|
822
842
|
---
|
|
823
843
|
|
|
@@ -1085,7 +1105,9 @@ Unlike `proot`, which rewrites paths via `ptrace`, Chroot-Distro uses
|
|
|
1085
1105
|
real kernel features:
|
|
1086
1106
|
|
|
1087
1107
|
- **Bind mounts** (`mount --bind`) for host directories inside the guest.
|
|
1088
|
-
- **Session tracking** under `$RUNTIME_DIR/data/<name>/sessions
|
|
1108
|
+
- **Session tracking** under `$RUNTIME_DIR/data/<name>/sessions` (counter)
|
|
1109
|
+
and `$RUNTIME_DIR/sessions/<pid>.json` (per-session registry for `ps`,
|
|
1110
|
+
with `flock`-based liveness detection).
|
|
1089
1111
|
- **Automatic mount/unmount**: the first session mounts; the last session
|
|
1090
1112
|
exiting unmounts everything.
|
|
1091
1113
|
- **Lazy unmount fallback** (`umount -l`) when a target is busy.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "chroot-distro"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.4.0"
|
|
8
8
|
description = "chroot-distro is a lightweight Linux container management utility built around chroot."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -9,11 +9,19 @@ from chroot_distro.constants import (
|
|
|
9
9
|
|
|
10
10
|
_ISOLATED_OPT = (
|
|
11
11
|
"--isolated",
|
|
12
|
-
"
|
|
13
|
-
"(mount, PID, UTS, IPC via unshare/nsenter).
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
12
|
+
"Maximum isolation: bind NOTHING from the host plus Linux namespace "
|
|
13
|
+
"isolation (mount, PID, UTS, IPC via unshare/nsenter). The host /dev, "
|
|
14
|
+
"/sys and /proc are NOT bound; the container gets a fresh procfs, a "
|
|
15
|
+
"read-only sysfs and a fresh tmpfs /dev (null, zero, tty, random, "
|
|
16
|
+
"urandom, full) instead. The namespace holder (PID 1) is itself chrooted "
|
|
17
|
+
"into the rootfs and the procfs is mounted with hidepid=2, so there is no "
|
|
18
|
+
"host path to escape through (e.g. 'chroot /proc/1/root' no longer reaches "
|
|
19
|
+
"the host). Requires kernel "
|
|
20
|
+
"namespace support; aborts if unavailable. Sharing flags (--shared-home, "
|
|
21
|
+
"--shared-tmp, --shared-display, --bind) are ignored and a warning is "
|
|
22
|
+
"printed, since they would expose a host path. Use CD_USE_NS=1 instead if "
|
|
23
|
+
"you want namespace isolation but keep the default mounts. Not a full "
|
|
24
|
+
"container runtime (no network namespace).",
|
|
17
25
|
)
|
|
18
26
|
_MINIMAL_OPT = (
|
|
19
27
|
"--minimal",
|
|
@@ -570,10 +578,18 @@ HELP_PAGES: dict[str, dict[str, typing.Any]] = {
|
|
|
570
578
|
),
|
|
571
579
|
("-w, --work-dir [PATH]", "Set the initial working directory."),
|
|
572
580
|
("-e, --env VAR=VALUE", "Set an environment variable. Can be specified multiple times."),
|
|
581
|
+
(
|
|
582
|
+
"-d, --detach",
|
|
583
|
+
"Run the command in the background and return immediately. "
|
|
584
|
+
"Output is written to a per-container log file (its path is "
|
|
585
|
+
"printed) and the container stays mounted. Stop the detached "
|
|
586
|
+
f"command with '{PROGRAM_NAME} kill CONTAINER'.",
|
|
587
|
+
),
|
|
573
588
|
("--get-chroot-cmd", "Print the fully assembled chroot command line and exit without running it."),
|
|
574
589
|
],
|
|
575
590
|
"examples": [
|
|
576
591
|
f"{PROGRAM_NAME} run nextcloud",
|
|
592
|
+
f"{PROGRAM_NAME} run --detach nextcloud",
|
|
577
593
|
f"{PROGRAM_NAME} run ubuntu --isolated -- /bin/echo hi",
|
|
578
594
|
],
|
|
579
595
|
"footer": [
|
|
@@ -591,37 +607,39 @@ HELP_PAGES: dict[str, dict[str, typing.Any]] = {
|
|
|
591
607
|
],
|
|
592
608
|
},
|
|
593
609
|
"kill": {
|
|
594
|
-
"usage": "kill CONTAINER",
|
|
610
|
+
"usage": "kill (CONTAINER | PID)",
|
|
595
611
|
"aliases": ("k", "stop"),
|
|
596
612
|
"summary": (
|
|
597
|
-
"Forcibly stop a running container.
|
|
598
|
-
"
|
|
599
|
-
"
|
|
600
|
-
"
|
|
601
|
-
"
|
|
613
|
+
"Forcibly stop a running container. The argument may be a container "
|
|
614
|
+
"name or a session PID shown by 'ps'. When a PID is given, the "
|
|
615
|
+
"owning container is resolved from the session registry; arbitrary "
|
|
616
|
+
"host PIDs are rejected. All processes inside the container's chroot "
|
|
617
|
+
"are sent SIGTERM and then SIGKILL after a short grace period, the "
|
|
618
|
+
"filesystem bindings are unmounted, and the namespace holder (if any) "
|
|
619
|
+
"is released. This is the abrupt counterpart to 'unmount'."
|
|
602
620
|
),
|
|
603
621
|
"options": [
|
|
604
622
|
("-h, --help", "Show this help."),
|
|
605
623
|
],
|
|
606
624
|
"examples": [
|
|
607
625
|
f"{PROGRAM_NAME} kill ubuntu",
|
|
626
|
+
f"{PROGRAM_NAME} kill 111579",
|
|
608
627
|
],
|
|
609
628
|
},
|
|
610
629
|
"ps": {
|
|
611
630
|
"usage": "ps [OPTIONS]",
|
|
612
631
|
"summary": (
|
|
613
|
-
"List
|
|
614
|
-
"
|
|
615
|
-
"
|
|
632
|
+
"List every active container session (one row per live "
|
|
633
|
+
"login or run). Shows PID, container name, session type "
|
|
634
|
+
"(login or run), user, uptime, and command."
|
|
616
635
|
),
|
|
617
636
|
"options": [
|
|
618
637
|
("-h, --help", "Show this help."),
|
|
619
|
-
("-
|
|
620
|
-
("-q, --quiet", "Print only container names, one per line."),
|
|
638
|
+
("-q, --quiet", "Print only PIDs, one per line (for scripting)."),
|
|
621
639
|
],
|
|
622
640
|
"examples": [
|
|
623
641
|
f"{PROGRAM_NAME} ps",
|
|
624
|
-
f"{PROGRAM_NAME} ps
|
|
642
|
+
f"{PROGRAM_NAME} ps -q",
|
|
625
643
|
],
|
|
626
644
|
},
|
|
627
645
|
"diff": {
|
|
@@ -753,7 +771,7 @@ TOP_COMMANDS = [
|
|
|
753
771
|
("sync", "Sync files from/to container."),
|
|
754
772
|
("build", "Build an OCI image from a Dockerfile."),
|
|
755
773
|
("push", "Push a locally built image to a registry."),
|
|
756
|
-
("ps", "List
|
|
774
|
+
("ps", "List active container sessions."),
|
|
757
775
|
("kill", "Forcibly stop a running container."),
|
|
758
776
|
("diff", "Inspect filesystem changes in a container."),
|
|
759
777
|
("search", "Search Docker Hub for images."),
|
|
@@ -6,6 +6,18 @@ import subprocess
|
|
|
6
6
|
from dataclasses import dataclass, field
|
|
7
7
|
|
|
8
8
|
from chroot_distro.arch import detect_installed_arch, get_device_cpu_arch, supports_32bit
|
|
9
|
+
from chroot_distro.commands.kernel_config import (
|
|
10
|
+
CONFIG_BUILTIN,
|
|
11
|
+
CONFIG_MODULE,
|
|
12
|
+
CONFIG_UNKNOWN,
|
|
13
|
+
KERNEL_FLAG_GROUPS,
|
|
14
|
+
PROBE_ABSENT,
|
|
15
|
+
PROBE_PRESENT,
|
|
16
|
+
find_kernel_config,
|
|
17
|
+
lookup_flag,
|
|
18
|
+
parse_kernel_config,
|
|
19
|
+
probe_flag_runtime,
|
|
20
|
+
)
|
|
9
21
|
from chroot_distro.commands.list_cmd import (
|
|
10
22
|
_ensure_manifest_readable,
|
|
11
23
|
_iter_container_names,
|
|
@@ -525,22 +537,95 @@ def _render_capabilities(caps: list[_Capability]) -> None:
|
|
|
525
537
|
)
|
|
526
538
|
|
|
527
539
|
|
|
540
|
+
def _flag_status(flag, parsed: dict | None) -> tuple[str, str, str, bool]:
|
|
541
|
+
"""Resolve one kernel flag to (glyph, color, state_text, counts_as_missing).
|
|
542
|
+
|
|
543
|
+
Uses the static kernel config when available; otherwise falls back to a
|
|
544
|
+
live runtime probe (so Android, where /proc/config.gz is root-only and
|
|
545
|
+
`info` runs rootless, still gets a meaningful answer). *counts_as_missing*
|
|
546
|
+
is True only when the option is both required and confirmed absent, so the
|
|
547
|
+
summary line never flags a merely-unknown option as blocking.
|
|
548
|
+
"""
|
|
549
|
+
if parsed is not None:
|
|
550
|
+
status = lookup_flag(parsed, flag.name)
|
|
551
|
+
if status in (CONFIG_BUILTIN, CONFIG_MODULE):
|
|
552
|
+
state = "enabled" if status == CONFIG_BUILTIN else "enabled (module)"
|
|
553
|
+
return _OK, "GREEN", state, False
|
|
554
|
+
if status == CONFIG_UNKNOWN:
|
|
555
|
+
return "\u2022", "CYAN", "unknown", False
|
|
556
|
+
# Confirmed missing in a readable config.
|
|
557
|
+
if flag.required:
|
|
558
|
+
return _BAD, "RED", "missing (required)", True
|
|
559
|
+
return _WARN, "YELLOW", "missing (optional)", False
|
|
560
|
+
|
|
561
|
+
# No static config: probe the live kernel.
|
|
562
|
+
probe = probe_flag_runtime(flag.name)
|
|
563
|
+
if probe == PROBE_PRESENT:
|
|
564
|
+
return _OK, "GREEN", "available (runtime)", False
|
|
565
|
+
if probe == PROBE_ABSENT:
|
|
566
|
+
if flag.required:
|
|
567
|
+
return _BAD, "RED", "unavailable (required)", True
|
|
568
|
+
return _WARN, "YELLOW", "unavailable (optional)", False
|
|
569
|
+
return "\u2022", "CYAN", "unknown", False
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
def _render_kernel_config() -> None:
|
|
573
|
+
"""Show which CONFIG_* options chroot-distro relies on are enabled.
|
|
574
|
+
|
|
575
|
+
Prefers the static kernel build config (``/proc/config.gz`` and friends).
|
|
576
|
+
When that cannot be read (commonly on Android, where /proc/config.gz is
|
|
577
|
+
root-only and `info` runs rootless), it falls back to probing the running
|
|
578
|
+
kernel directly (namespace files, /proc/filesystems, /sys/fs/cgroup) so
|
|
579
|
+
the report stays useful instead of giving up.
|
|
580
|
+
"""
|
|
581
|
+
_render_section("KERNEL CONFIG")
|
|
582
|
+
path, text = find_kernel_config()
|
|
583
|
+
parsed = parse_kernel_config(text) if text is not None else None
|
|
584
|
+
|
|
585
|
+
if parsed is not None:
|
|
586
|
+
msg(f" {C['CYAN']}Read from {path}{C['RST']}")
|
|
587
|
+
else:
|
|
588
|
+
msg(
|
|
589
|
+
f" {C['CYAN']}Kernel config not readable; probing the running "
|
|
590
|
+
f"kernel instead. For a definitive report run "
|
|
591
|
+
f"'CONFIG=/path/to/.config {PROGRAM_NAME} info' or as root.{C['RST']}"
|
|
592
|
+
)
|
|
593
|
+
|
|
594
|
+
missing_required: list[str] = []
|
|
595
|
+
for group in KERNEL_FLAG_GROUPS:
|
|
596
|
+
msg()
|
|
597
|
+
msg(f" {C['WHITE']}{group.title}{C['RST']}")
|
|
598
|
+
label_w = max(len("CONFIG_" + flag.name) for flag in group.flags) + 1
|
|
599
|
+
for flag in group.flags:
|
|
600
|
+
glyph, color, state, counts_missing = _flag_status(flag, parsed)
|
|
601
|
+
if counts_missing:
|
|
602
|
+
missing_required.append("CONFIG_" + flag.name)
|
|
603
|
+
label = "CONFIG_" + flag.name
|
|
604
|
+
msg(
|
|
605
|
+
f" {C[color]}{glyph}{C['RST']} "
|
|
606
|
+
f"{C['CYAN']}{label + ':':<{label_w}}{C['RST']} "
|
|
607
|
+
f"{C['WHITE']}{state}{C['RST']} "
|
|
608
|
+
f"{C['CYAN']}({flag.purpose}){C['RST']}"
|
|
609
|
+
)
|
|
610
|
+
|
|
611
|
+
msg()
|
|
612
|
+
if missing_required:
|
|
613
|
+
msg(
|
|
614
|
+
f" {C['RED']}{_BAD}{C['RST']} "
|
|
615
|
+
f"{C['WHITE']}Namespace isolation (--isolated, CD_USE_NS=1) cannot "
|
|
616
|
+
f"work fully without: {', '.join(missing_required)}.{C['RST']}"
|
|
617
|
+
)
|
|
618
|
+
else:
|
|
619
|
+
msg(
|
|
620
|
+
f" {C['GREEN']}{_OK}{C['RST']} "
|
|
621
|
+
f"{C['WHITE']}All kernel options required for namespace isolation "
|
|
622
|
+
f"are present.{C['RST']}"
|
|
623
|
+
)
|
|
624
|
+
|
|
625
|
+
|
|
528
626
|
def _running_summary(images: list[_ImageInfo]) -> int:
|
|
529
627
|
"""Return the number of containers with live processes or a namespace holder."""
|
|
530
|
-
if
|
|
531
|
-
return 0
|
|
532
|
-
try:
|
|
533
|
-
from chroot_distro.commands.ps import _is_running
|
|
534
|
-
except ImportError:
|
|
535
|
-
return 0
|
|
536
|
-
count = 0
|
|
537
|
-
for img in images:
|
|
538
|
-
try:
|
|
539
|
-
if _is_running(img.name):
|
|
540
|
-
count += 1
|
|
541
|
-
except OSError:
|
|
542
|
-
continue
|
|
543
|
-
return count
|
|
628
|
+
return sum(1 for img in images if img.status != "idle")
|
|
544
629
|
|
|
545
630
|
|
|
546
631
|
def _render_analysis(images: list[_ImageInfo]) -> None:
|
|
@@ -575,6 +660,7 @@ def command_info(args) -> None:
|
|
|
575
660
|
_render_basic()
|
|
576
661
|
_render_host(host, host_arch)
|
|
577
662
|
_render_capabilities(capabilities)
|
|
663
|
+
_render_kernel_config()
|
|
578
664
|
_render_images(images)
|
|
579
665
|
if images:
|
|
580
666
|
msg()
|