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,輸出就可以了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM