apue学习笔记(第六章 系统数据文件和信息)

本文深入探讨了UNIX系统中与用户认证、权限管理、组管理等核心功能相关的数据文件,包括口令文件、阴影文件、组文件以及附属组ID的管理,详细介绍了这些文件的结构、访问方式及系统标识、时间日期例程等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

UNIX系统的正常运作需要使用大量与系统有关的数据文件,例如,口令文件/etc/passwd和组文件/etc/group就是经常被多个程序频繁使用的两个文件。

 

口令文件

UNIX系统口令文件包含如下字段,这些字段包含在<pwd.h>中定义的passwd结构中

口令文件是/etc/passwd,每一行包含上面各字段,字段之间用冒号分隔。可以使用finger命令打印指定用户的有关信息:finger -p 用户名

POSIX.1定义了两个获取口令文件项的函数,在给定用户登录名或数值用户ID后,这两个函数就能查看相关项

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

下面两个函数可以实现查看整个口令文件

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

调用getpwent时,它返回口令文件中的下一个记录项。函数setpwent反绕它所使用的文件(定位到文件开始处),endpwent则关闭这些文件,下面给出使用这3个函数实现getpwnam函数的程序

#include <pwd.h>
#include <stddef.h>
#include <string.h>

struct passwd *
getpwnam(const char *name)
{
    struct passwd  *ptr;

    setpwent();
    while ((ptr = getpwent()) != NULL)
        if (strcmp(name, ptr->pw_name) == 0)
            break;        /* found a match */
    endpwent();
    return(ptr);    /* ptr is NULL if no match found */
}

 

 

阴影文件

现在,某些系统将加密口令存放在另一个通常称为阴影口令的文件中:/etc/shadow

与访问口令文件的一组函数相类似,有另一组函数可用于访问阴影口令文件

#include <shadow.h>
struct spwd *getspnam(cosnt char *name);
struct spwd *getspent(void);
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);

类似于口令文件,如果需要搜索整个组文件,可以使用下面3个函数

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

 

 

附属组ID

当用户登录时,系统就按口令文件记录项中的数值组ID,赋给它实际组ID。在任何时刻执行newgrp更改组ID

一个用户可能参与多个项目,因此也就要同时属于多个组,使用附属组ID的优点是不必再显式地经常更改组。

为了获取和设置附属组ID,提供了下列3个函数

#include <unistd.h>
int getgroups(int gidsetsize,gid_t grouplist[]);
int setgroups(int ngroups,const gid_t grouplist[]);
int init groups(const char *username,gid_t basegid);

getgroups将进程所属用户的各附属组ID填写到数组grouplist中,最多为gidsetsize个

setgroups可由超级用户调用以便为调用进程设置附属组ID表。

通常,只有initgroups函数调用setgroups,用来设置用户的附属组ID。

 

 

其他数据文件

下图给出访问系统数据文件的一些例程

对于这些数据文件的接口都都与上述对口令文件和组文件的相似,一般情况下,对于每个数据文件至少提供一下3个函数

1 get函数:读下一个记录

2 set函数:打开相应数据文件,然后反绕该文件

3 end函数:关闭相应数据文件

 

 

系统标识

POSIX.1定义了uname函数,它返回与主机和操作系统有关的信息

#include <sys/utsname.h>
int uname(struct utsname *name);

POSIX.1定义了该结构中最少需提供的字段

 struct utsname {
         char sysname[];    /* Operating system name (e.g., "Linux") */
         char nodename[];   /* Name within "some implementation-defined network" */
         char release[];    /* Operating system release (e.g., "2.6.28") */
         char version[];    /* Operating system version */
         char machine[];    /* Hardware identifier */
}

 

 

时间和日期例程

time函数返回当前时间和日期。它是自公元1970年1月1日00:00:00以来经过的秒数(日历时间)

#include <time.h>
time_t time(time_t *calptr);

如果参数非空,则时间值也存放在由calptr指向的单元内。

下面两个函数将日历时间转换成分解的时间,并将这些存放在一个tm结构中

#include <time.h>
struct tm *gmtime(const time_t *calptr);
struct tm *localtime(const time_t *calptr);
struct tm {
         int tm_sec;         /* seconds [0-60] */
         int tm_min;         /* minutes  [0-59] */
         int tm_hour;        /* hours [0-23] */
         int tm_mday;        /* day of the month [1-31] */
         int tm_mon;         /* month [0-11] */
         int tm_year;        /* year since 1900*/
         int tm_wday;        /* day of the week [0-6]*/
         int tm_yday;        /* day in the year [0-365]*/
         int tm_isdst;       /* daylight saving time */
};

mktime函数将tm结构转换成time_t值

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

strftime用于格式化时间值

#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);

下面列出format参数的格式

strptime是strftime的反过来的版本,将字符串时间转换成分解时间

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

 

### APUE 第三章 学习笔记 #### 文件 I/O 基础 APUE 的第三章主要讨论了 Unix 系统中的文件 I/O 操作基础。这一章节涵盖了多个重要的概念技术细节,对于理解如何高效地操作文件至关重要。 #### 打开关闭文件 为了打开一个文件,程序通常会使用 `open` 或者 `creat` 函数[^1]。这两个函数都返回一个小于零的整数作为错误指示,而成功的调用则返回一个非负整数表示新创建的文件描述符。当不再需要访问某个特定文件时,应该通过调用 `close` 来关闭它。这不仅释放了与该文件关联的操作系统资源,而且也使得这个文件描述符能够被重新利用。 ```c #include <fcntl.h> /* For O_* constants */ #include <unistd.h> /* For open(), close() */ int fd; fd = open("example.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd >= 0) { // File opened successfully. } // Later... close(fd); ``` #### 文件读写 一旦有了有效的文件描述符,就可以对其进行读取 (`read`) 写入 (`write`) 操作。这些基本的 I/O 操作允许应用程序直接处理底层的数据流而不必关心具体的设备特性[^2]。 ```c char buffer[BUFSIZ]; ssize_t n; n = read(fd, buffer, BUFSIZ - 1); if (n > 0) { buffer[n] = '\0'; // Null terminate the string printf("%s\n", buffer); } const char *msg = "Hello world!"; write(fd, msg, strlen(msg)); ``` #### 文件定位 除了简单的顺序读写外,还可以改变当前文件偏移量来实现随机访问。这是通过 `lseek` 实现的功能之一,它可以向前或向后移动文件指针的位置以便从不同的位置开始读写数据[^3]。 ```c off_t offset; offset = lseek(fd, SEEK_SET, 0); // Move to beginning of file if (offset != -1L) { // Seek succeeded. } ``` #### 特殊文件类型的支持 Unix 系统支持多种特殊类型的文件对象,比如管道、套接字以及终端设备等。本章还介绍了针对这些不同类型文件的具体 API 接口支持机制[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值