1

On an embedded system with Linux as OS I want to call a 3rd party binary to retrieve data from a database and to append this data to an existing file. The command string which is handed over to the system() function looks like:

"export_from_db >> /tmp/myFile"

Unfortunately, this doesn't work. /tmp/myFile never gets created! If I omit the redirection, then the database export is printed to stdout.

I wonder if system() and the redirection via ">>" go together well? On the prompt I successfully tested this command "export_fom_db >> /tmp/myFile"! Does anybody know how to achieve it using system()? Is there some kind of quoting necessary?

4

2 回答 2

1

嗯..实际上,对我来说似乎没问题..这正是 system() 的用途 - 在当前 shell 下执行一行。嵌入式 linux 的 shell 是否支持 >> 运算符?您是否在终端中手动尝试过?

另一个想法是您的应用程序可能在其他用户帐户下运行,并且该帐户可能具有一些奇怪的配置,例如使用一些 csh 或 ksh 而不是 bash(反之亦然,取决于您喜欢什么)。检查实际拥有该进程的用户并检查 /etc/passwd 的 shell 设置。

此外,运行应用程序的用户帐户根本没有写入 /tmp 的权限的可能性很小 :) 一定要检查一下

另外...在您的“嵌入式Linux”上,仅以简单的方式实现 system() 的可能性很小,它只是使用给定的参数调用应用程序并跳过所有其他shell-wise 运算符。这样做是为了节省资源,因为 system() 可能很少使用,或者只是被你的 linux 设计者“太重”了..这取决于发行版..如果你告诉我们哪一个是的,那么有更多知识的人可能会说是否是这种情况。

于 2012-10-02T22:35:59.433 回答
1

在嵌入式系统上,您最好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()上述函数的扩展版本)。

希望您觉得这个有帮助。

于 2012-10-03T00:19:17.110 回答