zoukankan      html  css  js  c++  java
  • 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         }
    31}

     

             找到符合uid的条目后,my_getpwuid函数得到username,输出就可以了。

     

  • 相关阅读:
    HTTP状态码的详细解释,供参考
    js中实现页面跳转(返回前一页、后一页)
    CRUD工程师——基础容器LinkedList
    CRUD工程师——基础容器ArrayList
    Servlet入门
    Linux
    flex弹性布局
    div布局
    递归函数
    运算符
  • 原文地址:https://www.cnblogs.com/NeilHappy/p/2912577.html
Copyright © 2011-2022 走看看