view scripts/fc-rfcal-tee.c @ 97:037d9200aae4

INSTALL: refer to doc/Cable-config-howto
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 17 Jul 2017 19:15:44 +0000
parents 713749548df6
children
line wrap: on
line source

/*
 * This C program is a workaround for a stupidity in Bourne shell.
 * I would like to have a shell script like the following:
 *
 * set -e
 * fc-rfcal-vcxo | tee vcxo
 * fc-rfcal-rxband 900 | tee rx-900
 * fc-rfcal-rxband 1800 | tee rx-1800
 * ...
 *
 * and if one of the fc-rfcal-* steps encounters an error and returns
 * a non-zero exit code, I want the script to stop right there, hence
 * the set -e at the beginning.  Sounds like a very simple and reasonable
 * desire, doesn't it?  But oh noes - because I am piping the output
 * through tee in order to save it in log files, the process return
 * codes from fc-rfcal-* get *ignored* by the shell (the always successful
 * exit code from tee is all that counts), and it will keep executing
 * the following lines without stopping.
 *
 * This C program is like tee, but with invokation of the "main" command
 * whose output is to be saved built in.  The process forks, the "main"
 * command is executed in the child, the parent performs the tee function,
 * and when the child terminates, the parent propagates its exit code.
 */

#include <sys/types.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

char shell_pathname[] = "/bin/sh";
int log_fd;

tee_process(pipe_fd)
{
	char buf[1024];
	int cc;

	while ((cc = read(pipe_fd, buf, sizeof buf)) > 0) {
		write(1, buf, cc);
		if (log_fd > 2)
			write(log_fd, buf, cc);
	}
}

main(argc, argv)
	char **argv;
{
	int p[2];
	pid_t child, waitres;
	int status;

	if (argc != 3) {
		fprintf(stderr, "usage: %s command logfile\n", argv[0]);
		exit(1);
	}
	if (pipe(p) < 0) {
		perror("pipe");
		exit(1);
	}
	child = fork();
	if (child < 0) {
		perror("fork");
		exit(1);
	}
	if (!child) {
		dup2(p[1], 1);
		close(p[0]);
		close(p[1]);
		execl(shell_pathname, "sh", "-c", argv[1], 0);
		perror(shell_pathname);
		exit(1);
	}
	close(p[1]);
	log_fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0666);
	if (log_fd < 0)
		perror(argv[2]);
	tee_process(p[0]);
	waitres = waitpid(child, &status, 0);
	if (waitres == child && WIFEXITED(status))
		exit(WEXITSTATUS(status));
	else
		exit(1);
}