diff --git a/src/utils/execmd.cpp b/src/utils/execmd.cpp index 1afe7524..126fb94a 100644 --- a/src/utils/execmd.cpp +++ b/src/utils/execmd.cpp @@ -80,8 +80,8 @@ extern char **environ; class ExecCmd::Internal { public: Internal() - : m_advise(0), m_provide(0), m_timeoutMs(1000), - m_rlimit_as_mbytes(0) { + : m_advise(0), m_provide(0), m_timeoutMs(1000), + m_rlimit_as_mbytes(0) { } static bool o_useVfork; @@ -107,59 +107,62 @@ public: // Reset internal state indicators. Any resources should have been // previously freed void reset() { - m_killRequest = false; - m_pipein[0] = m_pipein[1] = m_pipeout[0] = m_pipeout[1] = -1; - m_pid = -1; - sigemptyset(&m_blkcld); + m_killRequest = false; + m_pipein[0] = m_pipein[1] = m_pipeout[0] = m_pipeout[1] = -1; + m_pid = -1; + sigemptyset(&m_blkcld); } // Child process code - inline void dochild(const std::string &cmd, const char **argv, - const char **envv, bool has_input, bool has_output); + inline void dochild(const std::string& cmd, const char **argv, + const char **envv, bool has_input, bool has_output); }; bool ExecCmd::Internal::o_useVfork = false; ExecCmd::ExecCmd(int) { m = new Internal(); - if (m) + if (m) { m->reset(); + } } -void ExecCmd::setAdvise(ExecCmdAdvise *adv) +void ExecCmd::setAdvise(ExecCmdAdvise *adv) { m->m_advise = adv; } -void ExecCmd::setProvide(ExecCmdProvide *p) +void ExecCmd::setProvide(ExecCmdProvide *p) { m->m_provide = p; } -void ExecCmd::setTimeout(int mS) +void ExecCmd::setTimeout(int mS) { - if (mS > 30) + if (mS > 30) { m->m_timeoutMs = mS; + } } -void ExecCmd::setStderr(const std::string &stderrFile) +void ExecCmd::setStderr(const std::string& stderrFile) { m->m_stderrFile = stderrFile; } -pid_t ExecCmd::getChildPid() +pid_t ExecCmd::getChildPid() { return m->m_pid; } -void ExecCmd::setKill() +void ExecCmd::setKill() { m->m_killRequest = true; } -void ExecCmd::zapChild() +void ExecCmd::zapChild() { - setKill(); + setKill(); (void)wait(); } bool ExecCmd::requestChildExit() { if (m->m_pid > 0) { - if (kill(m->m_pid, SIGTERM) == 0) + if (kill(m->m_pid, SIGTERM) == 0) { return true; + } } return false; } @@ -171,47 +174,50 @@ static bool exec_is_there(const char *candidate) /* XXX work around access(2) false positives for superuser */ if (access(candidate, X_OK) == 0 && - stat(candidate, &fin) == 0 && - S_ISREG(fin.st_mode) && - (getuid() != 0 || - (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) { - return true; + stat(candidate, &fin) == 0 && + S_ISREG(fin.st_mode) && + (getuid() != 0 || + (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) { + return true; } return false; } bool ExecCmd::which(const string& cmd, string& exepath, const char* path) { - if (cmd.empty()) - return false; + if (cmd.empty()) { + return false; + } if (cmd[0] == '/') { - if (exec_is_there(cmd.c_str())) { - exepath = cmd; - return true; - } else { - return false; - } + if (exec_is_there(cmd.c_str())) { + exepath = cmd; + return true; + } else { + return false; + } } const char *pp; if (path) { - pp = path; + pp = path; } else { - pp = getenv("PATH"); + pp = getenv("PATH"); + } + if (pp == 0) { + return false; } - if (pp == 0) - return false; vector pels; stringToTokens(pp, pels, ":"); for (vector::iterator it = pels.begin(); it != pels.end(); it++) { - if (it->empty()) - *it = "."; - string candidate = (it->empty() ? string(".") : *it) + "/" + cmd; - if (exec_is_there(candidate.c_str())) { - exepath = candidate; - return true; - } + if (it->empty()) { + *it = "."; + } + string candidate = (it->empty() ? string(".") : *it) + "/" + cmd; + if (exec_is_there(candidate.c_str())) { + exepath = candidate; + return true; + } } return false; } @@ -227,12 +233,12 @@ void ExecCmd::useVfork(bool on) Internal::o_useVfork = on; } -void ExecCmd::putenv(const string &ea) +void ExecCmd::putenv(const string& ea) { m->m_env.push_back(ea); } -void ExecCmd::putenv(const string &name, const string& value) +void ExecCmd::putenv(const string& name, const string& value) { string ea = name + "=" + value; putenv(ea); @@ -246,62 +252,68 @@ static void msleep(int millis) nanosleep(&spec, 0); } -/** A resource manager to ensure that execcmd cleans up if an exception is +/** A resource manager to ensure that execcmd cleans up if an exception is * raised in the callback, or at different places on errors occurring * during method executions */ class ExecCmdRsrc { public: - ExecCmdRsrc(ExecCmd::Internal *parent) + ExecCmdRsrc(ExecCmd::Internal *parent) : m_parent(parent), m_active(true) { } void inactivate() { m_active = false; } ~ExecCmdRsrc() { - if (!m_active || !m_parent) - return; - LOGDEB1(("~ExecCmdRsrc: working. mypid: %d\n", (int)getpid())); + if (!m_active || !m_parent) { + return; + } + LOGDEB1(("~ExecCmdRsrc: working. mypid: %d\n", (int)getpid())); - // Better to close the descs first in case the child is waiting in read - if (m_parent->m_pipein[0] >= 0) - close(m_parent->m_pipein[0]); - if (m_parent->m_pipein[1] >= 0) - close(m_parent->m_pipein[1]); - if (m_parent->m_pipeout[0] >= 0) - close(m_parent->m_pipeout[0]); - if (m_parent->m_pipeout[1] >= 0) - close(m_parent->m_pipeout[1]); + // Better to close the descs first in case the child is waiting in read + if (m_parent->m_pipein[0] >= 0) { + close(m_parent->m_pipein[0]); + } + if (m_parent->m_pipein[1] >= 0) { + close(m_parent->m_pipein[1]); + } + if (m_parent->m_pipeout[0] >= 0) { + close(m_parent->m_pipeout[0]); + } + if (m_parent->m_pipeout[1] >= 0) { + close(m_parent->m_pipeout[1]); + } - // It's apparently possible for m_pid to be > 0 and getpgid to fail. In - // this case, we have to conclude that the child process does - // not exist. Not too sure what causes this, but the previous code - // definitely tried to call killpg(-1,) from time to time. - pid_t grp; - if (m_parent->m_pid > 0 && (grp = getpgid(m_parent->m_pid)) > 0) { - LOGDEB(("ExecCmd: killpg(%d, SIGTERM)\n", grp)); + // It's apparently possible for m_pid to be > 0 and getpgid to fail. In + // this case, we have to conclude that the child process does + // not exist. Not too sure what causes this, but the previous code + // definitely tried to call killpg(-1,) from time to time. + pid_t grp; + if (m_parent->m_pid > 0 && (grp = getpgid(m_parent->m_pid)) > 0) { + LOGDEB(("ExecCmd: killpg(%d, SIGTERM)\n", grp)); int ret = killpg(grp, SIGTERM); - if (ret == 0) { - for (int i = 0; i < 3; i++) { - msleep(i == 0 ? 5 : (i == 1 ? 100 : 2000)); - int status; - (void)waitpid(m_parent->m_pid, &status, WNOHANG); - if (kill(m_parent->m_pid, 0) != 0) - break; - if (i == 2) { - LOGDEB(("ExecCmd: killpg(%d, SIGKILL)\n", grp)); - killpg(grp, SIGKILL); - (void)waitpid(m_parent->m_pid, &status, WNOHANG); - } - } - } else { + if (ret == 0) { + for (int i = 0; i < 3; i++) { + msleep(i == 0 ? 5 : (i == 1 ? 100 : 2000)); + int status; + (void)waitpid(m_parent->m_pid, &status, WNOHANG); + if (kill(m_parent->m_pid, 0) != 0) { + break; + } + if (i == 2) { + LOGDEB(("ExecCmd: killpg(%d, SIGKILL)\n", grp)); + killpg(grp, SIGKILL); + (void)waitpid(m_parent->m_pid, &status, WNOHANG); + } + } + } else { LOGERR(("ExecCmd: error killing process group %d: %d\n", grp, errno)); } - } - m_parent->m_tocmd.reset(); - m_parent->m_fromcmd.reset(); - pthread_sigmask(SIG_UNBLOCK, &m_parent->m_blkcld, 0); - m_parent->reset(); + } + m_parent->m_tocmd.reset(); + m_parent->m_fromcmd.reset(); + pthread_sigmask(SIG_UNBLOCK, &m_parent->m_blkcld, 0); + m_parent->reset(); } private: ExecCmd::Internal *m_parent; @@ -311,11 +323,12 @@ private: ExecCmd::~ExecCmd() { ExecCmdRsrc(this->m); - if (m) + if (m) { delete m; + } } -// In child process. Set up pipes and exec command. +// In child process. Set up pipes and exec command. // This must not return. _exit() on error. // *** This can be called after a vfork, so no modification of the // process memory at all is allowed *** @@ -323,19 +336,19 @@ ExecCmd::~ExecCmd() // errors, which we would most definitely want to have a hint about. // // Note that any of the LOGXX calls could block on a mutex set in the -// father process, so that only absolutely exceptional conditions, +// father process, so that only absolutely exceptional conditions, // should be logged, for debugging and post-mortem purposes // If one of the calls block, the problem manifests itself by 20mn // (filter timeout) of looping on "ExecCmd::doexec: selectloop // returned 1', because the father is waiting on the read descriptor -inline void ExecCmd::Internal::dochild(const string &cmd, const char **argv, +inline void ExecCmd::Internal::dochild(const string& cmd, const char **argv, const char **envv, bool has_input, bool has_output) { // Start our own process group if (setpgid(0, getpid())) { - LOGINFO(("ExecCmd::DOCHILD: setpgid(0, %d) failed: errno %d\n", - getpid(), errno)); + LOGINFO(("ExecCmd::DOCHILD: setpgid(0, %d) failed: errno %d\n", + getpid(), errno)); } // Restore SIGTERM to default. Really, signal handling should be @@ -351,7 +364,7 @@ inline void ExecCmd::Internal::dochild(const string &cmd, const char **argv, // to mess with the global process signal disposition. if (signal(SIGTERM, SIG_DFL) == SIG_ERR) { - //LOGERR(("ExecCmd::DOCHILD: signal() failed, errno %d\n", errno)); + //LOGERR(("ExecCmd::DOCHILD: signal() failed, errno %d\n", errno)); } sigset_t sset; sigfillset(&sset); @@ -361,69 +374,69 @@ inline void ExecCmd::Internal::dochild(const string &cmd, const char **argv, #ifdef HAVE_SETRLIMIT #if defined RLIMIT_AS || defined RLIMIT_VMEM || defined RLIMIT_DATA if (m_rlimit_as_mbytes > 2000 && sizeof(rlim_t) < 8) { - // Impossible limit, don't use it - m_rlimit_as_mbytes = 0; + // Impossible limit, don't use it + m_rlimit_as_mbytes = 0; } if (m_rlimit_as_mbytes > 0) { - struct rlimit ram_limit = { - static_cast(m_rlimit_as_mbytes * 1024 * 1024), - RLIM_INFINITY - }; - int resource; + struct rlimit ram_limit = { + static_cast(m_rlimit_as_mbytes * 1024 * 1024), + RLIM_INFINITY + }; + int resource; - // RLIMIT_AS and RLIMIT_VMEM are usually synonyms when VMEM is - // defined. RLIMIT_AS is Posix. Both don't really do what we - // want, because they count e.g. shared lib mappings, which we - // don't really care about. - // RLIMIT_DATA only limits the data segment. Modern mallocs - // use mmap and will not be bound. (Otoh if we only have this, - // we're probably not modern). - // So we're unsatisfied either way. + // RLIMIT_AS and RLIMIT_VMEM are usually synonyms when VMEM is + // defined. RLIMIT_AS is Posix. Both don't really do what we + // want, because they count e.g. shared lib mappings, which we + // don't really care about. + // RLIMIT_DATA only limits the data segment. Modern mallocs + // use mmap and will not be bound. (Otoh if we only have this, + // we're probably not modern). + // So we're unsatisfied either way. #ifdef RLIMIT_AS - resource = RLIMIT_AS; + resource = RLIMIT_AS; #elif defined RLIMIT_VMEM - resource = RLIMIT_VMEM; + resource = RLIMIT_VMEM; #else - resource = RLIMIT_DATA; + resource = RLIMIT_DATA; #endif - setrlimit(resource, &ram_limit); + setrlimit(resource, &ram_limit); } #endif #endif // have_setrlimit if (has_input) { - close(m_pipein[1]); - if (m_pipein[0] != 0) { - dup2(m_pipein[0], 0); - close(m_pipein[0]); - } + close(m_pipein[1]); + if (m_pipein[0] != 0) { + dup2(m_pipein[0], 0); + close(m_pipein[0]); + } } if (has_output) { - close(m_pipeout[0]); - if (m_pipeout[1] != 1) { - if (dup2(m_pipeout[1], 1) < 0) { - LOGERR(("ExecCmd::DOCHILD: dup2() failed. errno %d\n", errno)); - } - if (close(m_pipeout[1]) < 0) { - LOGERR(("ExecCmd::DOCHILD: close() failed. errno %d\n", errno)); - } - } + close(m_pipeout[0]); + if (m_pipeout[1] != 1) { + if (dup2(m_pipeout[1], 1) < 0) { + LOGERR(("ExecCmd::DOCHILD: dup2() failed. errno %d\n", errno)); + } + if (close(m_pipeout[1]) < 0) { + LOGERR(("ExecCmd::DOCHILD: close() failed. errno %d\n", errno)); + } + } } // Do we need to redirect stderr ? if (!m_stderrFile.empty()) { - int fd = open(m_stderrFile.c_str(), O_WRONLY|O_CREAT + int fd = open(m_stderrFile.c_str(), O_WRONLY | O_CREAT #ifdef O_APPEND - |O_APPEND + | O_APPEND #endif - , 0600); - if (fd < 0) { - close(2); - } else { - if (fd != 2) { - dup2(fd, 2); - } - lseek(2, 0, 2); - } + , 0600); + if (fd < 0) { + close(2); + } else { + if (fd != 2) { + dup2(fd, 2); + } + lseek(2, 0, 2); + } } // Close all descriptors except 0,1,2 @@ -434,7 +447,7 @@ inline void ExecCmd::Internal::dochild(const string &cmd, const char **argv, // existence of the executable before calling dochild... Until we // did this check, this was the chief cause of LOG mutex deadlock LOGERR(("ExecCmd::DOCHILD: execve(%s) failed. errno %d\n", cmd.c_str(), - errno)); + errno)); _exit(127); } @@ -443,29 +456,30 @@ void ExecCmd::setrlimit_as(int mbytes) m->m_rlimit_as_mbytes = mbytes; } -int ExecCmd::startExec(const string &cmd, const vector& args, - bool has_input, bool has_output) +int ExecCmd::startExec(const string& cmd, const vector& args, + bool has_input, bool has_output) { - { // Debug and logging - string command = cmd + " "; - for (vector::const_iterator it = args.begin(); - it != args.end(); it++) { - command += "{" + *it + "} "; - } - LOGDEB(("ExecCmd::startExec: (%d|%d) %s\n", - has_input, has_output, command.c_str())); + { + // Debug and logging + string command = cmd + " "; + for (vector::const_iterator it = args.begin(); + it != args.end(); it++) { + command += "{" + *it + "} "; + } + LOGDEB(("ExecCmd::startExec: (%d|%d) %s\n", + has_input, has_output, command.c_str())); } // The resource manager ensures resources are freed if we return early ExecCmdRsrc e(this->m); if (has_input && pipe(m->m_pipein) < 0) { - LOGERR(("ExecCmd::startExec: pipe(2) failed. errno %d\n", errno)); - return -1; + LOGERR(("ExecCmd::startExec: pipe(2) failed. errno %d\n", errno)); + return -1; } if (has_output && pipe(m->m_pipeout) < 0) { - LOGERR(("ExecCmd::startExec: pipe(2) failed. errno %d\n", errno)); - return -1; + LOGERR(("ExecCmd::startExec: pipe(2) failed. errno %d\n", errno)); + return -1; } @@ -478,9 +492,9 @@ int ExecCmd::startExec(const string &cmd, const vector& args, // Allocate arg vector (2 more for arg0 + final 0) typedef const char *Ccharp; Ccharp *argv; - argv = (Ccharp *)malloc((args.size()+2) * sizeof(char *)); + argv = (Ccharp *)malloc((args.size() + 2) * sizeof(char *)); if (argv == 0) { - LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n", errno)); + LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n", errno)); return -1; } // Fill up argv @@ -488,27 +502,29 @@ int ExecCmd::startExec(const string &cmd, const vector& args, int i = 1; vector::const_iterator it; for (it = args.begin(); it != args.end(); it++) { - argv[i++] = it->c_str(); + argv[i++] = it->c_str(); } argv[i] = 0; Ccharp *envv; int envsize; - for (envsize = 0; ; envsize++) - if (environ[envsize] == 0) - break; + for (envsize = 0; ; envsize++) + if (environ[envsize] == 0) { + break; + } envv = (Ccharp *)malloc((envsize + m->m_env.size() + 2) * sizeof(char *)); if (envv == 0) { - LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n", errno)); + LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n", errno)); free(argv); return -1; } int eidx; - for (eidx = 0; eidx < envsize; eidx++) - envv[eidx] = environ[eidx]; - for (vector::const_iterator it = m->m_env.begin(); - it != m->m_env.end(); it++) { - envv[eidx++] = it->c_str(); + for (eidx = 0; eidx < envsize; eidx++) { + envv[eidx] = environ[eidx]; + } + for (vector::const_iterator it = m->m_env.begin(); + it != m->m_env.end(); it++) { + envv[eidx++] = it->c_str(); } envv[eidx] = 0; @@ -526,7 +542,7 @@ int ExecCmd::startExec(const string &cmd, const vector& args, // Note that posix_spawn provides no way to setrlimit() the child. { posix_spawnattr_t attrs; - posix_spawnattr_init (&attrs); + posix_spawnattr_init(&attrs); short flags; posix_spawnattr_getflags(&attrs, &flags); @@ -537,7 +553,7 @@ int ExecCmd::startExec(const string &cmd, const vector& args, sigset_t sset; sigemptyset(&sset); - posix_spawnattr_setsigmask (&attrs, &sset); + posix_spawnattr_setsigmask(&attrs, &sset); flags |= POSIX_SPAWN_SETSIGMASK; sigemptyset(&sset); @@ -567,11 +583,11 @@ int ExecCmd::startExec(const string &cmd, const vector& args, // Do we need to redirect stderr ? if (!m->m_stderrFile.empty()) { - int oflags = O_WRONLY|O_CREAT; + int oflags = O_WRONLY | O_CREAT; #ifdef O_APPEND oflags |= O_APPEND; #endif - posix_spawn_file_actions_addopen(&facts, 2, m->m_stderrFile.c_str(), + posix_spawn_file_actions_addopen(&facts, 2, m->m_stderrFile.c_str(), oflags, 0600); } LOGDEB1(("using SPAWN\n")); @@ -583,12 +599,12 @@ int ExecCmd::startExec(const string &cmd, const vector& args, posix_spawn_file_actions_addclose(&facts, i); } - int ret = posix_spawn(&m->m_pid, exe.c_str(), &facts, &attrs, + int ret = posix_spawn(&m->m_pid, exe.c_str(), &facts, &attrs, (char *const *)argv, (char *const *)envv); posix_spawnattr_destroy(&attrs); posix_spawn_file_actions_destroy(&facts); if (ret) { - LOGERR(("ExecCmd::startExec: posix_spawn() failed. errno %d\n", + LOGERR(("ExecCmd::startExec: posix_spawn() failed. errno %d\n", ret)); return -1; } @@ -597,22 +613,22 @@ int ExecCmd::startExec(const string &cmd, const vector& args, #else if (Internal::o_useVfork) { LOGDEB1(("using VFORK\n")); - m->m_pid = vfork(); + m->m_pid = vfork(); } else { LOGDEB1(("using FORK\n")); - m->m_pid = fork(); + m->m_pid = fork(); } if (m->m_pid < 0) { - LOGERR(("ExecCmd::startExec: fork(2) failed. errno %d\n", errno)); - return -1; + LOGERR(("ExecCmd::startExec: fork(2) failed. errno %d\n", errno)); + return -1; } if (m->m_pid == 0) { - // e.inactivate() is not needed. As we do not return, the call - // stack won't be unwound and destructors of local objects - // won't be called. - m->dochild(exe, argv, envv, has_input, has_output); - // dochild does not return. Just in case... - _exit(1); + // e.inactivate() is not needed. As we do not return, the call + // stack won't be unwound and destructors of local objects + // won't be called. + m->dochild(exe, argv, envv, has_input, has_output); + // dochild does not return. Just in case... + _exit(1); } #endif @@ -627,7 +643,7 @@ int ExecCmd::startExec(const string &cmd, const vector& args, // Set the process group for the child. This is also done in the // child process see wikipedia(Process_group) if (setpgid(m->m_pid, m->m_pid)) { - // This can fail with EACCES if the son has already done execve + // This can fail with EACCES if the son has already done execve // (linux at least) LOGDEB2(("ExecCmd: father setpgid(son)(%d,%d) errno %d (ok)\n", m->m_pid, m->m_pid, errno)); @@ -638,18 +654,18 @@ int ExecCmd::startExec(const string &cmd, const vector& args, pthread_sigmask(SIG_BLOCK, &m->m_blkcld, 0); if (has_input) { - close(m->m_pipein[0]); - m->m_pipein[0] = -1; - NetconCli *iclicon = new NetconCli(); - iclicon->setconn(m->m_pipein[1]); - m->m_tocmd = STD_SHARED_PTR(iclicon); + close(m->m_pipein[0]); + m->m_pipein[0] = -1; + NetconCli *iclicon = new NetconCli(); + iclicon->setconn(m->m_pipein[1]); + m->m_tocmd = STD_SHARED_PTR(iclicon); } if (has_output) { - close(m->m_pipeout[1]); - m->m_pipeout[1] = -1; - NetconCli *oclicon = new NetconCli(); - oclicon->setconn(m->m_pipeout[0]); - m->m_fromcmd = STD_SHARED_PTR(oclicon); + close(m->m_pipeout[1]); + m->m_pipeout[1] = -1; + NetconCli *oclicon = new NetconCli(); + oclicon->setconn(m->m_pipeout[0]); + m->m_fromcmd = STD_SHARED_PTR(oclicon); } /* Don't want to undo what we just did ! */ @@ -661,27 +677,27 @@ int ExecCmd::startExec(const string &cmd, const vector& args, // Netcon callback. Send data to the command's input class ExecWriter : public NetconWorker { public: - ExecWriter(const string *input, ExecCmdProvide *provide, + ExecWriter(const string *input, ExecCmdProvide *provide, ExecCmd::Internal *parent) - : m_cmd(parent), m_input(input), m_cnt(0), m_provide(provide) { + : m_cmd(parent), m_input(input), m_cnt(0), m_provide(provide) { } void shutdown() { close(m_cmd->m_pipein[1]); m_cmd->m_pipein[1] = -1; - m_cmd->m_tocmd.reset(); + m_cmd->m_tocmd.reset(); } - virtual int data(NetconData *con, Netcon::Event reason) - { - if (!m_input) + virtual int data(NetconData *con, Netcon::Event reason) { + if (!m_input) { return -1; - LOGDEB1(("ExecWriter: input m_cnt %d input length %d\n", m_cnt, - m_input->length())); - if (m_cnt >= m_input->length()) { - // Fd ready for more but we got none. Try to get data, else + } + LOGDEB1(("ExecWriter: input m_cnt %d input length %d\n", m_cnt, + m_input->length())); + if (m_cnt >= m_input->length()) { + // Fd ready for more but we got none. Try to get data, else // shutdown; - if (!m_provide) { + if (!m_provide) { shutdown(); - return 0; + return 0; } m_provide->newData(); if (m_input->empty()) { @@ -691,18 +707,18 @@ public: // Ready with new buffer, reset use count m_cnt = 0; } - LOGDEB2(("ExecWriter: provide m_cnt %d input length %d\n", + LOGDEB2(("ExecWriter: provide m_cnt %d input length %d\n", m_cnt, m_input->length())); - } - int ret = con->send(m_input->c_str() + m_cnt, - m_input->length() - m_cnt); - LOGDEB2(("ExecWriter: wrote %d to command\n", ret)); - if (ret <= 0) { - LOGERR(("ExecWriter: data: can't write\n")); - return -1; - } - m_cnt += ret; - return ret; + } + int ret = con->send(m_input->c_str() + m_cnt, + m_input->length() - m_cnt); + LOGDEB2(("ExecWriter: wrote %d to command\n", ret)); + if (ret <= 0) { + LOGERR(("ExecWriter: data: can't write\n")); + return -1; + } + m_cnt += ret; + return ret; } private: ExecCmd::Internal *m_cmd; @@ -714,22 +730,22 @@ private: // Netcon callback. Get data from the command output. class ExecReader : public NetconWorker { public: - ExecReader(string *output, ExecCmdAdvise *advise) - : m_output(output), m_advise(advise) - {} - virtual int data(NetconData *con, Netcon::Event reason) - { - char buf[8192]; - int n = con->receive(buf, 8192); - LOGDEB1(("ExecReader: got %d from command\n", n)); - if (n < 0) { - LOGERR(("ExecCmd::doexec: receive failed. errno %d\n", errno)); - } else if (n > 0) { - m_output->append(buf, n); - if (m_advise) - m_advise->newData(n); - } // else n == 0, just return - return n; + ExecReader(string *output, ExecCmdAdvise *advise) + : m_output(output), m_advise(advise) { + } + virtual int data(NetconData *con, Netcon::Event reason) { + char buf[8192]; + int n = con->receive(buf, 8192); + LOGDEB1(("ExecReader: got %d from command\n", n)); + if (n < 0) { + LOGERR(("ExecCmd::doexec: receive failed. errno %d\n", errno)); + } else if (n > 0) { + m_output->append(buf, n); + if (m_advise) { + m_advise->newData(n); + } + } // else n == 0, just return + return n; } private: string *m_output; @@ -737,12 +753,12 @@ private: }; -int ExecCmd::doexec(const string &cmd, const vector& args, - const string *input, string *output) +int ExecCmd::doexec(const string& cmd, const vector& args, + const string *input, string *output) { if (startExec(cmd, args, input != 0, output != 0) < 0) { - return -1; + return -1; } // Cleanup in case we return early @@ -751,50 +767,52 @@ int ExecCmd::doexec(const string &cmd, const vector& args, int ret = 0; if (input || output) { // Setup output - if (output) { - NetconCli *oclicon = m->m_fromcmd.get(); - if (!oclicon) { - LOGERR(("ExecCmd::doexec: no connection from command\n")); - return -1; - } - oclicon->setcallback(STD_SHARED_PTR - (new ExecReader(output, m->m_advise))); - myloop.addselcon(m->m_fromcmd, Netcon::NETCONPOLL_READ); - // Give up ownership - m->m_fromcmd.reset(); - } + if (output) { + NetconCli *oclicon = m->m_fromcmd.get(); + if (!oclicon) { + LOGERR(("ExecCmd::doexec: no connection from command\n")); + return -1; + } + oclicon->setcallback(STD_SHARED_PTR + (new ExecReader(output, m->m_advise))); + myloop.addselcon(m->m_fromcmd, Netcon::NETCONPOLL_READ); + // Give up ownership + m->m_fromcmd.reset(); + } // Setup input - if (input) { - NetconCli *iclicon = m->m_tocmd.get(); - if (!iclicon) { - LOGERR(("ExecCmd::doexec: no connection from command\n")); - return -1; - } - iclicon->setcallback(STD_SHARED_PTR - (new ExecWriter(input, m->m_provide, m))); - myloop.addselcon(m->m_tocmd, Netcon::NETCONPOLL_WRITE); - // Give up ownership - m->m_tocmd.reset(); - } + if (input) { + NetconCli *iclicon = m->m_tocmd.get(); + if (!iclicon) { + LOGERR(("ExecCmd::doexec: no connection from command\n")); + return -1; + } + iclicon->setcallback(STD_SHARED_PTR + (new ExecWriter(input, m->m_provide, m))); + myloop.addselcon(m->m_tocmd, Netcon::NETCONPOLL_WRITE); + // Give up ownership + m->m_tocmd.reset(); + } // Do the actual reading/writing/waiting - myloop.setperiodichandler(0, 0, m->m_timeoutMs); - while ((ret = myloop.doLoop()) > 0) { - LOGDEB(("ExecCmd::doexec: selectloop returned %d\n", ret)); - if (m->m_advise) - m->m_advise->newData(0); - if (m->m_killRequest) { - LOGINFO(("ExecCmd::doexec: cancel request\n")); - break; - } - } - LOGDEB0(("ExecCmd::doexec: selectloop returned %d\n", ret)); + myloop.setperiodichandler(0, 0, m->m_timeoutMs); + while ((ret = myloop.doLoop()) > 0) { + LOGDEB(("ExecCmd::doexec: selectloop returned %d\n", ret)); + if (m->m_advise) { + m->m_advise->newData(0); + } + if (m->m_killRequest) { + LOGINFO(("ExecCmd::doexec: cancel request\n")); + break; + } + } + LOGDEB0(("ExecCmd::doexec: selectloop returned %d\n", ret)); // Check for interrupt request: we won't want to waitpid() - if (m->m_advise) + if (m->m_advise) { m->m_advise->newData(0); + } // The netcons don't take ownership of the fds: we have to close them - // (have to do it before wait, this may be the signal the child is + // (have to do it before wait, this may be the signal the child is // waiting for exiting). if (input) { close(m->m_pipein[1]); @@ -810,8 +828,9 @@ int ExecCmd::doexec(const string &cmd, const vector& args, e.inactivate(); int ret1 = ExecCmd::wait(); - if (ret) - return -1; + if (ret) { + return -1; + } return ret1; } @@ -819,19 +838,20 @@ int ExecCmd::send(const string& data) { NetconCli *con = m->m_tocmd.get(); if (con == 0) { - LOGERR(("ExecCmd::send: outpipe is closed\n")); - return -1; + LOGERR(("ExecCmd::send: outpipe is closed\n")); + return -1; } unsigned int nwritten = 0; while (nwritten < data.length()) { - if (m->m_killRequest) - break; - int n = con->send(data.c_str() + nwritten, data.length() - nwritten); - if (n < 0) { - LOGERR(("ExecCmd::send: send failed\n")); - return -1; - } - nwritten += n; + if (m->m_killRequest) { + break; + } + int n = con->send(data.c_str() + nwritten, data.length() - nwritten); + if (n < 0) { + LOGERR(("ExecCmd::send: send failed\n")); + return -1; + } + nwritten += n; } return nwritten; } @@ -840,8 +860,8 @@ int ExecCmd::receive(string& data, int cnt) { NetconCli *con = m->m_fromcmd.get(); if (con == 0) { - LOGERR(("ExecCmd::receive: inpipe is closed\n")); - return -1; + LOGERR(("ExecCmd::receive: inpipe is closed\n")); + return -1; } const int BS = 4096; char buf[BS]; @@ -867,14 +887,15 @@ int ExecCmd::getline(string& data) { NetconCli *con = m->m_fromcmd.get(); if (con == 0) { - LOGERR(("ExecCmd::receive: inpipe is closed\n")); - return -1; + LOGERR(("ExecCmd::receive: inpipe is closed\n")); + return -1; } const int BS = 1024; char buf[BS]; int timeosecs = m->m_timeoutMs / 1000; - if (timeosecs == 0) + if (timeosecs == 0) { timeosecs = 1; + } // Note that we only go once through here, except in case of // timeout, which is why I think that the goto is more expressive @@ -884,15 +905,16 @@ again: if (n < 0) { if (con->timedout()) { LOGDEB(("ExecCmd::getline: timeout\n")); - if (m->m_advise) + if (m->m_advise) { m->m_advise->newData(0); + } goto again; } - LOGERR(("ExecCmd::getline: error\n")); + LOGERR(("ExecCmd::getline: error\n")); } else if (n > 0) { - data.append(buf, n); + data.append(buf, n); } else { - LOGDEB(("ExecCmd::getline: got 0\n")); + LOGDEB(("ExecCmd::getline: got 0\n")); } return n; } @@ -935,7 +957,7 @@ int ExecCmd::getline(string& data, int timeosecs) // Just calling waitpid() with WNOHANG with a sleep() between tries // does not work: the first waitpid() usually comes too early and // reaps nothing, resulting in almost always one sleep() or more. -// +// // So no timeout here. This has not been a problem in practise inside recoll. // In case of need, using a semi-busy loop with short sleeps // increasing from a few mS might work without creating too much @@ -945,12 +967,12 @@ int ExecCmd::wait() ExecCmdRsrc e(this->m); int status = -1; if (!m->m_killRequest && m->m_pid > 0) { - if (waitpid(m->m_pid, &status, 0) < 0) { - LOGERR(("ExecCmd::waitpid: returned -1 errno %d\n", errno)); - status = -1; - } + if (waitpid(m->m_pid, &status, 0) < 0) { + LOGERR(("ExecCmd::waitpid: returned -1 errno %d\n", errno)); + status = -1; + } LOGDEB(("ExecCmd::wait: got status 0x%x\n", status)); - m->m_pid = -1; + m->m_pid = -1; } // Let the ExecCmdRsrc cleanup, it will do the killing/waiting if needed return status; @@ -962,23 +984,23 @@ bool ExecCmd::maybereap(int *status) *status = -1; if (m->m_pid <= 0) { - // Already waited for ?? - return true; + // Already waited for ?? + return true; } pid_t pid = waitpid(m->m_pid, status, WNOHANG); if (pid < 0) { LOGERR(("ExecCmd::maybereap: returned -1 errno %d\n", errno)); - m->m_pid = -1; - return true; + m->m_pid = -1; + return true; } else if (pid == 0) { - LOGDEB1(("ExecCmd::maybereap: not exited yet\n")); - e.inactivate(); - return false; + LOGDEB1(("ExecCmd::maybereap: not exited yet\n")); + e.inactivate(); + return false; } else { LOGDEB(("ExecCmd::maybereap: got status 0x%x\n", status)); - m->m_pid = -1; - return true; + m->m_pid = -1; + return true; } } @@ -1002,43 +1024,45 @@ ReExec::ReExec(int argc, char *args[]) void ReExec::init(int argc, char *args[]) { for (int i = 0; i < argc; i++) { - m_argv.push_back(args[i]); + m_argv.push_back(args[i]); } m_cfd = open(".", 0); char *cd = getcwd(0, 0); - if (cd) - m_curdir = cd; + if (cd) { + m_curdir = cd; + } free(cd); } void ReExec::insertArgs(const vector& args, int idx) { vector::iterator it, cit; - unsigned int cmpoffset = (unsigned int)-1; + unsigned int cmpoffset = (unsigned int) - 1; if (idx == -1 || string::size_type(idx) >= m_argv.size()) { - it = m_argv.end(); - if (m_argv.size() >= args.size()) { - cmpoffset = m_argv.size() - args.size(); - } + it = m_argv.end(); + if (m_argv.size() >= args.size()) { + cmpoffset = m_argv.size() - args.size(); + } } else { - it = m_argv.begin() + idx; - if (idx + args.size() <= m_argv.size()) { - cmpoffset = idx; - } + it = m_argv.begin() + idx; + if (idx + args.size() <= m_argv.size()) { + cmpoffset = idx; + } } // Check that the option is not already there - if (cmpoffset != (unsigned int)-1) { - bool allsame = true; - for (unsigned int i = 0; i < args.size(); i++) { - if (m_argv[cmpoffset + i] != args[i]) { - allsame = false; - break; - } - } - if (allsame) - return; + if (cmpoffset != (unsigned int) - 1) { + bool allsame = true; + for (unsigned int i = 0; i < args.size(); i++) { + if (m_argv[cmpoffset + i] != args[i]) { + allsame = false; + break; + } + } + if (allsame) { + return; + } } m_argv.insert(it, args.begin(), args.end()); @@ -1046,10 +1070,11 @@ void ReExec::insertArgs(const vector& args, int idx) void ReExec::removeArg(const string& arg) { - for (vector::iterator it = m_argv.begin(); - it != m_argv.end(); it++) { - if (*it == arg) - it = m_argv.erase(it); + for (vector::iterator it = m_argv.begin(); + it != m_argv.end(); it++) { + if (*it == arg) { + it = m_argv.erase(it); + } } } @@ -1059,30 +1084,30 @@ void ReExec::reexec() #if 0 char *cwd; - cwd = getcwd(0,0); + cwd = getcwd(0, 0); FILE *fp = stdout; //fopen("/tmp/exectrace", "w"); if (fp) { - fprintf(fp, "reexec: pwd: [%s] args: ", cwd?cwd:"getcwd failed"); - for (vector::const_iterator it = m_argv.begin(); - it != m_argv.end(); it++) { - fprintf(fp, "[%s] ", it->c_str()); - } - fprintf(fp, "\n"); + fprintf(fp, "reexec: pwd: [%s] args: ", cwd ? cwd : "getcwd failed"); + for (vector::const_iterator it = m_argv.begin(); + it != m_argv.end(); it++) { + fprintf(fp, "[%s] ", it->c_str()); + } + fprintf(fp, "\n"); } #endif // Execute the atexit funcs while (!m_atexitfuncs.empty()) { - (m_atexitfuncs.top())(); - m_atexitfuncs.pop(); + (m_atexitfuncs.top())(); + m_atexitfuncs.pop(); } // Try to get back to the initial working directory if (m_cfd < 0 || fchdir(m_cfd) < 0) { - LOGINFO(("ReExec::reexec: fchdir failed, trying chdir\n")); - if (!m_curdir.empty() && chdir(m_curdir.c_str())) { - LOGERR(("ReExec::reexec: chdir failed\n")); - } + LOGINFO(("ReExec::reexec: fchdir failed, trying chdir\n")); + if (!m_curdir.empty() && chdir(m_curdir.c_str())) { + LOGERR(("ReExec::reexec: chdir failed\n")); + } } // Close all descriptors except 0,1,2 @@ -1091,17 +1116,17 @@ void ReExec::reexec() // Allocate arg vector (1 more for final 0) typedef const char *Ccharp; Ccharp *argv; - argv = (Ccharp *)malloc((m_argv.size()+1) * sizeof(char *)); + argv = (Ccharp *)malloc((m_argv.size() + 1) * sizeof(char *)); if (argv == 0) { - LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n", errno)); - return; + LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n", errno)); + return; } - + // Fill up argv int i = 0; vector::const_iterator it; for (it = m_argv.begin(); it != m_argv.end(); it++) { - argv[i++] = it->c_str(); + argv[i++] = it->c_str(); } argv[i] = 0; execvp(m_argv[0].c_str(), (char *const*)argv); @@ -1135,20 +1160,20 @@ using namespace std; // Testing the rclexecm protocol outside of recoll. Here we use the // rcldoc.py filter, you can try with rclaudio too, adjust the file arg // accordingly -bool exercise_mhexecm(const string& cmdstr, const string& mimetype, +bool exercise_mhexecm(const string& cmdstr, const string& mimetype, vector& files) { ExecCmd cmd; - vector myparams; + vector myparams; if (cmd.startExec(cmdstr, myparams, 1, 1) < 0) { - cerr << "startExec " << cmdstr << " failed. Missing command?\n"; - return false; + cerr << "startExec " << cmdstr << " failed. Missing command?\n"; + return false; } for (vector::const_iterator it = files.begin(); - it != files.end(); it++) { + it != files.end(); it++) { // Build request message ostringstream obuf; obuf << "Filename: " << (*it).length() << "\n" << (*it); @@ -1157,7 +1182,7 @@ bool exercise_mhexecm(const string& cmdstr, const string& mimetype, obuf << "BogusParam: " << string("bogus").length() << "\n" << "bogus"; obuf << "\n"; cerr << "SENDING: [" << obuf.str() << "]\n"; - // Send it + // Send it if (cmd.send(obuf.str()) < 0) { // The real code calls zapchild here, but we don't need it as // this will be handled by ~ExecCmd @@ -1167,7 +1192,7 @@ bool exercise_mhexecm(const string& cmdstr, const string& mimetype, } // Read answer - for (int loop=0;;loop++) { + for (int loop = 0;; loop++) { string name, data; // Code from mh_execm.cpp: readDataElement @@ -1204,21 +1229,22 @@ bool exercise_mhexecm(const string& cmdstr, const string& mimetype, string& slen = *it; int len; if (sscanf(slen.c_str(), "%d", &len) != 1) { - cerr << "bad line in filter output (no len): [" << - ibuf << "]\n"; + cerr << "bad line in filter output (no len): [" << + ibuf << "]\n"; return false; } // Read element data data.erase(); if (len > 0 && cmd.receive(data, len) != len) { - cerr << "MHExecMultiple: expected " << len << - " bytes of data, got " << data.length() << endl; + cerr << "MHExecMultiple: expected " << len << + " bytes of data, got " << data.length() << endl; return false; } // Empty element: end of message - if (name.empty()) + if (name.empty()) { break; + } cerr << "Got name: [" << name << "] data [" << data << "]\n"; } } @@ -1228,19 +1254,19 @@ bool exercise_mhexecm(const string& cmdstr, const string& mimetype, static char *thisprog; static char usage [] = -"trexecmd [-c -r -i -o] cmd [arg1 arg2 ...]\n" -" -c : test cancellation (ie: trexecmd -c sleep 1000)\n" -" -r : run reexec. Must be separate option.\n" -" -i : command takes input\n" -" -o : command produces output\n" -" If -i is set, we send /etc/group contents to whatever command is run\n" -" If -o is set, we print whatever comes out\n" -"trexecmd -m [file ...]: test execm:\n" -" should be the path to an execm filter\n" -" the type of the file parameters\n" -"trexecmd -w cmd : do the 'which' thing\n" -"trexecmd -l cmd test getline\n" -; + "trexecmd [-c -r -i -o] cmd [arg1 arg2 ...]\n" + " -c : test cancellation (ie: trexecmd -c sleep 1000)\n" + " -r : run reexec. Must be separate option.\n" + " -i : command takes input\n" + " -o : command produces output\n" + " If -i is set, we send /etc/group contents to whatever command is run\n" + " If -o is set, we print whatever comes out\n" + "trexecmd -m [file ...]: test execm:\n" + " should be the path to an execm filter\n" + " the type of the file parameters\n" + "trexecmd -w cmd : do the 'which' thing\n" + "trexecmd -l cmd test getline\n" + ; static void Usage(void) { @@ -1263,19 +1289,19 @@ static int op_flags; class MEAdv : public ExecCmdAdvise { public: void newData(int cnt) { - if (op_flags & OPT_c) { + if (op_flags & OPT_c) { #ifdef BUILDING_RECOLL - static int callcnt; - if (callcnt++ == 10) { + static int callcnt; + if (callcnt++ == 10) { // Just sets the cancellation flag - CancelCheck::instance().setCancel(); + CancelCheck::instance().setCancel(); // Would be called from somewhere else and throws an // exception. We call it here for simplicity CancelCheck::instance().checkCancel(); - } + } #endif - } - cerr << "newData(" << cnt << ")" << endl; + } + cerr << "newData(" << cnt << ")" << endl; } }; @@ -1284,22 +1310,22 @@ class MEPv : public ExecCmdProvide { public: FILE *m_fp; string *m_input; - MEPv(string *i) - : m_input(i) - { - m_fp = fopen("/etc/group", "r"); + MEPv(string *i) + : m_input(i) { + m_fp = fopen("/etc/group", "r"); } ~MEPv() { - if (m_fp) - fclose(m_fp); + if (m_fp) { + fclose(m_fp); + } } void newData() { - char line[1024]; - if (m_fp && fgets(line, 1024, m_fp)) { - m_input->assign((const char *)line); - } else { - m_input->erase(); - } + char line[1024]; + if (m_fp && fgets(line, 1024, m_fp)) { + m_input->assign((const char *)line); + } else { + m_input->erase(); + } } }; @@ -1311,47 +1337,70 @@ int main(int argc, char *argv[]) reexec.init(argc, argv); if (0) { - // Disabled: For testing reexec arg handling - vector newargs; - newargs.push_back("newarg"); - newargs.push_back("newarg1"); - newargs.push_back("newarg2"); - newargs.push_back("newarg3"); - newargs.push_back("newarg4"); - reexec.insertArgs(newargs, 2); + // Disabled: For testing reexec arg handling + vector newargs; + newargs.push_back("newarg"); + newargs.push_back("newarg1"); + newargs.push_back("newarg2"); + newargs.push_back("newarg3"); + newargs.push_back("newarg4"); + reexec.insertArgs(newargs, 2); } thisprog = argv[0]; - argc--; argv++; + argc--; + argv++; while (argc > 0 && **argv == '-') { - (*argv)++; - if (!(**argv)) - /* Cas du "adb - core" */ - Usage(); - while (**argv) - switch (*(*argv)++) { - case 'c': op_flags |= OPT_c; break; - case 'r': op_flags |= OPT_r; break; - case 'w': op_flags |= OPT_w; break; + (*argv)++; + if (!(**argv)) + /* Cas du "adb - core" */ + { + Usage(); + } + while (**argv) + switch (*(*argv)++) { + case 'c': + op_flags |= OPT_c; + break; + case 'r': + op_flags |= OPT_r; + break; + case 'w': + op_flags |= OPT_w; + break; #ifdef BUILDING_RECOLL - case 'm': op_flags |= OPT_m; break; + case 'm': + op_flags |= OPT_m; + break; #endif - case 'i': op_flags |= OPT_i; break; - case 'l': op_flags |= OPT_l; break; - case 'o': op_flags |= OPT_o; break; - default: Usage(); break; - } - argc--; argv++; + case 'i': + op_flags |= OPT_i; + break; + case 'l': + op_flags |= OPT_l; + break; + case 'o': + op_flags |= OPT_o; + break; + default: + Usage(); + break; + } + argc--; + argv++; } - if (argc < 1) - Usage(); + if (argc < 1) { + Usage(); + } - string arg1 = *argv++; argc--; + string arg1 = *argv++; + argc--; vector l; while (argc > 0) { - l.push_back(*argv++); argc--; + l.push_back(*argv++); + argc--; } #ifdef BUILDING_RECOLL @@ -1361,11 +1410,11 @@ int main(int argc, char *argv[]) signal(SIGPIPE, SIG_IGN); if (op_flags & OPT_r) { - // Test reexec. Normally only once, next time we fall through + // Test reexec. Normally only once, next time we fall through // because we remove the -r option (only works if it was isolated, not like -rc - chdir("/"); + chdir("/"); argv[0] = strdup(""); - sleep(1); + sleep(1); cerr << "Calling reexec\n"; // We remove the -r arg from list, otherwise we are going to // loop (which you can try by commenting out the following @@ -1375,20 +1424,21 @@ int main(int argc, char *argv[]) } if (op_flags & OPT_w) { - // Test "which" method - string path; - if (ExecCmd::which(arg1, path)) { - cout << path << endl; + // Test "which" method + string path; + if (ExecCmd::which(arg1, path)) { + cout << path << endl; return 0; - } - return 1; + } + return 1; #ifdef BUILDING_RECOLL } else if (op_flags & OPT_m) { - if (l.size() < 2) + if (l.size() < 2) { Usage(); + } string mimetype = l[0]; l.erase(l.begin()); - return exercise_mhexecm(arg1, mimetype, l) ? 0 : 1; + return exercise_mhexecm(arg1, mimetype, l) ? 0 : 1; #endif } else if (op_flags & OPT_l) { ExecCmd mexec; @@ -1403,7 +1453,7 @@ int main(int argc, char *argv[]) cerr << "Waiting\n"; int status = mexec.wait(); cerr << "Got status " << status << endl; - exit (status); + exit(status); } else { // Default: execute command line arguments ExecCmd mexec; @@ -1417,7 +1467,7 @@ int main(int argc, char *argv[]) // Stderr output goes there mexec.setStderr("/tmp/trexecStderr"); - + // A few environment variables. Check with trexecmd env mexec.putenv("TESTVARIABLE1=TESTVALUE1"); mexec.putenv("TESTVARIABLE2=TESTVALUE2"); @@ -1425,7 +1475,7 @@ int main(int argc, char *argv[]) string input, output; MEPv pv(&input); - + string *ip = 0; if (op_flags & OPT_i) { ip = &input; @@ -1447,7 +1497,7 @@ int main(int argc, char *argv[]) if (op_flags & OPT_o) { cout << output; } - exit (status >> 8); + exit(status >> 8); } } #endif // TEST diff --git a/src/utils/execmd.h b/src/utils/execmd.h index 64b7aa0c..559a7feb 100644 --- a/src/utils/execmd.h +++ b/src/utils/execmd.h @@ -21,27 +21,27 @@ #include #include -/** - * Callback function object to advise of new data arrival, or just periodic - * heartbeat if cnt is 0. +/** + * Callback function object to advise of new data arrival, or just periodic + * heartbeat if cnt is 0. * * To interrupt the command, the code using ExecCmd should either - * raise an exception inside newData() (and catch it in doexec's caller), or - * call ExecCmd::setKill() - * + * raise an exception inside newData() (and catch it in doexec's caller), or + * call ExecCmd::setKill() + * */ class ExecCmdAdvise { - public: +public: virtual ~ExecCmdAdvise() {} virtual void newData(int cnt) = 0; }; -/** +/** * Callback function object to get more input data. Data has to be provided * into the initial input string, set it to empty to signify eof. */ class ExecCmdProvide { - public: +public: virtual ~ExecCmdProvide() {} virtual void newData() = 0; }; @@ -51,43 +51,43 @@ class ExecCmdProvide { * asynchronous io as appropriate for things to work). * * Input to the command can be provided either once in a parameter to doexec - * or provided in chunks by setting a callback which will be called to + * or provided in chunks by setting a callback which will be called to * request new data. In this case, the 'input' parameter to doexec may be * empty (but not null) * * Output from the command is normally returned in a single string, but a * callback can be set to be called whenever new data arrives, in which case * it is permissible to consume the data and erase the string. - * + * * Note that SIGPIPE should be ignored and SIGCLD blocked when calling doexec, * else things might fail randomly. (This is not done inside the class because * of concerns with multithreaded programs). * */ class ExecCmd { - public: +public: // Use vfork instead of fork. Our vfork usage is multithread-compatible as // far as I can see, but just in case... static void useVfork(bool on); - /** + /** * Add/replace environment variable before executing command. This must * be called before doexec() to have an effect (possibly multiple * times for several variables). * @param envassign an environment assignment string ("name=value") */ - void putenv(const std::string &envassign); - void putenv(const std::string &name, const std::string& value); + void putenv(const std::string& envassign); + void putenv(const std::string& name, const std::string& value); - /** + /** * Try to set a limit on child process vm size. This will use * setrlimit() and RLIMIT_AS/VMEM if available. Parameter is in - * units of 2**10. Must be called before starting the command, default + * units of 2**10. Must be called before starting the command, default * is inherit from parent. */ void setrlimit_as(int mbytes); - /** + /** * Set function objects to call whenever new data is available or on * select timeout. The data itself is stored in the output string. * Must be set before calling doexec. @@ -101,59 +101,60 @@ class ExecCmd { void setProvide(ExecCmdProvide *p); /** - * Set select timeout in milliseconds. The default is 1 S. + * Set select timeout in milliseconds. The default is 1 S. * This is NOT a time after which an error will occur, but the period of * the calls to the advise routine (which normally checks for cancellation). */ void setTimeout(int mS); - /** - * Set destination for stderr data. The default is to let it alone (will + /** + * Set destination for stderr data. The default is to let it alone (will * usually go to the terminal or to wherever the desktop messages go). * There is currently no option to put stderr data into a program variable * If the parameter can't be opened for writing, the command's * stderr will be closed. */ - void setStderr(const std::string &stderrFile); + void setStderr(const std::string& stderrFile); /** - * Execute command. + * Execute command. * - * Both input and output can be specified, and asynchronous + * Both input and output can be specified, and asynchronous * io (select-based) is used to prevent blocking. This will not * work if input and output need to be synchronized (ie: Q/A), but * works ok for filtering. - * The function is exception-safe. In case an exception occurs in the + * The function is exception-safe. In case an exception occurs in the * advise callback, fds and pids will be cleaned-up properly. * - * @param cmd the program to execute. This must be an absolute file name + * @param cmd the program to execute. This must be an absolute file name * or exist in the PATH. * @param args the argument vector (NOT including argv[0]). * @param input Input to send TO the command. * @param output Output FROM the command. * @return the exec output status (0 if ok), or -1 */ - int doexec(const std::string &cmd, const std::vector& args, - const std::string *input = 0, - std::string *output = 0); + int doexec(const std::string& cmd, const std::vector& args, + const std::string *input = 0, + std::string *output = 0); /** Same as doexec but cmd and args in one vector */ - int doexec1(const std::vector& args, - const std::string *input = 0, + int doexec1(const std::vector& args, + const std::string *input = 0, std::string *output = 0) { - if (args.empty()) + if (args.empty()) { return -1; + } return doexec(args[0], std::vector(args.begin() + 1, args.end()), input, output); } /* - * The next four methods can be used when a Q/A dialog needs to be + * The next four methods can be used when a Q/A dialog needs to be * performed with the command */ - int startExec(const std::string &cmd, const std::vector& args, - bool has_input, bool has_output); + int startExec(const std::string& cmd, const std::vector& args, + bool has_input, bool has_output); int send(const std::string& data); int receive(std::string& data, int cnt = -1); @@ -162,16 +163,16 @@ class ExecCmd { /** Read line. Timeout after timeosecs seconds */ int getline(std::string& data, int timeosecs); - + int wait(); - /** Wait with WNOHANG set. - @return true if process exited, false else. - @param O: status, the wait(2) call's status value */ + /** Wait with WNOHANG set. + @return true if process exited, false else. + @param O: status, the wait(2) call's status value */ bool maybereap(int *status); pid_t getChildPid(); - /** + /** * Cancel/kill command. This can be called from another thread or * from the advise callback, which could also raise an exception * to accomplish the same thing. In the owner thread, any I/O loop @@ -187,7 +188,7 @@ class ExecCmd { void zapChild(); /** - * Request process termination (SIGTERM or equivalent). This returns + * Request process termination (SIGTERM or equivalent). This returns * immediately */ bool requestChildExit(); @@ -197,8 +198,8 @@ class ExecCmd { // a viewer. The default is to hide the window, // because it avoids windows appearing and // disappearing when executing stuff for previewing - EXF_SHOWWINDOW = 1, - }; + EXF_SHOWWINDOW = 1, + }; ExecCmd(int flags = 0); ~ExecCmd(); @@ -221,37 +222,39 @@ class ExecCmd { static bool backtick(const std::vector cmd, std::string& out); class Internal; - private: +private: Internal *m; /* Copyconst and assignment are private and forbidden */ - ExecCmd(const ExecCmd &) {} - ExecCmd& operator=(const ExecCmd &) {return *this;}; + ExecCmd(const ExecCmd&) {} + ExecCmd& operator=(const ExecCmd&) { + return *this; + }; }; -/** - * Rexecute self process with the same arguments. +/** + * Rexecute self process with the same arguments. * * Note that there are some limitations: - * - argv[0] has to be valid: an executable name which will be found in - * the path when exec is called in the initial working directory. This is + * - argv[0] has to be valid: an executable name which will be found in + * the path when exec is called in the initial working directory. This is * by no means guaranteed. The shells do this, but argv[0] could be an * arbitrary string. * - The initial working directory must be found and remain valid. * - We don't try to do anything with fd 0,1,2. If they were changed by the - * program, their initial meaning won't be the same as at the moment of the + * program, their initial meaning won't be the same as at the moment of the * initial invocation. - * - We don't restore the signals. Signals set to be blocked + * - We don't restore the signals. Signals set to be blocked * or ignored by the program will remain ignored even if this was not their * initial state. * - The environment is also not restored. * - Others system aspects ? - * - Other program state: application-dependant. Any external cleanup - * (temp files etc.) must be performed by the application. ReExec() - * duplicates the atexit() function to make this easier, but the + * - Other program state: application-dependant. Any external cleanup + * (temp files etc.) must be performed by the application. ReExec() + * duplicates the atexit() function to make this easier, but the * ReExec().atexit() calls must be done explicitely, this is not automatic - * - * In short, this is usable in reasonably controlled situations and if there + * + * In short, this is usable in reasonably controlled situations and if there * are no security issues involved, but this does not perform miracles. */ class ReExec { @@ -259,13 +262,14 @@ public: ReExec() {} ReExec(int argc, char *argv[]); void init(int argc, char *argv[]); - int atexit(void (*function)(void)) - { - m_atexitfuncs.push(function); - return 0; + int atexit(void (*function)(void)) { + m_atexitfuncs.push(function); + return 0; } void reexec(); - const std::string& getreason() {return m_reason;} + const std::string& getreason() { + return m_reason; + } // Insert new args into the initial argv. idx designates the place // before which the new args are inserted (the default of 1 // inserts after argv[0] which would probably be an appropriate diff --git a/src/utils/netcon.cpp b/src/utils/netcon.cpp index fe46d70f..151130ea 100644 --- a/src/utils/netcon.cpp +++ b/src/utils/netcon.cpp @@ -84,9 +84,9 @@ using namespace std; static const int one = 1; static const int zero = 0; -#define LOGSYSERR(who, call, spar) \ - LOGERR(("%s: %s(%s) errno %d (%s)\n", who, call, \ - spar, errno, strerror(errno))) +#define LOGSYSERR(who, call, spar) \ + LOGERR(("%s: %s(%s) errno %d (%s)\n", who, call, \ + spar, errno, strerror(errno))) #ifndef MIN #define MIN(a,b) (a::iterator it = m_polldata.begin(); + for (map::iterator it = m_polldata.begin(); it != m_polldata.end(); it++) { - NetconP &pll = it->second; + NetconP& pll = it->second; int fd = it->first; - LOGDEB2(("Selectloop: fd %d flags 0x%x\n",fd, pll->m_wantedEvents)); + LOGDEB2(("Selectloop: fd %d flags 0x%x\n", fd, pll->m_wantedEvents)); if (pll->m_wantedEvents & Netcon::NETCONPOLL_READ) { FD_SET(fd, &rd); nfds = MAX(nfds, fd + 1); @@ -275,7 +275,7 @@ int SelectLoop::doLoop() continue; } - map::iterator it = m_polldata.find(fd); + map::iterator it = m_polldata.find(fd); if (it == m_polldata.end()) { /// This should not happen actually LOGDEB2(("Netcon::selectloop: fd %d not found\n", fd)); @@ -284,14 +284,14 @@ int SelectLoop::doLoop() // Next start will be one beyond last serviced (modulo nfds) m_placetostart = fd + 1; - NetconP &pll = it->second; + NetconP& pll = it->second; if (canread && pll->cando(Netcon::NETCONPOLL_READ) <= 0) { pll->m_wantedEvents &= ~Netcon::NETCONPOLL_READ; } if (canwrite && pll->cando(Netcon::NETCONPOLL_WRITE) <= 0) { pll->m_wantedEvents &= ~Netcon::NETCONPOLL_WRITE; } - if (!(pll->m_wantedEvents & (Netcon::NETCONPOLL_WRITE|Netcon::NETCONPOLL_READ))) { + if (!(pll->m_wantedEvents & (Netcon::NETCONPOLL_WRITE | Netcon::NETCONPOLL_READ))) { LOGDEB0(("Netcon::selectloop: fd %d has 0x%x mask, erasing\n", it->first, it->second->m_wantedEvents)); m_polldata.erase(it); @@ -324,7 +324,7 @@ int SelectLoop::remselcon(NetconP con) return -1; } LOGDEB1(("Netcon::remselcon: fd %d\n", con->m_fd)); - map::iterator it = m_polldata.find(con->m_fd); + map::iterator it = m_polldata.find(con->m_fd); if (it == m_polldata.end()) { LOGDEB1(("Netcon::remselcon: con not found for fd %d\n", con->m_fd)); return -1; @@ -336,7 +336,7 @@ int SelectLoop::remselcon(NetconP con) ////////////////////////////////////////////////////////// // Base class (Netcon) methods -Netcon::~Netcon() +Netcon::~Netcon() { closeconn(); if (m_peer) { @@ -369,7 +369,7 @@ void Netcon::setpeer(const char *hostname) int Netcon::settcpnodelay(int on) { - LOGDEB2(( "Netcon::settcpnodelay\n" )); + LOGDEB2(("Netcon::settcpnodelay\n")); if (m_fd < 0) { LOGERR(("Netcon::settcpnodelay: connection not opened\n")); return -1; @@ -386,7 +386,7 @@ int Netcon::settcpnodelay(int on) int Netcon::set_nonblock(int onoff) { int flags = fcntl(m_fd, F_GETFL, 0); - if (flags != -1 ) { + if (flags != -1) { int newflags = onoff ? flags | O_NONBLOCK : flags & ~O_NONBLOCK; if (newflags != flags) if (fcntl(m_fd, F_SETFL, newflags) < 0) { @@ -399,7 +399,7 @@ int Netcon::set_nonblock(int onoff) ///////////////////////////////////////////////////////////////////// // Data socket (NetconData) methods -NetconData::~NetconData() +NetconData::~NetconData() { freeZ(m_buf); m_bufbase = 0; @@ -511,7 +511,7 @@ int NetconData::doreceive(char *buf, int cnt, int timeo) LOGDEB2(("Netcon::doreceive: cnt %d, timeo %d\n", cnt, timeo)); cur = 0; while (cnt > cur) { - got = receive(buf, cnt-cur, timeo); + got = receive(buf, cnt - cur, timeo); LOGDEB2(("Netcon::doreceive: got %d\n", got)); if (got < 0) { return -1; @@ -551,7 +551,7 @@ int NetconData::getline(char *buf, int cnt, int timeo) for (;;) { // Transfer from buffer. Have to take a lot of care to keep counts and // pointers consistant in all end cases - int maxtransf = MIN(m_bufbytes, cnt-1); + int maxtransf = MIN(m_bufbytes, cnt - 1); int nn = maxtransf; LOGDEB2(("Before loop, bufbytes %d, maxtransf %d, nn: %d\n", m_bufbytes, maxtransf, nn)); @@ -648,7 +648,7 @@ int NetconCli::openconn(const char *host, unsigned int port, int timeo) } else { struct hostent *hp; if ((hp = gethostbyname(host)) == 0) { - LOGERR(("NetconCli::openconn: gethostbyname(%s) failed\n", + LOGERR(("NetconCli::openconn: gethostbyname(%s) failed\n", host)); return -1; } @@ -723,7 +723,7 @@ int NetconCli::openconn(const char *host, const char *serv, int timeo) if (host[0] != '/') { struct servent *sp; if ((sp = getservbyname(serv, "tcp")) == 0) { - LOGERR(("NetconCli::openconn: getservbyname failed for %s\n",serv)); + LOGERR(("NetconCli::openconn: getservbyname failed for %s\n", serv)); return -1; } // Callee expects the port number in host byte order @@ -749,7 +749,7 @@ int NetconCli::setconn(int fd) /////////////////////////////////////////////////////////////////////// // Methods for the main (listening) server connection -NetconServLis::~NetconServLis() +NetconServLis::~NetconServLis() { #ifdef NETCON_ACCESSCONTROL freeZ(okaddrs.intarray); @@ -759,7 +759,7 @@ NetconServLis::~NetconServLis() #if 0 // code for dumping a struct servent -static void dump_servent(struct servent *servp) +static void dump_servent(struct servent *servp) { fprintf(stderr, "Official name %s\n", servp->s_name); for (char **cpp = servp->s_aliases; *cpp; cpp++) { @@ -822,7 +822,7 @@ int NetconServLis::openservice(const char *serv, int backlog) LOGDEB1(("NetconServLis::openservice: service opened ok\n")); ret = 0; - out: +out: if (ret < 0 && m_fd >= 0) { close(m_fd); m_fd = -1; @@ -841,14 +841,14 @@ int NetconServLis::openservice(int port, int backlog) } #endif int ret = -1; - struct sockaddr_in ipaddr; + struct sockaddr_in ipaddr; if ((m_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { LOGSYSERR("NetconServLis", "socket", ""); return -1; } - (void) setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR,(char *)&one, sizeof(one)); + (void) setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); #ifdef SO_REUSEPORT - (void) setsockopt(m_fd, SOL_SOCKET, SO_REUSEPORT,(char *)&one, sizeof(one)); + (void) setsockopt(m_fd, SOL_SOCKET, SO_REUSEPORT, (char *)&one, sizeof(one)); #endif /*SO_REUSEPORT*/ memset(&ipaddr, 0, sizeof(ipaddr)); ipaddr.sin_family = AF_INET; @@ -983,10 +983,10 @@ NetconServLis::accept(int timeo) // Retrieve peer's host name. Errors are non fatal if (m_serv.empty() || m_serv[0] != '/') { struct hostent *hp; - if ((hp = gethostbyaddr((char *) & (who.sin_addr), + if ((hp = gethostbyaddr((char *) & (who.sin_addr), sizeof(struct in_addr), AF_INET)) == 0) { LOGERR(("NetconServLis::accept: gethostbyaddr failed for addr 0x%lx\n", - who.sin_addr.s_addr)); + who.sin_addr.s_addr)); con->setpeer(inet_ntoa(who.sin_addr)); } else { con->setpeer(hp->h_name); @@ -1033,7 +1033,7 @@ NetconServLis::checkperms(void *cl, int) if (i < okmasks.len) { mask = okmasks.intarray[i]; } else { - mask = okmasks.intarray[okmasks.len-1]; + mask = okmasks.intarray[okmasks.len - 1]; } LOGDEB2(("checkperms: trying okaddr 0x%x, mask 0x%x\n", okaddrs.intarray[i], mask)); @@ -1080,9 +1080,9 @@ Usage() static int op_flags; #define OPT_MOINS 0x1 -#define OPT_s 0x2 /* Server */ -#define OPT_c 0x4 /* Client */ -#define OPT_n 0x8 /* Client sleeps forever */ +#define OPT_s 0x2 /* Server */ +#define OPT_c 0x4 /* Client */ +#define OPT_n 0x8 /* Client sleeps forever */ extern int trycli(char *host, char *serv); extern int tryserv(char *serv); @@ -1118,7 +1118,7 @@ int main(int argc, char **argv) default: Usage(); break; - } + } argc--; argv++; } @@ -1209,8 +1209,8 @@ int trycli(char *host, char *serv) return 1; } int port = atoi(serv); - int ret = port > 0 ? - clicon->openconn(host, port) : clicon->openconn(host, serv); + int ret = port > 0 ? + clicon->openconn(host, port) : clicon->openconn(host, serv); if (ret < 0) { fprintf(stderr, "openconn(%s, %s) failed\n", host, serv); return 1; @@ -1271,7 +1271,7 @@ public: } if (reason & Netcon::NETCONPOLL_READ) { #define LL 200 - char buf[LL+1]; + char buf[LL + 1]; int n; if ((n = con->receive(buf, LL)) < 0) { fprintf(stderr, "receive failed\n"); @@ -1282,7 +1282,7 @@ public: } buf[n] = 0; fprintf(stderr, "%d received \"%s\"\n", getpid(), buf); - con->setselevents(Netcon::NETCONPOLL_READ|Netcon::NETCONPOLL_WRITE); + con->setselevents(Netcon::NETCONPOLL_READ | Netcon::NETCONPOLL_WRITE); } return 0; } @@ -1292,7 +1292,7 @@ private: class MyNetconServLis : public NetconServLis { public: - MyNetconServLis(SelectLoop &loop) + MyNetconServLis(SelectLoop& loop) : NetconServLis(), m_loop(loop) { } protected: @@ -1344,8 +1344,8 @@ int tryserv(char *serv) sigaction(SIGTERM, &sa, 0); int port = atoi(serv); - int ret = port > 0 ? - servlis->openservice(port) : servlis->openservice(serv); + int ret = port > 0 ? + servlis->openservice(port) : servlis->openservice(serv); if (ret < 0) { fprintf(stderr, "openservice(%s) failed\n", serv); return 1; diff --git a/src/utils/netcon.h b/src/utils/netcon.h index 5dff0985..9c39355e 100644 --- a/src/utils/netcon.h +++ b/src/utils/netcon.h @@ -36,7 +36,7 @@ /// endpoints. Netcon also has server-side static code to handle a set /// of client connections in parallel. This should be moved to a /// friend class. -/// +/// /// The client data transfer class can also be used for /// timeout-protected/asynchronous io using a given fd (ie a pipe /// descriptor) @@ -48,25 +48,25 @@ class SelectLoop; class Netcon { public: - enum Event {NETCONPOLL_READ = 0x1, NETCONPOLL_WRITE=0x2}; - Netcon() - : m_peer(0), m_fd(-1), m_ownfd(true), m_didtimo(0), m_wantedEvents(0), - m_loop(0) { + enum Event {NETCONPOLL_READ = 0x1, NETCONPOLL_WRITE = 0x2}; + Netcon() + : m_peer(0), m_fd(-1), m_ownfd(true), m_didtimo(0), m_wantedEvents(0), + m_loop(0) { } virtual ~Netcon(); - /// Remember whom we're talking to. We let external code do this because + /// Remember whom we're talking to. We let external code do this because /// the application may have a non-dns method to find the peer name. virtual void setpeer(const char *hostname); /// Retrieve the peer's hostname. Only works if it was set before ! virtual const char *getpeer() { - return m_peer ? (const char *)m_peer : "none"; + return m_peer ? (const char *)m_peer : "none"; } - /// Set or reset the TCP_NODELAY option. - virtual int settcpnodelay(int on = 1); + /// Set or reset the TCP_NODELAY option. + virtual int settcpnodelay(int on = 1); /// Did the last receive() call time out ? Resets the flag. virtual int timedout() { - int s = m_didtimo; - m_didtimo = 0; + int s = m_didtimo; + m_didtimo = 0; return s; } /// Return string version of last syscall error @@ -111,7 +111,7 @@ public: static int select1(int fd, int secs, int writing = 0); protected: - char *m_peer; // Name of the connected host + char *m_peer; // Name of the connected host int m_fd; bool m_ownfd; int m_didtimo; @@ -127,7 +127,7 @@ protected: }; -/// The selectloop interface is used to implement parallel servers. +/// The selectloop interface is used to implement parallel servers. // The select loop mechanism allows several netcons to be used for io // in a program without blocking as long as there is data to be read // or written. In a multithread program which is also using select, it @@ -136,13 +136,13 @@ protected: class SelectLoop { public: SelectLoop() - : m_selectloopDoReturn(false), m_selectloopReturnValue(0), - m_placetostart(0), - m_periodichandler(0), m_periodicparam(0), m_periodicmillis(0) { + : m_selectloopDoReturn(false), m_selectloopReturnValue(0), + m_placetostart(0), + m_periodichandler(0), m_periodicparam(0), m_periodicmillis(0) { } /// Loop waiting for events on the connections and call the - /// cando() method on the object when something happens (this will in + /// cando() method on the object when something happens (this will in /// turn typically call the app callback set on the netcon). Possibly /// call the periodic handler (if set) at regular intervals. /// @return -1 for error. 0 if no descriptors left for i/o. 1 for periodic @@ -151,8 +151,8 @@ public: /// Call from data handler: make selectloop return the param value void loopReturn(int value) { - m_selectloopDoReturn = true; - m_selectloopReturnValue = value; + m_selectloopDoReturn = true; + m_selectloopReturnValue = value; } /// Add a connection to be monitored (this will usually be called /// from the server's listen connection's accept callback) @@ -162,11 +162,11 @@ public: int remselcon(NetconP con); /// Set a function to be called periodically, or a time before return. - /// @param handler the function to be called. + /// @param handler the function to be called. /// - if it is 0, selectloop() will return after ms mS (and can be called /// again - /// - if it is not 0, it will be called at ms mS intervals. If its return - /// value is <= 0, selectloop will return. + /// - if it is not 0, it will be called at ms mS intervals. If its return + /// value is <= 0, selectloop will return. /// @param clp client data to be passed to handler at every call. /// @param ms milliseconds interval between handler calls or /// before return. Set to 0 for no periodic handler. @@ -195,12 +195,12 @@ private: /////////////////////// class NetconData; -/// Class for the application callback routine (when in selectloop). +/// Class for the application callback routine (when in selectloop). /// /// This is set by the app on the NetconData by calling /// setcallback(). It is then called from the NetconData's cando() /// routine, itself called by selectloop. -/// +/// /// It would be nicer to override cando() in a subclass instead of /// setting a callback, but this can't be done conveniently because /// accept() always creates a base NetconData (another approach would @@ -229,7 +229,7 @@ public: /// Read from the connection /// @param buf the data buffer - /// @param cnt the number of bytes we should try to read (but we return + /// @param cnt the number of bytes we should try to read (but we return /// as soon as we get data) /// @param timeo maximum number of seconds we should be waiting for data. /// @return the count of bytes actually read. 0 for timeout (call @@ -251,16 +251,16 @@ public: } private: - char *m_buf; // Buffer. Only used when doing getline()s + char *m_buf; // Buffer. Only used when doing getline()s char *m_bufbase; // Pointer to current 1st byte of useful data - int m_bufbytes; // Bytes of data. - int m_bufsize; // Total buffer size + int m_bufbytes; // Bytes of data. + int m_bufsize; // Total buffer size STD_SHARED_PTR m_user; virtual int cando(Netcon::Event reason); // Selectloop slot }; /// Network endpoint, client side. -class NetconCli : public NetconData { +class NetconCli : public NetconData { public: NetconCli(int silent = 0) { m_silentconnectfailure = silent; @@ -276,7 +276,7 @@ public: /// AF_UNIX service. serv is ignored in this case. int openconn(const char *host, unsigned int port, int timeo = -1); - /// Reuse existing fd. + /// Reuse existing fd. /// We DONT take ownership of the fd, and do no closin' EVEN on an /// explicit closeconn() or setconn() (use getfd(), close, /// setconn(-1) if you need to really close the fd and have no @@ -289,7 +289,7 @@ public: } private: - int m_silentconnectfailure; // No logging of connection failures if set + int m_silentconnectfailure; // No logging of connection failures if set }; class NetconServCon; @@ -316,9 +316,9 @@ class NetconServLis : public Netcon { public: NetconServLis() { #ifdef NETCON_ACCESSCONTROL - permsinit = 0; - okaddrs.len = okmasks.len = 0; - okaddrs.intarray = okmasks.intarray = 0; + permsinit = 0; + okaddrs.len = okmasks.len = 0; + okaddrs.intarray = okmasks.intarray = 0; #endif /* NETCON_ACCESSCONTROL */ } ~NetconServLis(); @@ -327,7 +327,7 @@ public: int openservice(const char *serv, int backlog = 10); /// Open service by port number. int openservice(int port, int backlog = 10); - /// Wait for incoming connection. Returned connected Netcon + /// Wait for incoming connection. Returned connected Netcon NetconServCon *accept(int timeo = -1); protected: @@ -337,7 +337,7 @@ protected: virtual int cando(Netcon::Event reason); // Empty if port was numeric, else service name or socket path - std::string m_serv; + std::string m_serv; private: #ifdef NETCON_ACCESSCONTROL @@ -353,16 +353,16 @@ private: /// Server-side accepted client connection. The only specific code /// allows closing the listening endpoint in the child process (in the /// case of a forking server) -class NetconServCon : public NetconData { +class NetconServCon : public NetconData { public: - NetconServCon(int newfd, Netcon* lis = 0) { - m_liscon = lis; - m_fd = newfd; + NetconServCon(int newfd, Netcon* lis = 0) { + m_liscon = lis; + m_fd = newfd; } /// This is for forked servers that want to get rid of the main socket void closeLisCon() { - if (m_liscon) { - m_liscon->closeconn(); + if (m_liscon) { + m_liscon->closeconn(); } } private: diff --git a/src/utils/readfile.cpp b/src/utils/readfile.cpp index bbb71cc9..513471b1 100644 --- a/src/utils/readfile.cpp +++ b/src/utils/readfile.cpp @@ -22,12 +22,16 @@ #endif #include -#include "safefcntl.h" #include +#ifdef _WIN32 +#include "safefcntl.h" #include "safesysstat.h" #include "safeunistd.h" -#ifndef _WIN32 +#else #define O_BINARY 0 +#include +#include +#include #endif #include @@ -41,33 +45,34 @@ public: FileToString(string& data) : m_data(data) {} string& m_data; bool init(size_t size, string *reason) { - if (size > 0) - m_data.reserve(size); - return true; + if (size > 0) { + m_data.reserve(size); + } + return true; } bool data(const char *buf, int cnt, string *reason) { - try { - m_data.append(buf, cnt); - } catch (...) { - catstrerror(reason, "append", errno); - return false; - } - return true; + try { + m_data.append(buf, cnt); + } catch (...) { + catstrerror(reason, "append", errno); + return false; + } + return true; } }; -bool file_to_string(const string &fn, string &data, string *reason) +bool file_to_string(const string& fn, string& data, string *reason) { return file_to_string(fn, data, 0, size_t(-1), reason); } -bool file_to_string(const string &fn, string &data, off_t offs, size_t cnt, +bool file_to_string(const string& fn, string& data, off_t offs, size_t cnt, string *reason) { FileToString accum(data); return file_scan(fn, &accum, offs, cnt, reason); } -bool file_scan(const string &fn, FileScanDo* doer, string *reason) +bool file_scan(const string& fn, FileScanDo* doer, string *reason) { return file_scan(fn, doer, 0, size_t(-1), reason); } @@ -77,29 +82,29 @@ const int RDBUFSZ = 8192; // on both linux i586 and macosx (compared to just append()) // Also tried a version with mmap, but it's actually slower on the mac and not // faster on linux. -bool file_scan(const string &fn, FileScanDo* doer, off_t startoffs, +bool file_scan(const string& fn, FileScanDo* doer, off_t startoffs, size_t cnttoread, string *reason) { if (startoffs < 0) { *reason += " file_scan: negative startoffs not allowed"; return false; } - + bool ret = false; bool noclosing = true; int fd = 0; struct stat st; - // Initialize st_size: if fn.empty() , the fstat() call won't happen. + // Initialize st_size: if fn.empty() , the fstat() call won't happen. st.st_size = 0; // If we have a file name, open it, else use stdin. if (!fn.empty()) { - fd = open(fn.c_str(), O_RDONLY|O_BINARY); - if (fd < 0 || fstat(fd, &st) < 0) { - catstrerror(reason, "open/stat", errno); - return false; - } - noclosing = false; + fd = open(fn.c_str(), O_RDONLY | O_BINARY); + if (fd < 0 || fstat(fd, &st) < 0) { + catstrerror(reason, "open/stat", errno); + return false; + } + noclosing = false; } #if defined O_NOATIME && O_NOATIME != 0 @@ -108,12 +113,12 @@ bool file_scan(const string &fn, FileScanDo* doer, off_t startoffs, } #endif - if (cnttoread != (size_t)-1 && cnttoread) { - doer->init(cnttoread+1, reason); + if (cnttoread != (size_t) - 1 && cnttoread) { + doer->init(cnttoread + 1, reason); } else if (st.st_size > 0) { - doer->init(size_t(st.st_size+1), reason); + doer->init(size_t(st.st_size + 1), reason); } else { - doer->init(0, reason); + doer->init(0, reason); } off_t curoffs = 0; @@ -130,36 +135,40 @@ bool file_scan(const string &fn, FileScanDo* doer, off_t startoffs, for (;;) { size_t toread = RDBUFSZ; if (startoffs > 0 && curoffs < startoffs) { - toread = size_t(MIN(RDBUFSZ, startoffs - curoffs)); + toread = size_t(MIN(RDBUFSZ, startoffs - curoffs)); } if (cnttoread != size_t(-1)) { toread = MIN(toread, cnttoread - totread); } - ssize_t n = static_cast(read(fd, buf, toread)); - if (n < 0) { - catstrerror(reason, "read", errno); - goto out; - } - if (n == 0) - break; + ssize_t n = static_cast(read(fd, buf, toread)); + if (n < 0) { + catstrerror(reason, "read", errno); + goto out; + } + if (n == 0) { + break; + } curoffs += n; - if (curoffs - n < startoffs) + if (curoffs - n < startoffs) { continue; - - if (!doer->data(buf, n, reason)) { - goto out; - } + } + + if (!doer->data(buf, n, reason)) { + goto out; + } totread += n; - if (cnttoread > 0 && totread >= cnttoread) + if (cnttoread > 0 && totread >= cnttoread) { break; + } } ret = true; - out: - if (fd >= 0 && !noclosing) - close(fd); +out: + if (fd >= 0 && !noclosing) { + close(fd); + } return ret; } @@ -181,29 +190,28 @@ using namespace std; using namespace std; class myCB : public FsTreeWalkerCB { - public: - FsTreeWalker::Status processone(const string &path, - const struct stat *st, - FsTreeWalker::CbFlag flg) - { - if (flg == FsTreeWalker::FtwDirEnter) { - //cout << "[Entering " << path << "]" << endl; - } else if (flg == FsTreeWalker::FtwDirReturn) { - //cout << "[Returning to " << path << "]" << endl; - } else if (flg == FsTreeWalker::FtwRegular) { - //cout << path << endl; - string s, reason; - if (!file_to_string(path, s, &reason)) { - cerr << "Failed: " << reason << " : " << path << endl; - } else { - //cout << - //"================================================" << endl; - cout << path << endl; - // cout << s; - } - reason.clear(); - } - return FsTreeWalker::FtwOk; +public: + FsTreeWalker::Status processone(const string& path, + const struct stat *st, + FsTreeWalker::CbFlag flg) { + if (flg == FsTreeWalker::FtwDirEnter) { + //cout << "[Entering " << path << "]" << endl; + } else if (flg == FsTreeWalker::FtwDirReturn) { + //cout << "[Returning to " << path << "]" << endl; + } else if (flg == FsTreeWalker::FtwRegular) { + //cout << path << endl; + string s, reason; + if (!file_to_string(path, s, &reason)) { + cerr << "Failed: " << reason << " : " << path << endl; + } else { + //cout << + //"================================================" << endl; + cout << path << endl; + // cout << s; + } + reason.clear(); + } + return FsTreeWalker::FtwOk; } }; @@ -214,8 +222,8 @@ static int op_flags; static const char *thisprog; static char usage [] = -"trreadfile [-o offs] [-c cnt] topdirorfile\n\n" -; + "trreadfile [-o offs] [-c cnt] topdirorfile\n\n" + ; static void Usage(void) { @@ -228,51 +236,71 @@ int main(int argc, const char **argv) off_t offs = 0; size_t cnt = size_t(-1); thisprog = argv[0]; - argc--; argv++; + argc--; + argv++; - while (argc > 0 && **argv == '-') { - (*argv)++; - if (!(**argv)) - /* Cas du "adb - core" */ - Usage(); - while (**argv) - switch (*(*argv)++) { - case 'c': op_flags |= OPT_c; if (argc < 2) Usage(); - cnt = atoll(*(++argv)); argc--; - goto b1; - case 'o': op_flags |= OPT_o; if (argc < 2) Usage(); - offs = strtoull(*(++argv), 0, 0); argc--; - goto b1; - default: Usage(); break; - } - b1: argc--; argv++; - } + while (argc > 0 && **argv == '-') { + (*argv)++; + if (!(**argv)) + /* Cas du "adb - core" */ + { + Usage(); + } + while (**argv) + switch (*(*argv)++) { + case 'c': + op_flags |= OPT_c; + if (argc < 2) { + Usage(); + } + cnt = atoll(*(++argv)); + argc--; + goto b1; + case 'o': + op_flags |= OPT_o; + if (argc < 2) { + Usage(); + } + offs = strtoull(*(++argv), 0, 0); + argc--; + goto b1; + default: + Usage(); + break; + } +b1: + argc--; + argv++; + } - if (argc != 1) - Usage(); - string top = *argv++;argc--; - cerr << "filename " << top << " offs " << offs << " cnt " << cnt << endl; + if (argc != 1) { + Usage(); + } + string top = *argv++; + argc--; + cerr << "filename " << top << " offs " << offs << " cnt " << cnt << endl; - struct stat st; - if (!top.empty() && stat(top.c_str(), &st) < 0) { - perror("stat"); - exit(1); - } - if (!top.empty() && S_ISDIR(st.st_mode)) { - FsTreeWalker walker; - myCB cb; - walker.walk(top, cb); - if (walker.getErrCnt() > 0) - cout << walker.getReason(); - } else { - string s, reason; - if (!file_to_string(top, s, offs, cnt, &reason)) { - cerr << reason << endl; - exit(1); - } else { - cout << s; - } - } - exit(0); + struct stat st; + if (!top.empty() && stat(top.c_str(), &st) < 0) { + perror("stat"); + exit(1); + } + if (!top.empty() && S_ISDIR(st.st_mode)) { + FsTreeWalker walker; + myCB cb; + walker.walk(top, cb); + if (walker.getErrCnt() > 0) { + cout << walker.getReason(); + } + } else { + string s, reason; + if (!file_to_string(top, s, offs, cnt, &reason)) { + cerr << reason << endl; + exit(1); + } else { + cout << s; + } + } + exit(0); } #endif //TEST_READFILE diff --git a/src/utils/readfile.h b/src/utils/readfile.h index 35620904..aa578b5c 100644 --- a/src/utils/readfile.h +++ b/src/utils/readfile.h @@ -21,8 +21,8 @@ #include -/** - * Read file in chunks, calling an accumulator for each chunk. Can be used +/** + * Read file in chunks, calling an accumulator for each chunk. Can be used * for reading in a file, computing an md5... */ class FileScanDo { @@ -31,20 +31,20 @@ public: virtual bool init(size_t size, std::string *reason) = 0; virtual bool data(const char *buf, int cnt, std::string* reason) = 0; }; -bool file_scan(const std::string &filename, FileScanDo* doer, std::string *reason = 0); -/* Same but only process count cnt from offset offs. Set cnt to size_t(-1) +bool file_scan(const std::string& filename, FileScanDo* doer, std::string *reason = 0); +/* Same but only process count cnt from offset offs. Set cnt to size_t(-1) * for no limit */ -bool file_scan(const std::string &fn, FileScanDo* doer, off_t offs, size_t cnt, +bool file_scan(const std::string& fn, FileScanDo* doer, off_t offs, size_t cnt, std::string *reason = 0); /** * Read file into string. * @return true for ok, false else */ -bool file_to_string(const std::string &filename, std::string &data, std::string *reason = 0); +bool file_to_string(const std::string& filename, std::string& data, std::string *reason = 0); /** Read file chunk into string. Set cnt to size_t(-1) for whole file */ -bool file_to_string(const std::string &filename, std::string &data, +bool file_to_string(const std::string& filename, std::string& data, off_t offs, size_t cnt, std::string *reason = 0); #endif /* _READFILE_H_INCLUDED_ */