// ---------------------------------------------------------------------- // File: ConsolePipe.cc // Author: Andreas-Joachim Peters - CERN // ---------------------------------------------------------------------- /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2011 CERN/Switzerland * * * * This program 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. * * * * This program 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 this program. If not, see .* ************************************************************************/ /*----------------------------------------------------------------------------*/ #include "ConsolePipe.hh" #include "common/Path.hh" #include "common/IoPipe.hh" /*----------------------------------------------------------------------------*/ #include "XrdSys/XrdSysLogger.hh" #include "XrdSys/XrdSysPthread.hh" #include "XrdOuc/XrdOucString.hh" #include "XrdNet/XrdNetOpts.hh" #include "XrdNet/XrdNetSocket.hh" /*----------------------------------------------------------------------------*/ #include #include #include #include /*----------------------------------------------------------------------------*/ extern eos::common::IoPipe iopipe; static void* StaticThreadReaderStdout (void* arg) { int fd = ((unsigned long long) arg) % 65536; XrdOucString sline = ""; do { char c; int nread = read(fd, &c, 1); if (nread == 1) { sline += c; if (c == '\n') { if (sline.find("#__STOP__#") != STR_NPOS) { sline.replace("#__STOP__#\n", ""); fprintf(stdout, "%s", sline.c_str()); return 0; } fprintf(stdout, "%s", sline.c_str()); sline = ""; } } else { fprintf(stderr, "socket read failed on fd %d\n", fd); } } while (1); return 0; } static void* StaticThreadReaderStderr (void* arg) { int fd = ((unsigned long long) arg) % 65536; XrdOucString sline = ""; do { char c; int nread = read(fd, &c, 1); if (nread == 1) { sline += c; if (c == '\n') { if (sline.find("#__STOP__#\n") != STR_NPOS) { sline.replace("#__STOP__#\n", ""); fprintf(stderr, "%s", sline.c_str()); return 0; } fprintf(stderr, "%s", sline.c_str()); sline = ""; } } else { fprintf(stderr, "socket read failed on fd %d\n", fd); } } while (1); return 0; } void pipe_exit_handler (int a) { fprintf(stdout, "\n"); fprintf(stderr, "\n"); iopipe.KillProducer(); iopipe.UnLockConsumer(); exit(-1); } int pipe_command (const char* cmd) { if (!cmd) { return -1; } XrdSysLogger* logger = new XrdSysLogger(); XrdSysError eDest(logger); if (!iopipe.Init()) { fprintf(stderr, "error: cannot set IoPipe\n"); return -1; } iopipe.LockConsumer(); int stdinfd = iopipe.AttachStdin(eDest); int stdoutfd = iopipe.AttachStdout(eDest); int stderrfd = iopipe.AttachStderr(eDest); int retcfd = iopipe.AttachRetc(eDest); if ((stdinfd < 0) || (stdoutfd < 0) || (stderrfd < 0) || (retcfd < 0)) { fprintf(stderr, "error: cannot attache to pipes\n"); return -1; } pthread_t thread1; pthread_t thread2; XrdSysThread::Run(&thread1, StaticThreadReaderStdout, (void*) (unsigned long long)stdoutfd, XRDSYSTHREAD_HOLD, "Stdout Thread"); XrdSysThread::Run(&thread2, StaticThreadReaderStderr, (void*) (unsigned long long)stderrfd, XRDSYSTHREAD_HOLD, "Stderr Thread"); signal(SIGINT, pipe_exit_handler); signal(SIGPIPE, SIG_IGN); int n = write(stdinfd, cmd, strlen(cmd)); if (n != (int) strlen(cmd)) { fprintf(stderr, "error: communication error to the connector - write failed errno=%d\n", errno); } XrdSysThread::Join(thread1, NULL); XrdSysThread::Join(thread2, NULL); // read the response code char a[2]; n = read(retcfd, a, 2); if (n != 2) { fprintf(stderr, "error: socket read failed on fd %d\n", retcfd); pipe_exit_handler(-1); return -1; // we don't get here anyway } else { iopipe.UnLockConsumer(); return (a[0]); } }