《unix环境高级编程》 读书笔记 (4)

时间:2022-08-24 22:08:54
目录: http://blog.****.net/alex_my/article/details/39346381

system data files and infomation



1 password file

终端上输入cat /etc/passwd
可以看见很多相关信息。

也可以通过以下函数:

#include <sys/types.h>
#include <pwd.h>

struct passwd* getpwnam(const char* name);
struct passwd* getpwuid(uid_t uid);

int getpwnam_r(const char* name, struct passwd* pwd, char* buf, size_t buflen, struct passwd** result);
int getpwuid_r(uid_t uid, struct passwd* pwd, char* buf, size_t buflen, struct passwd** result);

结构体passwd(<pwd.h>):

struct passwd 
{
     char*     pw_name;       /* username */
     char*     pw_passwd;     /* user password */
     uid_t     pw_uid;        /* user ID */
     gid_t     pw_gid;        /* group ID */
     char*     pw_gecos;      /* user information */
     char*     pw_dir;        /* home directory */
     char*     pw_shell;      /* shell program */
};

如果不能理解每个成员的意思,可以通过man 5 passwd查阅。

getpwuid和getpwnam的程序用例:

#include <stdio.h>
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>

static void PrintfPwd(const passwd* pwdInfo)
{
     if(!pwdInfo)
          return;

     printf("name: \t%s\n", pwdInfo->pw_name);
     printf("passwd: \t%s\n", pwdInfo->pw_passwd);
     printf("uid: \t%d\n", pwdInfo->pw_uid);
     printf("gid: \t%d\n", pwdInfo->pw_gid);
     printf("gecos: \t%s\n", pwdInfo->pw_gecos);
     printf("dir: \t%s\n", pwdInfo->pw_dir);
     printf("shell: \t\%s\n", pwdInfo->pw_shell);
}

int main(int argc, char* argv[])
{
     printf("test getpwuid: \n");
     uid_t uid = getuid();
     printf("uid: %d\n", uid);

     // test getpwuid
     struct passwd* pwdInfo = getpwuid(uid);
     if(!pwdInfo)
          return 1;

     PrintfPwd(pwdInfo);

     // test getpwnam
     printf("\n\ntest getpwnam: \n");
     struct passwd* pwdInfo2 = getpwnam(pwdInfo->pw_name);
     PrintfPwd(pwdInfo2);

     return 0;
}


getpwuid_r用例:

#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
#include <unistd.h>
#include <errno.h>

static void PrintfPwd(const passwd* pwdInfo)
{
     if(!pwdInfo)
          return;
     printf("name: \t%s\n", pwdInfo->pw_name);
     printf("passwd: \t%s\n", pwdInfo->pw_passwd);
     printf("uid: \t%d\n", pwdInfo->pw_uid);
     printf("gid: \t%d\n", pwdInfo->pw_gid);
     printf("gecos: \t%s\n", pwdInfo->pw_gecos);
     printf("dir: \t%s\n", pwdInfo->pw_dir);
     printf("shell: \t\%s\n", pwdInfo->pw_shell);
}


int main(int argc, char* argv[])
{
     uid_t uid = getuid();

     size_t len = sysconf(_SC_GETPW_R_SIZE_MAX);
     if(len == -1)
          len = 16384;

     char* buffer = new char[len];
     if(!buffer)
     {
          printf("buffer create failed. error[%d]\n", errno);
          return 1;
     }

     struct passwd pwd;
     struct passwd* result = NULL;

     int ret = getpwuid_r(uid, &pwd, buffer, len, &result);
     if(!result)
     {
          printf("getpwuid failed. ret[%d]\n", ret);
          return 1;
     }

     printf("----------pwd---------- \n");
     PrintfPwd(&pwd);

     printf("\n\n----------result----------\n");
     PrintfPwd(result);

     printf("\n\n----------buffer----------\n");
     printf("buffer: %s\n", buffer);

     return 0;
}

以下三个函数与读取/etc/passwd相关:

#include <sys/types.h>
#include <pwd.h>

struct passwd* getpwent(void);
void setpwent(void);
void endpwent(void);

getpwent: 获取passwd文件中的一个口令,严格的说,是获取下一个口令
setpwent: 将获取口令重置到第一个
endpwent: 关闭由getpwent打开的文件

程序用例:

#include <stdio.h>
#include <pwd.h>

int main(int argc, char* argv[])
{
     // 为了测试方便,最多只打印10个口令信息
     struct passwd* pwd;
     // 设置从头开始读取
     setpwent();
     int n = 0;
     while((pwd = getpwent()) != NULL)
     {
          printf("name: %s \t uid: %d\n", pwd->pw_name, pwd->pw_uid);
          if(++n >= 10)
               break;
     }

     endpwent();

     return 0;
}



2 shadow passwords

看着名字就知道它藏的好深。

有以下函数可以操作这个文件:

#include <shadow.h>

struct spwd* getspnam(const char* name);
struct spwd* getspent(void);
void setspent(void);
void endspent(void);

struct spwd* fgetspent(FILE* fp);
struct spwd* sgetspent(const char* s);

int putspent(struct spwd* p, FILE* fp);
int lckpwdf(void);
int ulckpwdf(void);

/* GNU extension */
#include <shadow.h>

int getspent_r(struct spwd* spbuf, char* buf, size_t buflen, struct spwd** spbufp);
int getspnam_r(const char* name, struct spwd* spbuf, char* buf, size_t buflen, struct spwd** spbufp);
int fgetspent_r(FILE* fp, struct spwd* spbuf, char* buf, size_t buflen, struct spwd** spbufp);
int sgetspent_r(const char* s, struct spwd* spbuf, char* buf, size_t buflen, struct spwd** spbufp);

其中的struct spwd定义如下:

struct spwd 
{
     char* sp_namp;     /* Login name */
     char* sp_pwdp;     /* Encrypted password */
     long  sp_lstchg;   /* Date of last change
                           (measured in days since
                           1970-01-01 00:00:00 +0000 (UTC)) */
     long  sp_min;      /* Min # of days between changes */
     long  sp_max;      /* Max # of days between changes */
     long  sp_warn;     /* # of days before password expires
                           to warn user to change it */
     long  sp_inact;    /* # of days after password expires
                           until account is disabled */
     long  sp_expire;   /* Date when account expires
                           (measured in days since
                           1970-01-01 00:00:00 +0000 (UTC)) */
     unsigned long sp_flag;  /* Reserved */
};

getspnam程序用例:

#include <stdio.h>
#include <shadow.h>
#include <errno.h>
#include <string.h>

int main(int argc, char* argv[])
{
     struct spwd* pwd = getspnam("alex_my");
     if(!pwd)
     {
          printf("getspnam failed, error: [%d] [%s]\n", errno, strerror(errno));
          return 1;
     }

     printf("name: %s\t password: %s\n", pwd->sp_namp, pwd->sp_pwdp);


     return 0;
}

如果在普通账号下运行,就会发生错误,因为读取文件的权限不够。



3 group file

位于/etc/group

有以下函数可以操作:

#include <sys/types.h>
#include <grp.h>

struct group *getgrnam(const char *name);
struct group *getgrgid(gid_t gid);

int getgrnam_r(const char *name, struct group *grp, char *buf, size_t buflen, struct group **result);
int getgrgid_r(gid_t gid, struct group *grp, char *buf, size_t buflen, struct group **result);

用法可以参考passwd file

用户在登陆的时候,就会获取到group ID,属于某一个group,可以通过命令来改变所属的组。但总体来说不方便。
于是,出现了supplementary group IDs(附加组ID)。


4 获取本地主机名

#include <unistd.h>

int gethostname(char* name, size_t namelen);

#include <stdio.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
     char name[256] = { 0 };
     gethostname(name, sizeof(name));
     printf("name: %s\n", name);

     return 0;
}