The UTS namespace is used to isolate two specific elements of the system that relate to the uname system call. UTS is an abbreviation of UNIX Time Sharing, a term that dates back to the fledgling days of UNIX, when multi-user, multi-tasking operating systems were a novelty.

Ken Thompson & Dennis Ritchie

Ken Thompson & Dennis Ritchie

The UTS namespace is named after the data structure used to store information returned by the uname system call. Specifically, the UTS namespace isolates the hostname and the NIS domain name. NIS, an abbreviation of Network Information Service, is an outdated directory service created by Sun Microsystems for the Solaris operating system, which was discontinued by Oracle after its acquisition of Sun Microsystems. In short, the UTS namespace is about isolating hostnames.

To demonstrate its use, the program we used in the last article about the mount namespace, has been further adapted as invoke_ns3.c, and is available here. Unsurprisingly, we’ve added a new command line option to our program, -u, which must be accompanied with a string that will be used to set the hostname in our newly created UTS namespace:

$ ./invoke_ns -h
Usage: ./invoke_ns [options] [cmd [arg...]]
Options can be:
    -h           display this help message
    -v           display verbose messages
    -p           new PID namespace
    -m           new MNT namespace
    -u hostname  new UTS namespace with associated hostname

We’ve added some code to parse the command line when -u is specified, which adds the CLONE_NEWUTS constant to the clone flags, and stores the hostname in some dynamically allocated memory. The pointer to the memory is passed as part of the args structure to the clone system call, which provides the arguments to childFunction:

// Parse command line options and construct arguments
// to be passed to childFunction
while ((option = getopt(argc, argv, "+hvpmu:")) != -1) {
    switch (option) {
        case 'u':
            flags |= CLONE_NEWUTS;
            args.hostname = malloc(sizeof(char) * (strlen(optarg) + 1));
            strcpy(args.hostname, optarg);
            break;
        case 'm':
            flags |= CLONE_NEWNS;
            break;
        case 'p':
            flags |= CLONE_NEWPID;
            break;
        case 'v':
            args.verbose = 1;
            break;
        case 'h':
            usage(argv[0]);
            exit(EXIT_SUCCESS);
        default:
            usage(argv[0]);
            exit(EXIT_FAILURE);
    }
}

In order to set the hostname inside the new UTS namespace, we need to add some code to childFunction using the sethostname system call:

// Set new hostname in UTS namespace if applicable
if (args->flags & CLONE_NEWUTS)
    if (sethostname(args->hostname, strlen(args->hostname)) == -1)
        perror(" Child: childFunction: sethostname");

Having compiled invoke_ns3.c, we can run the program with sudo ./invoke_ns -vpmu calculus env PS1='\h\[\] [\[\]\w\[\]] ' bash, which will set the hostname inside the new UTS namespace as ‘calculus’. As part of the command that’s specified for the cloned process to run, we’ve set the bash shell prompt (using the environment variable PS1) to include the hostname, which is, of course, ‘calculus’. We can also use the hostname command to echo the hostname set for the UTS namespace:

$ sudo ./invoke_ns -vpmu calculus env PS1='\h\[\] [\[\]\w\[\]] ' bash --norc
Parent: PID of parent is 16375
Parent: PID of child is 16376
 Child: PID of child is 1
 Child: executing command env ...
calculus [/home/wolf] hostname
calculus 

Hence, it’s possible to provide processes running on a given host system, an entirely different identity in terms of hostname, provided they exist in their own unique UTS namespace.

The next article will cover the NET namespace.