Am 24. August 2011 00:32 schrieb Pierre Bernhardt <[email protected]>:
> Hallo,
>
> ich habe ein kleines Problem. Diverse proprietäre Programme geben auch mal 
> was auf stderr
> aus, kommen aber mit einem exit 0 zurück (manchmal aber auch > 0). Nun 
> benötige ich am
> besten per Pipe-Verbindung ein kleines Tool, was auf den stderr hört und sich 
> dann mit einem
> exitcode >0 beendet, wenn auf stderr etwas durch rauscht. Prinzipiell, sobald 
> es etwas findet,
> braucht es gar nicht mehr weiter am stderr hören und muss nur noch auf das 
> Ende warten, damit
> es seinen Exitcode los wird.
> Das alles soll ohne temporäre Dateien ablaufen und der stdout und stderr 
> müssen ca. 1:1 hinten
> wieder raus kommen.
>
> programm | tool | was auch immer noch dahinter kommt >logfile 2>&1
>
> Habt Ihr eine Idee dazu, ob es so etwas schon geben könnte?
>

Ich hatt da noch so ein Programm rumfliegen, hab das mal grad umgebastelt.
Einfach mit "gcc -O -o outf outf.c" kompilieren.
Dann kann man das als Wrapper benutzen:
$ ./outf sh -c "echo foo >> /dev/stderr"
foo
$ echo $?
1
$ ./outf sh -c "echo foo >> /dev/stdout"
foo
$ echo $?
0

Muesstest du dann irgendwo in den Pfad legen, z.B. /usr/local/bin

Man koennte das noch umbasteln das es als Pipe funzt, aber das is mir
jetzt zu warm hier...

> MfG...
> Pierre
>

Gruss
Jan

-- 
Murphy's Law of Combat
Rule #3: "Never forget that your weapon was manufactured by the
lowest bidder"
/* outf.c
 * wrapper prg which returns error if something was printed on STDERR
 *
 * Copyright (c) 2005-2011 Jan Seiffert
 *
 * This file is part of g2cd.
 *
 * g2cd is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * g2cd is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with g2cd.
 * If not, see <http://www.gnu.org/licenses/>.
 *
 * Licensed under the GNU Public License.
 *
 * $Id: $
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/poll.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <curses.h>
#include <term.h>

#define mkstr2(s) #s
#define mkstr(s) mkstr2(s)

#undef true
#undef false
#define true 1
#define false 0

struct my_buffer
{
	size_t pos, limit, capacity;
	char *data;
};

#define buffer_start(x) ((x).data + (x).pos)
#define buffer_remaining(x) ((x).limit - (x).pos)
#define buffer_flip(x) do { \
		(x).limit = (x).pos; \
		(x).pos = 0; \
	} while(0)
#define buffer_clear(x) do { \
		(x).limit = (x).capacity; \
		(x).pos = 0; \
	} while(0)
# define buffer_unflip(x) \
	do { \
		(x).pos = buffer_remaining(x); \
		(x).limit = (x).capacity; \
	} while(0)
# define buffer_compact(x) \
	do { \
		if(buffer_remaining(x)) \
			if((x).pos) memmove((x).data, \
				buffer_start(x), \
				buffer_remaining(x)); \
		buffer_unflip(x); \
	} while(0)

static int handle_output(int, int, int, int *, int *);
static int read_output(int, struct my_buffer *);
static int write_output(int, struct my_buffer *);
static int collect_child(pid_t);
static void invokation(char *);

int main(int argc, char **argv)
{
	int c_exit_status, have_written = false;
	int com_pipe[1][2];
	int std_emul_fds;
	pid_t c_pid = -1;

	if(2 > argc)
		goto BAIL_OUT;

	if(0 > pipe(com_pipe[0])) {
		perror(__FILE__ ", " mkstr(__LINE__) ", pipe()");
		return EXIT_FAILURE;
	}

	if(-1 == (c_pid = fork())) {
		perror(__FILE__ ", " mkstr(__LINE__) ", fork()");
		return EXIT_FAILURE;
	}
	else if(0 == c_pid) /* Child */
	{
		/* close the pipes read end */
		close(com_pipe[0][0]);

		/* set up stderr on the pipes */
		if(STDERR_FILENO != com_pipe[0][1]) {
			dup2(com_pipe[0][1], STDERR_FILENO);
			close(com_pipe[0][1]);
		}
		execvp(argv[1], &argv[1]);
		perror(argv[1]);
		return EXIT_FAILURE;
	}
	/* Parent */
	/* close pipes write end */
	close(com_pipe[0][1]);

	std_emul_fds = com_pipe[0][0];
	if(!handle_output(std_emul_fds, STDERR_FILENO, c_pid, &c_exit_status, &have_written)) {
		kill(c_pid, SIGKILL);
		return EXIT_FAILURE;
	}

	if(!have_written)
		return c_exit_status;
	else
		return EXIT_FAILURE;

BAIL_OUT:
	invokation(argv[0]);
	return EXIT_FAILURE;
}

static int handle_output(int fds, int tfd, int c_pid, int *c_exit_status, int *have_written)
{
	struct my_buffer data[1] = {{0,0,0,NULL}};
	struct pollfd poll_fds[1];
	int ret_val, poll_done[1] = {false};

	if(!(data[0].data = malloc(4096))) {
		perror(__FILE__ ", " mkstr(__LINE__) ", malloc()");
		return false;
	}
	data[0].capacity = data[0].limit = 4096;

	poll_fds[0].fd     = fds;
	poll_fds[0].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;

	do
	{
		int i;
		errno = 0;
		ret_val = poll(poll_fds, 1, -1);
		if(-1 == ret_val) {
			if(EINTR == errno)
				continue;
			perror(__FILE__ ", " mkstr(__LINE__) ", poll()");
			return false;
		}
		if(0 == ret_val && EAGAIN != errno)
			break;

		for(i = 0; ret_val && i < 1; i++)
		{
			if(!poll_fds[i].revents)
				continue;
			if(poll_fds[i].revents & POLLIN)
			{
				int read_status;
				if(-1 == (read_status = read_output(poll_fds[i].fd, &data[i])))
					return false;
				else if(1 == read_status) {
					poll_fds[i].events &= ~POLLIN;
					poll_done[i] = true;
				}
				buffer_flip(data[i]);
				if(buffer_remaining(data[i])) {
					int write_status;
					*have_written = true;
					if(-1 == (write_status = write_output(tfd, &data[i])))
						return false;
					else if(1 == write_status)
						return false;
				}
				buffer_compact(data[i]);
			}
			if(poll_fds[i].revents & ~POLLIN)
				poll_done[i] = true;
			ret_val--;
		}
	} while(!poll_done[0]);

	*c_exit_status = collect_child(c_pid);
	return true;
}

static int read_output(int fd, struct my_buffer *storage)
{
	ssize_t ret_val;
	do {
		errno = 0;
		ret_val = read(fd, buffer_start(*storage), buffer_remaining(*storage));
	} while(-1 == ret_val && EINTR == errno);

	if(-1 == ret_val) {
		if(EAGAIN == errno)
			return 0;
		perror(__FILE__ ", " mkstr(__LINE__) ", read()");
		return -1;
	} else if(0 == ret_val) {
		if(EAGAIN == errno)
			return 0;
		/* EOF reached */
		return 1;
	}
	else
	{
		storage->pos += ret_val;
		if(!buffer_remaining(*storage))
		{
			char *tmp_ptr = realloc(storage->data, storage->capacity * 2);
			if(!tmp_ptr) {
				perror(__FILE__ ", " mkstr(__LINE__) ", realloc()");
				return -1;
			}
			storage->data = tmp_ptr;
			storage->capacity *= 2;
			storage->limit = storage->capacity;
		}
		return 0;
	}
}

static int write_output(int tfd, struct my_buffer *storage)
{
	ssize_t ret_val;
	do {
		errno = 0;
		ret_val = write(tfd, buffer_start(*storage), buffer_remaining(*storage));
	} while(-1 == ret_val && EINTR == errno);

	if(-1 == ret_val) {
		if(EAGAIN == errno)
			return 0;
		perror(__FILE__ ", " mkstr(__LINE__)", write()");
		return -1;
	} else if(0 == ret_val) {
		if(EAGAIN == errno)
			return 0;
		/* EOF reached */
		return 1;
	} else {
		storage->pos += ret_val;
		return 0;
	}
}

static int collect_child(pid_t c_pid)
{
	pid_t ret_val;
	int status;

	do {
		status = 0;
		ret_val =  waitpid(c_pid, &status, 0);
	} while((0 > ret_val && EINTR == errno) || (0 <= ret_val && !WIFEXITED(status)));

	if (WIFEXITED(status))
		return WEXITSTATUS(status);
	else
		return EXIT_FAILURE;
}

static void invokation(char *prg_name)
{
	fprintf(stderr, "%s prg_name\n", prg_name);
}
-- 
Linux mailing list [email protected]
subscribe/unsubscribe: http://lug-owl.de/mailman/listinfo/linux
Hinweise zur Nutzung: http://www.lug-owl.de/Mailingliste/hints.epo

Antwort per Email an