检查0、1、2号文件描述符方案对比及ISC dhcpd实现逻辑疑问
ISC dhcpd 0/1/2 文件描述符检查逻辑解答
基础前提
Linux 系统中open()系统调用遵循固定规则:调用成功时,永远返回当前进程可用的最小编号的文件描述符。
守护进程运行时,有可能被父进程关闭标准输入(0号)、标准输出(1号)、标准错误(2号)三个默认描述符。如果不预先占住这三个编号,后续程序打开的普通文件、套接字等资源可能会占用0/1/2编号,导致原本要输出到stdout/stderr的日志、错误信息被意外写入业务文件,引发数据损坏或逻辑异常。这段代码的作用就是确保0、1、2号描述符一定被占用,哪怕是绑定到无实际作用的/dev/null上。
代码逻辑逐段解释
/* Make sure that file descriptors 0 (stdin), 1, (stdout), and 2 (stderr) are open. To do this, we assume that when we open a file the lowest available file descriptor is used. */ fd = open ("/dev/null", O_RDWR); if (fd == 0) fd = open ("/dev/null", O_RDWR); if (fd == 1) fd = open ("/dev/null", O_RDWR); if (fd == 2) log_perror = 0; /* No sense logging to /dev/null. */ else if (fd != -1) close (fd);
- 第一次调用
open("/dev/null", O_RDWR),拿到当前最小可用的文件描述符:- 如果返回值为0,说明之前0号描述符处于未打开状态,现在已经用
/dev/null补全,需要继续检查1号,所以再次调用open - 如果第二次
open返回值为1,说明之前1号描述符处于未打开状态,已经补全,需要继续检查2号,所以第三次调用open - 如果第三次
open返回值为2,说明之前2号描述符处于未打开状态,现在已经绑定到/dev/null,此时往stderr输出日志等于直接丢弃,所以将log_perror设为0关闭对应日志输出 - 如果最终拿到的fd大于2,说明0、1、2号原本就处于正常打开状态,刚才申请的fd没有实际作用,直接调用
close(fd)释放资源即可,不会产生任何副作用。
- 如果返回值为0,说明之前0号描述符处于未打开状态,现在已经用
多次打开/dev/null的原因就是逐位检查0、1、2号描述符的状态,缺位的就用/dev/null补上,直到所有必须的描述符都被占用为止。
测试代码返回3的原因
你编写的测试代码运行返回3是完全正常的现象:普通程序从shell启动时,shell会默认帮进程打开0、1、2号描述符,分别绑定到当前终端的输入、输出、错误流,所以当前进程最小可用的文件描述符就是3,open自然返回3。
如果运行dhcpd时这段代码拿到的fd始终是3,属于预期的正常场景,说明当前进程的0、1、2号描述符本来就正常打开,代码会自动关闭这个临时打开的3号fd,不会产生任何问题。
内容的提问来源于stack exchange,提问作者alirezaarzehgar
相关产品推荐
相关产品推荐

