busybox源码剖析(1)

来源:互联网 发布:四川省广电网络 编辑:程序博客网 时间:2024/05/16 08:36

     想找个简单的代码来看,学习代码的架构设计,就找到了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,输出就可以了。

 


<script type="text/javascript"><!--google_ad_client = "ca-pub-1944176156128447";/* cnblogs 首页横幅 */google_ad_slot = "5419468456";google_ad_width = 728;google_ad_height = 90;//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
原创粉丝点击