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.
Files changed (144) hide show
  1. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.github/workflows/ci.yml +2 -2
  2. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.github/workflows/codeql.yml +1 -1
  3. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/PKG-INFO +39 -17
  4. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/README.md +38 -16
  5. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/pyproject.toml +1 -1
  6. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/help/pages.py +36 -18
  7. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/info.py +100 -14
  8. chroot_distro-2.4.0/src/chroot_distro/commands/kernel_config.py +323 -0
  9. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/kill.py +18 -1
  10. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/login/__init__.py +315 -22
  11. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/login/bindings.py +104 -21
  12. chroot_distro-2.4.0/src/chroot_distro/commands/ps.py +132 -0
  13. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/completions/_chroot-distro +3 -3
  14. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/completions/chroot-distro.bash +1 -1
  15. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/completions/chroot-distro.fish +4 -4
  16. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/constants.py +1 -0
  17. chroot_distro-2.4.0/src/chroot_distro/helpers/max_iso_holder.py +167 -0
  18. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/mount_manager.py +127 -44
  19. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/namespace.py +195 -17
  20. chroot_distro-2.4.0/src/chroot_distro/helpers/session_registry.py +212 -0
  21. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/parser.py +9 -3
  22. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/paths.py +13 -1
  23. chroot_distro-2.4.0/tests/unit/test_kernel_config.py +186 -0
  24. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_kill.py +87 -8
  25. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_login_helpers.py +283 -2
  26. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_namespace.py +5 -1
  27. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_parser.py +25 -0
  28. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_paths.py +9 -0
  29. chroot_distro-2.4.0/tests/unit/test_session.py +264 -0
  30. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/uv.lock +1 -1
  31. chroot_distro-2.3.2/check-config.sh +0 -429
  32. chroot_distro-2.3.2/src/chroot_distro/commands/ps.py +0 -56
  33. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.editorconfig +0 -0
  34. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.github/codeql/codeql-config.yml +0 -0
  35. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.github/dependabot.yml +0 -0
  36. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.github/workflows/publish.yml +0 -0
  37. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.gitignore +0 -0
  38. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/.python-version +0 -0
  39. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/LICENSE +0 -0
  40. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/check-before-commit.sh +0 -0
  41. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/__init__.py +0 -0
  42. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/arch.py +0 -0
  43. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/atomic.py +0 -0
  44. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/cli.py +0 -0
  45. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/backup.py +0 -0
  46. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/build.py +0 -0
  47. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/clear_cache.py +0 -0
  48. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/copy.py +0 -0
  49. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/diff.py +0 -0
  50. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/help/__init__.py +0 -0
  51. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/help/render.py +0 -0
  52. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/install.py +0 -0
  53. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/install_local.py +0 -0
  54. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/list_cmd.py +0 -0
  55. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/login/chroot_cmd.py +0 -0
  56. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/login/env.py +0 -0
  57. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/login/passwd.py +0 -0
  58. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/push.py +0 -0
  59. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/remove.py +0 -0
  60. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/rename.py +0 -0
  61. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/reset.py +0 -0
  62. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/restore.py +0 -0
  63. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/run.py +0 -0
  64. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/search.py +0 -0
  65. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/sync.py +0 -0
  66. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/commands/unmount.py +0 -0
  67. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/elevate.py +0 -0
  68. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/exceptions.py +0 -0
  69. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/__init__.py +0 -0
  70. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/android.py +0 -0
  71. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_cache.py +0 -0
  72. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/__init__.py +0 -0
  73. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/constants.py +0 -0
  74. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/copy_step.py +0 -0
  75. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/dockerignore.py +0 -0
  76. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/engine.py +0 -0
  77. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/errors.py +0 -0
  78. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/handlers.py +0 -0
  79. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/parsing.py +0 -0
  80. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/run_step.py +0 -0
  81. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/stage.py +0 -0
  82. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/build_engine/users.py +0 -0
  83. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/display.py +0 -0
  84. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/__init__.py +0 -0
  85. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/cache.py +0 -0
  86. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/layers.py +0 -0
  87. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/media.py +0 -0
  88. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/pull.py +0 -0
  89. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/push.py +0 -0
  90. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/refs.py +0 -0
  91. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/docker/transport.py +0 -0
  92. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/dockerfile.py +0 -0
  93. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/download.py +0 -0
  94. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/gpu.py +0 -0
  95. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/layer_diff.py +0 -0
  96. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/nvidia.py +0 -0
  97. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/oci_writer.py +0 -0
  98. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/rootfs.py +0 -0
  99. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/session.py +0 -0
  100. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/sound.py +0 -0
  101. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/tar_extract.py +0 -0
  102. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/wayland.py +0 -0
  103. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/helpers/x11.py +0 -0
  104. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/locking.py +0 -0
  105. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/message.py +0 -0
  106. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/names.py +0 -0
  107. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/progress.py +0 -0
  108. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/py.typed +0 -0
  109. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/src/chroot_distro/rate_limit.py +0 -0
  110. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/conftest.py +0 -0
  111. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_android.py +0 -0
  112. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_arch.py +0 -0
  113. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_backup_restore.py +0 -0
  114. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_bind_options.py +0 -0
  115. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_cli.py +0 -0
  116. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_constants.py +0 -0
  117. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_diff_baseline_cache.py +0 -0
  118. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_display.py +0 -0
  119. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_display_sockets.py +0 -0
  120. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_docker_refs.py +0 -0
  121. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_dockerfile.py +0 -0
  122. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_download_algorithms.py +0 -0
  123. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_download_blob_multi.py +0 -0
  124. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_download_multi.py +0 -0
  125. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_elevate.py +0 -0
  126. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_gpu.py +0 -0
  127. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_info.py +0 -0
  128. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_install.py +0 -0
  129. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_install_local.py +0 -0
  130. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_layer_diff.py +0 -0
  131. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_list.py +0 -0
  132. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_locking.py +0 -0
  133. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_message.py +0 -0
  134. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_mount_manager_ns.py +0 -0
  135. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_names.py +0 -0
  136. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_progress.py +0 -0
  137. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_push_chunked.py +0 -0
  138. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_remove.py +0 -0
  139. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_rootfs.py +0 -0
  140. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_sound.py +0 -0
  141. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_tar_extract.py +0 -0
  142. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_unmount.py +0 -0
  143. {chroot_distro-2.3.2 → chroot_distro-2.4.0}/tests/unit/test_wayland.py +0 -0
  144. {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@v4
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@v4
50
+ uses: actions/checkout@v7
51
51
 
52
52
  - name: Set up Python ${{ matrix.python-version }}
53
53
  uses: actions/setup-python@v6
@@ -27,7 +27,7 @@ jobs:
27
27
 
28
28
  steps:
29
29
  - name: Checkout repository
30
- uses: actions/checkout@v4
30
+ uses: actions/checkout@v7
31
31
 
32
32
  - name: Initialize CodeQL
33
33
  uses: github/codeql-action/init@v4
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chroot-distro
3
- Version: 2.3.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-running-containers)
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 only the containers that are currently running
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 running containers
737
+ ### `ps` — List active sessions
737
738
 
738
739
  ```
739
740
  chroot-distro ps [OPTIONS]
740
741
  ```
741
742
 
742
- List only containers that are currently **running** those with a live
743
- process inside their chroot or an active namespace holder. Columns match
744
- `list` (rootfs size, image source, status). Does not require root.
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
- | `-a`, `--all` | Show all installed containers, not just running ones. |
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: all processes inside its chroot are
847
- sent `SIGTERM` and then `SIGKILL` after a short grace period, the bind
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-running-containers)
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 only the containers that are currently running
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 running containers
708
+ ### `ps` — List active sessions
708
709
 
709
710
  ```
710
711
  chroot-distro ps [OPTIONS]
711
712
  ```
712
713
 
713
- List only containers that are currently **running** those with a live
714
- process inside their chroot or an active namespace holder. Columns match
715
- `list` (rootfs size, image source, status). Does not require root.
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
- | `-a`, `--all` | Show all installed containers, not just running ones. |
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: all processes inside its chroot are
818
- sent `SIGTERM` and then `SIGKILL` after a short grace period, the bind
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.3.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
- "Enable Isolated Mode: fewer host bind mounts plus Linux namespace isolation "
13
- "(mount, PID, UTS, IPC via unshare/nsenter). On Termux, skip Android system, "
14
- "storage, and $PREFIX bindings unless requested with --shared-* or --bind. "
15
- "On Linux, skip default /tmp and display sharing unless --shared-tmp or "
16
- "--shared-display. Not a full container runtime (no network namespace).",
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. All processes inside the "
598
- "container's chroot are sent SIGTERM and then SIGKILL after a "
599
- "short grace period, the filesystem bindings are unmounted, and "
600
- "the namespace holder (if any) is released. This is the abrupt "
601
- "counterpart to 'unmount'."
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 running containers: those with a live process inside their "
614
- "chroot or an active namespace holder. Shows rootfs size, image "
615
- "source, and status, like 'list'."
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
- ("-a, --all", "Show all installed containers, not just running ones."),
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 --all",
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 running containers."),
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 not images:
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()