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
