diff --git a/lib/comms.cpp b/lib/comms.cpp index b0eb028d2..0be31e72e 100644 --- a/lib/comms.cpp +++ b/lib/comms.cpp @@ -360,7 +360,7 @@ namespace Comms{ Socket::hostBytesToStr(ip.data(), ip.size(), host); pid_t thisPid; std::deque args; - args.push_back(Util::getMyPath() + "MistSession"); + args.push_back("MistSession"); args.push_back(sessionId); // First bit defines whether to include stream name @@ -393,7 +393,7 @@ namespace Comms{ } setenv("SESSION_REQURL", reqUrl.c_str(), 1); int err = fileno(stderr); - thisPid = Util::Procs::StartPiped(args, 0, 0, &err); + thisPid = Util::Procs::StartPipedMist(args, 0, 0, &err); Util::Procs::forget(thisPid); unsetenv("SESSION_STREAM"); unsetenv("SESSION_IP"); diff --git a/lib/config.cpp b/lib/config.cpp index d2bc7392d..cad09aa0f 100644 --- a/lib/config.cpp +++ b/lib/config.cpp @@ -890,72 +890,6 @@ void Util::Config::addStandardPushCapabilities(JSON::Value &cap){ } -/// Gets directory the current executable is stored in. -std::string Util::getMyPath(){ - char mypath[500]; -#ifdef __CYGWIN__ - GetModuleFileName(0, mypath, 500); -#else -#ifdef __APPLE__ - memset(mypath, 0, 500); - unsigned int refSize = 500; - _NSGetExecutablePath(mypath, &refSize); -#else - int ret = readlink("/proc/self/exe", mypath, 500); - if (ret != -1){ - mypath[ret] = 0; - }else{ - mypath[0] = 0; - } -#endif -#endif - std::string tPath = mypath; - size_t slash = tPath.rfind('/'); - if (slash == std::string::npos){ - slash = tPath.rfind('\\'); - if (slash == std::string::npos){return "";} - } - tPath.resize(slash + 1); - return tPath; -} - -/// Gets all executables in getMyPath that start with "Mist". -void Util::getMyExec(std::deque &execs){ - std::string path = Util::getMyPath(); -#ifdef __CYGWIN__ - path += "\\Mist*"; - WIN32_FIND_DATA FindFileData; - HANDLE hdl = FindFirstFile(path.c_str(), &FindFileData); - while (hdl != INVALID_HANDLE_VALUE){ - if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){ - execs.push_back(FindFileData.cFileName); - } - if (!FindNextFile(hdl, &FindFileData)){ - FindClose(hdl); - hdl = INVALID_HANDLE_VALUE; - } - } -#else - DIR *d = opendir(path.c_str()); - if (!d){return;} - struct dirent *dp; - do{ - errno = 0; - if ((dp = readdir(d))){ - if (dp->d_type != DT_DIR && strncmp(dp->d_name, "Mist", 4) == 0){ - if (dp->d_type != DT_REG) { - struct stat st = {}; - stat(dp->d_name, &st); - if (!S_ISREG(st.st_mode)) - continue; - } - execs.push_back(dp->d_name);} - } - }while (dp != NULL); - closedir(d); -#endif -} - /// Sets the current process' running user void Util::setUser(std::string username){ if (username != "root"){ diff --git a/lib/config.h b/lib/config.h index d5b66ce69..327ffaf1c 100644 --- a/lib/config.h +++ b/lib/config.h @@ -68,12 +68,6 @@ namespace Util{ /// The port the current serveSocket function is listening on extern uint32_t listenPort; - /// Gets directory the current executable is stored in. - std::string getMyPath(); - - /// Gets all executables in getMyPath that start with "Mist". - void getMyExec(std::deque &execs); - /// Will set the active user to the named username. void setUser(std::string user); diff --git a/lib/procs.cpp b/lib/procs.cpp index 5b81bd540..58f141fe3 100644 --- a/lib/procs.cpp +++ b/lib/procs.cpp @@ -22,6 +22,7 @@ #include #include #include +#include std::set Util::Procs::plist; std::set Util::Procs::socketList; @@ -353,6 +354,31 @@ pid_t Util::Procs::StartPiped(std::deque &argDeq, int *fdin, int *f return ret; } +// Create a new deque with a rewritten first element to reflect the correct path +void mistifyDeque(std::deque &argDeq) { + argDeq[0] = Util::getMyPath() + argDeq[0]; +} + +// Start one of our Mist* processes, resolving our path automatically and such. +pid_t Util::Procs::StartPipedMist(std::deque &argDeq, int *fdin, int *fdout, int *fderr){ + mistifyDeque(argDeq); + return Util::Procs::StartPiped(argDeq, fdin, fdout, fderr); +} + +// Exec to one of our Mist* processes, resolving our path automatically and such. +int Util::Procs::ExecMist(std::deque &argDeq){ + mistifyDeque(argDeq); + char *const *argv = dequeToArgv(argDeq); + return execvp(argv[0], argv); +} + +// Check whether a given Mist* binary is available for us to run +bool Util::Procs::HasMistBinary(std::string binName){ + std::string tmparg = Util::getMyPath() + binName; + struct stat buf; + return ::stat(tmparg.c_str(), &buf) == 0; +} + /// Starts a new process with given fds if the name is not already active. /// \return 0 if process was not started, process PID otherwise. /// \arg argv Command for this process. @@ -558,3 +584,69 @@ void Util::Procs::remember(pid_t pid){ tthread::lock_guard guard(plistMutex); plist.insert(pid); } + +/// Gets directory the current executable is stored in. +std::string Util::getMyPath(){ + char mypath[500]; +#ifdef __CYGWIN__ + GetModuleFileName(0, mypath, 500); +#else +#ifdef __APPLE__ + memset(mypath, 0, 500); + unsigned int refSize = 500; + _NSGetExecutablePath(mypath, &refSize); +#else + int ret = readlink("/proc/self/exe", mypath, 500); + if (ret != -1){ + mypath[ret] = 0; + }else{ + mypath[0] = 0; + } +#endif +#endif + std::string tPath = mypath; + size_t slash = tPath.rfind('/'); + if (slash == std::string::npos){ + slash = tPath.rfind('\\'); + if (slash == std::string::npos){return "";} + } + tPath.resize(slash + 1); + return tPath; +} + +/// Gets all executables in getMyPath that start with "Mist". +void Util::getMyExec(std::deque &execs){ + std::string path = Util::getMyPath(); +#ifdef __CYGWIN__ + path += "\\Mist*"; + WIN32_FIND_DATA FindFileData; + HANDLE hdl = FindFirstFile(path.c_str(), &FindFileData); + while (hdl != INVALID_HANDLE_VALUE){ + if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){ + execs.push_back(FindFileData.cFileName); + } + if (!FindNextFile(hdl, &FindFileData)){ + FindClose(hdl); + hdl = INVALID_HANDLE_VALUE; + } + } +#else + DIR *d = opendir(path.c_str()); + if (!d){return;} + struct dirent *dp; + do{ + errno = 0; + if ((dp = readdir(d))){ + if (dp->d_type != DT_DIR && strncmp(dp->d_name, "Mist", 4) == 0){ + if (dp->d_type != DT_REG) { + struct stat st = {}; + stat(dp->d_name, &st); + if (!S_ISREG(st.st_mode)) + continue; + } + execs.push_back(dp->d_name);} + } + }while (dp != NULL); + closedir(d); +#endif +} diff --git a/lib/procs.h b/lib/procs.h index 716415510..7583cc86c 100644 --- a/lib/procs.h +++ b/lib/procs.h @@ -13,6 +13,12 @@ /// Contains utility code, not directly related to streaming media namespace Util{ + /// Gets directory the current executable is stored in. + std::string getMyPath(); + + /// Gets all executables in getMyPath that start with "Mist". + void getMyExec(std::deque &execs); + /// Deals with spawning, monitoring and stopping child processes class Procs{ private: @@ -35,6 +41,9 @@ namespace Util{ static std::string getLimitedOutputOf(char *const *argv, uint64_t maxWait, uint32_t maxValBytes); static pid_t StartPiped(const char *const *argv, int *fdin, int *fdout, int *fderr); static pid_t StartPiped(std::deque &argDeq, int *fdin, int *fdout, int *fderr); + static pid_t StartPipedMist(std::deque &argDeq, int *fdin, int *fdout, int *fderr); + static int ExecMist(std::deque &argDeq); + static bool HasMistBinary(std::string binName); static void Stop(pid_t name); static void Murder(pid_t name); static void StopAll(); diff --git a/lib/stream.cpp b/lib/stream.cpp index 48332c6cb..62428a437 100644 --- a/lib/stream.cpp +++ b/lib/stream.cpp @@ -640,21 +640,21 @@ bool Util::startInput(std::string streamname, std::string filename, bool forkFir setenv("MISTPROVIDER", "1", 1); } - std::string player_bin = Util::getMyPath() + "MistIn" + input["name"].asStringRef(); - char *argv[30] ={(char *)player_bin.c_str(), (char *)"-s", (char *)streamname.c_str(), - (char *)filename.c_str()}; - int argNum = 3; + std::deque argDeq; + argDeq.push_back("MistIn" + input["name"].asStringRef()); + argDeq.push_back("-s"); + argDeq.push_back(streamname); + argDeq.push_back(filename); std::string debugLvl; if (Util::printDebugLevel != DEBUG && !str_args.count("--debug")){ debugLvl = JSON::Value(Util::printDebugLevel).asString(); - argv[++argNum] = (char *)"--debug"; - argv[++argNum] = (char *)debugLvl.c_str(); + argDeq.push_back("--debug"); + argDeq.push_back(debugLvl); } for (std::map::iterator it = str_args.begin(); it != str_args.end(); ++it){ - argv[++argNum] = (char *)it->first.c_str(); - if (it->second.size()){argv[++argNum] = (char *)it->second.c_str();} + argDeq.push_back(it->first); + if (it->second.size()){argDeq.push_back(it->second);} } - argv[++argNum] = (char *)0; Util::Procs::setHandler(); @@ -683,13 +683,12 @@ bool Util::startInput(std::string streamname, std::string filename, bool forkFir Socket::Connection io(0, 1); io.drop(); std::stringstream args; - for (size_t i = 0; i < 30; ++i){ - if (!argv[i] || !argv[i][0]){break;} - args << argv[i] << " "; + for (int i = 0; i < argDeq.size(); i++){ + args << argDeq[i] << " "; } INFO_MSG("Starting %s", args.str().c_str()); - execvp(argv[0], argv); - FAIL_MSG("Starting process %s failed: %s", argv[0], strerror(errno)); + Util::Procs::ExecMist(argDeq); + FAIL_MSG("Starting process %s failed: %s", argDeq[0].c_str(), strerror(errno)); _exit(42); }else if (spawn_pid != NULL){ *spawn_pid = pid; diff --git a/src/controller/controller_connectors.cpp b/src/controller/controller_connectors.cpp index 52d9e9533..c0dd2b993 100644 --- a/src/controller/controller_connectors.cpp +++ b/src/controller/controller_connectors.cpp @@ -91,12 +91,12 @@ namespace Controller{ currentConnectors.clear(); } - static inline void builPipedPart(JSON::Value &p, char *argarr[], int &argnum, const JSON::Value &argset){ + static inline void buildPipedPart(JSON::Value &p, std::deque &argDeq, const JSON::Value &argset){ jsonForEachConst(argset, it){ if (it->isMember("option") && p.isMember(it.key())){ if (!it->isMember("type")){ if (JSON::Value(p[it.key()]).asBool()){ - argarr[argnum++] = (char *)((*it)["option"].c_str()); + argDeq.push_back((*it)["option"]); } continue; } @@ -109,35 +109,34 @@ namespace Controller{ } if ((*it)["type"].asStringRef() == "inputlist" && p[it.key()].isArray()){ jsonForEach(p[it.key()], iVal){ - (*iVal) = iVal->asString(); - argarr[argnum++] = (char *)((*it)["option"].c_str()); - argarr[argnum++] = (char *)((*iVal).c_str()); + argDeq.push_back((*it)["option"]); + argDeq.push_back(iVal->asString()); } continue; } if (p[it.key()].asStringRef().size() > 0){ - argarr[argnum++] = (char *)((*it)["option"].c_str()); - argarr[argnum++] = (char *)(p[it.key()].c_str()); + argDeq.push_back((*it)["option"]); + argDeq.push_back(p[it.key()].asString()); }else{ - argarr[argnum++] = (char *)((*it)["option"].c_str()); + argDeq.push_back((*it)["option"]); } } } } - static inline void buildPipedArguments(JSON::Value &p, char *argarr[], const JSON::Value &capabilities){ - int argnum = 0; + static inline void buildPipedArguments(JSON::Value &p, std::deque &argDeq, const JSON::Value &capabilities){ static std::string tmparg; - tmparg = Util::getMyPath() + std::string("MistOut") + p["connector"].asStringRef(); - struct stat buf; - if (::stat(tmparg.c_str(), &buf) != 0){ - tmparg = Util::getMyPath() + std::string("MistConn") + p["connector"].asStringRef(); + tmparg = std::string("MistOut") + p["connector"].asStringRef(); + if (!Util::Procs::HasMistBinary(tmparg)){ + tmparg = std::string("MistConn") + p["connector"].asStringRef(); + if (!Util::Procs::HasMistBinary(tmparg)) { + return; + } } - if (::stat(tmparg.c_str(), &buf) != 0){return;} - argarr[argnum++] = (char *)tmparg.c_str(); + argDeq.push_back(tmparg); const JSON::Value &pipedCapa = capabilities["connectors"][p["connector"].asStringRef()]; - if (pipedCapa.isMember("required")){builPipedPart(p, argarr, argnum, pipedCapa["required"]);} - if (pipedCapa.isMember("optional")){builPipedPart(p, argarr, argnum, pipedCapa["optional"]);} + if (pipedCapa.isMember("required")){buildPipedPart(p, argDeq, pipedCapa["required"]);} + if (pipedCapa.isMember("optional")){buildPipedPart(p, argDeq, pipedCapa["optional"]);} } ///\brief Checks current protocol configuration, updates state of enabled connectors if @@ -160,8 +159,6 @@ namespace Controller{ // used for building args int err = fileno(stderr); - char *argarr[15]; // approx max # of args (with a wide margin) - int i; std::string tmp; @@ -254,13 +251,12 @@ namespace Controller{ !Util::Procs::isActive(currentConnectors[*runningConns.begin()])){ Log("CONF", "Starting connector: " + *runningConns.begin()); action = true; - // clear out old args - for (i = 0; i < 15; i++){argarr[i] = 0;} + std::deque argDeq; // get args for this connector JSON::Value p = JSON::fromString(*runningConns.begin()); - buildPipedArguments(p, (char **)&argarr, capabilities); + buildPipedArguments(p, argDeq, capabilities); // start piped w/ generated args - currentConnectors[*runningConns.begin()] = Util::Procs::StartPiped(argarr, 0, 0, &err); + currentConnectors[*runningConns.begin()] = Util::Procs::StartPipedMist(argDeq, 0, 0, &err); Triggers::doTrigger("OUTPUT_START", *runningConns.begin()); // LTS } runningConns.erase(runningConns.begin());