APUE读书笔记(四)
作者:互联网
6 系统数据文件和信息
口令文件
UNIX系统口令文件(/etc/passwd)中的字段包含在<pwd.h>中定义的passwd
结构中,每一行包含一个登录项,各字段间用冒号分隔。
口令文件中通常有用户名为root的登录项,其用户ID是0(超级用户),加密口令字段包含一个占位符(现在将其存放在另一文件中),登录项的某些字段可以为空(加密口令字段为空则无加密口令),shell字段(包含可执行程序名)为空则取系统默认值(通常是/bin/sh
)、为设备则组织任何人以其登录到该系统,用户名nobody
意味着使任何人都可以登录到这个系统(同登录项的用户ID与用户组ID不提供任何特权)。
给出用户登录名或数值用户ID,得到相关项:
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);//通过用户ID得到相关项
struct passwd *getpwnam(const char *name);//通过用户登录名得到相关项
//返回值:成功则返回指针,出错则返回NULL
查看整个口令文件:
#include <pwd.h>
struct passwd *getpwent(void);//返回口令文件中下一个记录项
//返回值:成功则返回指针,出错或到达文件尾则返回NULL
void setpwent(void);//将getpwent()的读写地址绕回开头
void endpwent(void);//关闭口令文件
阴影口令
加密口令是经单向加密算法处理过的用户口令副本。
加密口令存放在称为阴影口令的文件(/ect/shadow)中,不是一般用户可以读取的,文件中用户登录名与加密口令两个字段是必需的。
访问阴影口令文件:
#include <shadow.h>
struct spwd *getspnam(const char *name);//通过登录名得到相关项
struct spwd *getspent(void);//返回阴影口令文件中下一个记录
//返回值:成功则返回指针,出错则返回NULL
void setspent(void);//将getspent()的读写地址绕回开头
void endspent(void);//关闭阴影口令文件
组文件
UNIX组文件(/etc/group)中的字段包含在<grp.h>中所定义的group
结构中。
查看组名或数值组ID的相关项:
#include <grp.h>
struct group *getgrgid(gid_t gid);//通过组ID得到相关项
struct group *getgrnam(const char *name);//通过组名得到相关项
//返回值:成功则返回指针,出错则返回NULL
搜索整个组文件:
#include <grp.h>
struct group *getgrent(void);//返回组文件中下一个记录
//返回值:成功则返回指针,出错或到达文件尾则返回NULL
void setgrent(void);//将getgrent()的读写地址绕回开头
void endgrent(void);//关闭组文件
附属组ID
附属组概念使得用户不仅可以属于口令文件记录项中组ID所对应的组,也可属于多至16个另外的组。文件访问权限检查时,不仅将进程的有效组ID与文件的组ID相比较,而且也将所有附属组ID与文件的组ID进行比较。
获取和数组附属组ID:
#include <unistd.h>
int getgroups(int gidsetsize, gid_t grouplist[]);//获取当前用户附属组
//返回值:成功则返回附属组ID数量,出错则返回-1
#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 and Solaris*/
#include <unistd.h>/*on FreeBSD and Mac OS X*/
int initgroups(const char *username, gid_t basegid);//为特定用户设置附属组(特权操作)
//返回值:成功则返回0,出错则返回-1
其他数据文件
访问系统数据文件的一些例程:
说明 | 数据文件 | 头文件 | 结构 | 附加的键搜索函数 |
---|---|---|---|---|
口令 | /etc/passwd | <pwd.h> | passwd |
getpwnam 、getpwuid |
组 | /etc/group | <grp.h> | group |
getgrnam 、getgrgid |
阴影 | /etc/shadow | <shadow.h> | spwd |
getspnam |
主机 | /etc/hosts | <netdb.h> | hostent |
getnameinfo 、getaddrinfo |
网络 | /etc/networks | <netdb.h> | netent |
getnetbyname 、getnetbyaddr |
协议 | /etc/protocols | <netdb.h> | protoent |
Getprotobyname 、getprotobynumber |
服务 | /etc/services | <netdb.h> | servent |
getservbyname 、getservbyport |
登录账户记录
大多数UNIX系统都提供下列两个数据文件:utmp文件记录当前登录到系统的各个用户;wtmp文件跟踪各个登录和注销事件。
系统标识
获取与主机和操作系统有关的信息:
#include <sys/utsname.h>
int uname(struct utsname *name);
//返回值:成功则返回非负值,出错则返回-1
获得主机名:
#include <unistd.h>
int gethostname(char *name, int namelen);
//返回值:成功则返回0,出错则返回-1
时间和日期例程
获取当前时间和日期(time_t
是日历时间,包括时间和日期):
#include <time.h>
time_t time(time_t *calptr);
//返回值:成功则返回时间值,出错则返回-1
//若calptr非空则时间值也存放于其指向的单元内
获取指定时钟的时间(时钟通过clockid_t
类型进行标识):
#include <sys/time.h>
int clock_gettime(clockid_t clock_id, struct timespec *tsp);
//返回值:成功则返回0,出错则返回-1
//返回的时间值存放于tsp指向的单元内
获取与时钟同精度的时间:
#include <sys/time.h>
int clock_getres(clockid_t clock_id, struct timespec *tsp);
//返回值:成功则返回0,出错则返回-1
对特定的时钟设置时间:
#include <sys/time.h>
int clock_settime(clockid_t clock_id, const struct timespec *tsp);
//返回值:成功则返回0,出错则返回-1
//将tsp指向的单元内的值设置为时间值
获取当前时间(日期与时间,精确到微秒,SUSv4指定其已弃用):
#include <sys/time.h>
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
//返回值:总是返回0
//结果存放于tp指向的单元内
//tzp唯一合法值是NULL,某些平台支持用其说明时区
各个时间函数之间的关系:
将日历时间转换成分解的时间(结构tm
用来存放分解时间):
#include <time.h>
struct tm *gmtime(const time_t *calptr);//转换为协调统一时间
struct tm *localtime(const time_t *calptr);//转换为本地时间(考虑到本地时区和夏令时标志)
//返回值:指向分解的tm结构实体,出错则返回NULL
将分解时间变换成日历时间即time_t
值(以本地时间的年、月、日作参数):
#include <time.h>
time_t mktime(struct tm *tmptr);
//返回值:成功则返回日历时间,出错则返回-1
通过分解时间来产生格式化时间字符串:
#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);
//返回值:若有空间则返回存入数组的字符数,否则返回0
通过格式化时间字符串来产生分解时间:
#include <time.h>
char *strptime(const char *restrict buf, const char *restrict format, struct tm *restrict tmptr);
//返回值:指向上次解析的字符的下一个字符的指针,否则返回NULL
7 进程环境
main函数
main
函数的原型(C程序总是从main
函数开始运行):
int main(int argc, char *argv[]);
//argc是命令行参数的数目,argv是指向参数的各个指针所构成的数组
进程终止
共8种方式可以使得进程终止(前5种是正常终止):
- 从
main
返回; - 调用
exit
; - 调用
_exit
或_Exit
; - 最后一个线程从其启动例程返回;
- 从最后一个线程调用
pthread_exit
; - 调用
abort
; - 接到一个信号;
- 最后一个线程对取消请求做出响应。
退出函数(_exit
和_Exit
立即进入内核,exit
则先执行一些清理处理):
#include <stdlib.h>
void exit(int status);//总是执行一个标准I/O库的清理关闭操作:对于所有打开流调用fclose函数,在main函数中exit(0)即return(0)
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
//status是终止状态
一个进程可以登记多至32个函数用来在调用exit
时倒序自动调用:
#include <stdlib.h>
int atexit(void (*func)(void));
//返回值:成功则返回0,出错则返回非0
命令行参数
ISO C和POSIX.1都要求argv[argc]
是一个空指针,而argv[0]
即运行的程序名。
环境表
每个程序都接收到一张环境表,是一个字符指针数组,用于存放环境变量。
C程序的存储空间布局
地址 | 分布 | 说明 |
---|---|---|
高地址 | 命令行参数和环境变量 | |
栈 | ||
…………………… | ||
堆 | ||
未初始化的数据(bss) | 由exec 初始化为0 |
|
初始化的数据 | 由exec 从程序文件中读入 |
|
低地址 | 正文 | 由exec 从程序文件中读入 |
共享库
共享库使得可执行文件中不再需要包含公用的库函数,而只需在所有进程都可引用的存储区中保存这种库例程的一个副本。
程序第一次执行或调用某个库函数时,用动态链接方法将程序与共享库函数相链接,可以减少执行文件长度,不过会增加一些运行时间开销,库函数在版本迭代后无需对使用该库的程序重新连接编辑。
存储空间分配
管理存储空间:
#include <stdlib.h>
void *malloc(size_t size);//分配字节数为size大小的存储区(其中初值不确定)
void *calloc(size_t nobj, size_t size);//分配数量为nobj、字节数为size大小的存储区(每一位都初始化为0)
void *realloc(void *ptr, size_t newsize);//减少或增加之前分配的存储区长度(字节数为newsize)
//返回值:成功则返回非空指针,出错则返回NULL
//动态分配内存
void free(void *ptr);//释放ptr指向的存储空间
忘记释放存储空间会导致内存泄漏。
环境变量
取环境变量值:
#include <stdlib.h>
char *getenv(const char *name);
//返回值:指向与name关联的value指针,未找到则返回NULL
设置或删除环境变量:
#include <stdlib.h>
int putenv(char *str);//取形式为name=value的字符串,将其放入环境表
//返回值:成功则返回0,出错则返回非0
int setenv(const char *name, const char *value, int rewrite);//将name设置为value,若rewrite非0则删除现有定义、为0则不删除现有定义
int unsetenv(const char *name);//删除name的定义(不存在也不出错)
//返回值:成功则返回0,出错则返回-1
函数setjmp和longjmp
跨越函数的跳转:
#include <setjmp.h>
int setjmp(jmp_buf env);//设置跳转点(必须先于longjmp运行),返回longjmp中的val值
//返回值:直接调用则返回0,从longjmp返回则为非0
void longjmp(jmp_buf env, int val);//跳转至先前setjmp处,使其返回val值
函数getrlimit和setrlimit
对进程的资源限制进行查询和修改:
#include <sys/resource.h>
int getrlimit(int resource, struct rlimit *rlptr);//获取资源限制
int setrlimit(int resource, const struct rlimit *rlptr);//设置资源限制
//返回值:成功则返回0,出错则返回非0
标签:返回,APUE,读书笔记,int,void,返回值,include,struct 来源: https://www.cnblogs.com/sigma711/p/14045949.html