Skip to content

Commit

Permalink
configuring commands via -c
Browse files Browse the repository at this point in the history
  • Loading branch information
insidewhy committed Sep 3, 2016
1 parent 7b99be4 commit 9a9ec5b
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 16 deletions.
79 changes: 64 additions & 15 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,12 @@ typedef struct {
/* args that form command, sent to execvp */
char **args;

/* 1 to watch, 0 to just run the command: see -f */
/* see -f */
bool watch;

/* see -c */
bool configuring;

pid_t pid;
} Cmd;

Expand Down Expand Up @@ -156,15 +159,41 @@ static void remove_term_and_int_handlers() {
return;
}

static void run_cmds(int n_cmds, Cmd *cmds) {
for (int i = 0; i < n_cmds; ++i)
/**
* Runs all commands marked with -c and waits for them to exit.
*/
static void run_configure_cmds(int n_cmds, Cmd *cmds) {
int run_configure_cmds = 0;
for (int i = 0; i < n_cmds; ++i) {
if (! cmds[i].configuring)
continue;

cmds[i].pid = run_proc(cmds[i].args);
++run_configure_cmds;
}

if (run_configure_cmds) {
DPRINTF("waiting for configuration commands to exit");
int status;
for (;;) {
if (waitpid(-1, &status, 0) == -1 && errno == ECHILD)
break;
}
DPRINTF("all configuration commands have exited");
}
}

static void run_cmds(int n_cmds, Cmd *cmds) {
for (int i = 0; i < n_cmds; ++i) {
if (! cmds[i].configuring)
cmds[i].pid = run_proc(cmds[i].args);
}
}

static void parse_cmd_args(Opts *opts, Cmd *cmd, char **arg_it, char **args_end) {
int c;
optind = 1; // reset global used as pointer by getopt
while ((c = getopt(args_end - arg_it, arg_it - 1, "+af")) != -1) {
while ((c = getopt(args_end - arg_it, arg_it - 1, "+acf")) != -1) {
switch(c) {
case 'a':
if (getpid() != 1) {
Expand All @@ -174,10 +203,21 @@ static void parse_cmd_args(Opts *opts, Cmd *cmd, char **arg_it, char **args_end)
opts->signal_everything = true;
break;

case 'c':
cmd->configuring = true;
break;

case 'f':
cmd->watch = true;
break;
}
}

if (cmd->configuring && cmd->watch) {
DPRINTF("cannot use -c and -w together for a single command");
exit(1);
}

cmd->args = arg_it + optind - 1;
}

Expand Down Expand Up @@ -232,9 +272,12 @@ int main(int argc, char *argv[]) {

// if -f hasn't been used then watch every command
if (0 == n_watch_cmds) {
n_watch_cmds = child_procs.n_cmds;
for (int i = 0; i < child_procs.n_cmds; ++i)
child_procs.cmds[i].watch = true;
for (int i = 0; i < child_procs.n_cmds; ++i) {
if (! child_procs.cmds[i].configuring) {
++n_watch_cmds;
child_procs.cmds[i].watch = true;
}
}
}

Cmd **watch_cmds = calloc(n_watch_cmds, sizeof(Cmd *));
Expand All @@ -247,14 +290,20 @@ int main(int argc, char *argv[]) {
}

install_term_and_int_handlers();
run_cmds(child_procs.n_cmds, child_procs.cmds);
int error_code = wait_for_requested_commands_to_exit(n_watch_cmds, watch_cmds);
remove_term_and_int_handlers();
alarm(WAIT_FOR_PROC_DEATH_TIMEOUT);
kill(opts.signal_everything ? -1 : 0, SIGTERM);
wait_for_all_processes_to_exit(error_code);

DPRINTF("all processes exited cleanly");

int error_code;
run_configure_cmds(child_procs.n_cmds, child_procs.cmds);

if (running) {
run_cmds(child_procs.n_cmds, child_procs.cmds);
error_code = wait_for_requested_commands_to_exit(n_watch_cmds, watch_cmds);
remove_term_and_int_handlers();
alarm(WAIT_FOR_PROC_DEATH_TIMEOUT);
kill(opts.signal_everything ? -1 : 0, SIGTERM);
wait_for_all_processes_to_exit(error_code);

DPRINTF("all processes exited cleanly");
}

free(watch_cmds);
free(child_procs.cmds);
Expand Down
12 changes: 11 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ smell-baron -f sleep 1 --- sleep 2

When `-f` is used then only the processes marked with `-f` will be watched, any other processes will be killed with `SIGTERM` after the watched process(es) have exited. In the above example `sleep 2` would be killed after one second. `-f` can be used many times and not specifying it is the same as specifying it before every command.

## Configuration processes

`-c` can be used to mark a command as a configuring command. `smell-baron` will delay running all commands not marked with `-c` until all commands marked with `-c` have exited.

```
smell-baron -c sleep 1 --- echo hello
```

In the above example `hello` will be echoed after one second.

## Cleaning up

After `smell-baron`'s supervised processes have exited it uses `kill(0, SIGTERM)` to kill remaining processes. This sends a kill signal to every process in the same process group. Some processes create processes in new process groups and then fail to terminate them when they are killed. The `-a` flag can be used to kill all reachable processes (by using `kill(-1, SIGTERM)`). This argument can only be used from the init process (a process with pid 1).
Expand Down Expand Up @@ -73,6 +83,6 @@ To to link against `musl` rather than `glibc` an `Alpine Linux` container can be

A prebuilt binary can be obtained from github:
```
wget https://github.com/ohjames/smell-baron/releases/download/v0.4.1/smell-baron
wget https://github.com/ohjames/smell-baron/releases/download/v0.4.2/smell-baron
chmod a+x smell-baron
```

0 comments on commit 9a9ec5b

Please sign in to comment.