如何在守护进程中使用 popen() 和 pclose() 获取通过管道执行的 shell 命令的正确退出代码?
How to get the correct exit code of a shell command executed via pipe using popen() and pclose() in a daemonized process?
我正在编写一个 C++ 守护程序,它将在 Linux 嵌入式系统上 运行 并执行 shell 命令。我正在尝试获取命令 (stdout) 的输出以及上述 shell 命令的退出代码。我遵循了以下关于如何在使用管道时获取 return 值或 shell 命令的退出代码的问题:
在我将进程守护进程之前,这会按预期工作。当我守护进程时 pclose()
总是 returns "-1" 无论命令是成功还是失败。这里的预期结果是成功执行的“0”和 shell 命令的错误代码的整数“>0”。
命令的输出 - stdout - 可以正确读取和解释,但尝试关闭管道以获取退出代码失败,错误代码为“-1”(See the man page for pclose and how to interpret the return value)
我使用这个 SO 问题作为如何创建 linux 守护进程的参考:“Creating a daemon in Linux" as well as the book "Linux-UNIX-Programmierung”(一本德语书籍)关于如何创建守护进程,到目前为止它已经为除了破坏 pclose() 的行为外,我没有任何问题。
以下是有关如何重现问题的示例:
#include <array> // For std::array
#include <memory> // For std::unique_ptr
#include <string>
#include <sys/stat.h>
#include <sys/syslog.h> // For all syslog things
#include <sys/wait.h>
#include <unistd.h>
// Just a helper method for signal handling
void signalHandler(int sig) {
switch (sig) {
case SIGINT:
case SIGTERM:
break;
}
}
int main(int argc, char *argv[]) {
/* Open log file to be able to use syslog */
setlogmask(LOG_UPTO(LOG_DEBUG));
openlog("MyDemoProg", LOG_PID, LOG_DAEMON);
#if 1 // Set to 0 to disable the daemonizing
/* Fork off the parent process */
pid_t pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);
/* On success: The child process becomes session leader */
if (setsid() < 0)
exit(EXIT_FAILURE);
/* Catch, ignore and handle signals */
signal(SIGCHLD, SIG_IGN);
/* Set up a signal handler */
struct sigaction newSigAction;
newSigAction.sa_handler = signalHandler;
sigemptyset(&newSigAction.sa_mask);
newSigAction.sa_flags = 0;
/* Signals to handle */
sigaction(SIGHUP, &newSigAction, NULL); /* catch hangup signal */
sigaction(SIGTERM, &newSigAction, NULL); /* catch term signal */
sigaction(SIGINT, &newSigAction, NULL); /* catch interrupt signal */
/* Fork off for the second time*/
pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);
/* Set new file permissions */
umask(0);
/* Change the working directory to the root directory */
/* or another appropriate directory */
chdir("/");
/* Close all open file descriptors */
int x;
for (x = sysconf(_SC_OPEN_MAX); x >= 0; x--) {
close(x);
}
#endif // end of daemonizing
std::string command = "ls /var/bla/; sleep 2; echo test";
syslog(LOG_DEBUG, "Command is: %s", command.c_str());
int rc = -999; // the return code variable, set to some value to see if it's
// truly changed
std::array<char, 16> buffer;
std::string commandResult;
// A wrapper function to be able to get the return code while still using the
// automatic close function wizzardy of unique_ptr
auto pclose_wrapper = [&rc](FILE *cmd) { rc = pclose(cmd); };
{
const std::unique_ptr<FILE, decltype(pclose_wrapper)> pipe(
popen(command.c_str(), "r"), pclose_wrapper);
if (!pipe) {
syslog(LOG_ERR, "Could not open pipe! Exiting");
return EXIT_FAILURE;
}
/* Read in the pipe and save the content to a buffer */
while (::fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
commandResult += buffer.data();
}
}
syslog(LOG_DEBUG, "Command result is: %s", commandResult.c_str());
syslog(LOG_DEBUG, "Return code is: %d", rc);
return EXIT_SUCCESS;
}
要从守护程序和常规版本切换,请将第 22 行的 #if
标志更改为“0”。这将禁用所有与守护进程相关的代码。
我在我的主要开发机器 运行ning Arch Linux x64 和 g++ (GCC) 版本 11.2.0 上使用 g++ main.cpp -o pcloseTest -Wall -Werror
编译了这段代码。然后我使用 ./pcloseTest
直接从终端 运行 程序并使用 journalctl (journalctl -f
).
监控日志记录的输出
我还使用我的 arm-cross-compile 工具链编译了相同的代码,以测试错误是否可以在另一个架构上重现。我的 arm-cross-compile 工具链的 GCC 版本是 7.3.0 和 OS 其中 运行s 该程序是 Yocto Linux
的定制版本,用于 32 位 ARM。
两者的行为相同并产生相同的输出 - 在非守护程序版本中产生预期输出,而在守护程序版本中产生意外输出“-1”。
这是启用了守护进程的嵌入式“Yocto Linux”系统 (/var/log/message
) 的系统日志文件的输出:
May 9 15:43:08 MY-EMBEDDED-SYSTEM daemon.debug MyDemoProg[10255]: Command is: ls /var/bla/; sleep 2; echo test
May 9 15:43:10 MY-EMBEDDED-SYSTEM daemon.debug MyDemoProg[10255]: Command result is: test
May 9 15:43:10 MY-EMBEDDED-SYSTEM daemon.debug MyDemoProg[10255]: Return code is: -1
此处禁用:
May 9 15:43:26 MY-EMBEDDED-SYSTEM daemon.debug MyDemoProg[10262]: Command is: ls /var/bla/; sleep 2; echo test
May 9 15:43:28 MY-EMBEDDED-SYSTEM daemon.debug MyDemoProg[10262]: Command result is: test
May 9 15:43:28 MY-EMBEDDED-SYSTEM daemon.debug MyDemoProg[10262]: Return code is: 0
为了比较,这里是我的 x64 Linux(systemd 和 journalctl)中用于守护程序代码的代码:
May 09 16:06:02 aero15 MyDemoProg[76950]: Command is: ls /var/bla/; sleep 2; echo test
May 09 16:06:04 aero15 MyDemoProg[76950]: Command result is: test
May 09 16:06:04 aero15 MyDemoProg[76950]: Return code is: -1
和正常代码:
May 09 16:05:34 aero15 MyDemoProg[76805]: Command is: ls /var/bla/; sleep 2; echo test
May 09 16:05:36 aero15 MyDemoProg[76805]: Command result is: test
May 09 16:05:36 aero15 MyDemoProg[76805]: Return code is: 0
如您所见,在所有四种情况下,命令结果都可以正确读取为“test”,而在非守护程序中,pclose()
的 return 代码如预期的那样为“0” (表示命令已成功执行)和守护程序版本中的“-1”,表明 pclose()
.
发生了意想不到的事情
我试图研究 popen()
或 pclose()
是否有一些已知的与守护进程相关的奇怪行为,但我找不到任何具体的东西。
我自己的怀疑是,某个信号可能没有被 pclose()
工作所需的守护进程处理,或者分叉两次以守护进程然后再次分叉以执行管道 popen
打破了一些东西。但我不是哪个信号可能没有正确处理或可能丢失。
作为参考,我还尝试使用 waitpid()
函数 as suggested by the man page RATIONALE 实现我自己的 pclose()
版本,但我放弃了它,因为它的行为类似于 pclose()
并且我'假设底层问题是相同的。
非常感谢您的帮助,如果需要更多信息或更多详细信息,请告诉我。
我的程序的问题是,信号 SIGCHLD
没有被我的程序处理。
评估 errno
并检查 pclose()
给出的错误后,我找到了解决方案。 errno
returned ECHILD
根据 errno man page 表示“没有子进程”。我通过向我的 pclose_wrapper
lambda 函数添加更多处理来捕获此错误:
...
auto pclose_wrapper = [&rc](FILE *cmd) {
rc = pclose(cmd);
if (rc < 0) {
/* Log the error if pclose returns "-1" signaling an error occured */
syslog(LOG_ERR, "rc is negativ - %s", strerror(errno));
}
};
...
经过更多研究并查看 man page for signal,我发现我的程序忽略了前面提到的 SIGCHLD
信号。如果子进程停止或终止,此信号会通知进程。
解决方案是添加 sigaction(SIGCHLD, &newSigAction, NULL);
并删除明确忽略信号的 signal(SIGCHLD, SIG_IGN);
行。
这是工作代码:
#include <array> // For std::array
#include <cstring>
#include <memory> // For std::unique_ptr
#include <string>
#include <sys/stat.h>
#include <sys/syslog.h> // For all syslog things
#include <sys/wait.h>
#include <unistd.h>
void signalHandler(int sig) {
switch (sig) {
case SIGINT:
case SIGTERM:
break;
case SIGCHLD:
/* Some child related action */
break;
}
}
int main(int argc, char *argv[]) {
/* Open log file to be able to use syslog */
setlogmask(LOG_UPTO(LOG_DEBUG));
openlog("MyDemoProg", LOG_PID, LOG_DAEMON);
#if 1 // Set to 0 to disable the daemonizing
pid_t pid = fork();
if (pid < 0)
exit(EXIT_FAILURE);
if (pid > 0)
exit(EXIT_SUCCESS);
if (setsid() < 0)
exit(EXIT_FAILURE);
struct sigaction newSigAction;
newSigAction.sa_handler = signalHandler;
sigemptyset(&newSigAction.sa_mask);
newSigAction.sa_flags = 0;
sigaction(SIGHUP, &newSigAction, NULL); /* catch hangup signal */
sigaction(SIGTERM, &newSigAction, NULL); /* catch term signal */
sigaction(SIGINT, &newSigAction, NULL); /* catch interrupt signal */
sigaction(SIGCHLD, &newSigAction,
NULL); /* catch child stopped or terminated signal */
pid = fork();
if (pid < 0)
exit(EXIT_FAILURE);
if (pid > 0)
exit(EXIT_SUCCESS);
umask(0);
chdir("/");
for (int x = sysconf(_SC_OPEN_MAX); x >= 0; x--) {
close(x);
}
syslog(LOG_DEBUG, "Daemonizing is enabled");
#else
syslog(LOG_DEBUG, "Daemonizing is disabled");
#endif
std::string command = "ls /var/bla/; sleep 2; echo test";
syslog(LOG_DEBUG, "Command is: %s", command.c_str());
int rc = -999;
std::array<char, 16> buffer;
std::string commandResult;
// A wrapper function to be able to get the return code while still using the
// automatic close function wizzardy of unique_ptr
auto pclose_wrapper = [&rc](FILE *cmd) {
rc = pclose(cmd);
if (rc < 0) {
/* Log the error if pclose returns "-1" signaling an error occured */
syslog(LOG_ERR, "rc is negativ - %s", strerror(errno));
}
};
{
const std::unique_ptr<FILE, decltype(pclose_wrapper)> pipe(
popen(command.c_str(), "r"), pclose_wrapper);
if (!pipe) {
syslog(LOG_ERR, "Could not open pipe! Exiting");
return EXIT_FAILURE;
}
/* Read in the pipe and save the content to a buffer */
while (::fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
commandResult += buffer.data();
}
}
syslog(LOG_DEBUG, "Command result is: %s", commandResult.c_str());
syslog(LOG_DEBUG, "Return code is: %d", rc);
return EXIT_SUCCESS;
}
这里是 non-daemonized 和守护版本的输出:
(我添加了一条系统日志消息来指示守护程序代码是启用还是禁用。)
May 10 09:24:30 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10872]: Daemonizing is disabled
May 10 09:24:30 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10872]: Command is: ls /var/bla/; sleep 2; echo test
May 10 09:24:32 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10872]: Command result is: test
May 10 09:24:32 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10872]: Return code is: 0
---
May 10 09:24:49 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10881]: Daemonizing is enabled
May 10 09:24:49 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10881]: Command is: ls /var/bla/; sleep 2; echo test
May 10 09:24:51 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10881]: Command result is: test
May 10 09:24:51 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10881]: Return code is: 0
现在两个版本都给出了预期的 return 代码“0”。
我正在编写一个 C++ 守护程序,它将在 Linux 嵌入式系统上 运行 并执行 shell 命令。我正在尝试获取命令 (stdout) 的输出以及上述 shell 命令的退出代码。我遵循了以下关于如何在使用管道时获取 return 值或 shell 命令的退出代码的问题:
在我将进程守护进程之前,这会按预期工作。当我守护进程时 pclose()
总是 returns "-1" 无论命令是成功还是失败。这里的预期结果是成功执行的“0”和 shell 命令的错误代码的整数“>0”。
命令的输出 - stdout - 可以正确读取和解释,但尝试关闭管道以获取退出代码失败,错误代码为“-1”(See the man page for pclose and how to interpret the return value)
我使用这个 SO 问题作为如何创建 linux 守护进程的参考:“Creating a daemon in Linux" as well as the book "Linux-UNIX-Programmierung”(一本德语书籍)关于如何创建守护进程,到目前为止它已经为除了破坏 pclose() 的行为外,我没有任何问题。
以下是有关如何重现问题的示例:
#include <array> // For std::array
#include <memory> // For std::unique_ptr
#include <string>
#include <sys/stat.h>
#include <sys/syslog.h> // For all syslog things
#include <sys/wait.h>
#include <unistd.h>
// Just a helper method for signal handling
void signalHandler(int sig) {
switch (sig) {
case SIGINT:
case SIGTERM:
break;
}
}
int main(int argc, char *argv[]) {
/* Open log file to be able to use syslog */
setlogmask(LOG_UPTO(LOG_DEBUG));
openlog("MyDemoProg", LOG_PID, LOG_DAEMON);
#if 1 // Set to 0 to disable the daemonizing
/* Fork off the parent process */
pid_t pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);
/* On success: The child process becomes session leader */
if (setsid() < 0)
exit(EXIT_FAILURE);
/* Catch, ignore and handle signals */
signal(SIGCHLD, SIG_IGN);
/* Set up a signal handler */
struct sigaction newSigAction;
newSigAction.sa_handler = signalHandler;
sigemptyset(&newSigAction.sa_mask);
newSigAction.sa_flags = 0;
/* Signals to handle */
sigaction(SIGHUP, &newSigAction, NULL); /* catch hangup signal */
sigaction(SIGTERM, &newSigAction, NULL); /* catch term signal */
sigaction(SIGINT, &newSigAction, NULL); /* catch interrupt signal */
/* Fork off for the second time*/
pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);
/* Set new file permissions */
umask(0);
/* Change the working directory to the root directory */
/* or another appropriate directory */
chdir("/");
/* Close all open file descriptors */
int x;
for (x = sysconf(_SC_OPEN_MAX); x >= 0; x--) {
close(x);
}
#endif // end of daemonizing
std::string command = "ls /var/bla/; sleep 2; echo test";
syslog(LOG_DEBUG, "Command is: %s", command.c_str());
int rc = -999; // the return code variable, set to some value to see if it's
// truly changed
std::array<char, 16> buffer;
std::string commandResult;
// A wrapper function to be able to get the return code while still using the
// automatic close function wizzardy of unique_ptr
auto pclose_wrapper = [&rc](FILE *cmd) { rc = pclose(cmd); };
{
const std::unique_ptr<FILE, decltype(pclose_wrapper)> pipe(
popen(command.c_str(), "r"), pclose_wrapper);
if (!pipe) {
syslog(LOG_ERR, "Could not open pipe! Exiting");
return EXIT_FAILURE;
}
/* Read in the pipe and save the content to a buffer */
while (::fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
commandResult += buffer.data();
}
}
syslog(LOG_DEBUG, "Command result is: %s", commandResult.c_str());
syslog(LOG_DEBUG, "Return code is: %d", rc);
return EXIT_SUCCESS;
}
要从守护程序和常规版本切换,请将第 22 行的 #if
标志更改为“0”。这将禁用所有与守护进程相关的代码。
我在我的主要开发机器 运行ning Arch Linux x64 和 g++ (GCC) 版本 11.2.0 上使用 g++ main.cpp -o pcloseTest -Wall -Werror
编译了这段代码。然后我使用 ./pcloseTest
直接从终端 运行 程序并使用 journalctl (journalctl -f
).
我还使用我的 arm-cross-compile 工具链编译了相同的代码,以测试错误是否可以在另一个架构上重现。我的 arm-cross-compile 工具链的 GCC 版本是 7.3.0 和 OS 其中 运行s 该程序是 Yocto Linux
的定制版本,用于 32 位 ARM。
两者的行为相同并产生相同的输出 - 在非守护程序版本中产生预期输出,而在守护程序版本中产生意外输出“-1”。
这是启用了守护进程的嵌入式“Yocto Linux”系统 (/var/log/message
) 的系统日志文件的输出:
May 9 15:43:08 MY-EMBEDDED-SYSTEM daemon.debug MyDemoProg[10255]: Command is: ls /var/bla/; sleep 2; echo test
May 9 15:43:10 MY-EMBEDDED-SYSTEM daemon.debug MyDemoProg[10255]: Command result is: test
May 9 15:43:10 MY-EMBEDDED-SYSTEM daemon.debug MyDemoProg[10255]: Return code is: -1
此处禁用:
May 9 15:43:26 MY-EMBEDDED-SYSTEM daemon.debug MyDemoProg[10262]: Command is: ls /var/bla/; sleep 2; echo test
May 9 15:43:28 MY-EMBEDDED-SYSTEM daemon.debug MyDemoProg[10262]: Command result is: test
May 9 15:43:28 MY-EMBEDDED-SYSTEM daemon.debug MyDemoProg[10262]: Return code is: 0
为了比较,这里是我的 x64 Linux(systemd 和 journalctl)中用于守护程序代码的代码:
May 09 16:06:02 aero15 MyDemoProg[76950]: Command is: ls /var/bla/; sleep 2; echo test
May 09 16:06:04 aero15 MyDemoProg[76950]: Command result is: test
May 09 16:06:04 aero15 MyDemoProg[76950]: Return code is: -1
和正常代码:
May 09 16:05:34 aero15 MyDemoProg[76805]: Command is: ls /var/bla/; sleep 2; echo test
May 09 16:05:36 aero15 MyDemoProg[76805]: Command result is: test
May 09 16:05:36 aero15 MyDemoProg[76805]: Return code is: 0
如您所见,在所有四种情况下,命令结果都可以正确读取为“test”,而在非守护程序中,pclose()
的 return 代码如预期的那样为“0” (表示命令已成功执行)和守护程序版本中的“-1”,表明 pclose()
.
我试图研究 popen()
或 pclose()
是否有一些已知的与守护进程相关的奇怪行为,但我找不到任何具体的东西。
我自己的怀疑是,某个信号可能没有被 pclose()
工作所需的守护进程处理,或者分叉两次以守护进程然后再次分叉以执行管道 popen
打破了一些东西。但我不是哪个信号可能没有正确处理或可能丢失。
作为参考,我还尝试使用 waitpid()
函数 as suggested by the man page RATIONALE 实现我自己的 pclose()
版本,但我放弃了它,因为它的行为类似于 pclose()
并且我'假设底层问题是相同的。
非常感谢您的帮助,如果需要更多信息或更多详细信息,请告诉我。
我的程序的问题是,信号 SIGCHLD
没有被我的程序处理。
评估 errno
并检查 pclose()
给出的错误后,我找到了解决方案。 errno
returned ECHILD
根据 errno man page 表示“没有子进程”。我通过向我的 pclose_wrapper
lambda 函数添加更多处理来捕获此错误:
...
auto pclose_wrapper = [&rc](FILE *cmd) {
rc = pclose(cmd);
if (rc < 0) {
/* Log the error if pclose returns "-1" signaling an error occured */
syslog(LOG_ERR, "rc is negativ - %s", strerror(errno));
}
};
...
经过更多研究并查看 man page for signal,我发现我的程序忽略了前面提到的 SIGCHLD
信号。如果子进程停止或终止,此信号会通知进程。
解决方案是添加 sigaction(SIGCHLD, &newSigAction, NULL);
并删除明确忽略信号的 signal(SIGCHLD, SIG_IGN);
行。
这是工作代码:
#include <array> // For std::array
#include <cstring>
#include <memory> // For std::unique_ptr
#include <string>
#include <sys/stat.h>
#include <sys/syslog.h> // For all syslog things
#include <sys/wait.h>
#include <unistd.h>
void signalHandler(int sig) {
switch (sig) {
case SIGINT:
case SIGTERM:
break;
case SIGCHLD:
/* Some child related action */
break;
}
}
int main(int argc, char *argv[]) {
/* Open log file to be able to use syslog */
setlogmask(LOG_UPTO(LOG_DEBUG));
openlog("MyDemoProg", LOG_PID, LOG_DAEMON);
#if 1 // Set to 0 to disable the daemonizing
pid_t pid = fork();
if (pid < 0)
exit(EXIT_FAILURE);
if (pid > 0)
exit(EXIT_SUCCESS);
if (setsid() < 0)
exit(EXIT_FAILURE);
struct sigaction newSigAction;
newSigAction.sa_handler = signalHandler;
sigemptyset(&newSigAction.sa_mask);
newSigAction.sa_flags = 0;
sigaction(SIGHUP, &newSigAction, NULL); /* catch hangup signal */
sigaction(SIGTERM, &newSigAction, NULL); /* catch term signal */
sigaction(SIGINT, &newSigAction, NULL); /* catch interrupt signal */
sigaction(SIGCHLD, &newSigAction,
NULL); /* catch child stopped or terminated signal */
pid = fork();
if (pid < 0)
exit(EXIT_FAILURE);
if (pid > 0)
exit(EXIT_SUCCESS);
umask(0);
chdir("/");
for (int x = sysconf(_SC_OPEN_MAX); x >= 0; x--) {
close(x);
}
syslog(LOG_DEBUG, "Daemonizing is enabled");
#else
syslog(LOG_DEBUG, "Daemonizing is disabled");
#endif
std::string command = "ls /var/bla/; sleep 2; echo test";
syslog(LOG_DEBUG, "Command is: %s", command.c_str());
int rc = -999;
std::array<char, 16> buffer;
std::string commandResult;
// A wrapper function to be able to get the return code while still using the
// automatic close function wizzardy of unique_ptr
auto pclose_wrapper = [&rc](FILE *cmd) {
rc = pclose(cmd);
if (rc < 0) {
/* Log the error if pclose returns "-1" signaling an error occured */
syslog(LOG_ERR, "rc is negativ - %s", strerror(errno));
}
};
{
const std::unique_ptr<FILE, decltype(pclose_wrapper)> pipe(
popen(command.c_str(), "r"), pclose_wrapper);
if (!pipe) {
syslog(LOG_ERR, "Could not open pipe! Exiting");
return EXIT_FAILURE;
}
/* Read in the pipe and save the content to a buffer */
while (::fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
commandResult += buffer.data();
}
}
syslog(LOG_DEBUG, "Command result is: %s", commandResult.c_str());
syslog(LOG_DEBUG, "Return code is: %d", rc);
return EXIT_SUCCESS;
}
这里是 non-daemonized 和守护版本的输出:
(我添加了一条系统日志消息来指示守护程序代码是启用还是禁用。)
May 10 09:24:30 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10872]: Daemonizing is disabled
May 10 09:24:30 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10872]: Command is: ls /var/bla/; sleep 2; echo test
May 10 09:24:32 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10872]: Command result is: test
May 10 09:24:32 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10872]: Return code is: 0
---
May 10 09:24:49 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10881]: Daemonizing is enabled
May 10 09:24:49 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10881]: Command is: ls /var/bla/; sleep 2; echo test
May 10 09:24:51 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10881]: Command result is: test
May 10 09:24:51 MY-EMBEDDED-DEVICE daemon.debug MyDemoProg[10881]: Return code is: 0
现在两个版本都给出了预期的 return 代码“0”。