想找个简单的代码来看,学习代码的架构设计,就找到了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,如需转载请自行联系原作者

busybox源码剖析(1)---whoami.c相关推荐

  1. K8s基础知识学习笔记及部分源码剖析

    K8s基础知识学习笔记及部分源码剖析 在学习b站黑马k8s视频资料的基础上,查阅了配套基础知识笔记和源码剖析,仅作个人学习和回顾使用. 参考资料: 概念 | Kubernetes 四层.七层负载均衡的 ...

  2. 【Busybox】Busybox源码分析-01 | 源码目录结构和程序入口

    文章目录 一.Busybox简介 (1-1)开源项目 (1-2)程序本体较小 (1-3)使用简单 二.Busybox源码目录结构 三.Busybox程序主体 四.Busybox程序运行剖析

  3. 老李推荐:第14章4节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-端口转发 1...

    老李推荐:第14章4节<MonkeyRunner源码剖析> HierarchyViewer实现原理-装备ViewServer-端口转发 在初始化HierarchyViewer的实例过程中, ...

  4. JS魔法堂:mmDeferred源码剖析

    一.前言 avalon.js的影响力愈发强劲,而作为子模块之一的mmDeferred必然成为异步调用模式学习之旅的又一站呢!本文将记录我对mmDeferred的认识,若有纰漏请各位指正,谢谢.项目请见 ...

  5. Kafka源码剖析 —— 网络I/O篇 —— 浅析KafkaSelector

    为什么80%的码农都做不了架构师?>>>    ##NioSelector和KafkaSelector有什么区别? 先说结论,KafkaSelector(org.apache.kaf ...

  6. Mongoose源码剖析:Introduction and Installation

    引言 要剖析Mongoose的源码,首先你得知道它的一些基本情况和特性.并去使用它.本文就是介绍Mongoose是个什么东西?及如何安装和使用?这里假设你知道什么web服务器软件.web服务器使用什么 ...

  7. 老李推荐:第5章5节《MonkeyRunner源码剖析》Monkey原理分析-启动运行: 获取系统服务引用 1...

    老李推荐:第5章5节<MonkeyRunner源码剖析>Monkey原理分析-启动运行: 获取系统服务引用 上一节我们描述了monkey的命令处理入口函数run是如何调用optionPro ...

  8. 老李推荐:第3章3节《MonkeyRunner源码剖析》脚本编写示例: MonkeyImage API使用示例 1...

    老李推荐:第3章3节<MonkeyRunner源码剖析>脚本编写示例: MonkeyImage API使用示例 在上一节的第一个"增加日记"的示例中,我们并没有看到日记 ...

  9. Mongoose源码剖析:外篇之web服务器

    引言 在深入Mongoose源码剖析之前,我们应该清楚web服务器是什么?它提供什么服务?怎样提供服务?使用什么协议?客户端如何唯一标识web服务器的资源?下面我们抛开Mongoose,来介绍一个we ...

最新文章

  1. 在JavaScript中使用正好两位小数格式化数字
  2. 概率统计概念复习:MAPMLE
  3. 程序员面试题精选100题(26)-和为n连续正数序列[算法]
  4. 光流 | MATLAB实现HS Optical Flow(代码类)
  5. dart系列之:创建Library package
  6. 捍卫者usb管理控制系统_捍卫Java
  7. [vue] 怎么捕获组件vue的错误信息?
  8. python爬虫淘宝评论_Python爬取淘宝店铺和评论
  9. UWP开发细节记录:判断文件类型
  10. linux软件安装方法
  11. Vector3.MoveTowards与Vector3.Lerp()区别
  12. oracle 查询判断语句
  13. Atitit 提升开发效率 提升团队人员能力 目录 1. 多语言扩展 提升抽象度 2 2. 从上到下法 vs 从下倒上 问题诊断解决法 2 2.1. 培训机制 上到下法 2 2.2. 问题案例
  14. Windows程序设计:使用VS2010创建窗口程序
  15. 如何将两段音乐合并成一段?
  16. Android 根据手机自带GPS获取当前位置,经纬度
  17. oracle 图片批量导入,【SQL】Oracle BLOB 批量导入导出图片到文件夹相关语句
  18. 手游沙巴克传奇当前服务器维护,《沙巴克传奇》12月18日安卓、IOS维护公告
  19. Excel 表格图片压缩方法
  20. 深井冰!沙雕码农脑洞大,盘点Github上那些不忍直视奇葩脑回路的沙雕项目!

热门文章

  1. salesforce 零基础学习(三十四)动态的Custom Label
  2. Jsoup实现java模拟登陆
  3. a:hover span 隐藏/显示 问题
  4. 在线等差数列求和计算器
  5. 结巴(jieba)分词器入门
  6. ZJOI2007时态同步
  7. Codeforces Round #467 (Div. 2)
  8. iOS - UIActivityIndicatorView
  9. keepalived track script introduce
  10. jQuery选择器遇上一些特殊字符