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