/dev/initctl是一个管道文件,很多人知道它,但是知道怎么用。要想知道怎么用还是得看init程序的源代码,在init.c中就用到了 /dev/initctl管道文件。可以通过/dev/initctl改变系统的运行级别,但是怎么改变呢?比如说当前运行级别是2,我想将运行级别提到 3,那么想当然的做法就是:
[root@localhost zhaoy]# touch level
[root@localhost zhaoy]# echo '3'>level
[root@localhost zhaoy]# cat level >/dev/initctl
但是得到的结果却是:
INIT: got bogus initrequest
于是,我在init.c中搜以上错误字符串,在check_init_fifo中找到了它,以下看一下check_init_fifo函数的相关部分:
void check_init_fifo(void)
{
struct init_request request;
struct timeval tv;
struct stat st,st2;
fd_set fds;
int n;
int quit = 0;
if (stat(INIT_FIFO,&st2) < 0 && errno == ENOENT)
(void)mkfifo(INIT_FIFO,0600); //如果没有这个initctl管道,那么就建立它。
if (pipe_fd >= 0) { //如果已经打开了,那么就看看现在是否它的属性发生了变化
fstat(pipe_fd,&st);
if (stat(INIT_FIFO,&st2) < 0 ||
st.st_dev != st2.st_dev ||
st.st_ino != st2.st_ino) {
close(pipe_fd);
pipe_fd = -1;
}
}
if (pipe_fd < 0) { //原来打开却发生了变化或者根本没有打开都需要打开该管道
if ((pipe_fd = open(INIT_FIFO,O_RDWR|O_NONBLOCK)) >= 0) {
fstat(pipe_fd,&st);
if (!S_ISFIFO(st.st_mode)) {
initlog(L_VB,"%s is not a fifo",INIT_FIFO);
close(pipe_fd);
pipe_fd = -1;
}
}
if (pipe_fd >= 0) {
...//打开成功
}
}
if (pipe_fd >= 0) while(!quit) {//等待数据,如果没有数据就返回
FD_ZERO(&fds);
FD_SET(pipe_fd,&fds);
tv.tv_sec = 5;
tv.tv_usec = 0;
n = select(pipe_fd + 1,&fds,NULL,&tv);
if (n <= 0) {
if (n == 0 || errno == EINTR) return;
continue;
}
n = read(pipe_fd,&request,sizeof(request)); //读出一个??request是个什么东西,这个一会再谈。
if (n == 0) {
close(pipe_fd);
pipe_fd = -1;
return;
}
if (n <= 0) {
if (errno == EINTR) return;
continue;
}
console_init();
if (request.magic != INIT_MAGIC || n != sizeof(request)) { //检查魔术字
initlog(L_VB,"got bogus initrequest"); //终于找到那个出错信息,这就是切入点
continue;
}
switch(request.cmd) { //所有验证都通过,是一个合法请求
case INIT_CMD_RUNLVL: //要求改变运行级
sltime = request.sleeptime;
fifo_new_level(request.runlevel); //开始着手改变运行级
quit = 1;
break;
}
}
}
void fifo_new_level(int level)
{
int oldlevel;
if (level == runlevel)
return;
oldlevel = runlevel;
runlevel = read_level(level); //read_level检查level参数返回新的运行级别并赋给全局变量runlevel
if (runlevel == 'U') {
runlevel = oldlevel;
re_exec();
} else {
if (oldlevel != 'S' && runlevel == 'S') console_stty();
if (runlevel == '6' || runlevel == '0' || runlevel == '1')
console_stty();
read_inittab(); //重新加载/etc/inittab文件
fail_cancel();
setproctitle("init [%c]",runlevel);
}
}
check_init_fifo函数就是在那个init_main的主循环里被调用的,由此可见init进程时刻检测/dev/initctl管道,一旦 有请求马上处理,这真是太好了,我们也可以写一把/dev/initctl管道,但是怎么写呢?肯定得有一定的格式了,这个格式就是上面的??,实际上是一个结构体,我下面给出一个写/dev/initctl管道的完整代码,代码内部说一下那个initctl需要的数据结构:
#include
#include
#include
原文地址:https://www.jb51.cc/vb/262236.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。