zoukankan      html  css  js  c++  java
  • 系统数据文件和信息

    • 口令文件

    UNIX系统口令文件是etc/passwd,包含了图1所示的各字段,这些字段包含在<pwd.h>中定义的passwd结构中。

    图1 各系统etc/passwd文件中的字段

    Ubuntu系统的passwd结构(在/usr/include/pwd.h中)如下:

    图2 Ubuntu中的passwd结构

    Ubuntu系统的口令文件(etc/passwd)实例如图3所示,各字段用:分隔。

    图3 Ubuntu系统口令文件实例

    用户名为root的登陆项,其用户ID是0(超级用户)。

    加密口令字段包含了一个占位符X,现在加密口令字存放在另一个文件中。

    shell字段包含了一个可执行程序,这个程序被用作该用户的登陆shell。用bin/false用作登陆shell,是为了防止特定用户登陆系统。

    使用nobody用户名的目的是,使任何人都可登陆至系统,但其用户ID(65534)和组ID(65534)不提供任何特权,只可访问人人可读可写的文件。

    finger命令支持注释字段中的附加信息,各部分用逗号分隔,如Ader,,,中Ader为姓名,其余为空。

    图4 finger实例

    使用vipw命令,允许管理员使用该命令编辑口令文件,并且确保所作的更改与其他相关文件保持一致。

    获取口令文件项的函数有getpwuid和getpwnam:

    #include <pwd.h>
    
    struct passwd *getpwuid(uid_t uid);
    struct passwd *getpwname(const char *name);

     getpwuid由ls(1)程序使用,getpwnam函数由login(1)函数使用。

     

    如果要查看整个口令文件:

    #include <pwd.h>
    
    struct passwd *getpwent(void);
    
    void setpwent(void);
    void endpwent(void);

    调用getpwent,返回口令文件的下一个记录项passwd结构的指针,每次调用此函数都重写该结构。

    函数setpwent用来将getpwent的读写地址指向密码文件开头,但getpwent对口令文件中各个记录项的安排顺序并无要求(有些是hash算法)。

    endpwent则关闭这些文件,getpwent查看完口令文件后,一定要调用endpwent关闭这些文件。

    • 阴影口令

    加密口令是经单向加密算法处理过的用户口令副本,算法是单向的,不能从加密口令猜测到原来的口令。

    为了防止对口令进行猜测,系统将口令存放在另一个通常称为阴影口令(etc/shadow)的文件中,而不是在etc/passwd文件中。

    对口令加密将产生更长的加密口令字符串,因此口令文件(etc/passwd)中的加密口令字段,用单个字符(X)可以确保任一加密口令都不会与其匹配。

    阴影口令文件至少要包含用户名和加密口令

    图5 阴影口令文件(etc/shadow)中的字段

    阴影口令文件不是一般用户可以读取的:

    图6 阴影口令文件读取

    如图6所示,需要sudo才能读取etc/shadow文件。

    login和passwd命令,是设置用户ID为root的程序,可以访问shadow文件。

    在Linux 3.2.0和Solaris 10中,与反问口令文件的一组函数相似,有另一组函数可用于访问阴影口令文件。

    #include <shadow.h>
    
    struct spwd *getspnam(const char *name);
    struct spwd *getspent(void);
    
    void setspent(void);
    void endspent(void);
    • 组文件

    UNIX组文件包含了图7中所示字段,这些字段在grp.h中定义。

    图7 组文件中的字段

    Ubuntu中grp.h中gourp结构的定义,如图8所示:

    图8 group结构的定义

    Ubuntu中的组文件etc/group,如图9所示:

    图9 组文件etc/group

    获取组文件项的函数有getgrgid和getgrnam:

    #include <grp.h>
    
    struct group *getgrgid(gid_t gid);
    struct group *getgrnam(const char *name);

     

    如果要搜索整个组文件:

    #include <grp.h>
    
    struct group *getgrent(void);
    void setgrent(void);
    void endgrent(void);

    与口令文件相关函数功能相似。

    • 附属组ID

    在口令文件中,用户对应的组ID是有效组ID,如图3所示,ader用户对应的有效组ID为1000。

    在组文件中,如图9所示,可以看到有多个组包含了ader用户,adm/cdrom/sudo/dip/plugdev等,这些都是ader的附属组ID。

    获取和设置附属组ID,有三个函数:

    #include <unistd.h>
    int getgroups(int gidsetsize, gid_t grouplist[]);
    
    #include <grp.h> //on Linux
    #include <unistd.h> //on FreeBSD, Mac OS X, and Solaris
    int setgroups(int ngroups, const gid_t grouplist[]);
    
    #include <grp.h> //on Linux
    #include <unistd.h> //on FreeBSD, Mac OS X
    int initgroups(const char *username, gid_t basegid)

     通常只有initgroups函数调用setgroups,initgroups读整个组文件(etc/group),然后对username确定其组的成员关系。

    最后调用setgroups初始化附属组ID表,initgroups也在附属组ID表中包括了basegid。

    • 其他数据文件

    图10 访问系统数据文件例子

    etc/services记录各网络服务器所提供服务。

    etc/protocols记录协议信息。

    etc/networks记录网络信息。

    对这些数据文件至少有3个函数,get/set/end函数。另外还提供搜索指定键的函数。

    • 登录账户记录

    utmp文件记录当前登录到系统的各个用户,wtmp文件跟踪各个登录和注销事件。

    图11 登录记录结构

    登录时,login填写此结构,写入到utmp文件中,同时也添加到wtmp文件中。

    注销时,init进程将utmp文件相应记录擦除,添加一个新的记录到wtmp。

    系统再启动/系统时间和日期更改,都将在wtmp文件中追写特殊的记录项。

    相应的文件:var/run/utmp和var/log/wtmp

    • 系统标识

    uname函数,返回与主机和操作系统有关的信息。

    图12 uname函数

    函数将填写utsname结构,结构最少需要提供的字段如下:

    struct utsname {
        char sysname[];
        char nodename[];
        char release[];
        char version[];
        char machine[];
    }

     utsname结构中的信息通常可用uname命令打印,uname的用法如图13所示。

    图13 uname命令用法

    gethostname函数,可用来获取主机名,该名字通常是TCP/IP网络上主机的名字。

    #include <unistd.h>
    
    int gethostname(char *name, int namelen);

    命令hostname可用来获取和设置主机名,获取主机名用法如图14所示。

    图14 hostname获取主机名

    • 时间和日期Routines

    UNIX内核计算的是继协调时间(1970年1月1日)以来经过的秒数,这种秒数用time_t表示,称为日历时间。

    获取到日历时间后,需要转换为分解时间,生成人可读的时间和日期。

    时间相关的处理函数如图15所示:

    图15 时间和日期相关函数

    • 日历时间

    从内核中获取日历时间,有三个函数time/gettimeofday/clock_gettime

    time函数返回的是time_t结构,精度为秒;

    clock_gettime函数返回的是timespec结构,在系统支持高精度时间值的情况下,可获得纳秒精度时间值;

    gettimeofday函数返回的是timeval结构,可获得微秒级的精度时间;【SUSv4指定gettimeofday函数为弃用,不过一些程序仍然使用这个函数】

    函数原型如下:

    #include <time.h>
    time_t time(time_t *calptr);
    
    #include <sys/time.h>
    int clock_gettime(clockid_t clock_id, struct timespec *tsp);
    //获取指定时钟的时间
    //ID为CLOCK——REALTIME时,与time函数类似功能
    
    #include <sys/time.h>
    int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
    //tzp的唯一合法值为NULL

    timespec和timeval结构,截取其中的tv_sec就能转换为time_t。

    如果想要知道某个时钟的精度,可调用clock_getres函数来获取

    #include <sys/time.h>
    int clock_getres(clockid_t clock_id, struct timespec *tsp);
    //tsp指向的timespec结构,被初始化为与clock_id参数对应的时钟精度。
    //如精度为1毫秒,tv_sec字段为0,tv_nsec字段为1000000
    • 分解时间

    分解时间结构为tm,如下:

    struct tm { /* a broken-down time */
        int tm_sec; /* seconds after the minute: [0 - 60] */
        int tm_min; /* minutes after the hour: [0 - 59] */
        int tm_hour; /* hours after midnight: [0 - 23] */
        int tm_mday; /* day of the month: [1 - 31] */
        int tm_mon; /* months since January: [0 - 11] */
        int tm_year; /* years since 1900 */
        int tm_wday; /* days since Sunday: [0 - 6] */
        int tm_yday; /* days since January 1: [0 - 365] */
        int tm_isdst; /* daylight saving time flag: <0, 0, >0 */
    };

    将日历时间转化为分解时间,有gmtime/localtime函数。

    localtime函数将日历时间转为为本地时间(考虑到本地时区和夏令时标志)。如果定义了TZ,将使用该值替代系统默认时区。

    gmtime将日历时间转为为协调统一时间。

    #include <time.h>
    struct tm *gmtime(const time_t *calptr);
    struct tm *localtime(const time_t *calptr);

    将分解时间转为为日历时间,有函数mktime。

    #include <time.h>
    time_t mktime(struct tm *tmptr);

    mktime和localtime一样,受变量TZ的影响。

    • 格式化时间

    strftime/strftime_l函数将输出格式化的字符串时间。

    #include <time.h>
    size_t strftime(char *restrict buf, size_t maxsize,
                    const char *restrict format,
                    const struct tm *restrict tmptr);
    size_t strftime_l(char *restrict buf, size_t maxsize,
                      const char *restrict format,
                      const struct tm *restrict tmptr, locale_t locale);

    tmptr指向的分解时间,按format的格式要求,输出相应的字符串到buf

    strftime_l可通过参数locale指定时区,strftime通过TZ环境变量指定时区

    format控制时间值格式,如下:

    图16 strftime的格式转换说明

    strptime函数是strftime的逆过程,把字符串时间转为分解时间。

    #include <time.h>
    char *strptime(const char *restrict buf, const char *restrict format,
                   struct tm *restrict tmptr);

    根据format指定的格式,将buf指向的字符串时间,转为分解时间tmptr

    格式说明如图17:

    图17 strptime函数的格式转换说明

  • 相关阅读:
    android:background背景图片被拉伸问题
    面试积累(String和StringBuffer, StringBuilder的理解)
    面试积累(冒泡排序和选择排序)
    面试积累(java的内存分析)
    面试积累(java配置环境变量)
    异常积累(SQLException)
    【linux】fdisk磁盘分区
    【走马观花】十一月十八日通州雨
    【linux】CentOS查看硬件信息
    【linux】go安装及配置
  • 原文地址:https://www.cnblogs.com/songdechiu/p/10527430.html
Copyright © 2011-2022 走看看