如何调用各种API,获取Linux系统所提供的信息
Linux系统自己会用到的文件
分为两类:
文本文件
里面的内容都是文字编码
放的都是Linux系统要用到各种配置信息
Linux系统在启动和运行时,会用到里面的数据
文本形式的系统文件,大多放在了/etc这个目录下
纯二进制文件
比如各种编译好的库、以及可执行文件,里面放是能够被cpu执行的机器指令
库都放在了各种名叫lib的目录下,比如/lib- 各种
可执行文件,比如ls、mkdir等这些命令,放在了各种名叫bin的目录二进制文件,我们vi后是看不懂的
系统文件的所属用户都是root,所属组也基本都是root

普通用户操作系统文件时,只能以其它用户的身份去操作,而其它用户的权限往往只有r,所以不能写系统文件,只能读里面的数据,只要你不能写,就不会对Linux系统构成威胁。
有些非常重要的系统文件,甚至都不允许普通用户读,比如/etc/shadow文件
对于普通用户来说,如果你要修改里面的内容的话,必须要使用sudo,临时获取root身份,才能拥有root(管理员用户)才有写权限,只有这样才能修改系统文件。
(a)/etc/passwd: 存放用户账户信息的文件
(b)/ext/shadow: 存放密码,用户密码其实单独存放的
(c)/etc/group: 组信息
(d)/etc/setvices: 各种网络服务器的信息
(e)/etc/protocols:各种协议的协议号
(f)/etc/networks: 网络配置信息
...
本章重点:
每次登陆系统时,都需要输入用户名和密码,因此有必要了解下Linux是如何管理账户信息的
获取系统时间:

存放用户账户信息的文件,就是口令文件
/etc/passwd
文件内容
root:x:0:0:root:/root:/bin/bash 管理员用户的账户信息
其他的都是:Linux系统相关用户的账户信息
guojiawei:x:1000:1000:guojiawei,,,:/home/guojiawei:/bin/bash
分为7个字段,字段间使用:分隔
用户名:密码:用户ID:用户所在组的组ID:注释:用户主目录的路径:shell程序的路径
密码
为了安全起见,真实的密码并不放在这里,而是放在了**/etc/shadow**中,这里只是使用一个X来代表
用户ID都是由系统自动分配的
注释
账户注册者的个人信息,如果信息很多的话,信息之间使用,分隔如果在注册账户的时,不填写注册者的信息,那么注释字段是空的
用户主目录的路径
系统启动起来后,用户登录系统时,会用到主目录,所以这里记录主目录的路径,用户登陆后,系统便会从这里得到该用户的主目录路径千万不要去修改主目录的路径,修改之后很可能会导致你下一次无法登录
shell程序的路径
shell程序是一个命令的解释程序,说白了就是解析我们从终端输入的各种命令的
bin目录下都是二进制的可执行程序
- 在/bin下还有一个shell程序叫dash(/bin/dash)
这两个函数的作用:获取passwd文件中的账户数据
- 可以调用open、read等文件io函数来读取passwd文件的数据
- 但是Linux系统提供了更加便捷的API,通过这些API,可以更加方便的读取
getpwuid、getpwnam这个两个函数是c库函数,这两个函数也是靠封装open、read等函数来实现的。
#include
#include
//使用用户名(name),到/etc/passwd中搜索,并获取对应账户信息
struct passwd *getpwnam(const char *name);
//使用用户ID(uid),到/etc/passwd中搜索,并获取对应账户信息
struct passwd *getpwuid(uid_t uid);
/*
调用这两个函数时,函数会开辟一个struct passwd结构体变量,然后把从文件中读到的账户数据,保存到结构体变量。
*/
/*
返回值
(a)成功:返回struct passwd结构体变量的指针。
(b)失败:返回NULL,errno被设置。
*/
struct passwd{//zxf:x:1000:1000:zxf,,,:/home/zxf:/bin/bash
char *pw_name; /* 用户名,字符串形式 */
char *pw_passwd; /* 是否有密码 */
uid_t pw_uid; /* user ID ,用户ID*/
gid_t pw_gid; /* group ID ,组ID*/
char *pw_gecos; /* 注释 */
char *pw_dir; /* 主目录路径 */
char *pw_shell; /* shell程序路径 */
};
#include
#include
#include
#include
int main(){
//struct passwd *getpwnam(const char *name);
//struct passwd *getpwuid(uid_t uid);
struct passwd* p=NULL;
p=getpwuid(0);
struct passwd* q=NULL;
q=getpwnam("guojiawei");
printf("id---%s:%s:%d:%d:%s:%s:%s\n",\
p->pw_name,p->pw_passwd,p->pw_uid,p->pw_gid,\
p->pw_gecos,p->pw_dir,p->pw_shell);
printf("name---%s:%s:%d:%d:%s:%s:%s\n",\
q->pw_name,q->pw_passwd,q->pw_uid,q->pw_gid,\
q->pw_gecos,q->pw_dir,q->pw_shell);
return 0;
}
/*
id---root:x:0:0:root:/root:/bin/bash
name---guojiawei:x:1000:1000:guojiawei,,,:/home/guojiawei:/bin/bash
*/
里面放的是加密后的密码,路径:/etc/shadow
- 密码不能明文存放
加密使用的是
不可逆加密算法----就是不能通过密文,反过来推算出原文
- 密码单独放在一个文件中(/etc/shadow),而且普通用户无法查看
防止你猜密码
分成了8个字段,相互间被“:”隔开
(a)字段1:用户名(b)字段2:加密后的密码
ex:
$6$qmxD4ykF$Sa6Rag5jyietGlL/gM7Er0rosAeVrVIst0p3sX.y9Hi0MijpITvl6NkKk.n76uo3RUKP9eso7Pv2URNOSslBH/
$6$:加密盐巴//Linux也提供了的相应的API,用于获取/etc/shadow中密码信息
struct spwd *getspnam(const char *name);
/etc/group里面放的就是各种用户组相关的信息
- 多个用户在一起可以组成一组,其中的某个用户担任组长
- 组长用户ID就是组长ID
- 组长用户的名字就是整个组的名字
用vi查看“/etc/group”
分成4个字段:
1)字段1:组的名字,就是组长用户的用户名
2)字段2:组的密码,就是组长用户的密码,x表示有密码,字段为空的话,表示没有密码
3)字段3:组ID,就是组长用户的ID
4)字段4:组员有哪些---------如果字段为空,表示组员就一个,就组长自己
#include
#include
//利用组名搜索组文件,获取对应组的信息
struct group *getgrnam(const char *name);
//利用组ID搜索组文件,获取对应组的信息
struct group *getgrgid(gid_t gid);
//zxf:x:1000:
struct group
{
char *gr_name; /* 组名 */
char *gr_passwd; /* 是否有组密码 */
gid_t gr_gid; /* 组ID */
char **gr_mem; /* 指向组成员用户名的的指针数组 */
};
#include
#include
#include
#include
int main(){
//struct group *getgrnam(const char *name);
//struct group *getgrgid(gid_t gid);
struct group* p=NULL;
struct group* q=NULL;
p=getgrgid(0);
q=getgrnam("guojiawei");
printf("%s:%s:%d\n",\
p->gr_name,p->gr_passwd,p->gr_gid);
for(int i=0;p->gr_mem[i]!=NULL;i++){
printf("%s",p->gr_mem[i]);
}
printf("%s:%s:%d\n",\
q->gr_name,q->gr_passwd,q->gr_gid);
for(int i=0;q->gr_mem[i]!=NULL;i++){
printf("%s",q->gr_mem[i]);
}
return 0;
}
/*结果:
root:x:0
guojiawei:x:1000
*/
注意char******的用法
比如:
/etc/services: 记录了各种网络服务器提供的服务
/etc/protocols: 记录了各种的协议
/etc/networks: 记录网络信息
同样也有类似get***的函数,通过这样的函数,可以获取对应系统文件的信息
系统时间:就是年月日时分秒,有OS时,这个时间就是系统提供的,因此成为系统时间。
通过调用Linux系统提供系统 API——time,即可获取
总秒数我们可以自己去将这个总秒数转换成年月日、时分秒
Linux下的C库还提供了
gmtime、localtime、mktime、ctime、asctime、strftime等C库函数,调用这些函数就可以将time函数返回的总秒数,自动的转换为我们要的当前时间。

#include
//功能:返回总秒数
//参数:存放总秒数的缓存的地址
//返回值:函数调用成功返回总秒数,失败则返回(time_t)-1 ,errno被设置
time_t time(time_t *tloc);
#include
#include
#include
int main(){
//time_t time(time_t *tloc);
long int tim=0;
time(&tim);
printf("tim=%ld\n",tim);
return 0;
}
//#include
#include
#include
int main(){
//time_t time(time_t *tloc);
long int tim=0;
time(&tim);
printf("tim=%ld\n",tim);
return 0;
}
获取总秒数的方式有两种:
(a)通过返回值获取
time_t tim = time(NULL);
不使用参数时,参数指定为NULL。
(b)参数
time_t tim;
time(&tim);

库API:gmtime、localtime、mktime、ctime、asctime、strftime
#include
//功能:将time返回的总秒数,转为固定的格式时间,不过这个时间是国际时间
//参数:保存有总秒数的缓存的地址,这个总秒数,我们需要调用time来得到
/*
返回值
成功:转换后的时间字符串的指针
失败:返回NULL,errno被设置
*/
char *ctime(const time_t *timep);
#include
#include
#include
int main(){
time_t tim;
time(&tim);
//char *ctime(const time_t *timep);
char* p=NULL;
p=ctime(&tim);
printf("%s\n",p);
return 0;
}
//Sat Nov 5 18:17:18 2022
#include
//功能:将time返回的总秒数,转为国际时间的年 月 日 时 分 秒。
struct tm *gmtime(const time_t *timep);
//功能与gmtime完全一样,只不过是转为北京时间的年月日时分秒
struct tm *localtime(const time_t *timep);
//功能:将struct tm变量中的年月日时分秒,反过来转为总秒数
time_t mktime(struct tm *tm);
struct tm //gmtime()
{
int tm_sec; /* 秒 */
int tm_min; /* 分 */
int tm_hour; /* 时 */
int tm_mday; /* 月天 */
int tm_mon; /* 月份 */
int tm_year; /* 年 */
int tm_wday; /* 周天 */
int tm_yday; /* 年天 */
int tm_isdst; /* 夏时令设置 */
};
使用:
int main(){
time_t tim;
time(&tim);
//char *ctime(const time_t *timep);
char* p=NULL;
p=ctime(&tim);
//struct tm *gmtime(const time_t *timep);
struct tm* g_tmp=gmtime(&tim);
printf("%d\n",g_tmp->tm_mon);
//struct tm *localtime(const time_t *timep);
struct tm* l_tmp=localtime(&tim);
printf("%d\n",l_tmp->tm_mon);
//time_t mktime(struct tm *tm);
time_t mm=mktime(g_tmp);
printf("%ld\n",mm);
return 0;
}
#include
//负责将struct tm中的年月日时分秒,组合为固定格式的时间
char *asctime(const struct tm *tm);
//与asctime功能一样,只不过strftime能够组合为我们自己指定的时间格式
/*
s:缓存地址,这个缓存用于存放转换后的字符串。
max:缓存的大小
tm:放有年月日时分秒的结构体变量的地址
format:自定义时间格式;与printf指定打印格式的操作方式是一样的。
*/
//返回值-----返回转换后时间字符串的字符个数
size_t strftime(char *s, size_t max, const char *format,const struct tm *tm);
strftime(strtim_buf, sizeof(strtim_buf), “
%Y:%m:%d %H:%M:%S\n”, tm);
%Y:%m:%d %H:%M:%S指定的时间格式—年:月:日 时:分:秒

#include
#include
#include
int main(){
time_t tim=time(&tim);
//char *ctime(const time_t *timep);
char* p=ctime(&tim);
//struct tm *localtime(const time_t *timep);
struct tm* l_tmp=localtime(&tim);
//char *asctime(const struct tm *tm);
char* as_p=asctime(l_tmp);//直接传入localtime返回值即可
printf("%s\n",as_p);
//size_t strftime(char *s, size_t max,\
const char *format,const struct tm *tm);
char ss[100]={0};
strftime(ss,sizeof(ss),"%Y:%m:%d:%H:%M:%S\n",l_tmp);
printf("ss=%s\n",ss);
return 0;
}