diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
commit | 47e6e7c84f008a53061e661f31ae96629bc694ef (patch) | |
tree | 648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/pmdas/logger/util.c | |
download | pcp-debian/3.9.10.tar.gz |
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/pmdas/logger/util.c')
-rw-r--r-- | src/pmdas/logger/util.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/src/pmdas/logger/util.c b/src/pmdas/logger/util.c new file mode 100644 index 0000000..c79787f --- /dev/null +++ b/src/pmdas/logger/util.c @@ -0,0 +1,181 @@ +/* + * Utility functions for the logger PMDA. + * + * Copyright (c) 2011 Red Hat Inc. + * + * 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 2 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. + */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include "pmapi.h" +#include "impl.h" +#include "util.h" + +void +rstrip(char *str) +{ + char *ptr; + + /* Remove all trailing whitespace. Set ptr to last char of + * string. */ + ptr = str + strlen(str) - 1; + /* While trailing whitespace, move back. */ + while (ptr >= str && isspace((int)*ptr)) { + --ptr; + } + *(ptr+1) = '\0'; /* Now set '\0' as terminal byte. */ +} + +char * +lstrip(char *str) +{ + /* While leading whitespace, move forward. */ + char *ptr = str; + while (*ptr != '\0' && isspace((int)*ptr)) { + ptr++; + } + return ptr; +} + +int +start_cmd(const char *cmd, pid_t *ppid) +{ + pid_t child_pid; + int rc; + int pipe_fds[2]; +#define PARENT_END 0 /* parent end of the pipe */ +#define CHILD_END 1 /* child end of the pipe */ +#define STDOUT_FD 1 /* stdout fd */ + + /* FIXME items: + * (1) Should we be looking to handle shell metachars + * differently? Perhaps we should just allow isalnum()||isspace() + * chars only. + * (2) Do we need to clean up the environment in the child before + * the exec()? Remove things like IFS, CDPATH, ENV, and BASH_ENV. + */ + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + __pmNotifyErr(LOG_INFO, "%s: Trying to run command: %s", __FUNCTION__, + cmd); +#endif + + /* Create the pipes. */ +#if defined(HAVE_PIPE2) + rc = pipe2(pipe_fds, O_CLOEXEC|O_NONBLOCK); + if (rc < 0) { + __pmNotifyErr(LOG_ERR, "%s: pipe2() returned %s", __FUNCTION__, + strerror(-rc)); + return rc; + } +#else + rc = pipe(pipe_fds); + if (rc < 0) { + __pmNotifyErr(LOG_ERR, "%s: pipe() returned %s", __FUNCTION__, + strerror(-rc)); + return rc; + } + + /* Set the right flags on the pipes. */ + if (fcntl(pipe_fds[PARENT_END], F_SETFL, O_NDELAY) < 0 + || fcntl(pipe_fds[CHILD_END], F_SETFL, O_NDELAY) < 0) { + __pmNotifyErr(LOG_ERR, "%s: fcntl() returned %s", __FUNCTION__, + strerror(-rc)); + return rc; + } + if (fcntl(pipe_fds[PARENT_END], F_SETFD, O_CLOEXEC) < 0 + || fcntl(pipe_fds[CHILD_END], F_SETFD, O_CLOEXEC) < 0) { + __pmNotifyErr(LOG_ERR, "%s: fcntl() returned %s", __FUNCTION__, + strerror(-rc)); + return rc; + } +#endif + + /* Create the new process. */ + child_pid = fork(); + if (child_pid == 0) { /* child process */ + int i; + + /* Duplicate our pipe fd onto stdout of the child. Note that + * this clears O_CLOEXEC, so the new stdout should stay open + * when we call exec(). */ + if (pipe_fds[CHILD_END] != STDOUT_FD) { + if (dup2(pipe_fds[CHILD_END], STDOUT_FD) < 0) { + __pmNotifyErr(LOG_ERR, "%s: dup2() returned %s", __FUNCTION__, + strerror(errno)); + _exit(127); + } + } + + /* Close all other fds. */ + for (i = 0; i <= pipe_fds[CHILD_END]; i++) { + if (i != STDOUT_FD) { + close(i); + } + } + + /* Actually run the command. */ + execl ("/bin/sh", "sh", "-c", cmd, (char *)NULL); + _exit (127); + + } + else if (child_pid > 0) { /* parent process */ + close (pipe_fds[CHILD_END]); + if (ppid != NULL) { + *ppid = child_pid; + } + } + else if (child_pid < 0) { /* fork error */ + int errno_save = errno; + + __pmNotifyErr(LOG_ERR, "%s: fork() returned %s", __FUNCTION__, + strerror(errno_save)); + close (pipe_fds[PARENT_END]); + close (pipe_fds[CHILD_END]); + + return -errno_save; + } + + return pipe_fds[PARENT_END]; +} + +int +stop_cmd(pid_t pid) +{ + int rc; + pid_t wait_pid; + int wstatus; + + __pmNotifyErr(LOG_INFO, "%s: killing pid %" FMT_PID, __FUNCTION__, pid); + + /* Send the TERM signal. */ + rc = kill(pid, SIGTERM); + __pmNotifyErr(LOG_INFO, "%s: kill returned %d", __FUNCTION__, rc); + + /* Wait for the process to go away. */ + do { + wait_pid = waitpid (pid, &wstatus, 0); + __pmNotifyErr(LOG_INFO, "%s: waitpid returned %d", __FUNCTION__, + (int)wait_pid); + } while (wait_pid == -1 && errno == EINTR); + + /* Return process exit status. */ + return wstatus; +} |