#!/usr/bin/python
# Python bindings for some Linux system calls.
# These will all raise OSError on failure.
# Adam Sampson <ats@offog.org>

import ctypes

_libc = ctypes.cdll.LoadLibrary("libc.so.6")

# From linux/sched.h
CSIGNAL = 0x000000ff
CLONE_VM = 0x00000100
CLONE_FS = 0x00000200
CLONE_FILES = 0x00000400
CLONE_SIGHAND = 0x00000800
CLONE_PTRACE = 0x00002000
CLONE_VFORK = 0x00004000
CLONE_PARENT = 0x00008000
CLONE_THREAD = 0x00010000
CLONE_NEWNS = 0x00020000
CLONE_SYSVSEM = 0x00040000
CLONE_SETTLS = 0x00080000
CLONE_PARENT_SETTID = 0x00100000
CLONE_CHILD_CLEARTID = 0x00200000
CLONE_DETACHED = 0x00400000
CLONE_UNTRACED = 0x00800000
CLONE_CHILD_SETTID = 0x01000000
CLONE_NEWUTS = 0x04000000
CLONE_NEWIPC = 0x08000000
CLONE_NEWUSER = 0x10000000
CLONE_NEWPID = 0x20000000
CLONE_NEWNET = 0x40000000
CLONE_IO = 0x80000000

def unshare(flags):
    if _libc.unshare(ctypes.c_int(flags)) != 0:
        raise OSError("unshare failed")

def pivot_root(new_root, put_old):
    if _libc.pivot_root(ctypes.c_char_p(new_root), ctypes.c_char_p(put_old)) != 0:
        raise OSError("pivot_root failed")

# From sys/mount.h
MS_RDONLY = 1 << 0
MS_NOSUID = 1 << 1
MS_NODEV = 1 << 2
MS_NOEXEC = 1 << 3
MS_SYNCHRONOUS = 1 << 4
MS_REMOUNT = 1 << 5
MS_MANDLOCK = 1 << 6
MS_DIRSYNC = 1 << 7
MS_NOATIME = 1 << 10
MS_NODIRATIME = 1 << 11
MS_BIND = 1 << 12
MS_MOVE = 1 << 13
MS_REC = 1 << 14
MS_SILENT = 1 << 15
MS_POSIXACL = 1 << 16
MS_UNBINDABLE = 1 << 17
MS_PRIVATE = 1 << 18
MS_SLAVE = 1 << 19
MS_SHARED = 1 << 20
MS_RELATIME = 1 << 21
MS_KERNMOUNT = 1 << 22
MS_I_VERSION =  1 << 23
MS_STRICTATIME = 1 << 24
MS_ACTIVE = 1 << 30
MS_NOUSER = 1 << 31

def mount(source, target, fstype=None, flags=0, data=None):
    if _libc.mount(ctypes.c_char_p(source), ctypes.c_char_p(target),
                   ctypes.c_char_p(fstype), ctypes.c_ulong(flags),
                   ctypes.c_char_p(data)) != 0:
        raise OSError("mount failed")

# From sys/mount.h
MNT_FORCE = 1
MNT_DETACH = 2
MNT_EXPIRE = 4
UMOUNT_NOFOLLOW = 8

def umount2(target, flags=0):
    if _libc.umount2(ctypes.c_char_p(target), ctypes.c_int(flags)) != 0:
        raise OSError("umount2 failed")

# From linux/prctl.h
# This is a subset, since some calls expect pointers as args...
PR_CAPBSET_READ = 23
PR_CAPBSET_DROP = 24
PR_SET_NO_NEW_PRIVS = 38
PR_GET_NO_NEW_PRIVS = 39

def prctl(option, arg2=0, arg3=0, arg4=0, arg5=0):
    rc = _libc.prctl(ctypes.c_int(option),
                     ctypes.c_ulong(arg2), ctypes.c_ulong(arg3),
                     ctypes.c_ulong(arg4), ctypes.c_ulong(arg5))
    if rc == -1:
        raise OSError("prctl failed")
    return rc
