Unix环境高级编程学习笔记(第六章)

第6章 系统数据文件和信息

U N I X口令文件包含了下列所示的各字段,这些字段包含在< p w d . h >中定义的p a s s w d结构中。
注意,P O S I X . 1只指定p a s s w d结构中7个字段中的5个。另外2个元素由S V R 4和4 . 3 + B S D支持。
说 明                                  struct passwd 成员 P O S I X . 1
用户名                                char    *pw_name     *
加密口令                            char    *pw_passwd
数值用户I D                       uid_t   pw_uid            *
数值组I D                           gid_t   pw_gid            *
注释字段                            char    *pw_gecos
初始工作目录                    char    *pw_dir           *
初始s h e l l                      char    *pw_shell       *

P O S I X . 1只定义了两个存取口令文件中信息的函数。在给出用户登录名或数值用户 I D后,这两个函数就能查看相关记录。
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwuid(uid_t u i d) ;
struct passwd *getpwnam(const char *n a m e) ;
两个函数返回:若成功则为指针,若出错则为 N U L L
g e t p w u i d由l s ( 1 )程序使用,以便将包含在一个 i节点中的数值用户 I D映照为用户登录名。
g e t p w n a m在键入登录名时由l o g i n ( 1 )程序使用。
这两个函数都返回一个指向p a s s w d结构的指针,该结构已由这两个函数在执行时填入了所
需的信息。该结构通常是在相关函数内的静态变量,只要调用相关函数,其内容就会被重写。
如果要查看的只是一个登录名或用户I D,那么这两个P O S I X . 1函数能满足要求,但是也有
些程序要查看整个口令文件。下列三个函数则可用于此。
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwent(void);

void setpwent(void);
void endpwent(void);

调用g e t p w e n t时,它返回口令文件中的下一个记录。如同上面所述的两个 P O S I X . 1函数一
样,它返回一个由它填写好的p a s s w o r d结构的指针。每次调用此函数时都重写该结构。在第一
次调用该函数时,它打开它所使用的各个文件。在使用本函数时,对口令文件中各个记录安排
的顺序并无要求。
函数s e t p w e n t反绕它所使用的文件,(应该先调用s e t p w e n t,这是一种保护性的措施,以便在调用者在此之前已经调用过 g e t p w e n t的情况下,反绕有关文件使它们定位到文件开始处。)g e t p w n a m和g e t p w u i d完成后不应使有关文e n d p w e n t则关闭这些文件。在使用g e t p w e n t查看完口令文件后,一定要调用e n d p w e n t关闭这些文件。g e t p w e n t知道什么时间它应当打开它所使用的文件(第一次被调用时),但是它并不能知道何时关闭这些文件。

U N I X组文件包含了下载所示字段。这些字段包含在< g r p . h >中所定义的g r o u p结构中。
说 明                                         struct group 成员 P O S I X . 1
组名                                           char   *gr_name             *  
加密口令                                   char   *gr_passwd
数字组I D                                  int    gr_gid                     *
指向各用户名指针的数组       char   **gr_mem           *

字段g r _ m e m是一个指针数组,其中的指针各指向一个属于该组的用户名。该数组以 n u l l结尾。
可以用下列两个由P O S I X . 1定义的函数来查看组名或数值组I D。
#include <sys/types.h>
#include <grp.h>
struct group *getgrgid(gid_t g i d) ;
struct group *getgrnam(const char *n a m e) ;
两个函数返回:若成功则为指针,若出错则为 N U L L
如同对口令文件进行操作的函数一样,这两个函数通常也返回指向一个静态变量的指针,在每次调用时都重写该静态变量。
如果需要搜索整个组文件,则须使用另外几个函数。下列三个函数类似于针对口令文件的三个函数。
#include <sys/types.h>
#include <grp.h>

struct group *getgrent(void);
返回:若成功则为指针,若出错或到达文件尾端则为 N U L L
void setgrent(void);
void endgrent(void);
这三个函数由S V R 4和4 . 3 + B S D提供。P O S I X . 1并末定义这些函数。
s e t g r e n t打开组文件(如若它尚末被打开)并反绕它。g e t g r e n t从组文件中读下一个记录,如若该文件尚未打开则先打开它。e n d g r e n t关闭组文件。

为了存取和设置添加组I D提供了下列三个函数:
#include <sys/types.h>
#include <unistd.h>
int getgroups(int g i d s e t s i z e, gid_t g ro u p l i s t[ ] ) ;
返回:若成功则为添加的组I D数,若出错则为-1
int setgroups(int n g ro u p s, const gid_t g ro u p l i s t[ ] ) ;
int initgroups(const char *u s e r n a m e, gid_t b a s e g i d) ;
两个函数返回:若成功则为0,若出错则为-1
g e t g r o u p s将进程所属用户的各添加组 I D填写到数组g ro u p l i s t中,填写入该数组的添加组I D数最多为 g i d s e t s i z e个。实际填写到数组中的添加组 I D数由函数返回。如果系统常数N G R O U P S _ M A X为0,则返回0,这并不表示出错。
作为一种特殊情况,如若g i d s e t s i z e为0,则函数只返回添加组I D数,而对数组g ro u p l i s t则
不作修改。(这使调用者可以确定g ro u p l i s t数组的长度,以便进行分配。)
s e t g ro u p s可由超级用户调用以便为调用进程设置添加组 I D表。g ro u p l i s t是组I D数组,而n g ro u p s说明了数组中的元素数。
通常,只有i n i t g r o u p s函数调用setgroups, initgroups读整个组文件(用函数getgrent, setgrent和
e n d g r e n t ),然后对u s e r n a m e确定其组的成员关系。然后,它调用s e t g r o u p s ,以便为该用户初始化添加组I D表。因为i n i t g r o u p s调用s e t g r o u p s ,所以只有超级用户才能调用i n i t g r o u p s。除了在组文件中找到u s e r n a m e是成员的组,i n i t g r o u p s也在添加组I D表中包括了b a s e g i d。b a s e g i d是u s e r n a m e在口令文件中的组I D。i n i t g r o u p s只有少数几个程序调用,例如l o g i n ( 1 )程序在用户登录时调用该函数。

一般情况下每个数据文件至少有三个函数:
(1) get函数:读下一个记录,如果需要还打开该文件。此种函数通常返回指向一个结构的指针。当已达到文件尾端时返回空指针。大多数 g e t函数返回指向一个静态存储类结构的指针,如果要保存其内容,则需复制它。
(2) set函数:打开相应数据文件(如果尚末打开),然后反绕该文件。如果希望在相应文件起始处开始处理,则调用此函数。
(3) end函数:关闭相应数据文件。正如前述,在结束了对相应数据文件的读、写操作后,总应调用此函数以关闭所有相关文件。
另外,如果数据文件支持某种形式的关键字搜索,则也提供搜索具有指定关键字的记录的例程。例如,对于口令文件提供了两个按关键字进行搜索的程序: g e t p w n a m寻找具有指定用户名的记录;g e t p w u i d寻找具有指定用户I D的记录。

下面是存取系统数据文件的一些例程
说 明  数 据 文 件 头 文 件   结 构       附加的关键字搜索函数
口令 / e t c / p a s s w d      < p w d . h >   p a s s w d g e t p w n a m , g e t p w u i d
组  / e t c / g r o u p        < g r p . h >   g r o u p g e t g r n a m , g e t g r g i d
主机 / e t c / h o s t s        < n e t d b . h >  h o s t e n t g e t h o s t b y n a m e ,

                        g e t h o s t b y a d d r
网络 / e t c / n e t w o r k s      < n e t d b . h >  n e t e n t g e t n e t b y n a m e , g e t n e t b y a d d r
协议 / e t c / p r o t o c o l s      < n e t d b . h >  p r o t o e n t g e t p r o t o b y n a m e ,

                        g e t p r o t o b y n u m b e r
服务 / e t c / s e r v i c e s      < n e t d b . h > s e r v e n t getservbyname, getservbyport

 

大多数U N I X系统都提供下列两个数据文件: u t m p文件,它记录当前登录进系统的各个用户;w t m p文件,它跟踪各个登录和注销事件。在V 7中,包含下列结构的一个二进制记录写入这两个文件中:
struct utmp {
char  ut_line[8];  /* tty line: "ttyh0", "ttyd0", "ttyp0", ... */
char  ut_name[8];  /* login name */
long  ut_time;     /* seconds since Epoch */
} ;
登录时,l o g i n程序填写这样一个结构,然后将其写入到 u t m p文件中,同时也将其添写到w t m p
文件中。注销时,i n i t进程将u t m p文件中相应的记录擦除(每个字节都填以0 ),并将一个新记录
添写到w t m p文件中。读w t m p文件中的该注销记录,其u t _ n a m e字段清除为0。在系统再启动时,
以及更改系统时间和日期的前后,都在 w t m p文件中添写特殊的记录项。w h o ( 1 )程序读u t m p文
件,并以可读格式打印其内容。后来的 U N I X版本提供l a s t ( 1 )命令,它读w t m p文件并打印所选
择的记录。

P O S I X . 1定义了u n a m e函数,它返回与主机和操作系统有关的信息。
#include <sys/utsname.h>
int uname(struct utsname *n a m e) ;
返回:若成功则为非负值,若出错则为-1

通过该函数的参数向其传递一个u t s n a m e结构的地址,然后该函数填写此结构。P O S I X . 1只定义了该结构中至少需提供的字段(它们都是字符数组),而每个数组的长度则由实现确定。某些实现在该结构中提供了另外一些字段。在历史上,系统 V为每个数组分配9个字节,其中有1个字节用于字符串结束符( n u l l字符)。
struct utsname {
char sysname[9];   /* name of the operating system */
char nodename[9];  /* name of this node */
char release[9];   /* current release of operating system */
char version[9];   /* current version of this release */
char machine[9];   /* name of hardware type */
} ;
u t s n a m e结构中的信息通常可用u n a m e ( 1 )命令打印。

伯克利类的版本提供g e t h o s t n a m e函数,它只返回主机名,该名字通常就是T C P / I P网络上主机的名字。
#include <unistd.h>
int gethostname(char *n a m e, int n a m e l e n) ;
返回:若成功则为0,若出错则为-1
通过n a m e返回的字符串以 n u l l结尾(除非没有提供足够的空间 )。< s y s / p a r a m . h >中的常数M A X H O S T N A M E L E N规定了此名字的最大长度(通常是6 4字节)。如果宿主机联接到T C P / I P网络中,则此主机名通常是该主机的完整域名。
h o s t n a m e ( 1 )命令可用来存取和设置主机名。(超级用户用一个类似的函数s e t h o s t n a m e来设
置主机名。)主机名通常在系统自举时设置,它由/ e t c / r c取自一个启动文件。

由U N I X内核提供的基本时间服务是国际标准时间公元1 9 7 0年1月1日0 0 : 0 0 : 0 0以来经过的秒数这种秒数是以数据类型 t i m e _ t表示的。我们称它们为日历时间。日历时间包括时间和日期。U N I X在这方面与其他操作系统的区别是:( a )以国际标准时间而非本地时间计时;( b )可自动进行转换,例如变换到夏日制;( c )将时间和日期作为一个量值保存。t i m e函数返回当前时间和日期。
#include <time.h>
time_t time(time_t *c a l p t r) ;
返回:若成功则为时间值,若出错则为-1
时间值作为函数值返回。如果参数非n u l l,则时间值也存放在由c a l p t r指向的单元内。
一旦取得这种以秒计的很大的时间值后,通常要调用另一个时间函数将其变换为人们可读
的时间和日期(l o c a l t i m e、m k t i m e、c t i m e和s t r f t i m e)。

两个函数l o c a l t i m e和g m t i m e将日历时间变换成以年、月、日、时、分、秒间,并将这些存放在一个t m结构中。
struct tm {  /* a broken-down time */
int  tm_sec;   /* seconds after the minute: [0, 61] */
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;   /* month of the year: [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 */
} ;
秒可以超过5 9的理由是可以表示润秒。注意,除了月日字段,其他字段的值都以 0开始。如果夏时制生效,则夏时制标志值为正;如果已非夏时制时间则为 0;如果此信息不可用,则为负。
#include <time.h>
struct tm *gmtime(const time_t*c a l p t r) ;
struct tm *localtime(const time_t *c a l p t r) ;
两个函数返回:指向t m结构的指针
l o c a l t i m e和g m t i m e之间的区别是: l o c a l t i m e将日历时间变换成本地时间(考虑到本地时区和夏时
制标志),而g m t i m e则将日历时间变换成国际标准时间的年、月、日、时、分、秒、周日。
函数m k t i m e以本地时间的年、月、日等作为参数,将其变换成t i m e _ t值。
#include <time.h>
time_t mktime(struct tm *t m p t r) ;
返回:若成功则为日历时间,若出错则为- 1
a s c t i m e和c t i m e函数产生形式的2 6字节字符串,这与d a t e ( 1 )命令的系统默认输出形式类似:
Tue Jan 14 17:49:03 1992/n/0
#include <time.h>
char *asctime(const struct tm*t m p t r) ;
char *ctime(const time_t *c a l p t r) ;
两个函数返回:指向n u l l结尾的字符串
a s c t i m e的参数是指向年、月、日等字符串的指针,而c t i m e的参数则是指向日历时间的指针。
最后一个时间函数是s t r f t i m e,它是非常复杂的p r i n t f类的时间值函数。
#include <time.h>
size_t strftime(char *b u f, size_t m a x s i z e, const char *f o r m a t,const struct tm *t m p t r) ;
返回:若有空间,则存入数组的字符数,否则为 0
最后一个参数是要格式化的时间值,由一个指向一个年、月、日、时、分、秒、周日时间值的
指针说明。格式化结果存放在一个长度为m a x s i z e个字符的b u f数组中,如果b u f长度足以存放格
式化结果及一个n u l l终止符,则该函数返回在b u f中存放的字符数(不包括n u l l终止符),否则该函数返回0。
f o r m a t参数控制时间值的格式。如同p r i n t f函数一样。

l o c a l t i m e , m k t i m e , c t i m e和s t r f t i m e四个函数受到环境变量T Z的影响。如果定义了T Z,则这些函数将使用其值以代替系统默认时区。
如果T Z定义为空串(亦即T Z = ),则使用国际标准时间。T Z的值常常类似于:T Z = E S T 5 E D T,但是P O S I X . 1允许更详细的说明。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
UNIX环境高级编程笔记是关于在UNIX系统中进行高级编程的一些笔记和技巧的记录。这些笔记主要涉及文件I/O和进程管理等方面的内容。在UNIX系统中,文件I/O是通过文件描述符来进行操作的。文件描述符是一个整数,用来标识打开的文件。为了实现跨平台的兼容性,可以使用POSIX标准来进行文件操作。POSIX是一个操作系统接口的标准,它以UNIX为基础,但并不限于UNIX类系统。此外,Single UNIX Specification简称SUS,它是POSIX.1标准的一个超集,定义了UNIX系统的实现标准。在UNIX系统中,进程的初始化是由init进程来完成的。init进程会读取文件/etc/ttys,并根据其中定义的终端设备进行理。对于每个允许登录的终端设备,init进程会调用fork函数生成一个子进程,并通过exec函数执行getty程序来理该终端设备。通过这些技巧和方法,可以实现在UNIX环境下进行高级编程的需求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [UNIX环境高级编程笔记](https://blog.csdn.net/qq_55537010/article/details/127837953)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [《UNIX环境高级编程学习笔记](https://blog.csdn.net/qq_42526420/article/details/123143423)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值