• 系统时间和系统文件


    本章学习内容

    如何调用各种API,获取Linux系统所提供的信息

    • 第一部分:获取系统文件数据
    • 第二部分:获取系统时间

    系统文件

    Linux系统自己会用到的文件

    分为两类:

    • 文本文件
    • 里面的内容都是文字编码

    • 放的都是Linux系统要用到各种配置信息

      ​ Linux系统在启动和运行时,会用到里面的数据

    • 文本形式的系统文件,大多放在了/etc这个目录下

    • 纯二进制文件
    • 比如各种编译好的库、以及可执行文件,里面放是能够被cpu执行的机器指令

      1. 都放在了各种名叫lib的目录下,比如/lib
      2. 各种可执行文件,比如ls、mkdir等这些命令,放在了各种名叫bin的目录
    • 二进制文件,我们vi后是看不懂的

    系统文件的特点
    • 系统文件的所属用户都是root,所属组也基本都是root

    • 普通用户操作系统文件时,只能以其它用户的身份去操作,而其它用户的权限往往只有r,所以不能写系统文件,只能读里面的数据,只要你不能写,就不会对Linux系统构成威胁。

      有些非常重要的系统文件,甚至都不允许普通用户读,比如/etc/shadow文件

    • 对于普通用户来说,如果你要修改里面的内容的话,必须要使用sudo,临时获取root身份,才能拥有root(管理员用户)才有写权限,只有这样才能修改系统文件。

    linux常见的系统文件

                    (a)/etc/passwd:   存放用户账户信息的文件
    				(b)/ext/shadow:   存放密码,用户密码其实单独存放的
    				(c)/etc/group:    组信息
    				(d)/etc/setvices: 各种网络服务器的信息
    				(e)/etc/protocols:各种协议的协议号
    				(f)/etc/networks: 网络配置信息
    			       ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    本章重点:

    • /etc/passwd
    • /ext/shadow
    • /etc/group

    每次登陆系统时,都需要输入用户名和密码,因此有必要了解下Linux是如何管理账户信息的

    获取系统时间

    • Linux的系统API-----time
    • c库API(需要系统API time的支持)-----gmtime、localtime、mktime、ctime、asctime、strftime

    口令文件

    存放用户账户信息的文件,就是口令文件

    /etc/passwd

    • 对于这个文件,只有文件所属用户root才有写权限,组员用户以及其它用户只有读权限

    文件内容

    root:x:0:0:root:/root:/bin/bash 管理员用户的账户信息

    其他的都是:Linux系统相关用户的账户信息

    账户包含的信息
    guojiawei:x:1000:1000:guojiawei,,,:/home/guojiawei:/bin/bash
    
    • 1

    分为7个字段,字段间使用:分隔

    用户名:密码:用户ID:用户所在组的组ID:注释:用户主目录的路径:shell程序的路径

    密码
    为了安全起见,真实的密码并不放在这里,而是放在了**/etc/shadow**中,这里只是使用一个X来代表

    用户ID都是由系统自动分配的

    注释
    账户注册者的个人信息,如果信息很多的话,信息之间使用,分隔

    如果在注册账户的时,不填写注册者的信息,那么注释字段是空的

    用户主目录的路径
    系统启动起来后,用户登录系统时,会用到主目录,所以这里记录主目录的路径,用户登陆后,系统便会从这里得到该用户的主目录路径

    千万不要去修改主目录的路径,修改之后很可能会导致你下一次无法登录

    shell程序的路径

    shell程序是一个命令的解释程序,说白了就是解析我们从终端输入的各种命令的

    bin目录下都是二进制的可执行程序

    • 在/bin下还有一个shell程序叫dash(/bin/dash)
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vG723BCS-1667637039214)(/home/guojiawei/.config/Typora/typora-user-images/image-20221105163000479.png)]
    getpwuid();getpwnam()

    这两个函数的作用:获取passwd文件中的账户数据

    1. 可以调用open、read等文件io函数来读取passwd文件的数据
    2. 但是Linux系统提供了更加便捷的API,通过这些API,可以更加方便的读取

    getpwuidgetpwnam这个两个函数是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被设置。
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
     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程序路径 */
    				};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    #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
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    阴影文件

    里面放的是加密后的密码,路径:/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);
    
    • 1
    • 2
    组文件

    /etc/group里面放的就是各种用户组相关的信息

    • 多个用户在一起可以组成一组,其中的某个用户担任组长
    • 组长用户ID就是组长ID
    • 组长用户的名字就是整个组的名字

    用vi查看“/etc/group”

    分成4个字段:

    1)字段1:组的名字,就是组长用户的用户名
    2)字段2:组的密码,就是组长用户的密码,x表示有密码,字段为空的话,表示没有密码
    3)字段3:组ID,就是组长用户的ID
    4)字段4:组员有哪些---------如果字段为空,表示组员就一个,就组长自己

    getgrgid、getgrnam函数
    #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;        /* 指向组成员用户名的的指针数组 */
    		  };								
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    #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
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    注意char******的用法

    其他系统文件

    比如:
    /etc/services: 记录了各种网络服务器提供的服务
    /etc/protocols: 记录了各种的协议
    /etc/networks: 记录网络信息

    同样也有类似get***的函数,通过这样的函数,可以获取对应系统文件的信息


    获取系统时间

    系统时间:就是年月日时分秒,有OS时,这个时间就是系统提供的,因此成为系统时间。

    通过调用Linux系统提供系统 API——time,即可获取总秒数

    我们可以自己去将这个总秒数转换成年月日、时分秒

    Linux下的C库还提供了gmtime、localtime、mktime、ctime、asctime、strftime等C库函数,调用这些函数就可以将time函数返回的总秒数,自动的转换为我们要的当前时间。

    time
    #include 
    //功能:返回总秒数
    //参数:存放总秒数的缓存的地址
    //返回值:函数调用成功返回总秒数,失败则返回(time_t)-1 ,errno被设置
    time_t time(time_t *tloc);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    #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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    获取总秒数的方式有两种:
    (a)通过返回值获取
    time_t tim = time(NULL);
    不使用参数时,参数指定为NULL。
    (b)参数
    time_t tim;
    time(&tim);

    时间的C库API

    在这里插入图片描述

    库API:gmtime、localtime、mktime、ctime、asctime、strftime

    ctime
    #include 
    //功能:将time返回的总秒数,转为固定的格式时间,不过这个时间是国际时间
    //参数:保存有总秒数的缓存的地址,这个总秒数,我们需要调用time来得到
    /*
    返回值
    		成功:转换后的时间字符串的指针
    		失败:返回NULL,errno被设置
    */
    char *ctime(const time_t *timep);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    #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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    gmtime(),localtime(),mktime()
    #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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    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;       /* 夏时令设置 */
    			};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    使用:

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    asctime(),strftime()
    #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);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 相关阅读:
    总结一下 vue2 组件之间的通信
    【LeetCode】7. 整数反转
    SMART PLC如何构造ALT指令
    MySQL:order by排序查询,group by分组查询
    C++面经总结1——类相关
    FITC-PEG-MAL,荧光素聚乙二醇马来酰亚胺,FITC-PEG-Maleimidev
    物联网应用技术专业是属于什么类
    Spring Task定时任务框架
    AVL树性质和实现
    【python】eval函数
  • 原文地址:https://blog.csdn.net/weixin_47173597/article/details/127702571