1. 使用简介

UTS(UNIX Time Sharing) namespace 是最简单的一种 namespace。UTS 中主要包含了主机名(hostname)、域名(domainname)和一些版本信息:

struct uts_namespace {
struct kref kref;
struct new_utsname name; // UTS 主要存储的信息
struct user_namespace *user_ns;
struct ucounts *ucounts;
struct ns_common ns;
} __randomize_layout; ↓ struct new_utsname {
char sysname[__NEW_UTS_LEN + 1];
char nodename[__NEW_UTS_LEN + 1]; // host name
char release[__NEW_UTS_LEN + 1];
char version[__NEW_UTS_LEN + 1];
char machine[__NEW_UTS_LEN + 1];
char domainname[__NEW_UTS_LEN + 1]; // domain name
};

其中主机名(hostname)、域名(domainname)是可以被修改的,其他只能被读取。UTS 的主要作用就是给用户态、内核态提供这些信息。

1.1 hostname

针对主机名(hostname),系统提供了 hostname 命令来进行读取和设置。下面举例说明其使用方法:

1、查看普通进程的 hostname :

pwl@ubuntu:~$ hostname
ubuntu // 当前 hostname 为 ubuntu

2、创建一个新的 UTS namespace,并设置新的 hostname :

pwl@ubuntu:~$ sudo unshare --uts /bin/bash
[sudo] password for pwl:
root@ubuntu:~# hostname
ubuntu
root@ubuntu:~# hostname test
root@ubuntu:~# hostname
test // 在新的 UTS namespace 中更改 hostname 为 test
pwl@ubuntu:~$ hostname
ubuntu // 在旧的 UTS namespace 中的 hostname 仍然为 ubuntu

1.2 domainname

针对域名(domainname),系统提供了 domainname 命令来进行读取和设置。下面举例说明其使用方法:

1、查看普通进程的 hostname :

pwl@ubuntu:~$ domainname
(none) // 当前 hostname 为空

2、创建一个新的 UTS namespace,并设置新的 hostname :

pwl@ubuntu:~$ domainname
(none)
pwl@ubuntu:~$ sudo unshare --uts /bin/bash
root@ubuntu:~# domainname
(none)
root@ubuntu:~# domainname test
root@ubuntu:~# domainname
test // 在新的 UTS namespace 中更改 hostname 为 test
root@ubuntu:~#
pwl@ubuntu:~$ domainname
(none) // 在旧的 UTS namespace 中的 hostname 仍然为空

1.3 uname

针对 UTS 提供的其他信息,系统提供了 uname 命令来进行读取,且不支持配置。

pwl@ubuntu:~$ uname -a
Linux ubuntu 4.15.0-123-generic #126-Ubuntu SMP Wed Oct 21 09:40:11 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
pwl@ubuntu:~$ uname --help
Usage: uname [OPTION]...
Print certain system information. With no OPTION, same as -s. -a, --all print all information, in the following order,
except omit -p and -i if unknown:
-s, --kernel-name print the kernel name
-n, --nodename print the network node hostname
-r, --kernel-release print the kernel release
-v, --kernel-version print the kernel version
-m, --machine print the machine hardware name
-p, --processor print the processor type (non-portable)
-i, --hardware-platform print the hardware platform (non-portable)
-o, --operating-system print the operating system
--help display this help and exit
--version output version information and exit

2. 代码分析

我们简单分析一下 UTS namespace 的创建代码,以及几个相关系统调用的代码。

2.1 copy_utsname()

在进程创建或者 unshare()/setns() 系统调用时,如果设置了 CLONE_NEWUTS 标志会调用 copy_utsname() 创建一个新的 UTS namespace。其中的核心是创建一个新的 struct uts_namespace 结构,首先把旧的 struct uts_namespace 树复制过来:

struct uts_namespace *copy_utsname(unsigned long flags,
struct user_namespace *user_ns, struct uts_namespace *old_ns)
{
struct uts_namespace *new_ns; BUG_ON(!old_ns);
get_uts_ns(old_ns); if (!(flags & CLONE_NEWUTS))
return old_ns; new_ns = clone_uts_ns(user_ns, old_ns); put_uts_ns(old_ns);
return new_ns;
} ↓ static struct uts_namespace *clone_uts_ns(struct user_namespace *user_ns,
struct uts_namespace *old_ns)
{
struct uts_namespace *ns;
struct ucounts *ucounts;
int err; err = -ENOSPC;
ucounts = inc_uts_namespaces(user_ns);
if (!ucounts)
goto fail; err = -ENOMEM;
/* (1) 创建一个新的 uts namespace 结构 */
ns = create_uts_ns();
if (!ns)
goto fail_dec; /* (2) 分配一个新的 namespace 编号 */
err = ns_alloc_inum(&ns->ns);
if (err)
goto fail_free; ns->ucounts = ucounts;
ns->ns.ops = &utsns_operations; down_read(&uts_sem);
/* (3) 拷贝旧的 uts namespace 的内容 */
memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
ns->user_ns = get_user_ns(user_ns);
up_read(&uts_sem);
return ns; fail_free:
kfree(ns);
fail_dec:
dec_uts_namespaces(ucounts);
fail:
return ERR_PTR(err);
}

后面使用 sethostname()/setdomainname() 系统调用来独立的设置各个 uts namespace 下的 hostname/domainname。

2.2 sethostname()

SYSCALL_DEFINE2(sethostname, char __user *, name, int, len)
{
int errno;
char tmp[__NEW_UTS_LEN]; if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN))
return -EPERM; if (len < 0 || len > __NEW_UTS_LEN)
return -EINVAL;
errno = -EFAULT;
if (!copy_from_user(tmp, name, len)) {
struct new_utsname *u; down_write(&uts_sem);
u = utsname();
/* (1) 设置当前 uts namespace 中的 uts_ns->name->nodename */
memcpy(u->nodename, tmp, len);
memset(u->nodename + len, 0, sizeof(u->nodename) - len);
errno = 0;
uts_proc_notify(UTS_PROC_HOSTNAME);
up_write(&uts_sem);
}
return errno;
} ↓ static inline struct new_utsname *utsname(void)
{
return &current->nsproxy->uts_ns->name;
}

2.3 gethostname()

SYSCALL_DEFINE2(gethostname, char __user *, name, int, len)
{
int i;
struct new_utsname *u;
char tmp[__NEW_UTS_LEN + 1]; if (len < 0)
return -EINVAL;
down_read(&uts_sem);
u = utsname();
i = 1 + strlen(u->nodename);
if (i > len)
i = len;
/* (1) 获取当前 uts namespace 中的 uts_ns->name->nodename */
memcpy(tmp, u->nodename, i);
up_read(&uts_sem);
if (copy_to_user(name, tmp, i))
return -EFAULT;
return 0;
}

2.4 setdomainname()

SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len)
{
int errno;
char tmp[__NEW_UTS_LEN]; if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN))
return -EPERM;
if (len < 0 || len > __NEW_UTS_LEN)
return -EINVAL; errno = -EFAULT;
if (!copy_from_user(tmp, name, len)) {
struct new_utsname *u; down_write(&uts_sem);
u = utsname();
/* (1) 设置当前 uts namespace 中的 uts_ns->name->domainname */
memcpy(u->domainname, tmp, len);
memset(u->domainname + len, 0, sizeof(u->domainname) - len);
errno = 0;
uts_proc_notify(UTS_PROC_DOMAINNAME);
up_write(&uts_sem);
}
return errno;
}

2.5 uname()

SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
{
struct new_utsname tmp; down_read(&uts_sem);
/* (1) 获取当前 uts namespace 中的所有信息 */
memcpy(&tmp, utsname(), sizeof(tmp));
up_read(&uts_sem);
if (copy_to_user(name, &tmp, sizeof(tmp)))
return -EFAULT; if (override_release(name->release, sizeof(name->release)))
return -EFAULT;
if (override_architecture(name))
return -EFAULT;
return 0;
}

参考文档:

1.UTS namespace详解
2.Linux内核命名空间之(4)uts namespace

Linux ns 4. UTS Namespace 详解的更多相关文章

  1. Linux ns 6. Network Namespace 详解

    文章目录 1. 简介 1.1 Docker Network 桥接模式配置 2. 代码解析 2.1 copy_net_ns() 2.2 pernet_list 2.2.1 loopback_net_op ...

  2. Linux ns 5. IPC Namespace 详解

    文章目录 1. 简介 2. 源码分析 2.1 copy_ipcs() 2.2 ipcget() 2.3 ipc_check_perms() 2.4 相关系统调用 参考文档: 1. 简介 进程间通讯的机 ...

  3. Linux ns 3. Mnt Namespace 详解

    1. 文件系统层次化 对 Linux 系统来说一切皆文件,Linux 使用树形的层次化结构来管理所有的文件对象. 完整的Linux文件系统,是由多种设备.多种文件系统组成的一个混合的树形结构.我们首先 ...

  4. Linux下DNS服务器搭建详解

    Linux下DNS服务器搭建详解 DNS  即Domain Name System(域名系统)的缩写,它是一种将ip地址转换成对应的主机名或将主机名转换成与之相对应ip地址的一种机制.其中通过域名解析 ...

  5. Linux上的free命令详解、swap机制

    Linux上的free命令详解   解释一下Linux上free命令的输出. 下面是free的运行结果,一共有4行.为了方便说明,我加上了列号.这样可以把free的输出看成一个二维数组FO(Free ...

  6. linux PHP 编译安装参数详解

    linux PHP 编译安装参数详解 ./configure --prefix=/usr/local/php --with-config-file-path=/usr/local/php/etc -- ...

  7. Linux Shell数组常用操作详解

    Linux Shell数组常用操作详解 1数组定义: declare -a 数组名 数组名=(元素1 元素2 元素3 ) declare -a array array=( ) 数组用小括号括起,数组元 ...

  8. Linux CAT与ECHO命令详解 <<EOF EOF

    Linux CAT与ECHO命令详解 cat命令是Linux下的一个文本输出命令,通常是用于观看某个文件的内容的: cat主要有三大功能: .一次显示整个文件. $ cat filename .从键盘 ...

  9. linux:SUID、SGID详解

    linux:SUID.SGID详解 文章转载至:http://tech.ccidnet.com/art/2583/20071030/1258885_1.html 如果你对SUID.SGID仍有迷惑可以 ...

随机推荐

  1. [转载]CentOS 7 创建本地YUM源

    本文中的"本地YUM源"包括三种类型:一是直接使用CentOS光盘作为本地yum源,优点是简单便捷,缺点是光盘软件包可能不完整(centos 7 Everything 总共才6.5 ...

  2. 基于AM335X,如何搭建优良的Linux开发环境(下)

    接着上一篇文章的Linux开发环境搭建,文章中详细讲解了 VMware14.1.1虚拟机安装.基于虚拟机安装Ubuntu14.04.3操作系统.安装Ubuntu14.04.3操作系统.安装虚拟机工具. ...

  3. 基于深度学习的建筑能耗预测01——Anaconda3-4.4.0+Tensorflow1.7+Python3.6+Pycharm安装

    基于深度学习的建筑能耗预测-2021WS-02W 一,安装python及其环境的设置 (写python代码前,在电脑上安装相关必备的软件的过程称为环境搭建) · 完全可以先安装anaconda(会自带 ...

  4. 《手把手教你》系列技巧篇(二十五)-java+ selenium自动化测试-FluentWait(详细教程)

    1.简介 其实今天介绍也讲解的也是一种等待的方法,有些童鞋或者小伙伴们会问宏哥,这也是一种等待方法,为什么不在上一篇文章中竹筒倒豆子一股脑的全部说完,反而又在这里单独写了一篇.那是因为这个比较重要,所 ...

  5. Initialize this repository with a README

    在gitHub创建项目时,有很多小伙伴不太清楚 Initialize this repository with a README 在什么情况下需要勾选,在这里简单说明 如下: 1. 翻译 如果要导入现 ...

  6. 基于注解实现jackson动态JsonProperty

    基于注解实现jackson动态JsonProperty @JsonProperty 此注解用于属性上,作用是把该属性的名称序列化为另外一个名称,如把trueName属性序列化为name,但是值是固定的 ...

  7. Powerful Number 学习笔记

    定义 对于一个正整数 \(n\) ,若完全分解之后不存在指数 \(=1\) ,则称 \(n\) 为 \(\text{Powerful Number}\) . 可以发现的是,在 \([1,n]\) 中, ...

  8. 题解 CF241E Flights

    题目传送门 题目大意 给出一个 \(n\) 个点 \(m\) 条边的 \(\texttt{DAG}\) ,给每条边设定边权为 \(1\) 或者 \(2\) ,使得 \(1\to n\) 的每条路径长度 ...

  9. Redis 基础数据类型重温

    有一天你突然收到一条线上告警:Redis 内存使用率 85%.你吓坏了赶紧先进行扩容然后再去分析 big key.等你进行完这一系列操作之后老板叫你去复盘,期间你们聊到了业务的数据存储在 Redis ...

  10. NX Open,怎样取到面的环LOOP

    在封装的ufun .NET库里面,对UF_MODL_ask_face_loops这个函数并没有封装,导致我们很多不便,那我们在.NET下怎样才能使用这个函数呢??当然是手动处理一下 Public Fu ...