Chinaunix首页 | 论坛 | 博客
  • 博客访问: 176912
  • 博文数量: 43
  • 博客积分: 611
  • 博客等级: 中士
  • 技术积分: 1053
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-02 13:37
文章存档

2015年(3)

2013年(23)

2012年(17)

我的朋友

分类: LINUX

2013-02-15 08:53:24

     想找个简单的代码来看,学习代码的架构设计,就找到了busybox。先从最早的版本开始看。

     whoami命令是获取当前终端的用户名。/etc/passwd文件存储了所有用户名的清单。要注意的是/etc存储的配置文件大多是系统级的配置文件。而whoami想要达到目的,就需要与/etc/passwd文件打交道。

     首先来看whoami.c的主体程序:

extern int whoami_main(int argc, char **argv)
 {
     char user[9];
     uid_t uid = geteuid();
 
     if (argc > 1)
         show_usage();
 
     my_getpwuid(user, uid);
     if (*user) {
         puts(user);
         return EXIT_SUCCESS;
     }
     error_msg_and_die("cannot find username for UID %u", (unsigned) uid);
 }

     首先通过geteuid()系统调用获得uid,然后,通过my_getpwuid(user,uid)获得username。

     再看my_getpwuid函数。

void my_getpwuid(char *name, long uid)
 {
     struct passwd *myuser;
 
     myuser  = getpwuid(uid);
     if (myuser==NULL)
         sprintf(name, "%-8ld ", (long)uid);
     else
         strcpy(name, myuser->pw_name);
 }

      /etc/passwd中的每条记录都有相同的格式:

     name:password:uid:gid:comment:home:shell

     每项的具体内容可以查看。

     struct passwd 结构就对应了这个记录:

struct passwd
 {
   char *pw_name;        /* Username.  */
   char *pw_passwd;        /* Password.  */
   uid_t pw_uid;            /* User ID.  */
   gid_t pw_gid;            /* Group ID.  */
   char *pw_gecos;        /* Real name.  */
   char *pw_dir;            /* Home directory.  */
   char *pw_shell;        /* Shell program.  */
 };
      我们无法单独得到username,所有,我们必须先得到struct passwd结构。my_getpwuid函数中的getpwuid函数就实现这个功能。


struct passwd *getpwuid(uid_t uid)
 {
     int passwd_fd;
     struct passwd *passwd;
 
     if ((passwd_fd = open("/etc/passwd", O_RDONLY)) < 0)
         return NULL;
 
     while ((passwd = __getpwent(passwd_fd)) != NULL)
         if (passwd->pw_uid == uid) {
             close(passwd_fd);
             return passwd;
         }
 
     close(passwd_fd);
     return NULL;
 }
        第9行while不断读取/etc/passwd中的条目,找到目标就return。进入到__getpwent中。


if ((line_len = read(pwd_fd, line_buff, PWD_BUFFER_SIZE)) <= 0)  //
         return NULL;   //当read之后,pwd_fd所指向的文件的offet到了line_buff的末尾。这对后面的处理很重要。
     field_begin = strchr(line_buff, '\n');
     if (field_begin != NULL)
         lseek(pwd_fd, (long) (1 + field_begin - (line_buff + line_len)),
               SEEK_CUR);  //找到一个'\n'后,就需要进行parse。然后就要将offset调到当前'\n'的后一位,就是这个语句的作用了。
     else {                       
 
         do {
             if ((line_len = read(pwd_fd, line_buff, PWD_BUFFER_SIZE)) <= 0)
                 return NULL;
         } while (!(field_begin = strchr(line_buff, '\n')));
         lseek(pwd_fd, (long) (field_begin - line_buff) - line_len + 1,
               SEEK_CUR);  
         goto restart;
     }
     得到一个条目的首地址line_buff后,就可以parse了。过程很简单。

for (i = 0; i < 7; i++) {
         switch (i) {
         case 0:
             passwd.pw_name = field_begin;
             break;
         case 1:
             passwd.pw_passwd = field_begin;
             break;
         case 2:
             uid_ptr = field_begin;
             break;
         case 3:
             gid_ptr = field_begin;
             break;
         case 4:
             passwd.pw_gecos = field_begin;
             break;
         case 5:
             passwd.pw_dir = field_begin;
             break;
         case 6:
             passwd.pw_shell = field_begin;
             break;
         }
         if (i < 6) {
             field_begin = strchr(field_begin, ':');
             if (field_begin == NULL)
                 goto restart;
             *field_begin++ = '\0';
         }
         找到符合uid的条目后,my_getpwuid函数得到username,输出就可以了。

阅读(2104) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~