chicken-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Chicken-users] Interaction of subprocess and condition handling


From: Lassi Kortela
Subject: Re: [Chicken-users] Interaction of subprocess and condition handling
Date: Sat, 20 Jul 2019 01:13:53 +0300
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:60.0) Gecko/20100101 Thunderbird/60.8.0

I think you'd basically have to replicate the following C traditional programming technique in whatever mixture of Scheme and C is appropriate for Chicken. So when you run "./spawn date" it succeeds and prints output from the standard Unix "date" utility. But when you run "./spawn nonexistent" it writes an error message to stderr (the child process does the writing since it has access to the precise errno value after execve() whereas the parent does not, so the child can show a more precise error message). And the exit code from the parent is the nonzero code 1 to indicate error.

Obviously in Chicken you would not exit the parent, but you'd exit the child with code 126 as here. In Chicken you'd probably want some fancy way to propagate the errno value from the child to the parent after a failed execve(). It's unwise to do something like _exit(errno); One solution would be to open a close-on-exec pipe from parent to child at a known fd number and pass the errno value via the pipe. The parent would probably have to poll() or select() on the pipe to check for error, but I haven't thought this through.

Source code, also downloadable at <https://misc.lassi.io/2019/spawn.c>:

----------------------------------------------------------------------

// The child process uses the magic exit code 126 to indicate to the
// parent process that execve() failed. You could use another code,
// but IIRC this is the traditional choice.

#include <sys/wait.h>

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static void warn(const char *msg) {
    fprintf(stderr, "%s\n", msg);
}

static void warnsys(const char *msg) {
    fprintf(stderr, "%s: %s\n", msg, strerror(errno));
}

static void diesys(const char *msg) {
    warnsys(msg);
    exit(1);
}

static void die(const char *msg) {
    warn(msg);
    exit(1);
}

static void spawn(char **argv) {
    pid_t child;
    int status;

    if ((child = fork()) == -1) {
        diesys("cannot fork");
    }
    if (!child) {
        // We are in the new child process.
        execvp(argv[0], argv);
        warnsys("cannot exec child process");
        _exit(126);
    }
    // We are in the old parent process.
    if (waitpid(child, &status, 0) == -1) {
        diesys("cannot wait for child process");
    }
    if (!WIFEXITED(status)) {
        die("child process did not exit normally");
    }
    switch (WEXITSTATUS(status)) {
    case 0:
        // Success, all good.
        break;
    case 126:
        // Exec failed. Child already printed error message. Since
        // this we are the parent, we stay silent -- there's no need
        // to write a duplicate error message. But propagate the error
        // to the process that started _us_ by exiting with a nonzero
        // code anyway.
        exit(1);
    default:
        // Some other error.
        fprintf(stderr, "Child exited with code %d\n",
                (int)WEXITSTATUS(status));
        break;
    }
}

int main(int argc, char **argv) {
    if (argc < 2) {
        die("usage: spawn command [args...]");
    }
    spawn(&argv[1]);
    return 0;
}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]