Skip to content

Commit 44f70e6

Browse files
committed
Add Coprocess class
It provides a convenient way to spawn a process and read from/write to its stdin/stdout.
1 parent 3db6271 commit 44f70e6

12 files changed

+992
-305
lines changed

Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ OBJFILES = \
1010
gpg.o \
1111
key.o \
1212
util.o \
13-
parse_options.o
13+
parse_options.o \
14+
coprocess.o \
15+
fhstream.o
1416

1517
OBJFILES += crypto-openssl.o
1618
LDFLAGS += -lcrypto

coprocess-unix.cpp

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/*
2+
* Copyright 2015 Andrew Ayer
3+
*
4+
* This file is part of git-crypt.
5+
*
6+
* git-crypt is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* git-crypt is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with git-crypt. If not, see <http://www.gnu.org/licenses/>.
18+
*
19+
* Additional permission under GNU GPL version 3 section 7:
20+
*
21+
* If you modify the Program, or any covered work, by linking or
22+
* combining it with the OpenSSL project's OpenSSL library (or a
23+
* modified version of that library), containing parts covered by the
24+
* terms of the OpenSSL or SSLeay licenses, the licensors of the Program
25+
* grant you additional permission to convey the resulting work.
26+
* Corresponding Source for a non-source form of such a combination
27+
* shall include the source code for the parts of OpenSSL used as well
28+
* as that of the covered work.
29+
*/
30+
31+
#include "coprocess.hpp"
32+
#include "util.hpp"
33+
#include <sys/types.h>
34+
#include <sys/wait.h>
35+
#include <errno.h>
36+
37+
static int execvp (const std::string& file, const std::vector<std::string>& args)
38+
{
39+
std::vector<const char*> args_c_str;
40+
args_c_str.reserve(args.size());
41+
for (std::vector<std::string>::const_iterator arg(args.begin()); arg != args.end(); ++arg) {
42+
args_c_str.push_back(arg->c_str());
43+
}
44+
args_c_str.push_back(NULL);
45+
return execvp(file.c_str(), const_cast<char**>(&args_c_str[0]));
46+
}
47+
48+
Coprocess::Coprocess ()
49+
{
50+
pid = -1;
51+
stdin_pipe_reader = -1;
52+
stdin_pipe_writer = -1;
53+
stdin_pipe_ostream = NULL;
54+
stdout_pipe_reader = -1;
55+
stdout_pipe_writer = -1;
56+
stdout_pipe_istream = NULL;
57+
}
58+
59+
Coprocess::~Coprocess ()
60+
{
61+
close_stdin();
62+
close_stdout();
63+
}
64+
65+
std::ostream* Coprocess::stdin_pipe ()
66+
{
67+
if (!stdin_pipe_ostream) {
68+
int fds[2];
69+
if (pipe(fds) == -1) {
70+
throw System_error("pipe", "", errno);
71+
}
72+
stdin_pipe_reader = fds[0];
73+
stdin_pipe_writer = fds[1];
74+
stdin_pipe_ostream = new ofhstream(this, write_stdin);
75+
}
76+
return stdin_pipe_ostream;
77+
}
78+
79+
void Coprocess::close_stdin ()
80+
{
81+
delete stdin_pipe_ostream;
82+
stdin_pipe_ostream = NULL;
83+
if (stdin_pipe_writer != -1) {
84+
close(stdin_pipe_writer);
85+
stdin_pipe_writer = -1;
86+
}
87+
if (stdin_pipe_reader != -1) {
88+
close(stdin_pipe_reader);
89+
stdin_pipe_reader = -1;
90+
}
91+
}
92+
93+
std::istream* Coprocess::stdout_pipe ()
94+
{
95+
if (!stdout_pipe_istream) {
96+
int fds[2];
97+
if (pipe(fds) == -1) {
98+
throw System_error("pipe", "", errno);
99+
}
100+
stdout_pipe_reader = fds[0];
101+
stdout_pipe_writer = fds[1];
102+
stdout_pipe_istream = new ifhstream(this, read_stdout);
103+
}
104+
return stdout_pipe_istream;
105+
}
106+
107+
void Coprocess::close_stdout ()
108+
{
109+
delete stdout_pipe_istream;
110+
stdout_pipe_istream = NULL;
111+
if (stdout_pipe_writer != -1) {
112+
close(stdout_pipe_writer);
113+
stdout_pipe_writer = -1;
114+
}
115+
if (stdout_pipe_reader != -1) {
116+
close(stdout_pipe_reader);
117+
stdout_pipe_reader = -1;
118+
}
119+
}
120+
121+
void Coprocess::spawn (const std::vector<std::string>& args)
122+
{
123+
pid = fork();
124+
if (pid == -1) {
125+
throw System_error("fork", "", errno);
126+
}
127+
if (pid == 0) {
128+
if (stdin_pipe_writer != -1) {
129+
close(stdin_pipe_writer);
130+
}
131+
if (stdout_pipe_reader != -1) {
132+
close(stdout_pipe_reader);
133+
}
134+
if (stdin_pipe_reader != -1) {
135+
dup2(stdin_pipe_reader, 0);
136+
close(stdin_pipe_reader);
137+
}
138+
if (stdout_pipe_writer != -1) {
139+
dup2(stdout_pipe_writer, 1);
140+
close(stdout_pipe_writer);
141+
}
142+
143+
execvp(args[0], args);
144+
perror(args[0].c_str());
145+
_exit(-1);
146+
}
147+
if (stdin_pipe_reader != -1) {
148+
close(stdin_pipe_reader);
149+
stdin_pipe_reader = -1;
150+
}
151+
if (stdout_pipe_writer != -1) {
152+
close(stdout_pipe_writer);
153+
stdout_pipe_writer = -1;
154+
}
155+
}
156+
157+
int Coprocess::wait ()
158+
{
159+
int status = 0;
160+
if (waitpid(pid, &status, 0) == -1) {
161+
throw System_error("waitpid", "", errno);
162+
}
163+
return status;
164+
}
165+
166+
size_t Coprocess::write_stdin (void* handle, const void* buf, size_t count)
167+
{
168+
const int fd = static_cast<Coprocess*>(handle)->stdin_pipe_writer;
169+
ssize_t ret;
170+
while ((ret = write(fd, buf, count)) == -1 && errno == EINTR); // restart if interrupted
171+
if (ret < 0) {
172+
throw System_error("write", "", errno);
173+
}
174+
return ret;
175+
}
176+
177+
size_t Coprocess::read_stdout (void* handle, void* buf, size_t count)
178+
{
179+
const int fd = static_cast<Coprocess*>(handle)->stdout_pipe_reader;
180+
ssize_t ret;
181+
while ((ret = read(fd, buf, count)) == -1 && errno == EINTR); // restart if interrupted
182+
if (ret < 0) {
183+
throw System_error("read", "", errno);
184+
}
185+
return ret;
186+
}

coprocess-unix.hpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright 2015 Andrew Ayer
3+
*
4+
* This file is part of git-crypt.
5+
*
6+
* git-crypt is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* git-crypt is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with git-crypt. If not, see <http://www.gnu.org/licenses/>.
18+
*
19+
* Additional permission under GNU GPL version 3 section 7:
20+
*
21+
* If you modify the Program, or any covered work, by linking or
22+
* combining it with the OpenSSL project's OpenSSL library (or a
23+
* modified version of that library), containing parts covered by the
24+
* terms of the OpenSSL or SSLeay licenses, the licensors of the Program
25+
* grant you additional permission to convey the resulting work.
26+
* Corresponding Source for a non-source form of such a combination
27+
* shall include the source code for the parts of OpenSSL used as well
28+
* as that of the covered work.
29+
*/
30+
31+
#ifndef GIT_CRYPT_COPROCESS_HPP
32+
#define GIT_CRYPT_COPROCESS_HPP
33+
34+
#include "fhstream.hpp"
35+
#include <unistd.h>
36+
#include <vector>
37+
38+
class Coprocess {
39+
pid_t pid;
40+
41+
int stdin_pipe_reader;
42+
int stdin_pipe_writer;
43+
ofhstream* stdin_pipe_ostream;
44+
static size_t write_stdin (void*, const void*, size_t);
45+
46+
int stdout_pipe_reader;
47+
int stdout_pipe_writer;
48+
ifhstream* stdout_pipe_istream;
49+
static size_t read_stdout (void*, void*, size_t);
50+
51+
Coprocess (const Coprocess&); // Disallow copy
52+
Coprocess& operator= (const Coprocess&); // Disallow assignment
53+
public:
54+
Coprocess ();
55+
~Coprocess ();
56+
57+
std::ostream* stdin_pipe ();
58+
void close_stdin ();
59+
60+
std::istream* stdout_pipe ();
61+
void close_stdout ();
62+
63+
void spawn (const std::vector<std::string>&);
64+
65+
int wait ();
66+
};
67+
68+
#endif

0 commit comments

Comments
 (0)