Unix环境高级编程(四)数据系统文件和信息
本章主要介绍了Unix系统的正常运行要使用的与系统有关的数据文件和信息。如:口令文件,阴影文件、组文件、附加组、系统标识、时间和日期历程。
口令文件,即Unix系统用户数据库,存储在/etc/passwd中,是一个ASCII文件,包含的字段信息在<pwd.h>定义的passwd数据结构中。
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 */
};
获取口令文件函数,分别是根据用户ID和用户名。
struct passwd *getpwuid(uid_t uid); //根据用户ID
struct passwd *getpwnam(const char *name); //根据用户名
查看整个口令文件,需要对口令文件进行遍历。有如下函数:
struct passwd *getpwent(void); //返回口令文件中的下一个记录项
void setpwent(void); //反绕文件,从文件头开始
void endpwent(void); //关闭文件
可以用getpwent来实现getpwuid和getpwnam函数。写个程序查看root用户的相关信息及查看口令文件中所有用户的用户名,程序如下:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <pwd.h>
5
6 int main()
7 {
8 struct passwd *ppwd;
9 struct passwd *ptr;
10 //获取root用户信息
11 ppwd = getpwnam("root");
12 if(ppwd == NULL)
13 {
14 perror("getpwnam() error");
15 exit(-1);
16 }
17 printf("root user information as follow:\n");
18 printf("user_name is: %s\n",ppwd->pw_name);
19 printf("user_passwd is: %s\n",ppwd->pw_passwd);
20 printf("user_uid is: %d\n",ppwd->pw_uid);
21 printf("user_gid is: %d\n",ppwd->pw_gid);
22 printf("user_gecos is: %s\n",ppwd->pw_gecos);
23 printf("user_dir is: %s\n",ppwd->pw_dir);
24 printf("user_shell is: %s\n",ppwd->pw_shell);
25 printf("*****************************\n");
26 //反转口令文件,从文件头开始
27 setpwent();
28 printf("Print all user name:\n");
29 //遍历读取口令文件
30 while((ptr = getpwent())!= NULL)
31 {
32 printf("%s\t",ptr->pw_name);
33 }
34 putchar('\n');
35 //关闭口令文件
36 endpwent();
37 return 0;
38 }
测试结果如下:

阴影文件,存放加密口令,至少包含有用户名和加密口令。类似于口令文件,Unix在<shadow.h>都文件中针对阴影文件也提供类似的操作函数,但是只有超级用户(root)才能调用访问阴影文件的函数。阴影文件位于/etc/shadow文件中,文件结构及操作函数如下:
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 expire to warn user to change it */
long sp_inact; /* # of days after password expire 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 */
};
struct spwd *getspnam(const char *name);
struct spwd *getspent(void);
void setspent(void);
void endspent(void);
写个程序查看root用户的加密口令及所有用户的用户名及加密口令如下:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <shadow.h>
5
6 int main()
7 {
8 struct spwd *pspwd;
9 struct passwd *ptr;
10 pspwd = getspnam("root");
11 if(pspwd == NULL)
12 {
13 perror("getspnam() error");
14 exit(-1);
15 }
16 printf("root user information as follow:\n");
17 printf("user_name is: %s\n",pspwd->sp_namp);
18 printf("user_passwd is: %s\n",pspwd->sp_pwdp);
19 printf("*****************************\n");
20 setspent();
21 while((pspwd = getspent()) != NULL)
22 {
23 printf("user_name is: %s\n",pspwd->sp_namp);
24 printf("user_passwd is: %s\n",pspwd->sp_pwdp);
25 }
26 endspent();
27 return 0;
28 }
只能在超级用户下运行此程序,在普用户下提升权限不够。执行结果如下所示:

组文件,即组数据库文件,存储在/etc/group中,结构及操作函数包含在<grp.h>头文件中。具体结构和操作函数如下:
struct group {
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* group members */
};
struct group *getgrnam(const char *name);
struct group *getgrgid(gid_t gid);
搜索整个文件组函数:
struct group *getgrent(void);
void setgrent(void);
void endgrent(void);
写个程序,打印出组id为0的组名称及遍历整个组文件,输出组名称及组id。程序如下:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <grp.h>
5 #include <errno.h>
6
7 int main()
8 {
9 struct group *pgrg;
10 struct group *ptr;
11 gid_t gid = 0;
12 char *username = NULL;
13 //根据gid进行查询
14 pgrg = getgrgid(gid);
15 if(pgrg == NULL)
16 {
17 perror("getgrgid() error");
18 exit(-1);
19 }
20 printf("group name is: %s\n",pgrg->gr_name);
21 printf("group passwd is: %s\n",pgrg->gr_passwd);
22 printf("group gid is: %d\n",pgrg->gr_gid);
23 setgrent();
24 //遍历整个组文件
25 while((ptr = getgrent()) != NULL)
26 {
27 printf("group name is: %s\t",ptr->gr_name);
28 printf("group gid is: %d\n",ptr->gr_gid);
29 }
30 endgrent();
31 return 0;
32 }
程序执行结果如下所示:

附加组,一个用户可以属于多个组,这样可以参加多项工作,优点是不必显式地经常更改组。用户登录时候,系统按照口令文件记录项中的数值组ID,赋给实际组ID,可以在任何时候通过newgrp更改组ID。为了获取和设置附加组ID,提供操作函数如下:
int getgroups(int size, gid_t list[]); //将各个附加组ID填写到数组grouplist中
int setgroups(size_t size, const gid_t *list); //由超级用户调用,以便为调用进程设置附加组ID表
int initgroups(const char *user, gid_t group); //调用setgroups,确定其组的成员关系
其他数据文件 除了口令文件和组文件外,Linux也使用很多其他文件,一般情况下,这些文件都至少支持三个函数:
(1)get函数:读文件中的下一个记录项。
(2)set函数:将文件偏移量设置到文件起始处。
(3)end函数:关闭系统文件。
如果该文件支持关键字检索,例如口令文件支持基于用户名和用户ID的检索,因此实现了接口getpwnam和getpwuid函数,就会支持相应的函数。
| 说明 | 数据文件 | 头文件 | 结构 | 附加的关键字查找函数 |
| 口令 | /etc/passwd | <pwd.h> | passwd | getpwnam 、getpwuid |
| 组 | /etc/group | <grp.h> | group | getpwnam、getpwuid |
| 阴影 | /etc/shadow | <shadow.h> | spwd | getspnam |
| 主机 | /etc/hosts | <netdb.h> | hostent | gethostbyname、gethostbyaddr |
| 网络 | /etc/networks | <netdb.h> | netent | getnetbyname、getnetbyaddr |
| 协议 | /etc/protocols | <netdb.h> | protoent | getprotobyname、getprotobyaddr |
| 服务 | /etc/services | <netdb.h> | servent | getservbyname、getservbyad |
系统标识,uname函数返回与当前主机和操作系统有关的信息,函数字在<sys/utsname.h>头文件中定义。utsname结构信息和操作函数如下:
struct utsname {
char sysname[]; /* Operating system name (e.g., "Linux") */
char nodename[]; /* Name within "some implementation-defined network" */
char release[]; /* OS release (e.g., "2.6.28") */
char version[]; /* OS version */
char machine[]; /* Hardware identifier */
#ifdef _GNU_SOURCE
char domainname[]; /* NIS or YP domain name */
#endif
};
int uname(struct utsname *buf);
写个程序获取本机当前主机和操作系统信息,程序如下:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/utsname.h>
5 #include <errno.h>
6
7 int main()
8 {
9 struct utsname name;
10 if(uname(&name) == -1)
11 {
12 perror("uname() error");
13 exit(-1);
14 }
15 printf("system name is: %s\n",name.sysname);
16 printf("node name is: %s\n",name.nodename);
17 printf("release is: %s\n",name.release);
18 printf("version is: %s\n",name.version);
19 printf("machine is: %s\n",name.machine);
20 return 0;
21 }
程序执行结果如下:

时间和日期,Unix内核提供的基本时间服务是计算自国际标准时间公元1970年1月1日00:00:00以来经过的秒数,基本数据类型是time_t,称为日历时间,包括时间和日期,将时间和日期作为一个量值进行保存。类型定义如下:
time_t time(time_t *t); //返回当前时间及日期
#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz); //相比time提供更高的分辨率,微妙级
int settimeofday(const struct timeval *tv, const struct timezone *tz);
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
struct timezone {
int tz_minuteswest; /* minutes west of Greenwich */
int tz_dsttime; /* type of DST correction */
};
取得了这种以秒计的整型时间后,通常调用另外一个时间函数将其转化为人们可读的时间和日期。时间的结构及操作函数有:
struct tm {
int tm_sec; /* seconds */
int tm_min; /* minutes */
int tm_hour; /* hours */
int tm_mday; /* day of the month */
int tm_mon; /* month */
int tm_year; /* year */
int tm_wday; /* day of the week */
int tm_yday; /* day in the year */
int tm_isdst; /* daylight saving time */
};
char *asctime(const struct tm *tm);
char *ctime(const time_t *timep);
struct tm *gmtime(const time_t *timep); //转换为国际标准时间
struct tm *localtime(const time_t *timep); //转换为本地实际
time_t mktime(struct tm *tm);
size_t strftime(char *s, size_t max, const char *format,const struct tm *tm); //对tm进行格式化输出到一个字符串
函数之间的关系如下图:

写一个程序巩固时间函数,程序如下:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <time.h>
5 #include <errno.h>
6 #include <string.h>
7
8 int main()
9 {
10 time_t now;
11 struct tm *ptime;
12 char *ptstr;
13 char timebuf[100];
14 memset(timebuf,0,100);
15 //获取时间,秒数
16 now = time(&now);
17 printf("Global time is:\n");
18 //转化为国际时间
19 ptime = gmtime(&now);
20 ptime->tm_year += 1900;
21 ptime->tm_mon += 1;
22 printf("%d-%d-%d %d:%d:%d\n",ptime->tm_year,ptime->tm_mon,ptime->tm_mday,
23 ptime->tm_hour,ptime->tm_min,ptime->tm_sec);
24 printf("Local time is:\n");
25 //转化为本地时间
26 ptime = localtime(&now);
27 ptime->tm_year += 1900;
28 ptime->tm_mon += 1;
29 printf("%d-%d-%d %d:%d:%d\n",ptime->tm_year,ptime->tm_mon,ptime->tm_mday,
30 ptime->tm_hour,ptime->tm_min,ptime->tm_sec);
31 //将tm结构转换为字符串
32 ptstr = asctime(ptime);
33 printf("tm time stirng is: %s",ptstr);
34 //将time_t类型转换为字符串
35 ptstr = ctime(&now);
36 printf("time_t time string is: %s",ptstr);
37 //date 格式化输出时间
38 strftime(timebuf,100,"%YYear %mMonth %dDay %A %X",ptime);
39 printf("time buf is:%s\n",timebuf);
40 return 0;
41 }
程序执行结果如下所示:

总结:加深对Unix的系统数据文件及时间日期的认识,能够调用系统函数获取系统相关数据。
Unix环境高级编程(四)数据系统文件和信息的更多相关文章
- (四) 一起学 Unix 环境高级编程(APUE) 之 系统数据文件和信息
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (十三) [终篇] 一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (三) 一起学 Unix 环境高级编程 (APUE) 之 文件和目录
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (六) 一起学 Unix 环境高级编程 (APUE) 之 进程控制
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (七) 一起学 Unix 环境高级编程(APUE) 之 进程关系 和 守护进程
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (八) 一起学 Unix 环境高级编程 (APUE) 之 信号
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
随机推荐
- Retrofit 简介 wiki 文档
简介 Type-safe HTTP client for Android and Java by Square, Inc. GitHub主页:https://github.com/square/ret ...
- python3 操作sqlSever
相关代码如下: #coding =utf-8 import os import pyodbc import time class SqlDb: def __init__(self, server='D ...
- MybatisGen1.0 Mybatis JavaBean Mapper生成工具
MybatisGen 一:主要技术 1:apache commons dbutils 2:freemarker模板引擎 3:java(1.5+) 二:使用说明 1:配置文件是src/config.pr ...
- Windows 8.1 64位版本安装.Net Framework3.5
最近刚把个人电脑切换成了Win 8.1 64位版本,但在使用某些Ms的某此产品时会提示没有安装.Net Framework3.5,但按照他的提示需要在线安装而且速度很慢,因为之前搞过WinServer ...
- 笔记本建立wifi热点的实用详细步骤
准备工作: (1) 首先要打开开始菜单--->搜索“services.msc” 并打开(或者用win+R快捷键打开“运行”输入“service.msc”,点击确定)--->找到“WLAN ...
- 用vs2013开发node.js的addon.
下载node.js的源代码. https://github.com/joyent/node 如果用svn下载,后面加上/trunk,以免把用不着的branches也下载下来,浪费时间. 安装V ...
- 漫谈单点登录(SSO)(淘宝天猫)(转载)
1. 摘要 ( 注意:请仔细看下摘要,留心此文是否是您的菜,若浪费宝贵时间,深感歉意!!!) SSO这一概念由来已久,网络上对应不同场景的成熟SSO解决方案比比皆是,从简单到复杂,各式各样应有尽有!开 ...
- JavaScript 之 parseInt
首先还是从很热门的实例parseInt("09")==0说起. parseInt(numString, [radix])这个函数后面如果不跟第2个参数来表示进制的话,默认是10进制 ...
- nm 命令 程序符号信息查看
http://www.cnblogs.com/wangkangluo1/archive/2012/07/02/2572438.html 用途 显示关于对象文件.可执行文件以及对象文件库里的符号信息. ...
- ORACLE常用监控语句(未完待续)
--查询日志的切换频率 select t1.RECID as srecid ,t2.RECID as erecid ,t1.FIRST_TIME as stime ...