diff options
author | Karol Lewandowski <k.lewandowsk@samsung.com> | 2018-09-20 20:41:39 +0200 |
---|---|---|
committer | Karol Lewandowski <k.lewandowsk@samsung.com> | 2018-09-25 16:49:02 +0200 |
commit | 13c0baf21642315852cd5032a9fdb1f796799aaa (patch) | |
tree | cbd7b741fd17db4606140110e2372745814fc842 | |
parent | 52366f9e61112ab1d69713746faeafade3ae29a7 (diff) | |
download | crash-worker-sandbox/klewandowski/dump-systemstate-rewrite.tar.gz crash-worker-sandbox/klewandowski/dump-systemstate-rewrite.tar.bz2 crash-worker-sandbox/klewandowski/dump-systemstate-rewrite.zip |
WIP::: dump_systemstate: Rewritesandbox/klewandowski/dump-systemstate-rewrite
This change brings following changes:
- support for parallel command execution
All commands are started concurrently with their
stdout and stderr is connected to private pipe(s).
- timeout removal
Utility will not set any arbitrary timeouts to
executed commands - it's now dump_systemstate
caller responsibility.
- rewrite to c++
C++ brings non-trivial data structures and allows
to make code more readable. It's also lighter than
eg. glib.
Change-Id: Ia7f8996e2687451b13d11ec9d15c41ba0f3381ed
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rwxr-xr-x | src/dump_systemstate/CMakeLists.txt | 14 | ||||
-rw-r--r-- | src/dump_systemstate/dump_systemstate.c | 240 | ||||
-rw-r--r-- | src/dump_systemstate/dump_systemstate.cc | 237 | ||||
-rw-r--r-- | src/shared/command.cc | 132 | ||||
-rw-r--r-- | src/shared/command.hh | 46 |
6 files changed, 423 insertions, 248 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index d16b0ea..9947009 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) -PROJECT(crash-worker C) +PROJECT(crash-worker C CXX) SET(PREFIX ${CMAKE_INSTALL_PREFIX}) diff --git a/src/dump_systemstate/CMakeLists.txt b/src/dump_systemstate/CMakeLists.txt index 60737cb..296d85c 100755 --- a/src/dump_systemstate/CMakeLists.txt +++ b/src/dump_systemstate/CMakeLists.txt @@ -1,24 +1,24 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) -PROJECT(dump_systemstate C) +PROJECT(dump_systemstate C CXX) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src) SET(SRCS - dump_systemstate.c + dump_systemstate.cc + ${CMAKE_SOURCE_DIR}/src/shared/command.cc ${CMAKE_SOURCE_DIR}/src/shared/util.c ${CMAKE_SOURCE_DIR}/src/shared/spawn.c - ) +) INCLUDE(FindPkgConfig) pkg_check_modules(dump_systemstate_pkgs REQUIRED dlog libunwind) FOREACH(flag ${dump_systemstate_pkgs_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") + SET(EXTRA_CXXFLAGS "${EXTRA_CXXFLAGS} ${flag}") ENDFOREACH(flag) -SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -g -fno-omit-frame-pointer -finstrument-functions") - -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE") -MESSAGE("FLAGS: ${CMAKE_C_FLAGS}") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -D_GNU_SOURCE=1 -fPIE") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS} -D_GNU_SOURCE=1 -fPIE") ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS}) TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${dump_systemstate_pkgs_LDFLAGS} -pie) diff --git a/src/dump_systemstate/dump_systemstate.c b/src/dump_systemstate/dump_systemstate.c deleted file mode 100644 index c226203..0000000 --- a/src/dump_systemstate/dump_systemstate.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * dump_systemstate - * - * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file dump_systemstate.c - * @brief dump system states. - */ - -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <time.h> -#include <limits.h> -#include <getopt.h> -#include <sys/stat.h> -#include <sys/vfs.h> - -#include "shared/util.h" -#include "shared/log.h" -#include "shared/spawn.h" - -#define FILE_PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) - -#define TIMEOUT_DEFAULT_MS 60*1000 /* 60sec */ - -static struct dump_item { - const char *title; - const char *path; -} dump_item[] = { - {"==== Binary version " , "/etc/info.ini"}, - {"==== Tizen version " , "/etc/tizen-release"}, - {"==== Kernel version " , "/proc/version"}, - {"==== Boot arguments " , "/proc/cmdline"}, - {"==== CPU & system architecture " , "/proc/cpuinfo"}, - {"==== System uptime " , "/proc/uptime"}, - {"==== System statistics " , "/proc/stat"}, - {"==== System memory usage " , "/proc/meminfo"}, - {"==== Device major numbers " , "/proc/devices"}, - {"==== System disk I/O satistics " , "/proc/diskstats"}, -}; - -static void usage() -{ - fprintf(stderr, "usage: dump_systemstate [-k] [-d] [-f file]\n" - " -f: write to file (instead of stdout)\n" - " -k: dump kernel messages (only root)\n" - " -d: dump dlog messages\n" - " -j: dump journal log messages\n" - ); -} - -/* get disk used percentage */ -static int get_disk_used_percent(const char *path) -{ - struct statfs lstatfs; - int percent; - - if (!path) - return -1; - - if (statfs(path, &lstatfs) < 0) - return -1; - percent = (((lstatfs.f_blocks - lstatfs.f_bfree) * 1000) / (lstatfs.f_blocks)) + 9; - percent = percent/10; - return percent; -} - -int main(int argc, char *argv[]) -{ - int c, ret, i, is_root, dpercent; - const char *arg_file = NULL; - int out_fd = -1; - bool arg_dlog = false; - bool arg_dmesg = false; - bool arg_journal = false; - char timestr[80]; - time_t cur_time; - struct tm gm_tm; - struct tm loc_tm; - - while ((c = getopt(argc, argv, "hf:kdj")) != -1) { - switch (c) { - case 'd': - arg_dlog = true; - break; - case 'k': - arg_dmesg = true; - break; - case 'j': - arg_journal = true; - break; - case 'f': - arg_file = optarg; - break; - case '?': - case 'h': - printf("\n"); - usage(); - ret = 0; - goto exit; - } - } - ret = 0; - cur_time = time(NULL); - gmtime_r(&cur_time, &gm_tm); - localtime_r(&cur_time, &loc_tm); - is_root = !(geteuid()); - - /* open output file */ - if (arg_file == NULL) { - out_fd = STDOUT_FILENO; - } else { - out_fd = open(arg_file, O_WRONLY | O_TRUNC | O_CREAT, FILE_PERM); - if (out_fd < 0) { - perror("couldn't open output file"); - ret = out_fd; - goto exit; - } - } - /* print timestamp */ - strftime(timestr, sizeof(timestr), - "%Y-%m-%d %H:%M:%S%z", &loc_tm); - fprintf_fd(out_fd, "dump_systemstate: %s\n", timestr); - - for (i = 0; i < ARRAY_SIZE(dump_item); i++) { - fsync(out_fd); - fprintf_fd(out_fd, "\n%s(%s)\n", - dump_item[i].title, dump_item[i].path); - ret = dump_file_write_fd((char *)dump_item[i].path, out_fd); - if (ret < 0) - goto exit_close; - } - fprintf_fd(out_fd, "\n"); - - fprintf_fd(out_fd, "\n==== System disk space usage (/bin/df -h)\n"); - char *df_args[] = {"/bin/df", "-h", NULL}; - ret = spawn_wait(df_args, NULL, spawn_setstdout, (void *)out_fd, TIMEOUT_DEFAULT_MS); - if (ret != 0) - goto exit_close; - - dpercent = get_disk_used_percent("/opt"); - if (90 < dpercent) { - fprintf_fd(out_fd, "\n==== System disk space usage detail - %d%% (/bin/du -ah /opt)\n", dpercent); - char *du_args[] = {"/bin/du", "-ah", "/opt", "--exclude=/opt/usr", NULL}; - ret = spawn_wait(du_args, NULL, spawn_setstdout, (void *)out_fd, TIMEOUT_DEFAULT_MS); - if (ret != 0) - goto exit_close; - } - fprintf_fd(out_fd, "\n==== System timezone (ls -al /opt/etc/localtime)\n"); - char *ls_args[] = {"/bin/ls", "-al", "/opt/etc/localtime", NULL}; - ret = spawn_wait(ls_args, NULL, spawn_setstdout, (void *)out_fd, TIMEOUT_DEFAULT_MS); - if (ret != 0) - goto exit_close; - - fprintf_fd(out_fd, "\n==== System summary (/usr/bin/top -bcH -n 1)\n"); - char *top_args[] = {"/bin/top", "-bcH", "-n", "1", NULL}; - char *top_env[] = {"COLUMNS=200", NULL}; - ret = spawn_wait(top_args, top_env, spawn_setstdout, (void *)out_fd, TIMEOUT_DEFAULT_MS); - if (ret != 0) - goto exit_close; - - fprintf_fd(out_fd, "\n==== Current processes (/bin/ps auxfw)\n"); - char *ps_args[] = {"/bin/ps", "auxfw", NULL}; - ret = spawn_wait(ps_args, NULL, spawn_setstdout, (void *)out_fd, TIMEOUT_DEFAULT_MS); - if (ret != 0) - goto exit_close; - - fprintf_fd(out_fd, "\n==== System memory statistics (/usr/bin/memps -v)\n"); - char *memps_args[] = {"/bin/memps", "-v", NULL}; - ret = spawn_wait(memps_args, NULL, spawn_setstdout, (void *)out_fd, TIMEOUT_DEFAULT_MS); - if (ret != 0) - goto exit_close; - - if (is_root) { - fprintf_fd(out_fd, "\n==== System configuration (/usr/bin/vconftool get memory, db, file)\n"); - char *get_mem_args[] = {"/bin/vconftool", "get", "memory/", "-r", NULL}; - ret = spawn_wait(get_mem_args, NULL, spawn_setstdout, (void *)out_fd, TIMEOUT_DEFAULT_MS); - if (ret != 0) - goto exit_close; - - char *get_db_args[] = {"/bin/vconftool", "get", "db/", "-r", NULL}; - ret = spawn_wait(get_db_args, NULL, spawn_setstdout, (void *)out_fd, TIMEOUT_DEFAULT_MS); - if (ret != 0) - goto exit_close; - - char *get_file_args[] = {"/bin/vconftool", "get", "file/", "-r", NULL}; - ret = spawn_wait(get_file_args, NULL, spawn_setstdout, (void *)out_fd, TIMEOUT_DEFAULT_MS); - if (ret != 0) - goto exit_close; - } - - if (arg_dmesg && is_root) { - fprintf_fd(out_fd, "\n==== Kernel messages (TZ=UTC /bin/dmesg -T)\n"); - char *dmesg_args[] = {"/bin/dmesg", "-T", NULL}; - char *dmesg_env[] = {"TZ=UTC", NULL}; - ret = spawn_wait(dmesg_args, dmesg_env, spawn_setstdout, (void *)out_fd, TIMEOUT_DEFAULT_MS); - if (ret != 0) - goto exit_close; - } - - if (arg_dlog) { - fprintf_fd(out_fd, "\n==== Log messages\n"); - char *dlogutil_args[] = {"/bin/dlogutil", "-d", "-v", "threadtime", "-u", "16384", NULL}; - ret = spawn_wait(dlogutil_args, NULL, spawn_setstdout, (void *)out_fd, TIMEOUT_DEFAULT_MS); - if (ret != 0) - goto exit_close; - } - - if (arg_journal) { - fprintf_fd(out_fd, "\n==== Journal messages\n"); - char *journalctl_args[] = {"/bin/journalctl", "-b", "-n", "1024", NULL}; - ret = spawn_wait(journalctl_args, NULL, spawn_setstdout, (void *)out_fd, TIMEOUT_DEFAULT_MS); - if (ret != 0) - goto exit_close; - } - -exit_close: - if (arg_file) - close(out_fd); -exit: - return ret; -} diff --git a/src/dump_systemstate/dump_systemstate.cc b/src/dump_systemstate/dump_systemstate.cc new file mode 100644 index 0000000..50f43fd --- /dev/null +++ b/src/dump_systemstate/dump_systemstate.cc @@ -0,0 +1,237 @@ +/* + * dump_systemstate + * + * Copyright (c) 2012 - 2013, 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file dump_systemstate.cc + * @brief dump system states. + */ + +#include <assert.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <limits.h> +#include <getopt.h> +#include <sys/stat.h> +#include <sys/vfs.h> + +#include <vector> +#include <list> + +#define LOG_TAG "DUMP_SYSTEMSTATE" +#include "shared/log.h" +#include "shared/util.h" +#include "shared/command.hh" + +#define FILE_PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) + +static struct dump_path { + const char *title; + const char *path; +} dump_path[] = { + {"==== Binary version " , "/etc/info.ini"}, + {"==== Tizen version " , "/etc/tizen-release"}, + {"==== Kernel version " , "/proc/version"}, + {"==== Boot arguments " , "/proc/cmdline"}, + {"==== CPU & system architecture " , "/proc/cpuinfo"}, + {"==== System uptime " , "/proc/uptime"}, + {"==== System statistics " , "/proc/stat"}, + {"==== System memory usage " , "/proc/meminfo"}, + {"==== Device major numbers " , "/proc/devices"}, + {"==== System disk I/O satistics " , "/proc/diskstats"}, +}; + +static void usage() +{ + fprintf(stderr, "usage: dump_systemstate [-k] [-d] [-j] [-f file]\n" + " -f: write to file (instead of stdout)\n" + " -k: dump kernel messages (only root)\n" + " -d: dump dlog messages\n" + " -j: dump journal log messages\n"); +} + +static int dump_paths(int out_fd) +{ + for (unsigned u = 0; u < ARRAY_SIZE(dump_path); u++) { + dprintf(out_fd, "\n%s(%s)\n", dump_path[u].title, dump_path[u].path); + int ret = dump_file_write_fd((char *)dump_path[u].path, out_fd); + if (ret < 0) + return ret; + } + dprintf(out_fd, "\n"); + return 0; +} + +static int get_disk_used_percent(const char *path) +{ + struct statfs lstatfs; + int percent; + + if (!path || statfs(path, &lstatfs) < 0) + return -1; + percent = (((lstatfs.f_blocks - lstatfs.f_bfree) * 1000) / (lstatfs.f_blocks)) + 9; + percent = percent/10; + return percent; +} + +static std::list<Command *> prepare_commands(bool dump_dmesg, bool dump_dlog, bool dump_journal) +{ + std::list<Command *> cmd; + + cmd.push_back(new Command("System disk space usage", {"/bin/df", "-h"})); + + int dpercent = get_disk_used_percent("/opt"); + if (90 < dpercent) { + char *dtitle = NULL; + int r = asprintf(&dtitle, "System disk space usage detail - %d%%", dpercent); + if (!dtitle || r < 0) { + _W("Skipping 'System disk space usage detail' due to error: %m"); + } else { + cmd.push_back(new Command(dtitle, {"/bin/du", "-ah", "/opt", "--exclude=/opt/usr"})); + free(dtitle); + } + } + + cmd.push_back(new Command("System timezone", + {"/bin/ls", "-al", "/opt/etc/localtime"})); + cmd.push_back(new Command("System summary", + { "/bin/top", "-bcH", "-n", "1"}, {"COLUMNS=200"})); + cmd.push_back(new Command("Current processes", + {"/bin/ps", "auxfw"})); + cmd.push_back(new Command("System memory statistics", + {"/bin/memps", "-v"})); + + bool is_root = geteuid() == 0; + if (is_root) { + cmd.push_back(new Command("System configuration (memory, db, file)", + {"/bin/vconftool", "get", "memory/", "-r"})); + cmd.push_back(new Command(NULL, + {"/bin/vconftool", "get", "db/", "-r"})); + cmd.push_back(new Command(NULL, + {"/bin/vconftool", "get", "file/", "-r"})); + + if (dump_dmesg) + cmd.push_back(new Command("Kernel messages", + {"/bin/dmesg", "-T"}, {"TZ=UTC"})); + } + + if (dump_dlog) + cmd.push_back(new Command("Log messages", + {"/bin/dlogutil", "-d", "-v", "threadtime", "-u", "16384"})); + + if (dump_journal) + cmd.push_back(new Command("Journal messages", + {"/bin/journalctl", "-b", "-n", "1024"})); + + return cmd; +} + +static void process_commands(std::list<Command *> &cmd, int out_fd) +{ + for (auto c : cmd) + c->run(); + + for (auto c : cmd) + c->dump(out_fd); +} + +static void cleanup_commands(std::list<Command *> &cmd) +{ + for (auto c : cmd) + delete(c); +} + +void dump_header(int out_fd) +{ + char timestr[80]; + time_t cur_time; + struct tm gm_tm; + struct tm loc_tm; + + cur_time = time(NULL); + gmtime_r(&cur_time, &gm_tm); + localtime_r(&cur_time, &loc_tm); + + strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S%z", &loc_tm); + dprintf(out_fd, "dump_systemstate: %s\n", timestr); +} + +struct FdHelper { + FdHelper(const char *path) { + if (path) + fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, FILE_PERM); + else + fd = STDOUT_FILENO; + } + ~FdHelper() { + if (fd > 0) + fdatasync(fd); + if (fd != STDOUT_FILENO) + close(fd); + } + int fd; +}; + +int main(int argc, char *argv[]) +{ + const char *arg_file = NULL; + bool arg_dlog = false; + bool arg_dmesg = false; + bool arg_journal = false; + + for (int c; (c = getopt(argc, argv, "hf:kdj")) != -1; ) { + switch (c) { + case 'd': + arg_dlog = true; + break; + case 'k': + arg_dmesg = true; + break; + case 'j': + arg_journal = true; + break; + case 'f': + arg_file = optarg; + break; + case '?': + case 'h': + printf("\n"); + usage(); + return 0; + } + } + + FdHelper fh(arg_file); + if (fh.fd < 0) + return 1; + + dump_header(fh.fd); + + if (dump_paths(fh.fd) < 0) + return 2; + + auto cmd = prepare_commands(arg_dmesg, arg_dlog, arg_journal); + process_commands(cmd, fh.fd); + cleanup_commands(cmd); + + return 0; +} diff --git a/src/shared/command.cc b/src/shared/command.cc new file mode 100644 index 0000000..b3f66ef --- /dev/null +++ b/src/shared/command.cc @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <vector> +#include <cstdio> +#include <cstdlib> +#include <string> +#include <sstream> +#include <limits.h> +#include <unistd.h> +#include <fcntl.h> + +#include "command.hh" +#include "spawn.h" +#include "util.h" +#include "log.h" + +static constexpr int pipe_buf_size (1024*1024); + +Command::Command(const char *_title, + std::vector<const char *> _av, + std::vector<const char *> _ev) + : av(_av), + ev(_ev), + childpid(-1), + child_waitfd(-1), + child_datafd(-1) +{ + if (_title) + title.assign(_title); + + av.push_back(NULL); + ev.push_back(NULL); +} + +Command::~Command() +{ + if (child_waitfd != -1) + close(child_waitfd); + if (child_datafd != -1) + close(child_datafd); +} + +void Command::wait() +{ + if (childpid != -1) + wait_for_pid(childpid); + childpid = -1; +} + +void Command::run() +{ + int pipefd[2]; + if (pipe(pipefd) < 0) { + _E("pipe: %m"); + return; + } + fcntl(pipefd[1], F_SETPIPE_SZ, pipe_buf_size); + + auto args = av; + args.push_back(NULL); + auto envs = ev; + envs.push_back(NULL); + int r = spawn((char *const *)args.data(), (char *const *)envs.data(), + spawn_setstdouterr, (void*)pipefd[1], + &childpid, &child_waitfd); + + close(pipefd[1]); + + if (r != 0) + close(pipefd[0]); + + child_datafd = pipefd[0]; +} + +/* +static bool appendvec2string(const std::vector<const char *> &vec, std::stringstream &ss) +{ + if (vec.size() == 0) + return false; + + for (auto elem : vec) { + ss << elem; +// if (it != vec.cend()) +// ss << " "; + } + + return true; +} +*/ + +static bool appendvec2string(const std::vector<const char *> &vec, std::string &s) +{ + if (vec.size() == 0) + return false; + + for (auto elem : vec) { + s.append(elem); +// if (it != vec.cend()) +// ss << " "; + } + + return true; +} + +void Command::dump(int out_fd) +{ + if (title.length() > 0) { + std::string header = "\n==== "; + header.append(title); + header.append(" ("); + if (appendvec2string(ev, header)) + header.append(" "); + appendvec2string(av, header); + header.append(")\n"); + _D("ss is %s", header.c_str()); + dprintf(out_fd, header.c_str()); + } + copy_bytes(child_datafd, out_fd); +} diff --git a/src/shared/command.hh b/src/shared/command.hh new file mode 100644 index 0000000..3a6e9b1 --- /dev/null +++ b/src/shared/command.hh @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef COMMAND_HH +#define COMMAND_HH + +#include <string> +#include <vector> + +class Command { +public: + Command(const char *_title, + std::vector<const char *> _av, + std::vector<const char *> _ev = {}); + + ~Command(); + + void run(); + + void dump(int out_fd); + + void wait(); + +private: + std::string title; + std::vector<const char *> av, ev; + + pid_t childpid; + int child_waitfd; + int child_datafd; + +}; + +#endif |