summaryrefslogtreecommitdiff
path: root/noncore/applets/keyhelper/keyhelperapplet/anylnk/ProcessInvoker.cpp
Unidiff
Diffstat (limited to 'noncore/applets/keyhelper/keyhelperapplet/anylnk/ProcessInvoker.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/applets/keyhelper/keyhelperapplet/anylnk/ProcessInvoker.cpp424
1 files changed, 424 insertions, 0 deletions
diff --git a/noncore/applets/keyhelper/keyhelperapplet/anylnk/ProcessInvoker.cpp b/noncore/applets/keyhelper/keyhelperapplet/anylnk/ProcessInvoker.cpp
new file mode 100644
index 0000000..09605bd
--- a/dev/null
+++ b/noncore/applets/keyhelper/keyhelperapplet/anylnk/ProcessInvoker.cpp
@@ -0,0 +1,424 @@
1#include "ProcessInvoker.h"
2
3static ProcessInvoker* g_this;
4/* ------------------------------------------------------------------------ */
5 /* static functions */
6/* ------------------------------------------------------------------------ */
7
8static Sigfunc* setSignalHandler(int signo, Sigfunc* handler)
9{
10 struct sigaction act,oact;
11
12 act.sa_handler = handler;
13 ::sigemptyset(&act.sa_mask);
14 act.sa_flags = 0;
15 #ifdefSA_RESTART
16 act.sa_flags |= SA_RESTART;
17#endif
18 if(::sigaction(signo, &act, &oact) < 0){
19 return(NULL);
20 }
21 return(oact.sa_handler);
22}
23
24static void childHandler(int /*signo*/)
25{
26 pid_t pid;
27 int status;
28 while((pid = ::waitpid(-1, &status, WNOHANG)) > 0){
29 if(pid == g_this->m_child){
30 g_this->notifyFinish(status);
31 }
32 }
33}
34
35/* ------------------------------------------------------------------------ */
36 /* ProcessInvoker Class : parent process */
37/* ------------------------------------------------------------------------ */
38ProcessInvoker::ProcessInvoker()
39{
40 g_this = this;
41 m_isRunning = false;
42 m_child = 0;
43 m_defChildHandler = SIG_DFL;
44 m_pTimer = new QTimer(this);
45 m_stdfd[0] = m_stdfd[1] = -1;
46 m_errfd[0] = m_errfd[1] = -1;
47 connect(m_pTimer, SIGNAL(timeout()),
48 this, SLOT(readOutputs()));
49}
50
51ProcessInvoker::~ProcessInvoker()
52{
53 qDebug("ProcessInvoker::~ProcessInvoker()");
54}
55
56bool ProcessInvoker::openPipe()
57{
58 if(m_stdfd[0] >= 0) closePipe(m_stdfd, 0);
59 if(m_stdfd[1] >= 0) closePipe(m_stdfd, 1);
60 if(::pipe(m_stdfd) < 0){
61 return(false);
62 }
63 if(m_errfd[0] >= 0) closePipe(m_errfd, 0);
64 if(m_errfd[1] >= 0) closePipe(m_errfd, 1);
65 if(::pipe(m_errfd) < 0){
66 closePipe(m_stdfd);
67 return(false);
68 }
69 m_maxfdp1 = m_stdfd[0];
70 if(m_errfd[0] > m_maxfdp1){
71 m_maxfdp1 = m_errfd[0];
72 }
73 m_maxfdp1++;
74 return(true);
75}
76
77void ProcessInvoker::closePipe(int fd[], int n)
78{
79 if(fd == NULL){
80 closePipe(m_stdfd, n);
81 closePipe(m_errfd, n);
82 } else {
83 if(n != 1 && fd[0] >= 0){
84 ::close(fd[0]);
85 fd[0] = -1;
86 }
87 if(n != 0 && fd[1] >= 0){
88 ::close(fd[1]);
89 fd[1] = -1;
90 }
91 }
92}
93
94void ProcessInvoker::setRunning(int pid)
95{
96 m_child = pid;
97 m_isRunning = true;
98}
99
100bool ProcessInvoker::run(const QString& args)
101{
102 //setArguments(KHUtil::parseArgs(args));
103 setArguments(StringParser::split(' ', args));
104 return(run());
105}
106
107bool ProcessInvoker::run()
108{
109 if(m_isRunning){
110 return(false);
111 }
112 m_isRunning = true;
113 if(m_arguments.isEmpty()){
114 m_isRunning = false;
115 return(false);
116 }
117 if(m_arguments[0][0] != '/'){
118 m_isRunning = false;
119 return(false);
120 }
121
122 for(QStringList::Iterator it=m_arguments.begin();
123 it!=m_arguments.end(); ++it){
124 qDebug("arguments[%s]", (*it).ascii());
125 }
126
127 /* open pipe */
128 if(openPipe() == false){
129 m_isRunning = false;
130 return(false);
131 }
132
133 /* signal handler reset */
134 m_defChildHandler = setSignalHandler(SIGCHLD, SIG_DFL);
135
136 m_child = ::fork();
137 if(m_child < 0){
138 /* fork error */
139 closePipe();
140 setSignalHandler(SIGCHLD, m_defChildHandler);
141 m_isRunning = false;
142 return(false);
143 } else if(m_child == 0){
144 /* child process */
145 qDebug("child process[%d]", ::getpid());
146 m_child = ::getpid();
147 //setSignalHandler(SIGCHLD, SIG_DFL);
148 workerProc();
149 /* no return */
150 }
151 /* close pipe(write) */
152 closePipe(NULL, 1);
153#if 0
154 m_pTimer = new QTimer(this);
155 connect(m_pTimer, SIGNAL(timeout()),
156 this, SLOT(readOutputs()));
157#endif
158 m_pTimer->start(500);
159 {
160 emit start(m_child, m_arguments);
161 QCopEnvelope e(SC_CHANNEL, "start(int,QStringList)");
162 e << m_child << m_arguments;
163 if(m_isNotify){
164 int idx = m_arguments[0].findRev('/');
165 notifyStatus(m_arguments[0].mid(idx+1), m_child);
166 }
167 }
168 int status;
169 if(::waitpid(-1, &status, WNOHANG) > 0){
170 qDebug("finish");
171 notifyFinish(status);
172 } else {
173 /* signal handler set */
174 setSignalHandler(SIGCHLD, childHandler);
175 }
176 return(true);
177}
178
179void ProcessInvoker::terminate()
180{
181 if(m_isRunning && m_child > 0){
182 terminate(m_child);
183 }
184}
185
186void ProcessInvoker::terminate(pid_t pid)
187{
188 ::kill(pid, SIGTERM);
189}
190
191void ProcessInvoker::kill()
192{
193 if(m_isRunning && m_child > 0){
194 kill(m_child);
195 }
196}
197
198void ProcessInvoker::kill(pid_t pid)
199{
200 ::kill(pid, SIGKILL);
201}
202
203#if 0
204const QStringList ProcessInvoker::parseArgs(const QString& arguments)
205{
206 QString str;
207 QStringList args;
208 char quote = 0;
209 char c;
210 for(unsigned int i=0; i<arguments.length(); i++){
211 c = arguments[i];
212 switch(c){
213 case '\"':
214 if(quote == 0){
215 quote = c;
216 } else if(quote == '\"'){
217 if(str.length() > 0){
218 args.append(str);
219 }
220 str = "";
221 quote = 0;
222 } else {
223 str += c;
224 }
225 break;
226 case '\'':
227 if(quote == 0){
228 quote = c;
229 } else if(quote == '\''){
230 if(str.length() > 0){
231 args.append(str);
232 }
233 str = "";
234 quote = 0;
235 } else {
236 str += c;
237 }
238 break;
239 case ' ':
240 if(quote == 0){
241 if(str.length() > 0){
242 args.append(str);
243 str = "";
244 }
245 } else {
246 str += c;
247 }
248 break;
249 default:
250 str += c;
251 break;
252 }
253 }
254 if(str.length() > 0){
255 args.append(str);
256 }
257 return(args);
258}
259#endif
260
261void ProcessInvoker::readOutputs()
262{
263 struct timeval tmval;
264 tmval.tv_sec = 0;
265 tmval.tv_usec = 0;
266 fd_set rset;
267
268 QByteArray stdBuf, errBuf, resBuf;
269 QDataStream stdStream(stdBuf, IO_WriteOnly);
270 QDataStream errStream(errBuf, IO_WriteOnly);
271
272 int iRet;
273 bool running;
274 char buf[PIPE_BUF+1];
275 while(true){
276 running = false;
277 FD_ZERO(&rset);
278 if(m_stdfd[0] >= 0){
279 FD_SET(m_stdfd[0], &rset);
280 running = true;
281 }
282 if(m_errfd[0] >= 0){
283 FD_SET(m_errfd[0], &rset);
284 running = true;
285 }
286 if(running == false){
287 m_pTimer->stop();
288 //delete m_pTimer;
289 break;
290 }
291
292 if((iRet = ::select(m_maxfdp1, &rset, NULL, NULL, &tmval)) <= 0){
293 qDebug("select[%d]", iRet);
294 break;
295 }
296
297 if(m_stdfd[0] >= 0 && FD_ISSET(m_stdfd[0], &rset)){
298 int n = ::read(m_stdfd[0], buf, PIPE_BUF);
299 if(n > 0){
300 stdStream.writeRawBytes(buf, n);
301 } else {
302 qDebug("stdout close");
303 closePipe(m_stdfd, 0);
304 }
305 }
306 if(m_errfd[0] >= 0 && FD_ISSET(m_errfd[0], &rset)){
307 int n = ::read(m_errfd[0], buf, PIPE_BUF);
308 if(n > 0){
309 errStream.writeRawBytes(buf, n);
310 } else {
311 qDebug("stderr close");
312 closePipe(m_errfd, 0);
313 }
314 }
315 }
316
317 if(stdBuf.size() > 0){
318 QCopEnvelope e(SC_CHANNEL, "stdout(int,QByteArray)");
319 e << m_child << stdBuf;
320 }
321 if(errBuf.size() > 0){
322 QCopEnvelope e(SC_CHANNEL, "stderr(int,QByteArray)");
323 e << m_child << errBuf;
324 }
325 if(running == false){
326 QCopEnvelope e(SC_CHANNEL, "close(int)");
327 e << m_child;
328 }
329}
330
331#if 0
332void ProcessInvoker::waitFinish()
333{
334 int status;
335 if(::waitpid(m_child, &status, 0) > 0){
336 notifyFinish(status);
337 } else {
338 notifyFinish(0, false);
339 }
340}
341#endif
342
343void ProcessInvoker::notifyFinish(int status, bool success)
344{
345 bool stopped = false;
346 QString result;
347 int code;
348 if(success){
349 if(WIFEXITED(status)){
350 code = WEXITSTATUS(status);
351 if(code == 127){
352 result = "error";
353 } else {
354 result = "exit";
355 }
356 } else if(WIFSIGNALED(status)){
357 result = "terminated";
358 code = WTERMSIG(status);
359 } else if(WIFSTOPPED(status)){
360 result = "stopped";
361 code = WSTOPSIG(status);
362 stopped = true;
363 } else {
364 /* ¤³¤ì¤Ï̵¤¤¤Ï¤º? */
365 result = "error";
366 code = -2;
367 qWarning("ProcessInvoker: unknown status");
368 }
369 } else {
370 result = "error";
371 code = -1;
372 qWarning("ProcessInvoker: wait error");
373 }
374 emit finish(result, code);
375 QCopEnvelope e(SC_CHANNEL, "finish(int,QString,int)");
376 e << m_child << result << code;
377 if(m_isNotify){
378 notifyStatus(result, code);
379 setNotify(false);
380 }
381 if(stopped == false){
382 setSignalHandler(SIGCHLD, m_defChildHandler);
383 m_isRunning = false;
384 }
385}
386
387void ProcessInvoker::notifyStatus(const QString& result, int code)
388{
389 QString message = QString::number(code);
390 message.append(":");
391 message.append(result);
392 Global::statusMessage(message);
393}
394
395/* ------------------------------------------------------------------------ */
396 /* ProcessInvoker Class : child process */
397/* ------------------------------------------------------------------------ */
398void ProcessInvoker::workerProc()
399{
400 closePipe(m_stdfd, 0);
401 closePipe(m_errfd, 0);
402 if(m_stdfd[1] != STDOUT_FILENO){
403 ::dup2(m_stdfd[1], STDOUT_FILENO);
404 closePipe(m_stdfd, 1);
405 }
406 if(m_errfd[1] != STDERR_FILENO){
407 ::dup2(m_errfd[1], STDERR_FILENO);
408 closePipe(m_errfd, 1);
409 }
410
411 QCString* arglist = new QCString[m_arguments.count()+1];
412 const char** argv = new const char*[m_arguments.count()+1];
413 unsigned int i;
414 for(i=0; i<m_arguments.count(); i++){
415 //arglist[i] = m_arguments[i].local8Bit();
416 arglist[i] = m_arguments[i];
417 argv[i] = arglist[i];
418 }
419 argv[i] = 0;
420 ::execv(argv[0], (char*const*)argv);
421 delete[] arglist;
422 delete[] argv;
423 ::_exit(127);
424}