《APUE》读书笔记—第六章数据系统文件和信息

本章主要介绍了Unix系统的正常运行要使用的与系统有关的数据文件和信息。如:口令文件,阴影文件,组文件,附加组,系统标识,时间和日期历程。

口令文件,即Unix系统用户数据库,存储在/etc/passwd中,是一个ASCll文件,包含的字段信息在<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用户的相关信息及查看口令文件中所有用户的用户名,程序如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
int main()
{
    struct passwd *ppwd;
	struct passwd *ptr;
	//获取root用户信息
	ppwd = getpwnam("root");
	if (ppwd == NULL)
	{
		perror("getpwnam() error");
		exit(-1);
	}
     printf("root user information as follow:\n");
     printf("user_name is: %s\n",ppwd->pw_name);
     printf("user_passwd is: %s\n",ppwd->pw_passwd);
     printf("user_uid is: %d\n",ppwd->pw_uid);
     printf("user_gid is: %d\n",ppwd->pw_gid);
     printf("user_gecos is: %s\n",ppwd->pw_gecos);
     printf("user_dir is: %s\n",ppwd->pw_dir);
     printf("user_shell is: %s\n",ppwd->pw_shell);
     printf("*****************************\n");
	 //反转口令文件,从文件头开始
	 setpwent();
	 printf("Print all user name:\n");
	 //遍历读取口令文件
	 while ((ptr = getpwent()) != NULL)
	 {
		 printf("%s\t", ptr->pw_name);
	 }
	 putchar('\n');
	 //关闭口令文件
	 endpwent();
	return 0;
}

测试结果如下:


阴影文件,存放加密口令,至少包含用户名和加密口令。类似于口令文件,Unix在<shadow.h>文件中针对阴影文件也提供类似的操作函数,但是只有超级用户才能调用访问阴影文件的函数。阴影文件为于/etc/shadow中,文件结构及操作函数如下:

struct spwd {
   char *sp_namp;     /* Login name */
   char *sp_pwdp;     /* Encrypted password */
   long  sp_lstchg;   /* Date of last change (measured in dayssince 1970-01-01 00:00:00 +0000 (UTC)) */
   long  sp_min;      /* Min # of days betweenchanges */
   long  sp_max;      /* Max # of days betweenchanges */
   long  sp_warn;     /* # of days before password expireto warn user to change it */
   long  sp_inact;    /* # of days after password expire untilaccount is disabled */
   long  sp_expire;   /* Date when account expires (measured in dayssince 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用户的加密口令及用户的用户名及加密口令如下:

#include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <shadow.h>
 
 int main()
 {
 struct spwd *pspwd;
     struct passwd *ptr;
pspwd = getspnam("root");
if(pspwd == NULL)
{
perror("getspnam() error");
exit(-1);
}
printf("root user information as follow:\n");
printf("user_name is: %s\n",pspwd->sp_namp);
printf("user_passwd is: %s\n",pspwd->sp_pwdp);
printf("*****************************\n");
setspent();
while((pspwd = getspent()) != NULL)
{
printf("user_name is: %s\n",pspwd->sp_namp);
printf("user_passwd is: %s\n",pspwd->sp_pwdp);
}
endspent();
return 0;
}

只有超级用户下运行此程序,在普通用户下提升权限不够。执行结果如下所示:


组文件,即组数据库文件,存储在/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);
voidsetgrent(void);

void endgrent(void);
写个程序,打印出组id为0的组名称及遍历整个组文件,输出组名称及组id。程序如下:

#include <stdio.h>
  #include <stdlib.h>
 #include <unistd.h>
 #include <grp.h>
 #include <errno.h>
 
 int main()
 {
     struct group *pgrg;
    struct group *ptr;
     gid_t gid = 0;
    char *username = NULL;
     //根据gid进行查询
     pgrg = getgrgid(gid);
     if(pgrg == NULL)
    {
         perror("getgrgid() error");
         exit(-1);
    }
     printf("group name is: %s\n",pgrg->gr_name);
     printf("group passwd is: %s\n",pgrg->gr_passwd);
     printf("group gid is: %d\n",pgrg->gr_gid);
     setgrent();
     //遍历整个组文件
    while((ptr = getgrent()) != NULL)
     {
         printf("group name is: %s\t",ptr->gr_name);
         printf("group gid is: %d\n",ptr->gr_gid);
     }
     endgrent();
     return 0;
 }

程序执行结果如下所示:


附加组,一个用户可以属于多个组,这样可以参加多项工作,优点是不必显式地经常更改组。用户登录时候,系统按照口令文件记录项中的数值组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_tgroup); //调用setgroups,确定其组的成员关系

  其他数据文件  除了口令文件和组文件外,Linux也使用很多其他文件,一般情况下,这些文件都至少支持三个函数:
(1)get函数:读文件中的下一个记录项。
(2)set函数:将文件偏移量设置到文件起始处。
(3)end函数:关闭系统文件。
  如果该文件支持关键字检索,例如口令文件支持基于用户名和用户ID的检索,因此实现了接口getpwnam和getpwuid函数,就会支持相应的函数。

 

存取系统数据文件的类似例程

 

 

说明

存取系统数据文件的类似例程

口令

说明

数据文件

头文件

结构

口令

/etc/passwd

<pwd.h>

passwd

阴影

/etc/group

<grp.h>

group

主机

阴影

/etc/shadow

<shadow.h>

spwd

网络

主机

/etc/hosts

<netdb.h>

hostent

协议

网络

/etc/networks

<netdb.h>

netent

服务

协议

/etc/protocols

<netdb.h>

protoent

  系统标识,uname函数返回与当前主机和操作系统有关的信息,函数字在<sys/utsname.h>头文件中定义。utsname结构信息和操作函数如下:

  struct utsname {
      char sysname[];    /*Operating system name (e.g., "Linux") */
      char nodename[];   /* Namewithin "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 YPdomain name */
    #endif
  };

  int uname(struct utsname *buf);

写个程序获取本机当前主机和操作系统信息,程序如下:

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/utsname.h>
 #include <errno.h>
 
 int main()
 {
     struct utsname  name;
     if(uname(&name) == -1)
    {
         perror("uname() error");
        exit(-1);
     }
     printf("system name is: %s\n",name.sysname);
     printf("node name is: %s\n",name.nodename);
    printf("release is: %s\n",name.release);
     printf("version is: %s\n",name.version);
     printf("machine is: %s\n",name.machine);
     return 0;
 }

时间和日期,Unix内核提供的基本时间服务是计算自国际标准时间公元1970年1月1日00:00:00以来经过的秒数,基本数据类型是time_t,称为日历时间,包括时间和日期,将时间和日期作为一个量值进行保存。类型定义如下:

#ifndef __TIME_T

#define __TIME_T     /* 避免重复定义 time_t */

typedef long     time_t;    /* 时间值time_t 为长整型的别名*/

#endif

相关操作函数有:

#include <time.h>

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_ttv_usec;    /* microseconds */
};
struct timezone {
    inttz_minuteswest;     /* minutes west of Greenwich */
    inttz_dsttime;         /* type of DSTcorrection */
};

取得了这种以秒计的整型时间后,通常调用另外一个时间函数将其转化为人们可读的时间和日期。时间的结构及操作函数有:

struct tm {
    inttm_sec;         /* seconds */
    inttm_min;         /* minutes */
    inttm_hour;        /* hours */
    inttm_mday;        /* day of the month */
    inttm_mon;         /* month */
    inttm_year;        /* year */
    inttm_wday;        /* day of the week */
    inttm_yday;        /* day in the year */
    inttm_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(consttime_t *timep); //转换为本地实际
time_t mktime(struct tm *tm);
size_t strftime(char *s, size_t max,const char *format,const struct tm *tm); //对tm进行格式化输出到一个字符串
函数之间的关系如下图:

 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值