/***************************************************************************** * * $Id$ * Purpose ...............: MBSE BBS Execute pipe * ***************************************************************************** * Copyright (C) 1997-2004 * * Michiel Broek FIDO: 2:280/2802 * Beekmansbos 10 * 1971 BV IJmuiden * the Netherlands * * This file is part of MBSE BBS. * * This BBS 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 2, or (at your option) any * later version. * * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ #include "../config.h" #include "mbselib.h" static struct _fppid { FILE *fp; int pid; } fppid[] = { {NULL, 0}, {NULL, 0}, {NULL, 0} }; #define maxfppid 2 FILE *expipe(char *cmd, char *from, char *to) { char buf[256], *buflimit, *vector[16], *p, *q, *f=from, *t=to; FILE *fp; int i, rc, pid, slot, pipedes[2]; buflimit = buf + sizeof(buf) -1 - (f&&t&&(strlen(f)>strlen(t))?strlen(f):t?strlen(t):0); for (slot = 0; slot <= maxfppid; slot++) { if (fppid[slot].fp == NULL) break; } if (slot > maxfppid) { WriteError("Attempt to pipe more than %d processes", maxfppid + 1); return NULL; } for (p = cmd, q = buf; (*p); p++) { if (q > buflimit) { WriteError("Attempt to pipe too long command"); return NULL; } switch (*p) { case '$': switch (*(++p)) { case 'f': case 'F': if ((f)) while (*f) *(q++) = *(f++); f=from; break; case 't': case 'T': if ((t)) while (*t) *(q++) = *(t++); t=to; break; default: *(q++)='$'; *(q++)=*p; break; } break; case '\\': *(q++) = *(++p); break; default: *(q++) = *p; break; } } *q = '\0'; Syslog('+', "Expipe: %s",buf); i = 0; vector[i++] = strtok(buf," \t\n"); while ((vector[i++] = strtok(NULL," \t\n")) && (i<16)); vector[15] = NULL; fflush(stdout); fflush(stderr); if (pipe(pipedes) != 0) { WriteError("$Pipe failed for command \"%s\"", MBSE_SS(vector[0])); return NULL; } Syslog('e', "pipe() returned read=%d, write=%d", pipedes[0], pipedes[1]); if ((pid = fork()) == 0) { close(pipedes[1]); close(0); if (dup(pipedes[0]) != 0) { WriteError("$Reopen of stdin for command %s failed", MBSE_SS(vector[0])); exit(MBERR_EXEC_FAILED); } rc = execv(vector[0],vector); WriteError("$Exec \"%s\" returned %d", MBSE_SS(vector[0]), rc); exit(MBERR_EXEC_FAILED); } close(pipedes[0]); if ((fp = fdopen(pipedes[1],"w")) == NULL) { WriteError("$fdopen failed for pipe to command \"%s\"", MBSE_SS(vector[0])); } fppid[slot].fp = fp; fppid[slot].pid = pid; return fp; } int exclose(FILE *fp) { int status, rc, pid, slot, sverr; for (slot = 0; slot <= maxfppid; slot++) { if (fppid[slot].fp == fp) break; } if (slot > maxfppid) { WriteError("Attempt to close unopened pipe"); return -1; } pid = fppid[slot].pid; fppid[slot].fp = NULL; fppid[slot].pid = 0; Syslog('e', "Closing pipe to the child process %d",pid); if ((rc = fclose(fp)) != 0) { WriteError("$Error closing pipe to transport (rc=%d)", rc); if ((rc = kill(pid,SIGKILL)) != 0) WriteError("$kill for pid %d returned %d",pid,rc); } Syslog('e', "Waiting for process %d to finish",pid); do { rc = wait(&status); sverr = errno; if (status) Syslog('e', "$Wait returned %d, status %d,%d", rc, status >> 8, status & 0xff); } while (((rc > 0) && (rc != pid)) || ((rc == -1) && (sverr == EINTR))); switch (rc) { case -1:WriteError("$Wait returned %d, status %d,%d", rc, status >> 8, status & 0xff); return MBERR_EXEC_FAILED; case 0: return 0; default: if (WIFEXITED(status)) { rc = WEXITSTATUS(status); if (rc) { WriteError("Expipe: returned error %d", rc); return (rc + MBERR_EXTERNAL); } } if (WIFSIGNALED(status)) { rc = WTERMSIG(status); WriteError("Wait stopped on signal %d", rc); return rc; } if (rc) WriteError("Wait stopped unknown, rc=%d", rc); return rc; } return 0; }