- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
好吧,这是一个很长的,打起精神来! :)
最近我尝试在启动期间启动一个用 bash 编写的看门狗脚本。所以我在 rc.local 中添加了一行,其中包含以下内容:
su someuser -c "/home/someuser/watchdog.sh &"
watchdog.sh 看起来像这样:
#!/bin/bash
until /home/someuser/eventMonitoring.py
do
sleep 1
done
一切都很好,一切都很好,脚本开始了。然而一个新进程出现在进程列表中,并永远留在那里:
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
root 3048 1 0 1024 620 1 20:04 ? 00:00:00 startpar -f -- rc.local
现在,我的脚本 (watchdog.sh) 启动并成功分离,因为它的 PPID 也是 1。当时我的任务是找出那个进程是什么。 Startpar 是 sysvinit 引导系统 (http://savannah.nongnu.org/projects/sysvinit) 的一部分。我目前正在使用该系统的 Debian Wheezy 7.4.0。现在 man startpar
说:
startpar is used to run multiple run-level scripts in parallel.
通过反复试验,我基本上弄清楚了如何在启动期间正确启动我的脚本,而不是让 startpar 挂起。进程的所有文件描述符都需要重定向到文件或 /dev/null 或一起关闭。当您考虑时,这是一件理性的事情。我终于这样做了:
su someuser -c "some_script.sh >/dev/null 2>&1 &"
这解决了问题。但仍然让我想知道为什么会这样。为什么 startpar 的行为如此。这是错误还是功能。
所以我深入研究了代码(http://svn.savannah.nongnu.org/viewvc/startpar/trunk/startpar.c?root=sysvinit&view=markup)并开始从头到尾:
首先,我找到了调用 startpar -f -- rc.local 的位置:
第 741 行:
execlp(myname, myname, "-f", "--", p->name, NULL);
好的,这实际上会启动一个新的 startpar 进程,它将替换当前正在运行的实例。它基本上是对自身的递归调用。让我们看看 -f 参数的作用:
第 866 行:
case 'f':
forw = 1;
break;
好的,让我们看看将 forw 变量设置为 1 会发生什么...
第 900 行:
if (forw)
do_forward();
最后让我们看看这个函数是怎么回事:
第 615 行:
void do_forward(void)
{
char buf[4096], *b;
ssize_t r, rr;
setsid();
while ((r = read(0, buf, sizeof(buf))))
{
if (r < 0)
{
if (errno == EINTR)
continue;
#if defined(DEBUG) && (DEBUG > 0)
perror("\n\rstartpar: forward read");
#endif
break;
}
b = buf;
while (r > 0)
{
rr = write(1, b, r);
if (rr < 0)
{
if (errno == EINTR)
continue;
perror("\n\rstartpar: forward write");
rr = r;
}
r -= rr;
b += rr;
}
}
_exit(0);
}
据我了解。这会将所有来自文件描述符 0 的内容重定向到文件描述符 1。现在让我们看看真正链接到这些文件描述符的是什么:
root@server:~# ls -al /proc/3048/fd
total 0
dr-x------ 2 root root 0 Apr 2 21:13 .
dr-xr-xr-x 8 root root 0 Apr 2 21:13 ..
lrwx------ 1 root root 64 Apr 2 21:13 0 -> /dev/ptmx
lrwx------ 1 root root 64 Apr 2 21:13 1 -> /dev/console
lrwx------ 1 root root 64 Apr 2 21:13 2 -> /dev/console
嗯,很有趣...所以 ptmx 是根据人的说法:
The file /dev/ptmx is a character file with major number 5
and minor number 2, usually of mode 0666 and owner.group of root.root.
It is used to create a pseudoterminal master and slave pair.
和控制台:
The current console is also addressed by
/dev/console or /dev/tty0, the character device with major number 4
and minor number 0.
那时我来到了 stackoverflow。现在,有人可以告诉我这里发生了什么吗?我做对了吗,startpar 处于不断将到达 ptmx 的任何内容重定向到 console 的阶段?为什么要这样做?为什么选择 ptmx?这是错误吗?
最佳答案
这绝对不是 startpar
的错误,它正在做的正是它 promises to in the first place .
The output of each script is buffered and written when the script exits, so output lines of different scripts won't mix. You can modify this behaviour by setting a timeout.
在 startpar.c
中的 run()
函数中,
第 422 行:获取主伪终端的句柄(在本例中为 /dev/ptmx
)
p->fd = getpt();
第429行:获取对应slave伪终端的路径
else if ((m = ptsname(p->fd)) == 0 || grantpt(p->fd) || unlockpt(p->fd))
第 438 行:fork 一个子进程
if ((p->pid = fork()) == (pid_t)-1)
第 475 行:使默认 stdout
TEMP_FAILURE_RETRY(关闭(1));
第 476 行:获取从属伪终端的句柄。现在,这是 1
,即子节点的 stdout
现在重定向到从属伪终端(并由主伪终端节点接收)。
if (open(m, O_RDWR) != 1)
第 481 行:还通过使用 salve 伪终端 fd 复制它来捕获 stderr
。
TEMP_FAILURE_RETRY(dup2(1, 2));
第 561 行:在一些簿记之后,启动感兴趣的可执行文件(作为子进程)
execlp(p->name, p->arg0, (char *)0);
父进程稍后可以通过读取缓冲的主伪终端捕获这个新启动进程的所有输出/错误日志,并将其记录到实际的标准输出(即 /dev/console
在这种情况下)。
startpar -f ...
进程?显式标记可执行交互告诉 startpar
跳过 psedoterminal 主/从欺骗以缓冲终端 I/O,因为启动的交互式可执行文件的任何输出需要立即显示在屏幕上而不是缓冲.
这在几个地方修改了执行流程。主要在 1171 行,其中 startpar
不会为交互式可执行文件调用 run()
函数。
这已经过测试和描述here .
stdout
和stderr
。使用构造 ">/dev/null 2>&1 &"
丢弃要启动的可执行文件的 stdout
/stderr
。如果它们都显式设置为 NULL,即 startpar 不会像通常那样无限期地缓冲它们。
startpar
设置显式超时要么在startpar.c
timo
The timeout set with the
-t
option is used as buffer timeout. If the output buffer of a script is not empty and the last output was timeout seconds ago, startpar will flush the buffer.
或 startpar.c
gtimo
The
-T
option timeout works more globally. If no output is printed for more than global_timeout seconds, startpar will flush the buffer of the script with the oldest output. Afterwards it will only print output of this script until it is finished.
关于c - 弄清楚 startpar.c (sysvinit) 在做什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22840360/
目前我使用基于 ARM64 的 Debian Images 和 docker。 我想在启动时自动化 docker 守护进程,这样我们就不必手动启动它。但是图像不使用 systemd,而是使用 good
所以默认情况下我处于运行级别 3。在关闭期间我切换到运行级别 0。但是如果我将我的脚本(有一个 curl 调用)放在 /etc/rc0.d/,因为运行级别 0 网络已经停止,因此它无法执行 curl
好吧,这是一个很长的,打起精神来! :) 最近我尝试在启动期间启动一个用 bash 编写的看门狗脚本。所以我在 rc.local 中添加了一行,其中包含以下内容: su someuser -c "/h
首先,请不要将此帖子视为系统评论或批评,而只是简单地寻求帮助。 由于我无法通过 systemd 文档找到解决此问题的方法,所以这个问题已经有将近一年半的时间没有得到解决,而且从未收到任何答案。 所以,
我正在尝试使用 sudo yum install -y go-agent 安装 GoCD 代理 但是,我收到以下错误。 Resolving Dependencies --> Running trans
我有一个可以像这样启动的 Erlang 启动脚本: /usr/bin/erl -boot /path/to/my-boot-script 它在从控制台运行时有效,但在我从 systemd 运行时失败且
我是一名优秀的程序员,十分优秀!