busybox源码剖析(1)---whoami.c

简介:
  想找个简单的代码来看,学习代码的架构设计,就找到了busybox。先从最早的版本开始看。
     whoami命令是获取当前终端的用户名。/etc/passwd文件存储了所有用户名的清单。要注意的是/etc存储的配置文件大多是系统级的配置文件。而whoami想要达到目的,就需要与/etc/passwd文件打交道。
     首先来看whoami.c的主体程序:
 1 extern int whoami_main(int argc, char **argv)
 2 {
 3     char user[9];
 4     uid_t uid = geteuid();
 5 
 6     if (argc > 1)
 7         show_usage();
 8 
 9     my_getpwuid(user, uid);
10     if (*user) {
11         puts(user);
12         return EXIT_SUCCESS;
13     }
14     error_msg_and_die("cannot find username for UID %u", (unsigned) uid);
15 }
      首先通过geteuid()系统调用获得uid,然后,通过my_getpwuid(user,uid)获得username。
      再看my_getpwuid函数。
 1 void my_getpwuid(char *name, long uid)
 2 {
 3     struct passwd *myuser;
 4 
 5     myuser  = getpwuid(uid);
 6     if (myuser==NULL)
 7         sprintf(name, "%-8ld ", (long)uid);
 8     else
 9         strcpy(name, myuser->pw_name);
10 }
      /etc/passwd中的每条记录都有相同的格式:
     name:password:uid:gid:comment:home:shell
     每项的具体内容可以查看这里
     struct passwd 结构就对应了这个记录:
 1 struct passwd
 2 {
 3   char *pw_name;        /* Username.  */
 4   char *pw_passwd;        /* Password.  */
 5   uid_t pw_uid;            /* User ID.  */
 6   gid_t pw_gid;            /* Group ID.  */
 7   char *pw_gecos;        /* Real name.  */
 8   char *pw_dir;            /* Home directory.  */
 9   char *pw_shell;        /* Shell program.  */
10 };
      我们无法单独得到username,所有,我们必须先得到struct passwd结构。my_getpwuid函数中的getpwuid函数就实现这个功能。
 1 struct passwd *getpwuid(uid_t uid)
 2 {
 3     int passwd_fd;
 4     struct passwd *passwd;
 5 
 6     if ((passwd_fd = open("/etc/passwd", O_RDONLY)) < 0)
 7         return NULL;
 8 
 9     while ((passwd = __getpwent(passwd_fd)) != NULL)
10         if (passwd->pw_uid == uid) {
11             close(passwd_fd);
12             return passwd;
13         }
14 
15     close(passwd_fd);
16     return NULL;
17 }
         第9行while不断读取/etc/passwd中的条目,找到目标就return。进入到__getpwent中。
 1 if ((line_len = read(pwd_fd, line_buff, PWD_BUFFER_SIZE)) <= 0)  //
 2         return NULL;   //当read之后,pwd_fd所指向的文件的offet到了line_buff的末尾。这对后面的处理很重要。
 3     field_begin = strchr(line_buff, '\n');
 4     if (field_begin != NULL)
 5         lseek(pwd_fd, (long) (1 + field_begin - (line_buff + line_len)),
 6               SEEK_CUR);  //找到一个'\n'后,就需要进行parse。然后就要将offset调到当前'\n'的后一位,就是这个语句的作用了。
 7     else {                       
 8 
 9         do {
10             if ((line_len = read(pwd_fd, line_buff, PWD_BUFFER_SIZE)) <= 0)
11                 return NULL;
12         } while (!(field_begin = strchr(line_buff, '\n')));
13         lseek(pwd_fd, (long) (field_begin - line_buff) - line_len + 1,
14               SEEK_CUR);  
15         goto restart;
16     }
       得到一个条目的首地址line_buff后,就可以parse了。过程很简单。
 1 for (i = 0; i < 7; i++) {
 2         switch (i) {
 3         case 0:
 4             passwd.pw_name = field_begin;
 5             break;
 6         case 1:
 7             passwd.pw_passwd = field_begin;
 8             break;
 9         case 2:
10             uid_ptr = field_begin;
11             break;
12         case 3:
13             gid_ptr = field_begin;
14             break;
15         case 4:
16             passwd.pw_gecos = field_begin;
17             break;
18         case 5:
19             passwd.pw_dir = field_begin;
20             break;
21         case 6:
22             passwd.pw_shell = field_begin;
23             break;
24         }
25         if (i < 6) {
26             field_begin = strchr(field_begin, ':');
27             if (field_begin == NULL)
28                 goto restart;
29             *field_begin++ = '\0';
30         }
 
         找到符合uid的条目后,my_getpwuid函数得到username,输出就可以了。

本文转自NeilHappy 51CTO博客,原文链接:http://blog.51cto.com/neilhappy/1133800,如需转载请自行联系原作者
相关文章
|
缓存 Perl
如何修改openeuler为阿里源
修改openeuler为阿里源
6091 0
|
Python
python使用pip镜像源加速安装包(清华、阿里、中科大)
python使用pip镜像源加速安装包(清华、阿里、中科大)
8867 0
python使用pip镜像源加速安装包(清华、阿里、中科大)
|
10月前
|
计算机视觉
RT-DETR改进策略【损失函数篇】| Shape-IoU:考虑边界框形状和尺度的更精确度量
RT-DETR改进策略【损失函数篇】| Shape-IoU:考虑边界框形状和尺度的更精确度量
256 1
RT-DETR改进策略【损失函数篇】| Shape-IoU:考虑边界框形状和尺度的更精确度量
|
8月前
|
人工智能 安全 算法
深度解析DeepSeek一体机哪家好?deepseek一体机排名及选型参考
本文详细解析了DeepSeek一体机的选型框架与主流厂商产品对比,从技术架构、性能指标、场景覆盖、安全合规及成本效率五个维度展开分析。重点推荐优刻得DeepSeek一体机,其国产化率超95%,推理延迟仅83ms(领先行业45%),综合成本低于自建30%,已在多家省级政务云平台应用。此外,华为云与阿里云分别在混合云协同与云边协同方面表现突出,但成本较高。未来,DeepSeek一体机将向存算一体芯片、多模态能力增强等方向发展。对于金融、政务、医疗等行业用户,优刻得是首选方案。
|
Java 数据库连接 mybatis
idea无法下载Mybatis插件怎么办
idea无法下载Mybatis插件怎么办
|
物联网 SDN 网络虚拟化
VXLAN:彻底改变网络虚拟化
【7月更文挑战第3天】
1039 0
VXLAN:彻底改变网络虚拟化
怎样在GitHub上建立仓库、以及怎样实现分支代码的合并。保姆级别的教程
这篇文章是一份详细的GitHub使用教程,介绍了如何在GitHub上创建仓库、创建分支、编辑和发布更改内容、发起拉取请求以及合并分支的操作步骤。
怎样在GitHub上建立仓库、以及怎样实现分支代码的合并。保姆级别的教程
|
监控 安全 Unix
/var/log/faillog日志详解
【4月更文挑战第8天】`/var/log/faillog`是Unix和Linux系统中记录登录失败尝试的日志文件,帮助管理员检测恶意登录和错误密码尝试。每行包含用户名、登录终端、时间戳和失败次数。高失败次数可能暗示密码破解尝试,管理员应密切关注并采取安全措施。启用和配置此功能可能需使用`pam_faillock`。然而,`/var/log/faillog`仅是安全策略的一部分,应结合强密码、系统更新、访问限制和多日志监控以增强安全性。
442 1
/var/log/faillog日志详解
|
监控 项目管理
PMP项目变更管理及变更流程总结
PMP项目变更管理及变更流程总结
825 0
|
NoSQL 程序员 C语言
探秘Segmentation Fault错误:程序猿的噩梦
探秘Segmentation Fault错误:程序猿的噩梦
2665 0