{"id":21631075,"url":"https://github.com/nunum/linux_namespaces_tutorial","last_synced_at":"2025-08-23T06:30:43.185Z","repository":{"id":114413196,"uuid":"160585462","full_name":"NunuM/linux_namespaces_tutorial","owner":"NunuM","description":"Tutorial of Linux Namespaces","archived":false,"fork":false,"pushed_at":"2018-12-05T22:18:05.000Z","size":16,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-22T17:08:03.888Z","etag":null,"topics":["linux","namespaces","tutorial"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NunuM.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-12-05T22:15:47.000Z","updated_at":"2021-10-01T09:58:57.000Z","dependencies_parsed_at":"2024-01-21T20:21:40.985Z","dependency_job_id":"5360c075-8d48-459c-b503-cacc66977404","html_url":"https://github.com/NunuM/linux_namespaces_tutorial","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/NunuM/linux_namespaces_tutorial","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NunuM%2Flinux_namespaces_tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NunuM%2Flinux_namespaces_tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NunuM%2Flinux_namespaces_tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NunuM%2Flinux_namespaces_tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NunuM","download_url":"https://codeload.github.com/NunuM/linux_namespaces_tutorial/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NunuM%2Flinux_namespaces_tutorial/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271745670,"owners_count":24813521,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-23T02:00:09.327Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["linux","namespaces","tutorial"],"created_at":"2024-11-25T02:13:07.215Z","updated_at":"2025-08-23T06:30:43.096Z","avatar_url":"https://github.com/NunuM.png","language":null,"readme":"## Linux Namespaces\n\nThe subject of this tutorial is about Linux namespaces, with the objective of understanding and using them in order to implement basic containers. Containers introduces a lightweight kind of virtualization,\nall software that runs inside it, thinks that is running in physically host. Linux since kernel 2.6.23 offers tools to achieve this behaviour, namely Linux namespaces. Today we can use 6 namespaces:\n\n\n| Namespaces        | Constant           | Isolates  |\n| ------------- |:-------------:| -----:|\n| Cgroup    | CLONE_NEWCGROUP | Cgroup root directory  |\n| IPC    | CLONE_NEWIPC | System V IPC, POSIX message queues  |\n| Network    | CLONE_NEWNET | Network devices, stacks, ports, etc.  |\n| Mount    | CLONE_NEWNS | Mount points  |\n| PID |  CLONE_NEWPID | Process IDs  |\n| User |  CLONE_NEWUSER | User and group IDs  |\n| UTS | CLONE_NEWUTS  | Hostname and NIS domain name  |\n\nEach namespace wraps a particular global system resource in an abstraction that makes it appear to the processes within the namespace that they have their own isolated instance of the global resource.\n\n\n## Cgroups\n\nCgroup namspace gives the possibility of administrate a number of resources and set resource limits to them by using certain resources controllers also known as  Cgroup subsystems.\nWith tihs we can adminbstrate CPU, memory, network brandwith and I/O amonsgst hierarchically ordered groups of processes. In the hierarchies the are composed by slices, they dont have any \nprocesses instead, they prodive a blueprint for organizing a hierarchy around processes. A slice can have a scope (transient processes, eg: VM, user sessins) or a service (system services, normally started via systemd).\n\n\nsystemd-------\n\t     !\n         \n\t     !\n         \n       ______!_____\n      !      !\t   !\n    Service Scope  Slice\n\nThere are four default slices:\n\n1) -.slice: The root slice at the top of the Cgrpup tree\n\n2) System.slice: The default place for all system services\n\n3) User.slice: The default +lace for all user sessions\n\n4) Machine.slice: VM and containers.\n\n![SystemD](https://image.ibb.co/jhhW5d/Screenshot_from_2018_05_13_23_28_08.png)\n\n```bash\n# See Cgroup hierarchy of processes\nsystemd-cgls \n\n\n# See the number of tasks, CPU consuption, Memory, I/O\nsystemd-cgtop\n\n#Run transient process in a new sclice \nsystemd-run --unit=top --slice=nuno.slice top -b\n\n\n#Check if is running\nsystemctl status nuno.slice\n\n#Check again\nsystemd-cgls\n\n#stop it\nsystemctl stop nuno.slice\n\n#Apply Cgroup limit\n\n#Run a program that requires 2g of RAM\necho \"while true; do memhog 2g; sleep 2; done\" \u003e memhogtest.sh\n\ncat \u003c\u003cEOF \u003e memhogtest.service\n[Unit]\nAfter=network.target remote-fs.target nss-lookup.target\n\n[Service]\nType=notify\nExecStart=/home/nuno/memtest.sh -DBACKGROUND\nExecStop=/bin/kill -WINCH ${MAINPID}\nkillSignal=SIGTERM\nPrivateTmp=true\n\n[Install]\nWantedBy=multi-user.target\n\nEOF\n\ncp memhogtest.service /usr/lib/systemd/system\n\nsystemctl deamon-reaload\nsystemctl enable memhogtest.service\n\n#Force Ram limit\nsystemctl set-property --runtime memhogtest.service MemoryLimit=1G\n\nsystemctl deamon-reaload\n\n#Check if the proccess was killed\nsystemctl status memhogtest.service\n\n```\n\n![SystemDD](https://image.ibb.co/c7Q7dy/Screenshot_from_2018_05_13_23_30_42.png)\n\n\nOther way of limit process resources is to manipulate the files that kernel expose. To our goal we will limit the memory usage up to 100MB using Cgroups. \nAll containers that will be spawned will be this resource limited. The kernel exposes cgroups through the /sys/fs/cgroup directory.\n\n\n\n```bash\nls /sys/fs/cgroup\n#create new memory group\n\nmkdir /sys/fs/cgroup/memory/cogsi\n\n```\n\n\n![Cg](https://image.ibb.co/erjL0d/Screen_Shot_2018_05_15_at_01_54_24.png)\n\n\nOnce created the kernel creates all files that we can mannually configure. our goal is to set memory up to 100Mb and disable swap\n\n\n\n```bash\necho \"100000000\" \u003e /sys/fs/cgroup/memory/cogsi/memory.limit_in_bytes\necho \"0\" \u003e /sys/fs/cgroup/memory/demo/memory.swappiness\n```\n\nThe special task file, holds all PIDs that will have this policy activated, later on we will show a full container that \nhave this restriction.\n \n## Network\n\nThis let us have isolated network environments on a single host, each nampespace has its own interfaces and routing table.\n\n\n```bash\n#List all inherit namespaces\nip netns\n\n```\n\n\n-----------------------\n!    Linux Kernel     !\n!  ______________     !\n\n!  !_Default NS_!     !\n!_____________________!\n\n\n\nTo our project will have add two namespaces:\n\n1) net1\n\n2) net2\n\n\n```bash\n\nip netstat add net1\nip netstat add net2\n\n```\n\n    Default NS\n                     \n   net1     net2     \n\n\n\n```bash\n#Check if was created\nip netns list\n```\n\nonce a namespace is added, a new file is created in /var/run/netns with the same name as the namespace. Our next goal os to ping each other, using virtual switch.\n\n\n```bash\napt-get install openvswitch-switch\n\n#start\nsystemctl start openvswitch\n\n#Create a virtual switch\novs-vsctl add-br name_switch\n\n#Show created switch\novs-vsctl show\n\n```\n\n\nWe need 2 virtual ethernets to connect each network namespace, we can created a type of veth that create pair of tubes, we conect the one exterminty to the switch an other to the created namespace.\n\n\n```bash\n# netX-netsn will be in namespace, and the netX-ovs will bve on switch side\nip link add net1-netns type veth peer name net1-ovs\nip link add net2-netns type veth peer name net2-ovs\n\n# Connect the netX-netns to the netX namespace\nip link set net1-netns netns net1\nip link set net2-netns netns net2\n\n# Connect netX-ovs to the virtual switch\novs-vsctl add-port name_switch net1-ovs\novs-vsctl add-port name_switch net2-ovs\n\n```\n\n       OpenSwitch\n-------------------\n!  __net1-ovs __ net2-ovs\t\n! !  !\t     !  !  !\n! !--!\t     !--!  !\t\n---!-----------!---\n \n   !\t       !\t\n   !           !\n   !\t       !\t\nnet1-netns   net2-netns  \n   !           ! \n   !           !\n _ !_\t     _ !__\t\n!net1!\t    ! net2!\t\n\n\n```bash\n#Now we can enable the devices in the 'default' namespace\nsudo ip link set net1-ovs up\nsudo ip link set net2-ovs up\n\n#Enable into namespaced land\nsudo ip netns exec net1 ip link set dev lo up\nsudo ip netns exec net1 ip link set dev net1-netns up\n\nsudo ip netns exec net2 ip link set dev lo up\nsudo ip netns exec net2 ip link set dev net2-netns up\n\n#Assign static address\nsudo ip netns exec net1 ip addr add 10.0.0.1/24 dev net1-netns\nsudo ip netns exec net2 ip addr add 10.0.0.2/24 dev net2-netns\n\n#Ping between namespaces using ip command\nsudo ip netns exec net1 ping 10.0.0.2\n\n#Ping between namespaces using a friendly way\nsudo ip netns exec net1 /bin/bash\n#enter inside the namespace\nping 10.0.0.2\n\n```\n\nThis configurations let us have a local netowrk only for namspaces purposes.\n\n![Network](https://image.ibb.co/haAvWJ/Screenshot_from_2018_05_14_00_50_41.png)\n\nOn a fully isolated container (alike docker)\n![Container](https://image.ibb.co/bPGoJy/Screenshot_from_2018_05_14_01_04_04.png)\n\n\n## Mount\n\nThis namespace isolates the mounting points seen by the processes in a namespace. Exists four types or markers that we can give to a specific \nmounting point, the marker determinates the event propragation between them. Currently exists 4 type:\n\n1) MS_SHARED - All events are propageted to his peers\n\n2) MS_PRIVATE - No event is propagated to his peers\n\n3) MS_SLAVE - Events in a master are propagated, but not from slave to the master.\n\n4) MS_UNBINDABLE - Like private, thus  cannot bind mount operation\n\nTo acheive our goal, we will create a master slave configuration. The master will share a read only mounting point that contains config\nfiles and executable files, while the container has their own mounting point, that only it has permission to write. For emulate real block device,\nwe will create RAM disks. RAM disks use the normal RAM in main memory as if it were a partition on a hard drive rather than \nactually accessing the data bus normally used for secondary storage such as hard disk.\n\n```bash\n\nmkfs -q /dev/ram1 8192\nmkfs -q /dev/ram2 8192\n\nmkdir -p /mnt/ram1\nmkdir -p /mnt/ram2\n\nmkfs -t ext4 -q /dev/ram1 8192\nmkfs -t ext4 -q /dev/ram2 8192\n\nmount /dev/ram1 /opt/container/shared\n\nmount --make-shared /opt/container/shared\n\n# Share a read only filesystem into two containers\nmount --bind -o ro /opt/container/shared /opt/container/rootfs/shared\nmount --bind -o ro /opt/container/shared /opt/container/otherfs/shared\n\n```\n\n### Docker Alike Container.\n\nThis leads to the final of this sprint, that we have a program written in C that uses the namepsace API to compose\nallmost all of the mentioned namespaces. Soo far, we already have two network namespaces that can be used by two containers that \nrequire communication, one shared mounting point, that the two can read from, and one that they share.\n\nThis completes by joining to the network namespace with setns sys call, wich have a well known file. Before \nspwan a container we need a container image.\n\n```bash\n# Download image\nwget https://github.com/NunuM/containers/archive/v0.1.0.zip\n\nmkdir -p /opt/container\n\nmv v0.1.0.zip /opt/container\n\ncd /opt/container\n\nunzip v0.1.0.zip\n\ncd -\n\n# Compile the source code\ngcc file.c -o launcher\n\n#spawning a container\n./launcher -n -u -i -m -p -N net1 -M zion chroot /opt/container/rootfs /bin/bash\n\n```\nThis image is based on devian jessie, and has python. Now that we make are in our fresh container,\nrestained by RAM, let's create an hungry python program.\n\n```bash\ncat \u003c\u003cEOF \u003e hungry.py\nf = open(\"/dev/urandom\", \"r\")\ndata = \"\"\n\ni=0\nwhile True:\n    data += f.read(10000000) # 10mb\n    i += 1\n    print \"%dmb\" % (i*10,)\nEOF\n\n/usr/bin/python hungry.py\n\n```\nNote that if we want to execute the script it will fail, since we do not have the special file /dev/urandom, we need to create it.\n\n\n```bash\nmknod -m 444 /dev/urandom c 1 9\n```\n\n\n![Run Inside container](https://image.ibb.co/e59HDy/Screen_Shot_2018_05_15_at_02_49_22.png)\n\nThe script is killed by the control group that is associated with it.\n\nNext we want to have internet access inside the two containers. We almost have all set. To accomplish, was created a port in open vSwitch bridge 'name_switch' that we have created. The port \nwill bind the physically ethernet interface with 'name_switch'. (The host loses the internet connectivity, since the interface is not connected no more to the default IP stack of the system).\nIn order to recover internet connection, two steps were required: 1) remove physically interface address; 2) assign my_bridge with address. The systems will looks like: IP stack -\u003e name_bridge -\u003e enp0s25 \n\n```bash\n#find enp0s25 address\nip addr\n\n#add physicall interface - CAUTION : Lost cconnectivity after this command\novs-vsctl add-port name_switch enp0s25\n\n#delete adrress\nip addr del 192.168.2.60/24 dev enp0s25\n\n#configure name_switch\ndhclient name_switch\n```\n\nTo test the result of the documented steps were launched two containers in two diferrent terminals:\n\n```bash\n#copy a program to a shared filesystem\ncat \u003c\u003cEOF \u003e /opt/container/shared/hungry.py\nf = open(\"/dev/urandom\", \"r\")\ndata = \"\"\n\ni=0\nwhile True:\n    data += f.read(10000000) # 10mb\n    i += 1\n    print \"%dmb\" % (i*10,)\nEOF\n\n#launch zion - terminal 1\n./launcher -i -m -n -p -u -N net1 -H zion chroot /opt/container/rootfs /bin/bash\nping localhost\n\nping 10.0.0.2\n\nping 8.8.8.8\n\nping google.pt\n\n#launch moon - terminal 2\n./launcher -i -m -n -p -u -N net2 -H moon chroot /opt/container/otherfs /bin/bash\n\n```\nAs result\n\n![Inside a container](https://image.ibb.co/jENNFd/Screenshot_from_2018_05_15_14_41_56.png)\n\n\nWe also can install other sofware using apt tool command.\n\n![APT Tool](https://image.ibb.co/koiq1J/Screenshot_from_2018_05_15_14_46_04.png)\n\nrun a program from a shared filesystem\n\n![python prd](https://image.ibb.co/fO9mad/Screenshot_from_2018_05_15_14_48_26.png)\n\nThe last part is to demonstrate how to mount a filesystem in a running container, this will share a mounting point only and only between the two containers,\nevent the parent tree does not see this subtree.\n\n\n```bash\n#We can cat the /sys/fs/cgroup/memory/cogsi/tasks\ncat /sys/fs/cgroup/memory/cogsi/tasks\n\n#or uses ps\nps aux | grep bash\n#and to be sure  send a message to a pseudo-terminal, and repeat the process to find the other container\necho \"Is you container?\" \u003e /dev/pts/18\n\n```\n100% positive that we have find the PID\n\n![telephone ](https://image.ibb.co/ctLv1J/Screenshot_from_2018_05_15_14_57_45.png)\n\n```bash\n#now we can create the private filesystem\nnsenter -m -t [zion_PID] mount --make-slave --read-write /dev/ram2 /opt/container/rootfs/private\nnsenter -m -t [moon_PID] mount --make-slave --read-write /dev/ram1 /opt/container/otherfs/private\n\n#In a zion container - this file only is visible by the two containers\necho \"I am private\" \u003e /private/text.txt\n\n#In moon container\nls /private\n\n#We also can mount proc using this command\nnsenter -p -t [zion_PID] mount -t proc proc /opt/container/rootfs/proc\n```\n\nNsenter command allows us to executes commands inside a running container.\n\n![private](https://image.ibb.co/mxnuTy/Screenshot_from_2018_05_15_15_08_39.png)\n\n![proc](https://image.ibb.co/jdUmad/Screenshot_from_2018_05_15_15_16_24.png)\n\n\n\n```c\n\n#include \u003csched.h\u003e\n#include \u003cunistd.h\u003e\n#include \u003cstdlib.h\u003e\n#include \u003csys/wait.h\u003e\n#include \u003csignal.h\u003e\n#include \u003cfcntl.h\u003e\n#include \u003cstdio.h\u003e\n#include \u003cstring.h\u003e\n#include \u003climits.h\u003e\n#include \u003cerrno.h\u003e\n\n\n#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \\\n                        } while (0)\n\nstruct child_args {\n    char **argv;        /* Command to be executed by child, with arguments */\n    char * hostname;    /* Set Hostname UTS */\n    char * netns;       /* Set network namespace */\n    int    pipe_fd[2];  /* Pipe used to synchronize parent and child */\n};\n\nstatic int verbose;\n\nstatic void\nusage(char *pname)\n{\n    fprintf(stderr, \"Usage: %s [options] cmd [arg...]\\n\\n\", pname);\n    fprintf(stderr, \"Create a child process that executes a shell command in a new user namespace,\\n\");\n    fprintf(stderr, \"Options can be:\\n\\n\");\n#define fpe(str) fprintf(stderr, \"    %s\", str);\n    fpe(\"-i          New IPC namespace\\n\");\n    fpe(\"-m          New mount namespace\\n\");\n    fpe(\"-n          New network namespace\\n\");\n    fpe(\"-p          New PID namespace\\n\");\n    fpe(\"-u          New UTS namespace\\n\");\n    fpe(\"-U          New user namespace\\n\");\n    fpe(\"-M uid_map  Specify UID map for user namespace\\n\");\n    fpe(\"-G gid_map  Specify GID map for user namespace\\n\");\n    fpe(\"            If -M or -G is specified, -U is required\\n\");\n    fpe(\"-N          Join to network namespace\\n\");\n    fpe(\"-H          Set UTS namespace\\n\");\n    fpe(\"-v          Display verbose messages\\n\");\n    fpe(\"\\n\");\n    fpe(\"Map strings for -M and -G consist of records of the form:\\n\");\n    fpe(\"\\n\");\n    fpe(\"    ID-inside-ns   ID-outside-ns   len\\n\");\n    fpe(\"\\n\");\n\n    exit(EXIT_FAILURE);\n}\n\nstatic void update_map(char *mapping, char *map_file)\n{\n    int fd, j;\n    size_t map_len;     /* Length of 'mapping' */\n\n    map_len = strlen(mapping);\n    for (j = 0; j \u003c map_len; j++)\n        if (mapping[j] == ',')\n            mapping[j] = '\\n';\n\n    fd = open(map_file, O_RDWR);\n    if (fd == -1) {\n        fprintf(stderr, \"open %s: %s\\n\", map_file, strerror(errno));\n        exit(EXIT_FAILURE);\n    }\n\n    if (write(fd, mapping, map_len) != map_len) {\n        fprintf(stderr, \"write %s: %s\\n\", map_file, strerror(errno));\n        exit(EXIT_FAILURE);\n    }\n\n    close(fd);\n}\n\nstatic int childFunc(void *arg)\n{\n    struct child_args *args = (struct child_args *) arg;\n    char ch;\n\n    close(args-\u003epipe_fd[1]);\n\n    if (read(args-\u003epipe_fd[0], \u0026ch, 1) != 0) {\n        fprintf(stderr, \"Failure in child: read from pipe returned != 0\\n\");\n        exit(EXIT_FAILURE);\n    }\n\n    if(args-\u003ehostname != NULL \u0026\u0026 strlen(args-\u003ehostname) \u003e 0){\n       if (sethostname(args-\u003ehostname, strlen(args-\u003ehostname)) == -1){\n           errExit(\"sethostname\");\n\t}\n    }\n\n    int nslen = 0;\n    if(args-\u003enetns != NULL \u0026\u0026 (nslen = strlen(args-\u003enetns)) \u003e 0){\n        char * buf = (char *) malloc(124);\n\tsnprintf(buf, nslen + 18, \"/var/run/netns/%s\", args-\u003enetns);\n        int fd = open(buf, O_RDONLY); /* Get file descriptor for namespace */\n        if (fd == -1){\n            errExit(\"open\");\n\t}\n        if (setns(fd, 0) == -1){ /* Join network namespace */\n            errExit(\"setns\");\n\t}\n    }\n\n    /* Execute a shell command */\n\n    execvp(args-\u003eargv[0], args-\u003eargv);\n    errExit(\"execvp\");\n}\n\n#define STACK_SIZE (1024 * 1024)\n\nstatic char child_stack[STACK_SIZE];    /* Space for child's stack */\n\nint main(int argc, char *argv[])\n{\n    int flags, opt, fd,res;\n    pid_t child_pid;\n    struct child_args args;\n    char *uid_map, *gid_map,*hostname,*netns;\n    char map_path[PATH_MAX];\n\n    flags = 0;\n    verbose = 0;\n    gid_map = NULL;\n    uid_map = NULL;\n    while ((opt = getopt(argc, argv, \"+imnpuUM:G:H:N:v\")) != -1) {\n        switch (opt) {\n        case 'i': flags |= CLONE_NEWIPC;        break;\n        case 'm': flags |= CLONE_NEWNS;         break;\n        case 'n': flags |= CLONE_NEWNET;        break;\n        case 'p': flags |= CLONE_NEWPID;        break;\n        case 'u': flags |= CLONE_NEWUTS;        break;\n        case 'v': verbose = 1;                  break;\n        case 'M': uid_map = optarg;             break;\n        case 'G': gid_map = optarg;             break;\n        case 'U': flags |= CLONE_NEWUSER;       break;\n\tcase 'H': args.hostname = optarg;\tbreak;\n\tcase 'N': args.netns = optarg;\t\tbreak;\n        default:  usage(argv[0]);\n        }\n    }\n\n    if ((uid_map != NULL || gid_map != NULL) \u0026\u0026\n            !(flags \u0026 CLONE_NEWUSER))\n        usage(argv[0]);\n\n    args.argv = \u0026argv[optind];\n\n\n    if (pipe(args.pipe_fd) == -1)\n        errExit(\"pipe\");\n\n    /* Create the child in new namespace(s) */\n\n    child_pid = clone(childFunc, child_stack + STACK_SIZE,\n                      flags | SIGCHLD, \u0026args);\n    if (child_pid == -1)\n        errExit(\"clone\");\n\n    /* Parent falls through to here */\n\n    if (verbose)\n        printf(\"%s: PID of child created by clone() is %ld\\n\",\n                argv[0], (long) child_pid);\n\n    /* Update the UID and GID maps in the child */\n\n    if (uid_map != NULL) {\n        snprintf(map_path, PATH_MAX, \"/proc/%ld/uid_map\",\n                (long) child_pid);\n        update_map(uid_map, map_path);\n    }\n    if (gid_map != NULL) {\n        snprintf(map_path, PATH_MAX, \"/proc/%ld/gid_map\",\n                (long) child_pid);\n        update_map(gid_map, map_path);\n    }\n\n    /* Limit child memory */\n    fd = open(\"/sys/fs/cgroup/memory/cogsi/tasks\", O_RDWR);\n    if(fd == -1){\n\terrExit(\"open\");\n    }\n\n    const int n = snprintf(NULL, 0, \"%lu\", (long) child_pid);\n    char buf[n+1];\n    int c = snprintf(buf, n+1, \"%lu\", (long) child_pid);\n\n    res = write(fd, buf, n);\n    if(res == -1){\n        errExit(\"write\");\n    }\n\n    close(args.pipe_fd[1]);\n\n    if (waitpid(child_pid, NULL, 0) == -1)      /* Wait for child */\n        errExit(\"waitpid\");\n\n    if (verbose)\n        printf(\"%s: terminating\\n\", argv[0]);\n\n    exit(EXIT_SUCCESS);\n}\n\n\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnunum%2Flinux_namespaces_tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnunum%2Flinux_namespaces_tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnunum%2Flinux_namespaces_tutorial/lists"}