monotone

monotone Mtn Source Tree

Root/unix/process.cc

1// copyright (C) 2005 Jon Bright <jon@siliconcircus.com>
2// all rights reserved.
3// licensed to the public under the terms of the GNU GPL (>= 2)
4// see the file COPYING for details
5
6#include <sys/types.h>
7#include <sys/wait.h>
8#include <sys/stat.h>
9#include <signal.h>
10#include <unistd.h>
11#include <fcntl.h>
12#include <errno.h>
13#include <string.h>
14
15#include <sstream>
16
17#include "sanity.hh"
18#include "platform.hh"
19
20int existsonpath(const char *exe)
21{
22 L(FL("checking for program '%s'\n") % exe);
23 // this is horribly ugly, but at least it is rather portable
24 std::string cmd_str = (F("command -v '%s' >/dev/null 2>&1") % exe).str();
25 const char * const args[] = {"sh", "-c", cmd_str.c_str(), NULL};
26 int pid;
27 int res;
28 pid = process_spawn(args);
29 if (pid==-1)
30 {
31 L(FL("error in process_spawn\n"));
32 return -1;
33 }
34 if (process_wait(pid, &res))
35 {
36 L(FL("error in process_wait\n"));
37 return -1;
38 }
39 if (res==0)
40 {
41 L(FL("successful return; %s exists\n") % exe);
42 return 0;
43 }
44 L(FL("failure; %s does not exist\n") % exe);
45 return -1;
46}
47
48bool is_executable(const char *path)
49{
50 struct stat s;
51
52 int rc = stat(path, &s);
53 N(rc != -1, F("error getting status of file %s: %s") % path % os_strerror(errno));
54
55 return (s.st_mode & S_IXUSR) && !(s.st_mode & S_IFDIR);
56}
57
58// copied from libc info page
59static mode_t
60read_umask()
61{
62 mode_t mask = umask(0);
63 umask(mask);
64 return mask;
65}
66
67int make_executable(const char *path)
68{
69 mode_t mode;
70 struct stat s;
71 int fd = open(path, O_RDONLY);
72 N(fd != -1, F("error opening file %s: %s") % path % os_strerror(errno));
73 if (fstat(fd, &s))
74 return -1;
75 mode = s.st_mode;
76 mode |= ((S_IXUSR|S_IXGRP|S_IXOTH) & ~read_umask());
77 int ret = fchmod(fd, mode);
78 N(close(fd) == 0, F("error closing file %s: %s") % path % os_strerror(errno));
79 return ret;
80}
81
82pid_t process_spawn(const char * const argv[])
83{
84 {
85 std::ostringstream cmdline_ss;
86 for (const char *const *i = argv; *i; ++i)
87 {
88 if (i != argv)
89 cmdline_ss << ", ";
90 cmdline_ss << "'" << *i << "'";
91 }
92 L(FL("spawning command: %s\n") % cmdline_ss.str());
93 }
94 pid_t pid;
95 pid = fork();
96 switch (pid)
97 {
98 case -1: /* Error */
99 return -1;
100 case 0: /* Child */
101 execvp(argv[0], (char * const *)argv);
102 raise(SIGKILL);
103 default: /* Parent */
104 return pid;
105 }
106}
107
108struct redir
109{
110 struct bad_redir {};
111 int savedfd;
112 int fd;
113 redir(int which, char const * file);
114 ~redir();
115};
116redir::redir(int which, char const * file)
117 : savedfd(-1), fd(which)
118{
119 if (!file || *file == '\0')
120 return;
121 int tempfd = open(file, (which==0?O_RDONLY:O_WRONLY|O_CREAT|O_TRUNC), 0664);
122 if (tempfd == -1)
123 {
124 throw redir::bad_redir();
125 }
126 int oldfd = dup(which);
127 if (oldfd == -1)
128 {
129 close(tempfd);
130 throw redir::bad_redir();
131 }
132 close(which);
133 while (dup2(tempfd, which) == -1 && errno == EINTR) ;
134 close(tempfd);
135 fd = which;
136 savedfd = oldfd;
137}
138redir::~redir()
139{
140 if (savedfd != -1)
141 {
142 close(fd);
143 dup2(savedfd, fd);
144 close(savedfd);
145 }
146}
147
148pid_t process_spawn_redirected(char const * in,
149 char const * out,
150 char const * err,
151 char const * const argv[])
152{
153 try
154 {
155 redir i(0, in);
156 redir o(1, out);
157 redir e(2, err);
158 return process_spawn(argv);
159 }
160 catch (redir::bad_redir & r)
161 {
162 return -1;
163 }
164}
165
166pid_t process_spawn_pipe(char const * const argv[], FILE** in, FILE** out)
167{
168 int infds[2];
169 int outfds[2];
170 pid_t pid;
171
172 if (pipe(infds) < 0)
173 return -1;
174 if (pipe(outfds) < 0)
175 {
176 close(infds[0]);
177 close(infds[1]);
178 return -1;
179 }
180
181 switch(pid = vfork())
182 {
183 case -1:
184 close(infds[0]);
185 close(infds[1]);
186 close(outfds[0]);
187 close(outfds[1]);
188 return -1;
189 case 0:
190 {
191 if (infds[0] != STDIN_FILENO)
192 {
193 dup2(infds[0], STDIN_FILENO);
194 close(infds[0]);
195 }
196 close(infds[1]);
197 if (outfds[1] != STDOUT_FILENO)
198 {
199 dup2(outfds[1], STDOUT_FILENO);
200 close(outfds[1]);
201 }
202 close(outfds[0]);
203
204 execvp(argv[0], (char * const *)argv);
205 raise(SIGKILL);
206 }
207 }
208 close(infds[0]);
209 close(outfds[1]);
210 *in = fdopen(infds[1], "w");
211 *out = fdopen(outfds[0], "r");
212
213 return pid;
214}
215
216int process_wait(pid_t pid, int *res, int timeout)
217{
218 int status;
219 int flags = 0;
220 if (timeout == -1)
221 timeout = 0;
222 else
223 flags |= WNOHANG;
224 int r;
225 for (r = 0; r == 0 && timeout >= 0; --timeout)
226 {
227 r = waitpid(pid, &status, flags);
228 if (r == 0 && timeout > 0)
229 process_sleep(1);
230 }
231 if (r == 0)
232 return -1;
233 if (WIFEXITED(status))
234 *res = WEXITSTATUS(status);
235 else
236 *res = -WTERMSIG(status);
237 return 0;
238}
239
240int process_kill(pid_t pid, int signal)
241{
242 return kill(pid, signal);
243}
244
245int process_sleep(unsigned int seconds)
246{
247 return sleep(seconds);
248}
249
250pid_t get_process_id()
251{
252 return getpid();
253}
254
255void ignore_sigpipe()
256{
257 signal(SIGPIPE, SIG_IGN);
258}
259
260// Local Variables:
261// mode: C++
262// fill-column: 76
263// c-file-style: "gnu"
264// indent-tabs-mode: nil
265// End:
266// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status