Skip to content
This repository was archived by the owner on Dec 5, 2022. It is now read-only.

Commit 37e087d

Browse files
committed
initial commit with a working nsenter program
0 parents  commit 37e087d

File tree

5 files changed

+108
-0
lines changed

5 files changed

+108
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
build
2+
dist
3+
*.egg*

README.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
=======
2+
NSEnter
3+
=======

nsenter/__init__.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/usr/bin/env python3
2+
3+
'''
4+
nsenter - run program with namespaces of other processes
5+
'''
6+
7+
import argparse
8+
import ctypes
9+
import os
10+
import shlex
11+
import subprocess
12+
import logging
13+
from pathlib import Path
14+
from contextlib import ExitStack
15+
16+
NAMESPACE_NAMES = frozenset('mnt ipc net pid user uts'.split())
17+
18+
log = logging.getLogger('nsenter')
19+
20+
libc = ctypes.CDLL('libc.so.6')
21+
22+
def nsfd(process:str, ns_type:str) -> Path:
23+
"""
24+
Returns the namespace file descriptor for process (self or PID) and namespace type
25+
"""
26+
return Path('/proc') / process / 'ns' / ns_type
27+
28+
29+
class Namespace:
30+
def __init__(self, pid: str, ns_type: str):
31+
self.pid = pid
32+
self.ns_type = ns_type
33+
self.parent_fd = nsfd('self', ns_type).open()
34+
self.parent_fileno =self.parent_fd.fileno()
35+
self.target_fd = nsfd(pid, ns_type).open()
36+
self.target_fileno =self.target_fd.fileno()
37+
38+
def __enter__(self):
39+
log.debug('Entering %s namespace %s', self.ns_type, self.pid)
40+
libc.setns(self.target_fileno, 0)
41+
42+
def __exit__(self, type, value, tb):
43+
log.debug('Leaving %s namespace %s', self.ns_type, self.pid)
44+
libc.setns(self.parent_fileno, 0)
45+
46+
def main():
47+
parser = argparse.ArgumentParser(description=__doc__)
48+
parser.add_argument('--target', metavar='PID', help='Specify a target process to get contexts from.')
49+
for ns in NAMESPACE_NAMES:
50+
parser.add_argument('--{}'.format(ns), action='store_true', help='Enter the {} namespace'.format(ns))
51+
parser.add_argument('--all', action='store_true', help='Enter all namespaces')
52+
parser.add_argument('command')
53+
54+
args = parser.parse_args()
55+
56+
with ExitStack() as stack:
57+
namespaces = []
58+
for ns in NAMESPACE_NAMES:
59+
if getattr(args, ns) or args.all:
60+
namespaces.append(Namespace(args.target, ns))
61+
for ns in namespaces:
62+
stack.enter_context(ns)
63+
os.execl(args.command, args.command)
64+
65+
66+
if __name__ == '__main__':
67+
main()

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# empty

setup.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/env python3
2+
3+
import inspect
4+
import os
5+
import setuptools
6+
7+
__location__ = os.path.join(os.getcwd(), os.path.dirname(inspect.getfile(inspect.currentframe())))
8+
9+
def get_install_requirements(path):
10+
content = open(os.path.join(__location__, path)).read()
11+
return [req for req in content.split('\\n') if req != '']
12+
13+
def read(fname):
14+
return open(os.path.join(__location__, fname)).read()
15+
16+
def setup_package():
17+
install_reqs = get_install_requirements('requirements.txt')
18+
setuptools.setup(
19+
name='nsenter',
20+
version='0.1',
21+
url='https://github.com/zalando/python-nsenter',
22+
description='',
23+
author='Henning Jacobs',
24+
author_email='[email protected]',
25+
long_description=read('README.rst'),
26+
classifiers=['Development Status :: 4 - Beta', 'Programming Language :: Python'],
27+
test_suite='tests',
28+
packages=setuptools.find_packages(exclude=['tests', 'tests.*']),
29+
install_requires=install_reqs,
30+
entry_points={'console_scripts': ['nsenter = nsenter:main']}
31+
)
32+
33+
if __name__ == '__main__':
34+
setup_package()

0 commit comments

Comments
 (0)