<pwd.h> 中定义了 passwd 结构体,并提供了获取指定 passwd 项的函数
#include <pwd.h>
/* 根据uid获取passwd项 */
struct passwd *getpwuid(uid_t uid);
/* 根据用户名获取passwd项 */
struct passwd *getpwname(const char* name);
struct passwd{
char* pw_name; /* 用户名 */
char* pw_passwd; /* 加密密码 */
uid_t pw_uid; /* 数值用户ID */
git_t pw_gid; /* 数值组ID */
char* pw_gecos; /* 注释字段 */
char* pw_dir; /* 初始工作目录 */
char* pw_shell; /* 初始shell */
char* pw_class; /* 用户访问类 */
time_t pw_change; /* 下次更改密码时间 */
time_t pw_expire; /* 账户到期时间 */
}
下面三个函数,则提供了遍历获取 passwd 项的函数
#include <pwd.h>
/* 若未打开passwd文件则打开passwd文件,并将读指针放到第一条记录处 */
void setpwent();
/* 若未打开passwd文件则打开passwd文件,并读取下一条passwd项*/
struct passwd* getpwent();
/* 关闭passwd文件 */
void endpwent();
需要注意的是:
类似 passwd 相关函数
#include <shadow.h>
/* 根据用户名获取shadow项 */
struct spwd* getspnam(const char* name);
struct spwd{
char* sp_namp; /* 用户登录名 */
char* sp_pwdp; /* 加密口令 */
int sp_lstchg; /* 上次更改密码以来经过的时间 */
int sp_min; /* 经过多少天后允许更改密码 */
int sp_max; /* 多少天后要求更改密码 */
int sp_warn; /* 密码到期警告天数 */
int sp_inact; /* 账户失效前天数 */
int sp_expire; /* 账户到期天数 */
unsigned int sp_flag; /* 保留 */
}
/* 若未打开shadow文件则打开shadow文件,将读指针放到第一条记录处 */
void setspent();
/* 若未打开shadow文件则打开shadow文件,读取下一条shadow记录*/
struct spwd* getspent();
/* 关闭shaodw文件 */
void endspent();
#include <grp.h>
/* 根据gid获取group项 */
struct group* getgrgid(gid_t gid);
/* 根据组名称,获取group项 */
struct group* getgrnam(const char* name);
struct group{
char* gr_name; /* 组名 */
char* gr_passwd; /* 加密口令 */
int gr_gid; /* 组id */
char** gr_mem; /* 组成员名称列表 */
};
/* 下面三个函数用于遍历group项 */
/* 若未打开group文件则打开group文件,将读指针放到第一条记录 */
void setgrent();
/* 若未打开group文件则打开group文件,读取下一条group项*/
struct group* getgrent();
/* 关闭group文件 */
void endgrent();
但与 passwd 不同的是,UNIX 具有附加组的概念,为了获取和设置附加组 ID,提供了下列三个函数:
#include <grp.h>
#include <unistd.h>
/* 获取当前用户的附加组列表,返回用户附加组的个数,出错则返回-1 */
int getgroups(int group_array_size,gid_t group_size[]);
/* 为当前进程设置附加组 */
int setgroups(int group_array_size,gid_t group_size[]);
/* 为进程附加组设置为username的附加组 */
int initgroups(const char* username,gid_t base_gid);
对于 hosts、networks、protocols、services 等系统文件,UNIX 也提供了与 passwd 类似的函数。
| 系统文件说明 | 数据路径 | 头文件 | 结构体 | 附加的关键字查找函数 |
|---|---|---|---|---|
| 主机 | /etc/hosts | <netdb.h> | hostent | gethostbyname,gethostbyaddr |
| 网络 | /etc/networks | <netdb.h> | netent | getnetbyname,getnetbyaddr |
| 协议 | /etc/protocols | <netdb.h> | protoent | getprotobyname,getprotobynumber |
| 服务 | /etc/services | <netdb.h> | servent | getservbyname,getservbyport |
一般情况下,每个数据文件都会有三个函数:
若尚未打开数据文件,则打开数据文件,并将读指针放到第一条记录处
若尚未打开数据文件,则打开数据文件,并读取下一条数据项
当到达文件尾端则返回空指针,大多数 get 函数返回指向一个静态结构的指针,如果要保存该内容,则需要复制它
关闭响应数据文件。
本机信息存放在 /etc/hosts 中,可以通过调用 gethostent 查找本机主机信息
#include <netdb.h>
/* 获取主机信息 */
struct hostent* gethostent();
struct hostent{
char* h_name; /* 主机名称 */
char** h_aliases; /* 主机别名列表 */
int h_addrtype; /* 地址类型 */
int h_length; /* length in bytes of address */
char** h_addr_list; /* 网络地址列表 */
/* 其他成员 */
};
/* 打开主机文件,重置记录指针 */
void sethostent(int stayopen);
/* 关闭主机文件 */
void endhostent();
struct hostent* gethostbyname(const char* name);
/* 参数len为参数addr的长度,type表示是IPv4还是IPv6 */
struct hostent* gethostbyaddr(const char* addr,int len,int type);
gethostent 返回 /etc/hosts 文件中的下一个条目,若文件没打开,gethostent 还会打开它
#include <unistd.h>
#include <netdb.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void show_hostent(const struct hostent* h)
{
printf("h_name=[%s]\n",h->h_name);
int i = 0;
char* alias=NULL;
for(alias = h->h_aliases[i];alias !=NULL;++i){
printf("h_alias=[%s]\n",alias);
}
printf("h_addrtype=[%d]",h->h_addrtype);
printf("h_length=[%d]",h->h_length);
/* fflush(stdout); */
/* if(h->h_addrtype == AF_INET) { */
/* for(i = 0;i < h->h_length;++i){ */
/* struct in_addr** addresses = (struct in_addr**)h->h_addr_list; */
/* printf("h_addr=[%d]",addresses[i]->s_addr); */
/* } */
/* } */
}
int main()
{
struct hostent* h = gethostent();
show_hostent(h);
return 0;
}
我们使用以下函数获得网络名字和网络编号
#include <netdb.h>
struct netent* getnetbyaddr(uint32_t net,int type);
struct netent* getnetbyname(const char* name);
struct netent* getnetent();
void setnetent(int stayopen);
void endnetent();
struct netent
{
char* n_name; /* 网络名称 */
char** n_aliases; /* 网络别名列表 */
int n_addrtype; /* 地址类型,如AF_INET */
uint32_t n_net; /* 网络编号,按网络字节序返回 */
/* 其他成员 */
};
我们可以使用以下函数在协议名字和协议编号之间进行映射
#include <netdb.h>
struct protoent* getprotobyname(const char* name);
struct protoent* getprotobynumber(int proto);
struct protoent* getprotoent();
void setprotoent(int stayopen);
void endprotoent();
struct protoent
{
char* p_name; /* 协议名称 */
char** p_aliases; /* 协议别名列表 */
int p_proto; /* 协议编号 */
/* 其他成员 */
};
服务由地址的端口号部分表示,每个服务由一个唯一的总所周知的端口号来表示
#include <netdb.h>
/* proto指明了使用的网络协议 */
struct servent* getservbyname(const char* name,const char* proto);
struct servent* getservbyport(int port,const char* proto);
struct getservent();
void setservent(int stayopen);
void endservent();
struct servent
{
char* s_name; /* 服务名称 */
char** p_aliases; /* 协议别名列表 */
int p_proto; /* 服务使用的网络协议编号,如TCP,UDP等 */
};
大多数 UNIX 系统都提供下面两个数据文件:
每次写入这两个文件的是包含以下结构的二进制记录:
struct utmp{
char ut_line[8]; /* tty编号 */
char ut_name[8]; /* 登录名,注销时为空 */
long ut_time; /* 登录/注销事件 */
}
#include <sys/utsname.h>
int uname(struct utsname* name);
struct utsname{
char sysname[]; /* 操作系统名称 */
char nodename[]; /* 节点名称 */
char release[]; /* 操作系统的发布型号 */
char version[]; /* 操作系统发布版本 */
char machine[]; /* 硬件类型 */
};
#include <unistd.h>
ing gethostname(char* name,int bufsize);
最大主机名长度为 HOST_NAME_MAX

