博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux ns 4. UTS Namespace 详解
阅读量:3631 次
发布时间:2019-05-21

本文共 6329 字,大约阅读时间需要 21 分钟。

目录

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:~$ hostnameubuntu                                      // 当前 hostname 为 ubuntu

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

pwl@ubuntu:~$ sudo unshare --uts /bin/bash[sudo] password for pwl: root@ubuntu:~# hostnameubunturoot@ubuntu:~# hostname test                root@ubuntu:~# hostnametest                                        // 在新的 UTS namespace 中更改 hostname 为 testpwl@ubuntu:~$ hostnameubuntu                                      // 在旧的 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/bashroot@ubuntu:~# domainname(none)root@ubuntu:~# domainname testroot@ubuntu:~# domainnametest                                        // 在新的 UTS namespace 中更改 hostname 为 testroot@ubuntu:~# pwl@ubuntu:~$ domainname(none)                                      // 在旧的 UTS namespace 中的 hostname 仍然为空

1.3 uname

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

pwl@ubuntu:~$ uname -aLinux ubuntu 4.15.0-123-generic #126-Ubuntu SMP Wed Oct 21 09:40:11 UTC 2020 x86_64 x86_64 x86_64 GNU/Linuxpwl@ubuntu:~$ uname --helpUsage: 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.

2.

转载地址:http://pfiun.baihongyu.com/

你可能感兴趣的文章
Codeforces Round #576 (Div. 1) C. Matching vs Independent Set(思维好题)
查看>>
Codeforces Round #639 (Div. 2) D. Monopole Magnets(bfs+模拟)(恶心的阅读理解题)
查看>>
一分钟搞懂与、或、非、异或优先级!
查看>>
CodeBlocks无法编译的解决方案
查看>>
关于ZigBee的学习笔记1.0
查看>>
秒懂!用通俗的话讲解“ZigBee终端节点入网”过程
查看>>
完美解决:Ubuntu 12.04右键没有打开终端选项
查看>>
快速理解:memmove和memcopy的区别
查看>>
strsep函数详解
查看>>
秒懂之atoi()函数!
查看>>
一分钟快速理解:模拟信号和数字信号!
查看>>
MQTT之QoS
查看>>
【JavaWeb开发】"web应用程序的根目录"与"web站点的根目录"的分析
查看>>
【JavaWeb开发】EL表达式和JSTL标签的使用
查看>>
Spring学习(6)-Spring Bean的生命周期
查看>>
Spring学习(8)-AOP之ProxyFactoryBean、RegexMethodPointcutAdvisor、BeanNameAutoProxyCreator
查看>>
Spring学习(9)-AOP之使用aop:config标签
查看>>
【JavaWeb】常见数据库和JDBC错误的解决思路
查看>>
springmvc的静态资源无法访问解决方法(基本全面)
查看>>
【记坑】freemarker拿不到对象的值
查看>>