在嵌入式系统上,您最好system()
自己实现。考虑以下代码(未经测试!):
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
/* Helper function: Open the specified file at the desired descriptor.
*/
static int openfd(const int descriptor,
const char *const filename,
const int flags, const mode_t mode)
{
int fd, result;
if (!filename || descriptor == -1)
return errno = EINVAL;
/* Close existing descriptor. Ignore errors. Hopefully it is reused. */
do {
result = close(descriptor);
} while (result == -1 && errno == EINTR);
/* Open the desired file. */
do {
fd = open(filename, flags, mode);
} while (fd == -1 && errno == EINTR);
if (fd == -1)
return errno;
/* Did we get lucky, and get the correct descriptor already? */
if (fd == descriptor)
return 0;
/* Move the descriptor. */
do {
result = dup2(fd, descriptor);
} while (result == -1 && errno == EINTR);
if (result == -1) {
const int saved_errno = errno;
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
return errno = saved_errno;
}
/* Close the temporary descriptor. */
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
if (result == -1) {
const int saved_errno = errno;
do {
result = close(descriptor);
} while (result == -1 && errno == EINTR);
return errno = saved_errno;
}
return 0;
}
/* Start command on the background.
* Note: args[1] is the first argument, args[0] is the command name.
* NULL input/output/error redirects from/to /dev/null.
* Empty string for input/output/error does no redirections;
* the command the uses the same input/output/error.
* For non-empty output or error, specify the 'man 2 open' O_ flags too.
*
* Returns (pid_t)0 with errno set if an error occurs,
* otherwise the PID of the child process started.
*/
pid_t run(const char *file,
char *const args[],
const char *const input,
const char *const output, const int output_flags,
const char *const error, const int error_flags)
{
pid_t child;
int result, flags;
if (!cmd || !arg || !arg[0]) {
errno = EINVAL;
return (pid_t)0;
}
child = fork();
if (child == (pid_t)-1)
return (pid_t)0;
if (child)
return child;
/* This is the child process. */
if (input && *input)
result = openfd(STDIN_FILENO, input, O_RDONLY | O_NOCTTY, 0);
else
if (!input)
result = openfd(STDIN_FILENO, "/dev/null", O_RDONLY | O_NOCTTY, 0);
else
result = 0;
if (result)
exit(127);
if (output && *output)
result = openfd(STDOUT_FILENO, output, output_flags, 0666);
else
if (!output)
result = openfd(STDOUT_FILENO, "/dev/null", O_WRONLY | O_NOCTTY, 0);
else
result = 0;
if (result)
exit(127);
if (error && *error)
result = openfd(STDERR_FILENO, error, error_flags, 0666);
else
if (!error)
result = openfd(STDERR_FILENO, "/dev/null", O_WRONLY | O_NOCTTY, 0);
else
result = 0;
if (result)
exit(127);
execvp(file, args);
exit(127);
}
唯一启动命令,run()
您需要等待它完成。请注意,您的主程序可以同时进行有意义的工作,除非它需要立即退出状态(或命令应该创建的文件)。示例使用:
/* Command to run. NULL terminates the list. */
char *const cmd[] = { "ls", "-l", NULL };
pid_t child, p;
int status;
child = run(cmd[0], cmd,
NULL /* < /dev/null */,
"/tmp/some-log-file", O_WRONLY | O_CREAT | O_APPEND,
"", 0 /* No redirection for standard error */);
if (!child) {
fprintf(stderr, "Cannot run '%s': %s.\n", cmd[0], strerror(errno));
exit(1);
}
do {
status = 0;
p = waitpid(child, &status, 0);
} while (p == (pid_t)-1 && errno == EINTR);
if (p == (pid_t)-1) {
fprintf(stderr, "Lost '%s': %s.\n", cmd[0], strerror(errno));
exit(1);
}
if (WIFEXITED(status)) {
if (!WEXITSTATUS(status))
printf("Command executed successfully.\n");
else
printf("Command failed with exit status %d.\n", WEXITSTATUS(status));
} else
if (WSIGNALED(status))
printf("Command died from signal %s.\n", strsignal(WTERMSIG(status)));
else
printf("Command died unexpectedly.\n");
尽管最后一部分通常缩写为
if (WIFEXITED(status) && !WEXITSTATUS(status))
printf("'%s': Successful.\n", cmd[0]);
else
printf("'%s': Failed.\n", cmd[0]);
请注意,如果您仍然处理输出,您可能应该使用管道(或者popen()
上述函数的扩展版本)。
希望您觉得这个有帮助。