unix环境高级编程(系统数据文件和信息)笔记

unix系统的运行需要大量的数据文件,可以理解为配置文件,都是ASCII文本文件,可以用标准I/O对这些文件进行操作

口令文件

口令就是用于验证用户权限登录密码等信息的文件,文件地址/etc/passwd。文件里面的内容一行作为一条数据,一条数据里面的各各字段用冒号隔开,各字段对应到<pwd.h>的passwd结构体中。结构体如下:

struct passwd
{
  char *pw_name;		/* Username.  */
  char *pw_passwd;		/* Password.  */
  __uid_t pw_uid;		/* User ID.  */
  __gid_t pw_gid;		/* Group ID.  */
  char *pw_gecos;		/* Real name.  */
  char *pw_dir;			/* Home directory.  */
  char *pw_shell;		/* Shell program.  */
};

但是各各基于unix下的操作系统对上面的字段支持不一致,支持情况以及字段信息如下:
在这里插入图片描述

获取某个用户的口令结构体提供了如下函数:

#include <pwd.h>

struct passwd *getpwuid(uid_t uid);
struct passwd *getpwnam(const char *name);
										// 两个函数返回值:若成功,返回指针;若出错,返回NULL

函数返回的结构体是函数内部的静态变量,所以不需要调用者进行回收,并且下一次的调用会导致上一次返回的数据改变。
对于上面的口令文件的操作可以用一下函数:

#include <pwd.h>

struct passwd *getpwent(void); // 返回文件下一项,尾部返回NULL
										// 返回值:若成功,返回指针;若出错或到达文件尾端,返回NULL
void setpwent(void); // 将getpwent返回指针指向口令文件开头
void endpwent(void); // getpwent、getpwuid、getpwnam调用后 一定使用此函数将文件关闭

阴影文件

刚刚的口令文件中有个密码字段,密码需要进行加密操作,将加密的密码,保存在/etc/shadow,此文件就是阴影文件,与口令文件类似同样具有各种字段如下:
在这里插入图片描述
同样具有操作函数,功能与口令文件类似:

#include <shadow.h>

struct spwd *getspnam(const char* name);
struct spwd *getspent(void);
										// 两个函数返回值:若成功,返回指针;若出错,返回NULL
void setspent(void);
void endspent(void);

组文件

unix组文件(/etc/group)包含下图所示字段,这些字段包含在<grp.h>中所定义的group结构中:
在这里插入图片描述
字段gr_mem是一个指针数组,其中每个指针指向一个属于该组的用户名,该数组以null指针结尾。
与前面的函数一样,也有对应的操作函数,也是返回静态变量,各各函数的功能以及注意事项参考口令文件:

#include <grp.h>

struct group *getgrgid(gid_t gid);
struct group *getgrnam(const char *name);
										// 两个函数返回值:若成功,返回指针;若出错,返回NULL

struct group *getgrent(void);
										// 返回值:若成功,返回指针;若出错或到达文件尾端,返回NULL
void setgrent(void);
void endgrent(void);

附属组ID

unix中早期的时候,任何一个用户都只属于一个组,用户登录时,系统按口令文件中的信息,得到组ID。然后可以在任何时候使用newgrp更改组ID,也可以使用newgrp不带参数返回原来的组。组ID用于做文件访问权限检查。后来增加了附属组ID进行权限检查比较。
附属组的目的是避免频繁修改组ID(一个用户可能要参加多个项目,因此使用附属组ID)。
附属组ID相关的操作函数:

#include <unistd.h>
// getgroups将进程所属用户的各附属组ID填写到数值grouplist中,
// 填写入该数组的附属组ID数最多为gidsetsize个;
// 实际填写到数组中的附属组ID数由函数返回,若gidsetsize为0,则函数只返回附属组ID数,
// 而对数组grouplist则不做修改;
int getgroups(int gidsetsize, gid_t grouplist[]);
										// 返回值:若成功,返回附属组ID数量;若出错,返回-1

#include <grp.h>	/* on Linux */
#include <unistd.h>	/* on FreeBSD, Mac OS X, and Solaris */
// setgroups由超级用户调用来为调用进程设置附属组ID表,grouplist是组ID数组,
// 而ngroups说明数组中的元素数,ngroups的值不能大于NGROUPS_MAX;
int setgroups(int ngroups, const gid_t grouplist[]);

#include <grp.h>	/* on Linux and Solaris */
#include <unistd.h>	/* on FreeBSD and Mac OS X */
// initgroups函数调用setgroups,initgroups先读整个组文件,对username确定其组的成员关系;
// 然后,它调用setgroups,为该用户初始化附属组ID表;
// 除了在组文件中找到username的所有组,initgroups也在附属组ID表中包含了basegid,
// basegid是username在口令文件中的组ID。也需要超级用户才能调用
int initgroups(const char *username, gid_t basegid);
										// 两个函数的返回值:若成功,返回0;若出错,返回-1

其他数据文件

前面讲了口令文件和组文件,日常操作中还有其他文件,比如记录网络服务器所提供服务的数据文件/etc/services,记录协议信息的数据文件/etc/protocols等等,所幸的是这些数据文件和上面的接口函数都是类似的

  • get函数:读下一个记录,如果需要,还会打开该文件。此种函数通常返回指向一个结构的指针。当已达到文件尾端时返回空指针。大多数get函数返回指向一个静态存储类结构的指针,如果要保存其内容,则需复制它;
  • set函数:打开相应数据文件(如果尚未打开),然后反绕该文件。如果希望在相应文件起始处开始处理,则调用此函数;
  • end函数:关闭相应数据文件。在结束了对相应数据文件的读、写操作后,总应调用此函数以关闭所有相应文件。

在这里插入图片描述

其他接口函数

  1. 系统标识
#include <sys/utsname.h>

int uname(struct utsname *name);
										// 返回值:若成功,返回非负值;若出错,返回-1
// 函数往name结构体中填入信息

结构体中的字符串都是数组,根据不同的操作系统实现定义不同的长度。此结构体如下:
在这里插入图片描述
2. 主机名

#include <unistd.h>

int gethostname(char *name, int namelen);
										// 返回值:若成功,返回0;若出错,返回-1

  1. 时间和日期
#include <time.h>
// 如果函数返回值不为空,则时间值也存放在参数中
time_t time(time_t *calptr);
										// 返回值:若成功,返回时间值;若出错,返回-1

POSX1.1拓展了对个系统时钟的支持
在这里插入图片描述

#include <sys/time.h>

struct timespec {
	__kernel_time_t	tv_sec;			/* seconds */
	long		tv_nsec;		/* nanoseconds */
};


// clock_gettime函数用于获取指定时钟的时间,返回的时间在timespec结构中,它把时间表示为秒和纳秒
// 第一个就是上面表格中的常量,区分时间类型
// 如果系统支持高精度时间值的情况下,此函数可能比time获取的实时系统时间有更高的精度
int clock_gettime(clockid_t clock_id, struct timespec *tsp);
										// 返回值:若成功,返回0;若出错,返回-1
// 获取指定时间类型的精度,放在第二个参数中
int clock_getres(clockid_t clock_id, struct timespec *tsp);
										// 返回值:若成功,返回0;若出错,返回-1
// 设置指定时间类型的时间
int clock_settime(clockid_t clock_id, const struct timespec *tsp);
										// 返回值:若成功,返回0;若出错,返回-1

/* A time value that is accurate to the nearest
   microsecond but also has a range of years.  */
struct timeval
{
  __time_t tv_sec;		/* Seconds.  */
  __suseconds_t tv_usec;	/* Microseconds.  */
};


// 可能已经弃用,但是比time函数可以获得更高的精度,第二个参数一般为NULL,根据不同的操作系统进行传参
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
										// 返回值:总是返回0
									
/* ISO C `broken-down time' structure.  */
struct tm
{
  int tm_sec;			/* Seconds.	[0-60] (1 leap second) */
  int tm_min;			/* Minutes.	[0-59] */
  int tm_hour;			/* Hours.	[0-23] */
  int tm_mday;			/* Day.		[1-31] */
  int tm_mon;			/* Month.	[0-11] */
  int tm_year;			/* Year	- 1900.  */
  int tm_wday;			/* Day of week.	[0-6] */
  int tm_yday;			/* Days in year.[0-365]	*/
  int tm_isdst;			/* DST.		[-1/0/1]*/

# ifdef	__USE_MISC
  long int tm_gmtoff;		/* Seconds east of UTC.  */
  const char *tm_zone;		/* Timezone abbreviation.  */
# else
  long int __tm_gmtoff;		/* Seconds east of UTC.  */
  const char *__tm_zone;	/* Timezone abbreviation.  */
# endif
};

上面的函数得到的值需要转化成为人们可读的日期,各各函数之类的调用关系如图:
在这里插入图片描述
身下的函数可以查询其他资料看如何使用

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值