chorut 0.1.4__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.
- chorut-0.1.4/.gitignore +151 -0
- chorut-0.1.4/LICENSE +21 -0
- chorut-0.1.4/PKG-INFO +341 -0
- chorut-0.1.4/README.md +308 -0
- chorut-0.1.4/chorut/__init__.py +755 -0
- chorut-0.1.4/chorut/__main__.py +9 -0
- chorut-0.1.4/pyproject.toml +77 -0
chorut-0.1.4/.gitignore
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# UV
|
|
86
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
87
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
88
|
+
# commonly ignored for libraries.
|
|
89
|
+
uv.lock
|
|
90
|
+
|
|
91
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
92
|
+
__pypackages__/
|
|
93
|
+
|
|
94
|
+
# Celery stuff
|
|
95
|
+
celerybeat-schedule
|
|
96
|
+
celerybeat.pid
|
|
97
|
+
|
|
98
|
+
# SageMath parsed files
|
|
99
|
+
*.sage.py
|
|
100
|
+
|
|
101
|
+
# Environments
|
|
102
|
+
.env
|
|
103
|
+
.envrc
|
|
104
|
+
.venv
|
|
105
|
+
env/
|
|
106
|
+
venv/
|
|
107
|
+
ENV/
|
|
108
|
+
env.bak/
|
|
109
|
+
venv.bak/
|
|
110
|
+
|
|
111
|
+
# Spyder project settings
|
|
112
|
+
.spyderproject
|
|
113
|
+
.spyproject
|
|
114
|
+
|
|
115
|
+
# Rope project settings
|
|
116
|
+
.ropeproject
|
|
117
|
+
|
|
118
|
+
# mkdocs documentation
|
|
119
|
+
/site
|
|
120
|
+
|
|
121
|
+
# mypy
|
|
122
|
+
.mypy_cache/
|
|
123
|
+
.dmypy.json
|
|
124
|
+
dmypy.json
|
|
125
|
+
|
|
126
|
+
# Pyre type checker
|
|
127
|
+
.pyre/
|
|
128
|
+
|
|
129
|
+
# pytype static type analyzer
|
|
130
|
+
.pytype/
|
|
131
|
+
|
|
132
|
+
# Cython debug symbols
|
|
133
|
+
cython_debug/
|
|
134
|
+
|
|
135
|
+
# Visual Studio Code
|
|
136
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
137
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
138
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
139
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
140
|
+
.vscode/
|
|
141
|
+
|
|
142
|
+
# Ruff stuff:
|
|
143
|
+
.ruff_cache/
|
|
144
|
+
|
|
145
|
+
# PyPI configuration file
|
|
146
|
+
.pypirc
|
|
147
|
+
|
|
148
|
+
# Marimo
|
|
149
|
+
marimo/_static/
|
|
150
|
+
marimo/_lsp/
|
|
151
|
+
__marimo__/
|
chorut-0.1.4/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Antal A. Buss
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
chorut-0.1.4/PKG-INFO
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chorut
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Summary: Python implementation of an enhanced chroot functionality with minimal dependencies
|
|
5
|
+
Project-URL: Homepage, https://github.com/abuss/chorut
|
|
6
|
+
Project-URL: Repository, https://github.com/abuss/chorut.git
|
|
7
|
+
Project-URL: Issues, https://github.com/abuss/chorut/issues
|
|
8
|
+
Project-URL: Documentation, https://github.com/abuss/chorut#readme
|
|
9
|
+
Author: Antal Buss
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: chroot,containers,linux,namespaces
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: System Administrators
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Topic :: System :: Operating System
|
|
24
|
+
Classifier: Topic :: System :: Systems Administration
|
|
25
|
+
Classifier: Topic :: Utilities
|
|
26
|
+
Requires-Python: >=3.12
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pre-commit>=4.3.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# chorut
|
|
35
|
+
|
|
36
|
+
A Python library that provides chroot functionality inspired by arch-chroot with minimal dependencies, using only Python standard library modules.
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
- **Complete chroot setup**: Automatically mounts proc, sys, dev, devpts, shm, run, and tmp filesystems
|
|
41
|
+
- **Custom mounts**: Support for user-defined bind mounts and filesystem mounts
|
|
42
|
+
- **Unshare mode**: Support for running as non-root user using Linux namespaces
|
|
43
|
+
- **Context manager**: Clean automatic setup and teardown
|
|
44
|
+
- **resolv.conf handling**: Proper DNS configuration in chroot
|
|
45
|
+
- **String and list commands**: Execute commands using either list format or string format
|
|
46
|
+
- **Output capture**: Capture stdout and stderr from executed commands
|
|
47
|
+
- **Error handling**: Comprehensive error reporting and cleanup
|
|
48
|
+
- **Zero external dependencies**: Uses only Python standard library
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install chorut
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
### As a Library
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from chorut import ChrootManager
|
|
62
|
+
|
|
63
|
+
# Basic usage as root
|
|
64
|
+
with ChrootManager('/path/to/chroot') as chroot:
|
|
65
|
+
result = chroot.execute(['ls', '-la'])
|
|
66
|
+
|
|
67
|
+
# String commands (parsed with shlex.split)
|
|
68
|
+
with ChrootManager('/path/to/chroot') as chroot:
|
|
69
|
+
result = chroot.execute('ls -la /etc')
|
|
70
|
+
|
|
71
|
+
# Output capture
|
|
72
|
+
with ChrootManager('/path/to/chroot') as chroot:
|
|
73
|
+
result = chroot.execute('cat /etc/hostname', capture_output=True)
|
|
74
|
+
if result.returncode == 0:
|
|
75
|
+
hostname = result.stdout.strip()
|
|
76
|
+
print(f"Hostname: {hostname}")
|
|
77
|
+
|
|
78
|
+
# Non-root usage with unshare mode (requires complete chroot environment)
|
|
79
|
+
with ChrootManager('/path/to/complete/chroot', unshare_mode=True) as chroot:
|
|
80
|
+
result = chroot.execute(['whoami'])
|
|
81
|
+
|
|
82
|
+
# Manual setup/teardown
|
|
83
|
+
chroot = ChrootManager('/path/to/chroot')
|
|
84
|
+
chroot.setup()
|
|
85
|
+
try:
|
|
86
|
+
result = chroot.execute(['bash', '-c', 'echo "Hello from chroot"'])
|
|
87
|
+
finally:
|
|
88
|
+
chroot.teardown()
|
|
89
|
+
|
|
90
|
+
# With custom mounts
|
|
91
|
+
custom_mounts = [
|
|
92
|
+
{
|
|
93
|
+
"source": "/home",
|
|
94
|
+
"target": "home",
|
|
95
|
+
"bind": True,
|
|
96
|
+
"options": "ro" # Read-only bind mount
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"source": "tmpfs",
|
|
100
|
+
"target": "workspace",
|
|
101
|
+
"fstype": "tmpfs",
|
|
102
|
+
"options": "size=1G"
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
with ChrootManager('/path/to/chroot', custom_mounts=custom_mounts) as chroot:
|
|
107
|
+
result = chroot.execute(['df', '-h'])
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### String Commands and Shell Features
|
|
111
|
+
|
|
112
|
+
The `execute` method accepts both list and string commands:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
# List format (recommended for complex commands)
|
|
116
|
+
result = chroot.execute(['ls', '-la', '/etc'])
|
|
117
|
+
|
|
118
|
+
# String format (parsed with shlex.split or auto-wrapped with bash -c)
|
|
119
|
+
result = chroot.execute('ls -la /etc')
|
|
120
|
+
|
|
121
|
+
# Shell features now work automatically (auto_shell=True by default)
|
|
122
|
+
result = chroot.execute('ls | wc -l') # Pipes
|
|
123
|
+
result = chroot.execute('echo hello && echo world') # Logical operators
|
|
124
|
+
result = chroot.execute('echo `date`') # Command substitution
|
|
125
|
+
result = chroot.execute('ls *.txt') # Glob patterns
|
|
126
|
+
result = chroot.execute('echo $HOME') # Variable expansion
|
|
127
|
+
|
|
128
|
+
# Manual shell invocation still works
|
|
129
|
+
result = chroot.execute("bash -c 'ls | wc -l'")
|
|
130
|
+
|
|
131
|
+
# Disable auto-detection by setting auto_shell=False
|
|
132
|
+
chroot_manual = ChrootManager('/path/to/chroot', auto_shell=False)
|
|
133
|
+
result = chroot_manual.execute("bash -c 'ls | wc -l'") # Explicit bash -c needed
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Auto-Detection**: By default (`auto_shell=True`), string commands are automatically analyzed for shell metacharacters (pipes `|`, logical operators `&&`/`||`, redirects `<>`/`>`, command substitution `` `cmd` ``/`$(cmd)`, glob patterns `*`/`?`, variable expansion `$VAR`, etc.). When detected, the command is automatically wrapped with `bash -c`. Simple commands are still parsed with `shlex.split()` for security.
|
|
137
|
+
|
|
138
|
+
### Output Capture
|
|
139
|
+
|
|
140
|
+
Capture command output using the `capture_output` parameter:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
# Capture both stdout and stderr
|
|
144
|
+
result = chroot.execute('cat /etc/hostname', capture_output=True)
|
|
145
|
+
if result.returncode == 0:
|
|
146
|
+
hostname = result.stdout.strip()
|
|
147
|
+
|
|
148
|
+
# Capture with error handling
|
|
149
|
+
result = chroot.execute('ls /nonexistent', capture_output=True)
|
|
150
|
+
if result.returncode != 0:
|
|
151
|
+
error_msg = result.stderr.strip()
|
|
152
|
+
|
|
153
|
+
# Get raw bytes instead of text
|
|
154
|
+
result = chroot.execute('cat binary_file', capture_output=True, text=False)
|
|
155
|
+
binary_data = result.stdout
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Custom Mounts
|
|
159
|
+
|
|
160
|
+
You can specify additional mounts to be set up in the chroot environment. Each mount specification is a dictionary with the following keys:
|
|
161
|
+
|
|
162
|
+
- `source` (required): Source path, device, or filesystem type
|
|
163
|
+
- `target` (required): Target path relative to chroot root
|
|
164
|
+
- `fstype` (optional): Filesystem type (e.g., "tmpfs", "ext4")
|
|
165
|
+
- `options` (optional): Mount options (e.g., "ro", "size=1G")
|
|
166
|
+
- `bind` (optional): Whether this is a bind mount (default: False)
|
|
167
|
+
- `mkdir` (optional): Whether to create target directory (default: True)
|
|
168
|
+
|
|
169
|
+
#### Examples:
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
# Bind mount home directory as read-only
|
|
173
|
+
{
|
|
174
|
+
"source": "/home",
|
|
175
|
+
"target": "home",
|
|
176
|
+
"bind": True,
|
|
177
|
+
"options": "ro"
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
# Create a tmpfs workspace
|
|
181
|
+
{
|
|
182
|
+
"source": "tmpfs",
|
|
183
|
+
"target": "tmp/workspace",
|
|
184
|
+
"fstype": "tmpfs",
|
|
185
|
+
"options": "size=512M,mode=1777"
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
# Bind mount a specific directory
|
|
189
|
+
{
|
|
190
|
+
"source": "/var/cache/pacman",
|
|
191
|
+
"target": "var/cache/pacman",
|
|
192
|
+
"bind": True
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Command Line
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# Basic chroot (requires root)
|
|
200
|
+
sudo chorut /path/to/chroot
|
|
201
|
+
|
|
202
|
+
# Run specific command
|
|
203
|
+
sudo chorut /path/to/chroot ls -la
|
|
204
|
+
|
|
205
|
+
# Non-root mode (requires proper chroot environment)
|
|
206
|
+
chorut -N /path/to/complete/chroot
|
|
207
|
+
|
|
208
|
+
# Specify user
|
|
209
|
+
sudo chorut -u user:group /path/to/chroot
|
|
210
|
+
|
|
211
|
+
# Verbose output
|
|
212
|
+
chorut -v -N /path/to/chroot
|
|
213
|
+
|
|
214
|
+
# Custom mounts
|
|
215
|
+
chorut -m "/home:home:bind,ro" -m "tmpfs:workspace:size=1G" /path/to/chroot
|
|
216
|
+
|
|
217
|
+
# Multiple custom mounts
|
|
218
|
+
chorut -N \
|
|
219
|
+
-m "/var/cache:var/cache:bind" \
|
|
220
|
+
-m "tmpfs:tmp/build:size=2G" \
|
|
221
|
+
/path/to/chroot make -j4
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
#### Command Line Mount Format
|
|
225
|
+
|
|
226
|
+
The `-m/--mount` option accepts mount specifications in the format:
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
SOURCE:TARGET[:OPTIONS]
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
- **SOURCE**: Source path, device, or filesystem type
|
|
233
|
+
- **TARGET**: Target path relative to chroot (without leading slash)
|
|
234
|
+
- **OPTIONS**: Comma-separated mount options (optional)
|
|
235
|
+
|
|
236
|
+
Special options:
|
|
237
|
+
- `bind` - Creates a bind mount
|
|
238
|
+
- Other options are passed to the mount command
|
|
239
|
+
|
|
240
|
+
Examples:
|
|
241
|
+
- `-m "/home:home:bind,ro"` - Read-only bind mount of /home
|
|
242
|
+
- `-m "tmpfs:workspace:size=1G"` - 1GB tmpfs at /workspace
|
|
243
|
+
- `-m "/dev/sdb1:mnt/data:rw"` - Mount device with read-write access
|
|
244
|
+
|
|
245
|
+
### Command Line Options
|
|
246
|
+
|
|
247
|
+
- `-h, --help`: Show help message
|
|
248
|
+
- `-N, --unshare`: Run in unshare mode as regular user
|
|
249
|
+
- `-u USER[:GROUP], --userspec USER[:GROUP]`: Specify user/group to run as
|
|
250
|
+
- `-v, --verbose`: Enable verbose logging
|
|
251
|
+
- `-m SOURCE:TARGET[:OPTIONS], --mount SOURCE:TARGET[:OPTIONS]`: Add custom mount (can be used multiple times)
|
|
252
|
+
|
|
253
|
+
## API Reference
|
|
254
|
+
|
|
255
|
+
### ChrootManager
|
|
256
|
+
|
|
257
|
+
The main class for managing chroot environments.
|
|
258
|
+
|
|
259
|
+
#### Constructor
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
ChrootManager(chroot_dir, unshare_mode=False, custom_mounts=None, auto_shell=True)
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
- `chroot_dir`: Path to the chroot directory
|
|
266
|
+
- `unshare_mode`: Whether to use unshare mode for non-root operation
|
|
267
|
+
- `custom_mounts`: Optional list of custom mount specifications
|
|
268
|
+
- `auto_shell`: Whether to automatically detect shell features in string commands and wrap them with 'bash -c' (default: True)
|
|
269
|
+
|
|
270
|
+
#### Methods
|
|
271
|
+
|
|
272
|
+
- `setup()`: Set up the chroot environment
|
|
273
|
+
- `teardown()`: Clean up the chroot environment
|
|
274
|
+
- `execute(command=None, userspec=None, capture_output=False, text=True)`: Execute a command in the chroot
|
|
275
|
+
|
|
276
|
+
##### execute() Parameters
|
|
277
|
+
|
|
278
|
+
- `command`: Command to execute. Can be:
|
|
279
|
+
- `list[str]`: List of command and arguments (e.g., `['ls', '-la']`)
|
|
280
|
+
- `str`: String command parsed with `shlex.split()` (e.g., `'ls -la'`)
|
|
281
|
+
- `None`: Start interactive shell
|
|
282
|
+
- `userspec`: User specification in format "user" or "user:group"
|
|
283
|
+
- `capture_output`: If `True`, capture stdout and stderr (default: `False`)
|
|
284
|
+
- `text`: If `True`, decode output as text; if `False`, return bytes (default: `True`)
|
|
285
|
+
|
|
286
|
+
##### execute() Return Value
|
|
287
|
+
|
|
288
|
+
Returns a `subprocess.CompletedProcess` object with:
|
|
289
|
+
- `returncode`: Exit code of the command
|
|
290
|
+
- `stdout`: Command output (if `capture_output=True`)
|
|
291
|
+
- `stderr`: Command error output (if `capture_output=True`)
|
|
292
|
+
|
|
293
|
+
##### execute() Examples
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
# List command
|
|
297
|
+
result = chroot.execute(['ls', '-la'])
|
|
298
|
+
|
|
299
|
+
# String command
|
|
300
|
+
result = chroot.execute('ls -la')
|
|
301
|
+
|
|
302
|
+
# With output capture
|
|
303
|
+
result = chroot.execute('cat /etc/hostname', capture_output=True)
|
|
304
|
+
hostname = result.stdout.strip()
|
|
305
|
+
|
|
306
|
+
# Shell features require explicit bash
|
|
307
|
+
result = chroot.execute("bash -c 'ls | wc -l'", capture_output=True)
|
|
308
|
+
line_count = int(result.stdout.strip())
|
|
309
|
+
|
|
310
|
+
# Interactive shell (command=None)
|
|
311
|
+
chroot.execute() # Starts bash shell
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Exceptions
|
|
315
|
+
|
|
316
|
+
- `ChrootError`: Raised for chroot-related errors
|
|
317
|
+
- `MountError`: Raised for mount-related errors
|
|
318
|
+
|
|
319
|
+
## Requirements
|
|
320
|
+
|
|
321
|
+
- Python 3.12+
|
|
322
|
+
- Linux system with mount/umount utilities
|
|
323
|
+
- Root privileges (unless using unshare mode)
|
|
324
|
+
|
|
325
|
+
### Unshare Mode Requirements
|
|
326
|
+
|
|
327
|
+
When using unshare mode (`-N` flag), the following additional requirements apply:
|
|
328
|
+
|
|
329
|
+
- `unshare` command must be available
|
|
330
|
+
- The chroot directory must contain a complete filesystem with:
|
|
331
|
+
- Essential binaries in `/bin`, `/usr/bin`, etc.
|
|
332
|
+
- Required libraries in `/lib`, `/lib64`, `/usr/lib`, etc.
|
|
333
|
+
- Proper directory structure (`/etc`, `/proc`, `/sys`, `/dev`, etc.)
|
|
334
|
+
|
|
335
|
+
**Note**: Unshare mode performs all mount operations within an unshared mount namespace, allowing non-root users to create chroot environments. However, the target directory must still contain a complete, functional filesystem for the chroot to work properly.
|
|
336
|
+
|
|
337
|
+
For example, trying to chroot into `/tmp` will fail because it lacks the necessary binaries and libraries. You need a proper root filesystem (like those created by `debootstrap`, `pacstrap`, or similar tools).
|
|
338
|
+
|
|
339
|
+
## License
|
|
340
|
+
|
|
341
|
+
This project is in the public domain.
|