summaryrefslogtreecommitdiff
authorharlekin <harlekin>2003-02-15 20:44:27 (UTC)
committer harlekin <harlekin>2003-02-15 20:44:27 (UTC)
commit10b6cb1e9262b174ec0d8dc095d9f668f2d3e094 (patch) (unidiff)
treecbf28ef004a3777fb830d4068f4dde3e90e17b56
parent0b158c94f5d5567323871e80aefe85cf96d2d1a3 (diff)
downloadopie-10b6cb1e9262b174ec0d8dc095d9f668f2d3e094.zip
opie-10b6cb1e9262b174ec0d8dc095d9f668f2d3e094.tar.gz
opie-10b6cb1e9262b174ec0d8dc095d9f668f2d3e094.tar.bz2
not needed anymore, there is oprocess
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/net/opietooth/lib/kprocctrl.cpp268
-rw-r--r--noncore/net/opietooth/lib/kprocctrl.h120
-rw-r--r--noncore/net/opietooth/lib/kprocess.cpp915
-rw-r--r--noncore/net/opietooth/lib/kprocess.h804
4 files changed, 0 insertions, 2107 deletions
diff --git a/noncore/net/opietooth/lib/kprocctrl.cpp b/noncore/net/opietooth/lib/kprocctrl.cpp
deleted file mode 100644
index 330b0ee..0000000
--- a/noncore/net/opietooth/lib/kprocctrl.cpp
+++ b/dev/null
@@ -1,268 +0,0 @@
1/* This file is part of the KDE libraries
2 Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19//
20// KPROCESSCONTROLLER -- A helper class for KProcess
21//
22// version 0.3.1, Jan, 8th 1997
23//
24// (C) Christian Czezatke
25// e9025461@student.tuwien.ac.at
26// Ported by Holger Freyther
27//
28
29//#include <config.h>
30
31#include <sys/types.h>
32#include <sys/socket.h>
33
34#include <errno.h>
35#include <fcntl.h>
36#include <stdio.h>
37#include <string.h>
38#include <unistd.h>
39#include <assert.h>
40
41#include <qsocketnotifier.h>
42#include "kprocess.h"
43#include "kprocctrl.h"
44
45KProcessController *KProcessController::theKProcessController = 0;
46
47struct sigaction KProcessController::oldChildHandlerData;
48bool KProcessController::handlerSet = false;
49
50KProcessController::KProcessController()
51{
52 assert( theKProcessController == 0 );
53
54 if (0 > pipe(fd))
55 printf(strerror(errno));
56
57 notifier = new QSocketNotifier(fd[0], QSocketNotifier::Read);
58 notifier->setEnabled(true);
59 QObject::connect(notifier, SIGNAL(activated(int)),
60 this, SLOT(slotDoHousekeeping(int)));
61 connect( &delayedChildrenCleanupTimer, SIGNAL( timeout()),
62 SLOT( delayedChildrenCleanup()));
63
64 theKProcessController = this;
65
66 setupHandlers();
67}
68
69
70void KProcessController::setupHandlers()
71{
72 if( handlerSet )
73 return;
74 struct sigaction act;
75 act.sa_handler=theSigCHLDHandler;
76 sigemptyset(&(act.sa_mask));
77 sigaddset(&(act.sa_mask), SIGCHLD);
78 // Make sure we don't block this signal. gdb tends to do that :-(
79 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0);
80
81 act.sa_flags = SA_NOCLDSTOP;
82
83 // CC: take care of SunOS which automatically restarts interrupted system
84 // calls (and thus does not have SA_RESTART)
85
86#ifdef SA_RESTART
87 act.sa_flags |= SA_RESTART;
88#endif
89
90 sigaction( SIGCHLD, &act, &oldChildHandlerData );
91
92 act.sa_handler=SIG_IGN;
93 sigemptyset(&(act.sa_mask));
94 sigaddset(&(act.sa_mask), SIGPIPE);
95 act.sa_flags = 0;
96 sigaction( SIGPIPE, &act, 0L);
97 handlerSet = true;
98}
99
100void KProcessController::resetHandlers()
101{
102 if( !handlerSet )
103 return;
104 sigaction( SIGCHLD, &oldChildHandlerData, 0 );
105 // there should be no problem with SIGPIPE staying SIG_IGN
106 handlerSet = false;
107}
108
109// block SIGCHLD handler, because it accesses processList
110void KProcessController::addKProcess( KProcess* p )
111{
112 sigset_t newset, oldset;
113 sigemptyset( &newset );
114 sigaddset( &newset, SIGCHLD );
115 sigprocmask( SIG_BLOCK, &newset, &oldset );
116 processList.append( p );
117 sigprocmask( SIG_SETMASK, &oldset, 0 );
118}
119
120void KProcessController::removeKProcess( KProcess* p )
121{
122 sigset_t newset, oldset;
123 sigemptyset( &newset );
124 sigaddset( &newset, SIGCHLD );
125 sigprocmask( SIG_BLOCK, &newset, &oldset );
126 processList.remove( p );
127 sigprocmask( SIG_SETMASK, &oldset, 0 );
128}
129
130//using a struct which contains both the pid and the status makes it easier to write
131//and read the data into the pipe
132//especially this solves a problem which appeared on my box where slotDoHouseKeeping() received
133//only 4 bytes (with some debug output around the write()'s it received all 8 bytes)
134//don't know why this happened, but when writing all 8 bytes at once it works here, aleXXX
135struct waitdata
136{
137 pid_t pid;
138 int status;
139};
140
141void KProcessController::theSigCHLDHandler(int arg)
142{
143 struct waitdata wd;
144// int status;
145// pid_t this_pid;
146 int saved_errno;
147
148 saved_errno = errno;
149 // since waitpid and write change errno, we have to save it and restore it
150 // (Richard Stevens, Advanced programming in the Unix Environment)
151
152 bool found = false;
153 if( theKProcessController != 0 ) {
154 // iterating the list doesn't perform any system call
155 for( QValueList<KProcess*>::ConstIterator it = theKProcessController->processList.begin();
156 it != theKProcessController->processList.end();
157 ++it )
158 {
159 if( !(*it)->isRunning())
160 continue;
161 wd.pid = waitpid( (*it)->pid(), &wd.status, WNOHANG );
162 if ( wd.pid > 0 ) {
163 ::write(theKProcessController->fd[1], &wd, sizeof(wd));
164 found = true;
165 }
166 }
167 }
168 if( !found && oldChildHandlerData.sa_handler != SIG_IGN
169 && oldChildHandlerData.sa_handler != SIG_DFL )
170 oldChildHandlerData.sa_handler( arg ); // call the old handler
171 // handle the rest
172 if( theKProcessController != 0 ) {
173 static const struct waitdata dwd = { 0, 0 }; // delayed waitpid()
174 ::write(theKProcessController->fd[1], &dwd, sizeof(dwd));
175 } else {
176 int dummy;
177 while( waitpid( -1, &dummy, WNOHANG ) > 0 )
178 ;
179 }
180
181 errno = saved_errno;
182}
183
184
185
186void KProcessController::slotDoHousekeeping(int )
187{
188 unsigned int bytes_read = 0;
189 unsigned int errcnt=0;
190 // read pid and status from the pipe.
191 struct waitdata wd;
192 while ((bytes_read < sizeof(wd)) && (errcnt < 50)) {
193 int r = ::read(fd[0], ((char *)&wd) + bytes_read, sizeof(wd) - bytes_read);
194 if (r > 0) bytes_read += r;
195 else if (r < 0) errcnt++;
196 }
197 if (errcnt >= 50) {
198 fprintf(stderr,
199 "Error: Max. error count for pipe read "
200 "exceeded in KProcessController::slotDoHousekeeping\n");
201 return; // it makes no sense to continue here!
202 }
203 if (bytes_read != sizeof(wd)) {
204 fprintf(stderr,
205 "Error: Could not read info from signal handler %d <> %d!\n",
206 bytes_read, sizeof(wd));
207 return; // it makes no sense to continue here!
208 }
209 if (wd.pid==0) { // special case, see delayedChildrenCleanup()
210 delayedChildrenCleanupTimer.start( 1000, true );
211 return;
212 }
213
214 for( QValueList<KProcess*>::ConstIterator it = processList.begin();
215 it != processList.end();
216 ++it ) {
217 KProcess* proc = *it;
218 if (proc->pid() == wd.pid) {
219 // process has exited, so do emit the respective events
220 if (proc->run_mode == KProcess::Block) {
221 // If the reads are done blocking then set the status in proc
222 // but do nothing else because KProcess will perform the other
223 // actions of processHasExited.
224 proc->status = wd.status;
225 proc->runs = false;
226 } else {
227 proc->processHasExited(wd.status);
228 }
229 return;
230 }
231 }
232}
233
234// this is needed e.g. for popen(), which calls waitpid() checking
235// for its forked child, if we did waitpid() directly in the SIGCHLD
236// handler, popen()'s waitpid() call would fail
237void KProcessController::delayedChildrenCleanup()
238{
239 struct waitdata wd;
240 while(( wd.pid = waitpid( -1, &wd.status, WNOHANG ) ) > 0 ) {
241 for( QValueList<KProcess*>::ConstIterator it = processList.begin();
242 it != processList.end();
243 ++it )
244 {
245 if( !(*it)->isRunning() || (*it)->pid() != wd.pid )
246 continue;
247 // it's KProcess, handle it
248 ::write(fd[1], &wd, sizeof(wd));
249 break;
250 }
251 }
252}
253
254KProcessController::~KProcessController()
255{
256 assert( theKProcessController == this );
257 resetHandlers();
258
259 notifier->setEnabled(false);
260
261 close(fd[0]);
262 close(fd[1]);
263
264 delete notifier;
265 theKProcessController = 0;
266}
267
268//#include "kprocctrl.moc"
diff --git a/noncore/net/opietooth/lib/kprocctrl.h b/noncore/net/opietooth/lib/kprocctrl.h
deleted file mode 100644
index ac82b9d..0000000
--- a/noncore/net/opietooth/lib/kprocctrl.h
+++ b/dev/null
@@ -1,120 +0,0 @@
1/* This file is part of the KDE libraries
2 Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19//
20// KPROCESSCONTROLLER -- A helper class for KProcess
21//
22// version 0.3.1, Jan 8th 1997
23//
24// (C) Christian Czezatke
25// e9025461@student.tuwien.ac.at
26//
27
28#ifndef __KPROCCTRL_H__
29#define __KPROCCTRL_H__
30
31#include <qvaluelist.h>
32#include <qtimer.h>
33
34#include "kprocess.h"
35
36class KProcessControllerPrivate;
37class QSocketNotifier;
38
39/**
40 * @short Used internally by @ref KProcess
41 * @internal
42 * @author Christian Czezakte <e9025461@student.tuwien.ac.at>
43 *
44 * A class for internal use by KProcess only. -- Exactly one instance
45 * of this class is generated by the first instance of KProcess that is
46 * created (a pointer to it gets stored in @ref theKProcessController ).
47 *
48 * This class takes care of the actual (UN*X) signal handling.
49*/
50class KProcessController : public QObject
51{
52 Q_OBJECT
53
54public:
55 KProcessController();
56 ~KProcessController();
57 //CC: WARNING! Destructor Not virtual (but you don't derive classes from this anyhow...)
58
59public:
60
61 /**
62 * Only a single instance of this class is allowed at a time,
63 * and this static variable is used to track the one instance.
64 */
65 static KProcessController *theKProcessController;
66
67 /**
68 * Automatically called upon SIGCHLD.
69 *
70 * Normally you do not need to do anything with this function but
71 * if your application needs to disable SIGCHLD for some time for
72 * reasons beyond your control, you should call this function afterwards
73 * to make sure that no SIGCHLDs where missed.
74 */
75 static void theSigCHLDHandler(int signal);
76 // handler for sigchld
77
78 /**
79 * @internal
80 */
81 static void setupHandlers();
82 /**
83 * @internal
84 */
85 static void resetHandlers();
86 /**
87 * @internal
88 */
89 void addKProcess( KProcess* );
90 /**
91 * @internal
92 */
93 void removeKProcess( KProcess* );
94 public slots:
95 /**
96 * @internal
97 */
98 void slotDoHousekeeping(int socket);
99
100 private slots:
101 void delayedChildrenCleanup();
102private:
103 int fd[2];
104 QSocketNotifier *notifier;
105 static struct sigaction oldChildHandlerData;
106 static bool handlerSet;
107 QValueList<KProcess*> processList;
108 QTimer delayedChildrenCleanupTimer;
109
110 // Disallow assignment and copy-construction
111 KProcessController( const KProcessController& );
112 KProcessController& operator= ( const KProcessController& );
113
114 KProcessControllerPrivate *d;
115};
116
117
118
119#endif
120
diff --git a/noncore/net/opietooth/lib/kprocess.cpp b/noncore/net/opietooth/lib/kprocess.cpp
deleted file mode 100644
index ce7ed3e..0000000
--- a/noncore/net/opietooth/lib/kprocess.cpp
+++ b/dev/null
@@ -1,915 +0,0 @@
1/*
2
3 $Id$
4
5 This file is part of the KDE libraries
6 Copyright (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at)
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.
22*/
23
24
25//
26// KPROCESS -- A class for handling child processes in KDE without
27// having to take care of Un*x specific implementation details
28//
29// version 0.3.1, Jan 8th 1998
30//
31// (C) Christian Czezatke
32// e9025461@student.tuwien.ac.at
33//
34// Changes:
35//
36// March 2nd, 1998: Changed parameter list for KShellProcess:
37// Arguments are now placed in a single string so that
38// <shell> -c <commandstring> is passed to the shell
39// to make the use of "operator<<" consistent with KProcess
40
41#include "kprocess.h"
42#define _MAY_INCLUDE_KPROCESSCONTROLLER_
43#include "kprocctrl.h"
44
45//#include <config.h>
46
47#include <qfile.h>
48#include <qsocketnotifier.h>
49#include <qregexp.h>
50
51#include <sys/time.h>
52#include <sys/types.h>
53#include <sys/stat.h>
54#include <sys/socket.h>
55
56#include <errno.h>
57#include <fcntl.h>
58#include <stdlib.h>
59#include <signal.h>
60#include <stdio.h>
61#include <string.h>
62#include <unistd.h>
63#ifdef HAVE_SYS_SELECT_H
64#include <sys/select.h>
65#endif
66#ifdef HAVE_INITGROUPS
67#include <grp.h>
68#endif
69#include <pwd.h>
70
71#include <qapplication.h>
72#include <qmap.h>
73//#include <kdebug.h>
74
75/////////////////////////////
76// public member functions //
77/////////////////////////////
78
79class KProcessPrivate {
80public:
81 KProcessPrivate() : useShell(false) { }
82
83 bool useShell;
84 QMap<QString,QString> env;
85 QString wd;
86 QCString shell;
87};
88
89
90KProcess::KProcess()
91 : QObject(),
92 run_mode(NotifyOnExit),
93 runs(false),
94 pid_(0),
95 status(0),
96 keepPrivs(false),
97 innot(0),
98 outnot(0),
99 errnot(0),
100 communication(NoCommunication),
101 input_data(0),
102 input_sent(0),
103 input_total(0),
104 d(0)
105{
106 if (0 == KProcessController::theKProcessController) {
107 (void) new KProcessController();
108 CHECK_PTR(KProcessController::theKProcessController);
109 }
110
111 KProcessController::theKProcessController->addKProcess(this);
112 out[0] = out[1] = -1;
113 in[0] = in[1] = -1;
114 err[0] = err[1] = -1;
115}
116
117void
118KProcess::setEnvironment(const QString &name, const QString &value)
119{
120 if (!d)
121 d = new KProcessPrivate;
122 d->env.insert(name, value);
123}
124
125void
126KProcess::setWorkingDirectory(const QString &dir)
127{
128 if (!d)
129 d = new KProcessPrivate;
130 d->wd = dir;
131}
132
133void
134KProcess::setupEnvironment()
135{
136 if (d)
137 {
138 QMap<QString,QString>::Iterator it;
139 for(it = d->env.begin(); it != d->env.end(); ++it)
140 setenv(QFile::encodeName(it.key()).data(),
141 QFile::encodeName(it.data()).data(), 1);
142 if (!d->wd.isEmpty())
143 chdir(QFile::encodeName(d->wd).data());
144 }
145}
146
147void
148KProcess::setRunPrivileged(bool keepPrivileges)
149{
150 keepPrivs = keepPrivileges;
151}
152
153bool
154KProcess::runPrivileged() const
155{
156 return keepPrivs;
157}
158
159
160KProcess::~KProcess()
161{
162 // destroying the KProcess instance sends a SIGKILL to the
163 // child process (if it is running) after removing it from the
164 // list of valid processes (if the process is not started as
165 // "DontCare")
166
167 KProcessController::theKProcessController->removeKProcess(this);
168 // this must happen before we kill the child
169 // TODO: block the signal while removing the current process from the process list
170
171 if (runs && (run_mode != DontCare))
172 kill(SIGKILL);
173
174 // Clean up open fd's and socket notifiers.
175 closeStdin();
176 closeStdout();
177 closeStderr();
178
179 // TODO: restore SIGCHLD and SIGPIPE handler if this is the last KProcess
180 delete d;
181}
182
183void KProcess::detach()
184{
185 KProcessController::theKProcessController->removeKProcess(this);
186
187 runs = false;
188 pid_ = 0;
189
190 // Clean up open fd's and socket notifiers.
191 closeStdin();
192 closeStdout();
193 closeStderr();
194}
195
196bool KProcess::setExecutable(const QString& proc)
197{
198 if (runs) return false;
199
200 if (proc.isEmpty()) return false;
201
202 if (!arguments.isEmpty())
203 arguments.remove(arguments.begin());
204 arguments.prepend(QFile::encodeName(proc));
205
206 return true;
207}
208
209KProcess &KProcess::operator<<(const QStringList& args)
210{
211 QStringList::ConstIterator it = args.begin();
212 for ( ; it != args.end() ; ++it )
213 arguments.append(QFile::encodeName(*it));
214 return *this;
215}
216
217KProcess &KProcess::operator<<(const QCString& arg)
218{
219 return operator<< (arg.data());
220}
221
222KProcess &KProcess::operator<<(const char* arg)
223{
224 arguments.append(arg);
225 return *this;
226}
227
228KProcess &KProcess::operator<<(const QString& arg)
229{
230 arguments.append(QFile::encodeName(arg));
231 return *this;
232}
233
234void KProcess::clearArguments()
235{
236 arguments.clear();
237}
238
239bool KProcess::start(RunMode runmode, Communication comm)
240{
241 uint i;
242 uint n = arguments.count();
243 char **arglist;
244
245 if (runs || (0 == n)) {
246 return false; // cannot start a process that is already running
247 // or if no executable has been assigned
248 }
249 run_mode = runmode;
250 status = 0;
251
252 QCString shellCmd;
253 if (d && d->useShell)
254 {
255 if (d->shell.isEmpty())
256 {
257 qWarning( "Could not find a valid shell" );
258 return false;
259 }
260
261 arglist = static_cast<char **>(malloc( (4)*sizeof(char *)));
262 for (i=0; i < n; i++) {
263 shellCmd += arguments[i];
264 shellCmd += " "; // CC: to separate the arguments
265 }
266
267 arglist[0] = d->shell.data();
268 arglist[1] = (char *) "-c";
269 arglist[2] = shellCmd.data();
270 arglist[3] = 0;
271 }
272 else
273 {
274 arglist = static_cast<char **>(malloc( (n+1)*sizeof(char *)));
275 for (i=0; i < n; i++)
276 arglist[i] = arguments[i].data();
277 arglist[n]= 0;
278 }
279
280 if (!setupCommunication(comm))
281 qWarning( "Could not setup Communication!");
282
283 // We do this in the parent because if we do it in the child process
284 // gdb gets confused when the application runs from gdb.
285 uid_t uid = getuid();
286 gid_t gid = getgid();
287#ifdef HAVE_INITGROUPS
288 struct passwd *pw = getpwuid(uid);
289#endif
290
291 int fd[2];
292 if (0 > pipe(fd))
293 {
294 fd[0] = fd[1] = 0; // Pipe failed.. continue
295 }
296
297 runs = true;
298
299 QApplication::flushX();
300
301 // WABA: Note that we use fork() and not vfork() because
302 // vfork() has unclear semantics and is not standardized.
303 pid_ = fork();
304
305 if (0 == pid_) {
306 if (fd[0])
307 close(fd[0]);
308 if (!runPrivileged())
309 {
310 setgid(gid);
311#if defined( HAVE_INITGROUPS)
312 if(pw)
313 initgroups(pw->pw_name, pw->pw_gid);
314#endif
315 setuid(uid);
316 }
317 // The child process
318 if(!commSetupDoneC())
319 qWarning( "Could not finish comm setup in child!" );
320
321 setupEnvironment();
322
323 // Matthias
324 if (run_mode == DontCare)
325 setpgid(0,0);
326 // restore default SIGPIPE handler (Harri)
327 struct sigaction act;
328 sigemptyset(&(act.sa_mask));
329 sigaddset(&(act.sa_mask), SIGPIPE);
330 act.sa_handler = SIG_DFL;
331 act.sa_flags = 0;
332 sigaction(SIGPIPE, &act, 0L);
333
334 // We set the close on exec flag.
335 // Closing of fd[1] indicates that the execvp succeeded!
336 if (fd[1])
337 fcntl(fd[1], F_SETFD, FD_CLOEXEC);
338 execvp(arglist[0], arglist);
339 char resultByte = 1;
340 if (fd[1])
341 write(fd[1], &resultByte, 1);
342 _exit(-1);
343 } else if (-1 == pid_) {
344 // forking failed
345
346 runs = false;
347 free(arglist);
348 return false;
349 } else {
350 if (fd[1])
351 close(fd[1]);
352 // the parent continues here
353
354 // Discard any data for stdin that might still be there
355 input_data = 0;
356
357 // Check whether client could be started.
358 if (fd[0]) for(;;)
359 {
360 char resultByte;
361 int n = ::read(fd[0], &resultByte, 1);
362 if (n == 1)
363 {
364 // Error
365 runs = false;
366 close(fd[0]);
367 free(arglist);
368 pid_ = 0;
369 return false;
370 }
371 if (n == -1)
372 {
373 if ((errno == ECHILD) || (errno == EINTR))
374 continue; // Ignore
375 }
376 break; // success
377 }
378 if (fd[0])
379 close(fd[0]);
380
381 if (!commSetupDoneP()) // finish communication socket setup for the parent
382 qWarning( "Could not finish comm setup in parent!" );
383
384 if (run_mode == Block) {
385 commClose();
386
387 // The SIGCHLD handler of the process controller will catch
388 // the exit and set the status
389 while(runs)
390 {
391 KProcessController::theKProcessController->
392 slotDoHousekeeping(0);
393 }
394 runs = FALSE;
395 emit processExited(this);
396 }
397 }
398 free(arglist);
399 return true;
400}
401
402
403
404bool KProcess::kill(int signo)
405{
406 bool rv=false;
407
408 if (0 != pid_)
409 rv= (-1 != ::kill(pid_, signo));
410 // probably store errno somewhere...
411 return rv;
412}
413
414
415
416bool KProcess::isRunning() const
417{
418 return runs;
419}
420
421
422
423pid_t KProcess::pid() const
424{
425 return pid_;
426}
427
428
429
430bool KProcess::normalExit() const
431{
432 int _status = status;
433 return (pid_ != 0) && (!runs) && (WIFEXITED((_status)));
434}
435
436
437
438int KProcess::exitStatus() const
439{
440 int _status = status;
441 return WEXITSTATUS((_status));
442}
443
444
445
446bool KProcess::writeStdin(const char *buffer, int buflen)
447{
448 bool rv;
449
450 // if there is still data pending, writing new data
451 // to stdout is not allowed (since it could also confuse
452 // kprocess...
453 if (0 != input_data)
454 return false;
455
456 if (runs && (communication & Stdin)) {
457 input_data = buffer;
458 input_sent = 0;
459 input_total = buflen;
460 slotSendData(0);
461 innot->setEnabled(true);
462 rv = true;
463 } else
464 rv = false;
465 return rv;
466}
467
468void KProcess::suspend()
469{
470 if ((communication & Stdout) && outnot)
471 outnot->setEnabled(false);
472}
473
474void KProcess::resume()
475{
476 if ((communication & Stdout) && outnot)
477 outnot->setEnabled(true);
478}
479
480bool KProcess::closeStdin()
481{
482 bool rv;
483
484 if (communication & Stdin) {
485 communication = (Communication) (communication & ~Stdin);
486 delete innot;
487 innot = 0;
488 close(in[1]);
489 rv = true;
490 } else
491 rv = false;
492 return rv;
493}
494
495bool KProcess::closeStdout()
496{
497 bool rv;
498
499 if (communication & Stdout) {
500 communication = (Communication) (communication & ~Stdout);
501 delete outnot;
502 outnot = 0;
503 close(out[0]);
504 rv = true;
505 } else
506 rv = false;
507 return rv;
508}
509
510bool KProcess::closeStderr()
511{
512 bool rv;
513
514 if (communication & Stderr) {
515 communication = static_cast<Communication>(communication & ~Stderr);
516 delete errnot;
517 errnot = 0;
518 close(err[0]);
519 rv = true;
520 } else
521 rv = false;
522 return rv;
523}
524
525
526/////////////////////////////
527// protected slots //
528/////////////////////////////
529
530
531
532void KProcess::slotChildOutput(int fdno)
533{
534 if (!childOutput(fdno))
535 closeStdout();
536}
537
538
539void KProcess::slotChildError(int fdno)
540{
541 if (!childError(fdno))
542 closeStderr();
543}
544
545
546void KProcess::slotSendData(int)
547{
548 if (input_sent == input_total) {
549 innot->setEnabled(false);
550 input_data = 0;
551 emit wroteStdin(this);
552 } else
553 input_sent += ::write(in[1], input_data+input_sent, input_total-input_sent);
554}
555
556
557
558//////////////////////////////
559// private member functions //
560//////////////////////////////
561
562
563
564void KProcess::processHasExited(int state)
565{
566 if (runs)
567 {
568 runs = false;
569 status = state;
570
571 commClose(); // cleanup communication sockets
572
573 // also emit a signal if the process was run Blocking
574 if (DontCare != run_mode)
575 {
576 emit processExited(this);
577 }
578 }
579}
580
581
582
583int KProcess::childOutput(int fdno)
584{
585 if (communication & NoRead) {
586 int len = -1;
587 emit receivedStdout(fdno, len);
588 errno = 0; // Make sure errno doesn't read "EAGAIN"
589 return len;
590 }
591 else
592 {
593 char buffer[1024];
594 int len;
595
596 len = ::read(fdno, buffer, 1024);
597
598 if ( 0 < len) {
599 emit receivedStdout(this, buffer, len);
600 }
601 return len;
602 }
603}
604
605
606
607int KProcess::childError(int fdno)
608{
609 char buffer[1024];
610 int len;
611
612 len = ::read(fdno, buffer, 1024);
613
614 if ( 0 < len)
615 emit receivedStderr(this, buffer, len);
616 return len;
617}
618
619
620
621int KProcess::setupCommunication(Communication comm)
622{
623 int ok;
624
625 communication = comm;
626
627 ok = 1;
628 if (comm & Stdin)
629 ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, in) >= 0;
630
631 if (comm & Stdout)
632 ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, out) >= 0;
633
634 if (comm & Stderr)
635 ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, err) >= 0;
636
637 return ok;
638}
639
640
641
642int KProcess::commSetupDoneP()
643{
644 int ok = 1;
645
646 if (communication != NoCommunication) {
647 if (communication & Stdin)
648 close(in[0]);
649 if (communication & Stdout)
650 close(out[1]);
651 if (communication & Stderr)
652 close(err[1]);
653
654 // Don't create socket notifiers and set the sockets non-blocking if
655 // blocking is requested.
656 if (run_mode == Block) return ok;
657
658 if (communication & Stdin) {
659// ok &= (-1 != fcntl(in[1], F_SETFL, O_NONBLOCK));
660 innot = new QSocketNotifier(in[1], QSocketNotifier::Write, this);
661 CHECK_PTR(innot);
662 innot->setEnabled(false); // will be enabled when data has to be sent
663 QObject::connect(innot, SIGNAL(activated(int)),
664 this, SLOT(slotSendData(int)));
665 }
666
667 if (communication & Stdout) {
668// ok &= (-1 != fcntl(out[0], F_SETFL, O_NONBLOCK));
669 outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this);
670 CHECK_PTR(outnot);
671 QObject::connect(outnot, SIGNAL(activated(int)),
672 this, SLOT(slotChildOutput(int)));
673 if (communication & NoRead)
674 suspend();
675 }
676
677 if (communication & Stderr) {
678// ok &= (-1 != fcntl(err[0], F_SETFL, O_NONBLOCK));
679 errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this );
680 CHECK_PTR(errnot);
681 QObject::connect(errnot, SIGNAL(activated(int)),
682 this, SLOT(slotChildError(int)));
683 }
684 }
685 return ok;
686}
687
688
689
690int KProcess::commSetupDoneC()
691{
692 int ok = 1;
693 struct linger so;
694 memset(&so, 0, sizeof(so));
695
696 if (communication & Stdin)
697 close(in[1]);
698 if (communication & Stdout)
699 close(out[0]);
700 if (communication & Stderr)
701 close(err[0]);
702
703 if (communication & Stdin)
704 ok &= dup2(in[0], STDIN_FILENO) != -1;
705 else {
706 int null_fd = open( "/dev/null", O_RDONLY );
707 ok &= dup2( null_fd, STDIN_FILENO ) != -1;
708 close( null_fd );
709 }
710 if (communication & Stdout) {
711 ok &= dup2(out[1], STDOUT_FILENO) != -1;
712 ok &= !setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char*)&so, sizeof(so));
713 }
714 else {
715 int null_fd = open( "/dev/null", O_WRONLY );
716 ok &= dup2( null_fd, STDOUT_FILENO ) != -1;
717 close( null_fd );
718 }
719 if (communication & Stderr) {
720 ok &= dup2(err[1], STDERR_FILENO) != -1;
721 ok &= !setsockopt(err[1], SOL_SOCKET, SO_LINGER, reinterpret_cast<char *>(&so), sizeof(so));
722 }
723 else {
724 int null_fd = open( "/dev/null", O_WRONLY );
725 ok &= dup2( null_fd, STDERR_FILENO ) != -1;
726 close( null_fd );
727 }
728 return ok;
729}
730
731
732
733void KProcess::commClose()
734{
735 if (NoCommunication != communication) {
736 bool b_in = (communication & Stdin);
737 bool b_out = (communication & Stdout);
738 bool b_err = (communication & Stderr);
739 if (b_in)
740 delete innot;
741
742 if (b_out || b_err) {
743 // If both channels are being read we need to make sure that one socket buffer
744 // doesn't fill up whilst we are waiting for data on the other (causing a deadlock).
745 // Hence we need to use select.
746
747 // Once one or other of the channels has reached EOF (or given an error) go back
748 // to the usual mechanism.
749
750 int fds_ready = 1;
751 fd_set rfds;
752
753 int max_fd = 0;
754 if (b_out) {
755 fcntl(out[0], F_SETFL, O_NONBLOCK);
756 if (out[0] > max_fd)
757 max_fd = out[0];
758 delete outnot;
759 outnot = 0;
760 }
761 if (b_err) {
762 fcntl(err[0], F_SETFL, O_NONBLOCK);
763 if (err[0] > max_fd)
764 max_fd = err[0];
765 delete errnot;
766 errnot = 0;
767 }
768
769
770 while (b_out || b_err) {
771 // * If the process is still running we block until we
772 // receive data. (p_timeout = 0, no timeout)
773 // * If the process has already exited, we only check
774 // the available data, we don't wait for more.
775 // (p_timeout = &timeout, timeout immediately)
776 struct timeval timeout;
777 timeout.tv_sec = 0;
778 timeout.tv_usec = 0;
779 struct timeval *p_timeout = runs ? 0 : &timeout;
780
781 FD_ZERO(&rfds);
782 if (b_out)
783 FD_SET(out[0], &rfds);
784
785 if (b_err)
786 FD_SET(err[0], &rfds);
787
788 fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
789 if (fds_ready <= 0) break;
790
791 if (b_out && FD_ISSET(out[0], &rfds)) {
792 int ret = 1;
793 while (ret > 0) ret = childOutput(out[0]);
794 if ((ret == -1 && errno != EAGAIN) || ret == 0)
795 b_out = false;
796 }
797
798 if (b_err && FD_ISSET(err[0], &rfds)) {
799 int ret = 1;
800 while (ret > 0) ret = childError(err[0]);
801 if ((ret == -1 && errno != EAGAIN) || ret == 0)
802 b_err = false;
803 }
804 }
805 }
806
807 if (b_in) {
808 communication = (Communication) (communication & ~Stdin);
809 close(in[1]);
810 }
811 if (b_out) {
812 communication = (Communication) (communication & ~Stdout);
813 close(out[0]);
814 }
815 if (b_err) {
816 communication = (Communication) (communication & ~Stderr);
817 close(err[0]);
818 }
819 }
820}
821
822void KProcess::setUseShell(bool useShell, const char *shell)
823{
824 if (!d)
825 d = new KProcessPrivate;
826 d->useShell = useShell;
827 d->shell = shell;
828 if (d->shell.isEmpty())
829 d->shell = searchShell();
830}
831
832QString KProcess::quote(const QString &arg)
833{
834 QString res = arg;
835 res.replace(QRegExp(QString::fromLatin1("\'")),
836 QString::fromLatin1("'\"'\"'"));
837 res.prepend('\'');
838 res.append('\'');
839 return res;
840}
841
842QCString KProcess::searchShell()
843{
844 QCString tmpShell = QCString(getenv("SHELL")).stripWhiteSpace();
845 if (!isExecutable(tmpShell))
846 {
847 tmpShell = "/bin/sh";
848 }
849
850 return tmpShell;
851}
852
853bool KProcess::isExecutable(const QCString &filename)
854{
855 struct stat fileinfo;
856
857 if (filename.isEmpty()) return false;
858
859 // CC: we've got a valid filename, now let's see whether we can execute that file
860
861 if (-1 == stat(filename.data(), &fileinfo)) return false;
862 // CC: return false if the file does not exist
863
864 // CC: anyway, we cannot execute directories, block/character devices, fifos or sockets
865 if ( (S_ISDIR(fileinfo.st_mode)) ||
866 (S_ISCHR(fileinfo.st_mode)) ||
867 (S_ISBLK(fileinfo.st_mode)) ||
868#ifdef S_ISSOCK
869 // CC: SYSVR4 systems don't have that macro
870 (S_ISSOCK(fileinfo.st_mode)) ||
871#endif
872 (S_ISFIFO(fileinfo.st_mode)) ||
873 (S_ISDIR(fileinfo.st_mode)) ) {
874 return false;
875 }
876
877 // CC: now check for permission to execute the file
878 if (access(filename.data(), X_OK) != 0) return false;
879
880 // CC: we've passed all the tests...
881 return true;
882}
883
884void KProcess::virtual_hook( int, void* )
885{ /*BASE::virtual_hook( id, data );*/ }
886
887
888///////////////////////////
889// CC: Class KShellProcess
890///////////////////////////
891
892KShellProcess::KShellProcess(const char *shellname):
893 KProcess()
894{
895 setUseShell(true, shellname);
896}
897
898
899KShellProcess::~KShellProcess() {
900}
901
902QString KShellProcess::quote(const QString &arg)
903{
904 return KProcess::quote(arg);
905}
906
907bool KShellProcess::start(RunMode runmode, Communication comm)
908{
909 return KProcess::start(runmode, comm);
910}
911
912void KShellProcess::virtual_hook( int id, void* data )
913{ KProcess::virtual_hook( id, data ); }
914
915//#include "kprocess.moc"
diff --git a/noncore/net/opietooth/lib/kprocess.h b/noncore/net/opietooth/lib/kprocess.h
deleted file mode 100644
index e70f7e7..0000000
--- a/noncore/net/opietooth/lib/kprocess.h
+++ b/dev/null
@@ -1,804 +0,0 @@
1/* This file is part of the KDE libraries
2 Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19//
20// KPROCESS -- A class for handling child processes in KDE without
21// having to take care of Un*x specific implementation details
22//
23// version 0.3.1, Jan 8th 1998
24//
25// (C) Christian Czezatke
26// e9025461@student.tuwien.ac.at
27//
28
29#ifndef __kprocess_h__
30#define __kprocess_h__
31
32#include <sys/types.h> // for pid_t
33#include <sys/wait.h>
34#include <signal.h>
35#include <unistd.h>
36#include <qvaluelist.h>
37#include <qcstring.h>
38#include <qobject.h>
39
40class QSocketNotifier;
41class KProcessPrivate;
42
43/**
44 * Child process invocation, monitoring and control.
45 *
46 * @sect General usage and features
47 *
48 *This class allows a KDE application to start child processes without having
49 *to worry about UN*X signal handling issues and zombie process reaping.
50 *
51 *@see KProcIO
52 *
53 *Basically, this class distinguishes three different ways of running
54 *child processes:
55 *
56 *@li KProcess::DontCare -- The child process is invoked and both the child
57 *process and the parent process continue concurrently.
58 *
59 *Starting a DontCare child process means that the application is
60 *not interested in any notification to determine whether the
61 *child process has already exited or not.
62 *
63 *@li KProcess::NotifyOnExit -- The child process is invoked and both the
64 *child and the parent process run concurrently.
65 *
66 *When the child process exits, the KProcess instance
67 *corresponding to it emits the Qt signal @ref processExited().
68 *
69 *Since this signal is @em not emitted from within a UN*X
70 *signal handler, arbitrary function calls can be made.
71 *
72 *Be aware: When the KProcess objects gets destructed, the child
73 *process will be killed if it is still running!
74 *This means in particular, that you cannot use a KProcess on the stack
75 *with KProcess::NotifyOnExit.
76 *
77 *@li KProcess::Block -- The child process starts and the parent process
78 *is suspended until the child process exits. (@em Really not recommended
79 *for programs with a GUI.)
80 *
81 *KProcess also provides several functions for determining the exit status
82 *and the pid of the child process it represents.
83 *
84 *Furthermore it is possible to supply command-line arguments to the process
85 *in a clean fashion (no null -- terminated stringlists and such...)
86 *
87 *A small usage example:
88 *<pre>
89 *KProcess *proc = new KProcess;
90 *
91 **proc << "my_executable";
92 **proc << "These" << "are" << "the" << "command" << "line" << "args";
93 *QApplication::connect(proc, SIGNAL(processExited(KProcess *)),
94 * pointer_to_my_object, SLOT(my_objects_slot(KProcess *)));
95 *proc->start();
96 *</pre>
97 *
98 *This will start "my_executable" with the commandline arguments "These"...
99 *
100 *When the child process exits, the respective Qt signal will be emitted.
101 *
102 *@sect Communication with the child process
103 *
104 *KProcess supports communication with the child process through
105 *stdin/stdout/stderr.
106 *
107 *The following functions are provided for getting data from the child
108 *process or sending data to the child's stdin (For more information,
109 *have a look at the documentation of each function):
110 *
111 *@li bool @ref writeStdin(char *buffer, int buflen);
112 *@li -- Transmit data to the child process's stdin.
113 *
114 *@li bool @ref closeStdin();
115 *@li -- Closes the child process's stdin (which causes it to see an feof(stdin)).
116 *Returns false if you try to close stdin for a process that has been started
117 *without a communication channel to stdin.
118 *
119 *@li bool @ref closeStdout();
120 *@li -- Closes the child process's stdout.
121 *Returns false if you try to close stdout for a process that has been started
122 *without a communication channel to stdout.
123 *
124 *@li bool @ref closeStderr();
125 *@li -- Closes the child process's stderr.
126 *Returns false if you try to close stderr for a process that has been started
127 *without a communication channel to stderr.
128 *
129 *
130 *@sect QT signals:
131 *
132 *@li void @ref receivedStdout(KProcess *proc, char *buffer, int buflen);
133 *@li void @ref receivedStderr(KProcess *proc, char *buffer, int buflen);
134 *@li -- Indicates that new data has arrived from either the
135 *child process's stdout or stderr.
136 *
137 *@li void @ref wroteStdin(KProcess *proc);
138 *@li -- Indicates that all data that has been sent to the child process
139 *by a prior call to @ref writeStdin() has actually been transmitted to the
140 *client .
141 *
142 *@author Christian Czezakte e9025461@student.tuwien.ac.at
143 *
144 *
145 **/
146class KProcess : public QObject
147{
148 Q_OBJECT
149
150public:
151
152 /**
153 * Modes in which the communication channel can be opened.
154 *
155 * If communication for more than one channel is required,
156 * the values have to be or'ed together, for example to get
157 * communication with stdout as well as with stdin, you would
158 * specify @p Stdin @p | @p Stdout
159 *
160 * If @p NoRead is specified in conjunction with @p Stdout,
161 * no data is actually read from @p Stdout but only
162 * the signal @ref childOutput(int fd) is emitted.
163 */
164 enum Communication { NoCommunication = 0, Stdin = 1, Stdout = 2, Stderr = 4,
165 AllOutput = 6, All = 7,
166 NoRead };
167
168 /**
169 * Run-modes for a child process.
170 */
171 enum RunMode {
172 /**
173 * The application does not receive notifications from the subprocess when
174 * it is finished or aborted.
175 */
176 DontCare,
177 /**
178 * The application is notified when the subprocess dies.
179 */
180 NotifyOnExit,
181 /**
182 * The application is suspended until the started process is finished.
183 */
184 Block };
185
186 /**
187 * Constructor
188 */
189 KProcess();
190
191 /**
192 *Destructor:
193 *
194 * If the process is running when the destructor for this class
195 * is called, the child process is killed with a SIGKILL, but
196 * only if the run mode is not of type @p DontCare.
197 * Processes started as @p DontCare keep running anyway.
198 */
199 virtual ~KProcess();
200
201 /**
202 @deprecated
203
204 The use of this function is now deprecated. -- Please use the
205 "operator<<" instead of "setExecutable".
206
207 Sets the executable to be started with this KProcess object.
208 Returns false if the process is currently running (in that
209 case the executable remains unchanged.)
210
211 @see operator<<
212
213 */
214 bool setExecutable(const QString& proc);
215
216
217 /**
218 * Sets the executable and the command line argument list for this process.
219 *
220 * For example, doing an "ls -l /usr/local/bin" can be achieved by:
221 * <pre>
222 * KProcess p;
223 * ...
224 * p << "ls" << "-l" << "/usr/local/bin"
225 * </pre>
226 *
227 **/
228 KProcess &operator<<(const QString& arg);
229 /**
230 * Similar to previous method, takes a char *, supposed to be in locale 8 bit already.
231 */
232 KProcess &operator<<(const char * arg);
233 /**
234 * Similar to previous method, takes a QCString, supposed to be in locale 8 bit already.
235 */
236 KProcess &operator<<(const QCString & arg);
237
238 /**
239 * Sets the executable and the command line argument list for this process,
240 * in a single method call, or add a list of arguments.
241 **/
242 KProcess &operator<<(const QStringList& args);
243
244 /**
245 * Clear a command line argument list that has been set by using
246 * the "operator<<".
247 */
248 void clearArguments();
249
250 /**
251 * Starts the process.
252 * For a detailed description of the
253 * various run modes and communication semantics, have a look at the
254 * general description of the KProcess class.
255 *
256 * The following problems could cause this function to
257 * return false:
258 *
259 * @li The process is already running.
260 * @li The command line argument list is empty.
261 * @li The starting of the process failed (could not fork).
262 * @li The executable was not found.
263 *
264 * @param comm Specifies which communication links should be
265 * established to the child process (stdin/stdout/stderr). By default,
266 * no communication takes place and the respective communication
267 * signals will never get emitted.
268 *
269 * @return true on success, false on error
270 * (see above for error conditions)
271 **/
272 virtual bool start(RunMode runmode = NotifyOnExit,
273 Communication comm = NoCommunication);
274
275 /**
276 * Stop the process (by sending it a signal).
277 *
278 * @param signoThe signal to send. The default is SIGTERM.
279 * @return @p true if the signal was delivered successfully.
280 */
281 virtual bool kill(int signo = SIGTERM);
282
283 /**
284 @return @p true if the process is (still) considered to be running
285 */
286 bool isRunning() const;
287
288 /** Returns the process id of the process.
289 *
290 * If it is called after
291 * the process has exited, it returns the process id of the last
292 * child process that was created by this instance of KProcess.
293 *
294 * Calling it before any child process has been started by this
295 * KProcess instance causes pid() to return 0.
296 **/
297 pid_t pid() const;
298
299 /**
300 * Use pid().
301 * @deprecated
302 */
303 pid_t getPid() const { return pid(); }
304
305 /**
306 * Suspend processing of data from stdout of the child process.
307 */
308 void suspend();
309
310 /**
311 * Resume processing of data from stdout of the child process.
312 */
313 void resume();
314
315 /**
316 * @return @p true if the process has already finished and has exited
317 * "voluntarily", ie: it has not been killed by a signal.
318 *
319 * Note that you should check @ref KProcess::exitStatus() to determine
320 * whether the process completed its task successful or not.
321 */
322 bool normalExit() const;
323
324 /**
325 * Returns the exit status of the process.
326 *
327 * Please use
328 * @ref KProcess::normalExit() to check whether the process has exited
329 * cleanly (i.e., @ref KProcess::normalExit() returns @p true) before calling
330 * this function because if the process did not exit normally,
331 * it does not have a valid exit status.
332 */
333 int exitStatus() const;
334
335
336 /**
337 * Transmit data to the child process's stdin.
338 *
339 * KProcess::writeStdin may return false in the following cases:
340 *
341 * @li The process is not currently running.
342 *
343 * @li Communication to stdin has not been requested in the @ref start() call.
344 *
345 * @li Transmission of data to the child process by a previous call to
346 * @ref writeStdin() is still in progress.
347 *
348 * Please note that the data is sent to the client asynchronously,
349 * so when this function returns, the data might not have been
350 * processed by the child process.
351 *
352 * If all the data has been sent to the client, the signal
353 * @ref wroteStdin() will be emitted.
354 *
355 * Please note that you must not free "buffer" or call @ref writeStdin()
356 * again until either a @ref wroteStdin() signal indicates that the
357 * data has been sent or a @ref processHasExited() signal shows that
358 * the child process is no longer alive...
359 **/
360 bool writeStdin(const char *buffer, int buflen);
361
362 /**
363 * This causes the stdin file descriptor of the child process to be
364 * closed indicating an "EOF" to the child.
365 *
366 * @return @p false if no communication to the process's stdin
367 * had been specified in the call to @ref start().
368 */
369 bool closeStdin();
370
371 /**
372 * This causes the stdout file descriptor of the child process to be
373 * closed.
374 *
375 * @return @p false if no communication to the process's stdout
376 * had been specified in the call to @ref start().
377 */
378 bool closeStdout();
379
380 /**
381 * This causes the stderr file descriptor of the child process to be
382 * closed.
383 *
384 * @return @p false if no communication to the process's stderr
385 * had been specified in the call to @ref start().
386 */
387 bool closeStderr();
388
389 /**
390 * Lets you see what your arguments are for debugging.
391 */
392
393 const QValueList<QCString> &args() { return arguments; }
394
395 /**
396 * Controls whether the started process should drop any
397 * setuid/segid privileges or whether it should keep them
398 *
399 * The default is @p false : drop privileges
400 */
401 void setRunPrivileged(bool keepPrivileges);
402
403 /**
404 * Returns whether the started process will drop any
405 * setuid/segid privileges or whether it will keep them
406 */
407 bool runPrivileged() const;
408
409 /**
410 * Modifies the environment of the process to be started.
411 * This function must be called before starting the process.
412 */
413 void setEnvironment(const QString &name, const QString &value);
414
415 /**
416 * Changes the current working directory (CWD) of the process
417 * to be started.
418 * This function must be called before starting the process.
419 */
420 void setWorkingDirectory(const QString &dir);
421
422 /**
423 * Specify whether to start the command via a shell or directly.
424 * The default is to start the command directly.
425 * If @p useShell is true @p shell will be used as shell, or
426 * if shell is empty, the standard shell is used.
427 * @p quote A flag indicating whether to quote the arguments.
428 *
429 * When using a shell, the caller should make sure that all filenames etc.
430 * are properly quoted when passed as argument.
431 * @see quote()
432 */
433 void setUseShell(bool useShell, const char *shell = 0);
434
435 /**
436 * This function can be used to quote an argument string such that
437 * the shell processes it properly. This is e. g. necessary for
438 * user-provided file names which may contain spaces or quotes.
439 * It also prevents expansion of wild cards and environment variables.
440 */
441 static QString quote(const QString &arg);
442
443 /**
444 * Detaches KProcess from child process. All communication is closed.
445 * No exit notification is emitted any more for the child process.
446 * Deleting the KProcess will no longer kill the child process.
447 * Note that the current process remains the parent process of the
448 * child process.
449 */
450 void detach();
451
452
453
454signals:
455
456 /**
457 * Emitted after the process has terminated when
458 * the process was run in the @p NotifyOnExit (==default option to
459 * @ref start()) or the @ref Block mode.
460 **/
461 void processExited(KProcess *proc);
462
463
464 /**
465 * Emitted, when output from the child process has
466 * been received on stdout.
467 *
468 * To actually get
469 * these signals, the respective communication link (stdout/stderr)
470 * has to be turned on in @ref start().
471 *
472 * @param buffer The data received.
473 * @param buflen The number of bytes that are available.
474 *
475 * You should copy the information contained in @p buffer to your private
476 * data structures before returning from this slot.
477 **/
478 void receivedStdout(KProcess *proc, char *buffer, int buflen);
479
480 /**
481 * Emitted when output from the child process has
482 * been received on stdout.
483 *
484 * To actually get these signals, the respective communications link
485 * (stdout/stderr) has to be turned on in @ref start() and the
486 * @p NoRead flag should have been passed.
487 *
488 * You will need to explicitly call resume() after your call to start()
489 * to begin processing data from the child process's stdout. This is
490 * to ensure that this signal is not emitted when no one is connected
491 * to it, otherwise this signal will not be emitted.
492 *
493 * The data still has to be read from file descriptor @p fd.
494 **/
495 void receivedStdout(int fd, int &len);
496
497
498 /**
499 * Emitted, when output from the child process has
500 * been received on stderr.
501 * To actually get
502 * these signals, the respective communication link (stdout/stderr)
503 * has to be turned on in @ref start().
504 *
505 * @param buffer The data received.
506 * @param buflen The number of bytes that are available.
507 *
508 * You should copy the information contained in @p buffer to your private
509 * data structures before returning from this slot.
510 */
511 void receivedStderr(KProcess *proc, char *buffer, int buflen);
512
513 /**
514 * Emitted after all the data that has been
515 * specified by a prior call to @ref writeStdin() has actually been
516 * written to the child process.
517 **/
518 void wroteStdin(KProcess *proc);
519
520
521protected slots:
522
523 /**
524 * This slot gets activated when data from the child's stdout arrives.
525 * It usually calls "childOutput"
526 */
527 void slotChildOutput(int fdno);
528
529 /**
530 * This slot gets activated when data from the child's stderr arrives.
531 * It usually calls "childError"
532 */
533 void slotChildError(int fdno);
534 /*
535 Slot functions for capturing stdout and stderr of the child
536 */
537
538 /**
539 * Called when another bulk of data can be sent to the child's
540 * stdin. If there is no more data to be sent to stdin currently
541 * available, this function must disable the QSocketNotifier "innot".
542 */
543 void slotSendData(int dummy);
544
545protected:
546
547 /**
548 * Sets up the environment according to the data passed via
549 * setEnvironment(...)
550 */
551 void setupEnvironment();
552
553 /**
554 * The list of the process' command line arguments. The first entry
555 * in this list is the executable itself.
556 */
557 QValueList<QCString> arguments;
558 /**
559 * How to run the process (Block, NotifyOnExit, DontCare). You should
560 * not modify this data member directly from derived classes.
561 */
562 RunMode run_mode;
563 /**
564 * true if the process is currently running. You should not
565 * modify this data member directly from derived classes. For
566 * reading the value of this data member, please use "isRunning()"
567 * since "runs" will probably be made private in later versions
568 * of KProcess.
569 */
570 bool runs;
571
572 /**
573 * The PID of the currently running process (see "getPid()").
574 * You should not modify this data member in derived classes.
575 * Please use "getPid()" instead of directly accessing this
576 * member function since it will probably be made private in
577 * later versions of KProcess.
578 */
579 pid_t pid_;
580
581 /**
582 * The process' exit status as returned by "waitpid". You should not
583 * modify the value of this data member from derived classes. You should
584 * rather use @ref exitStatus than accessing this data member directly
585 * since it will probably be made private in further versions of
586 * KProcess.
587 */
588 int status;
589
590
591 /**
592 * See setRunPrivileged()
593 */
594 bool keepPrivs;
595
596 /*
597 Functions for setting up the sockets for communication.
598 setupCommunication
599 -- is called from "start" before "fork"ing.
600 commSetupDoneP
601 -- completes communication socket setup in the parent
602 commSetupDoneC
603 -- completes communication setup in the child process
604 commClose
605 -- frees all allocated communication resources in the parent
606 after the process has exited
607 */
608
609 /**
610 * This function is called from "KProcess::start" right before a "fork" takes
611 * place. According to
612 * the "comm" parameter this function has to initialize the "in", "out" and
613 * "err" data member of KProcess.
614 *
615 * This function should return 0 if setting the needed communication channels
616 * was successful.
617 *
618 * The default implementation is to create UNIX STREAM sockets for the communication,
619 * but you could overload this function and establish a TCP/IP communication for
620 * network communication, for example.
621 */
622 virtual int setupCommunication(Communication comm);
623
624 /**
625 * Called right after a (successful) fork on the parent side. This function
626 * will usually do some communications cleanup, like closing the reading end
627 * of the "stdin" communication channel.
628 *
629 * Furthermore, it must also create the QSocketNotifiers "innot", "outnot" and
630 * "errnot" and connect their Qt slots to the respective KProcess member functions.
631 *
632 * For a more detailed explanation, it is best to have a look at the default
633 * implementation of "setupCommunication" in kprocess.cpp.
634 */
635 virtual int commSetupDoneP();
636
637 /**
638 * Called right after a (successful) fork, but before an "exec" on the child
639 * process' side. It usually just closes the unused communication ends of
640 * "in", "out" and "err" (like the writing end of the "in" communication
641 * channel.
642 */
643 virtual int commSetupDoneC();
644
645
646 /**
647 * Immediately called after a process has exited. This function normally
648 * calls commClose to close all open communication channels to this
649 * process and emits the "processExited" signal (if the process was
650 * not running in the "DontCare" mode).
651 */
652 virtual void processHasExited(int state);
653
654 /**
655 * Should clean up the communication links to the child after it has
656 * exited. Should be called from "processHasExited".
657 */
658 virtual void commClose();
659
660
661 /**
662 * the socket descriptors for stdin/stdout/stderr.
663 */
664 int out[2];
665 int in[2];
666 int err[2];
667
668 /**
669 * The socket notifiers for the above socket descriptors.
670 */
671 QSocketNotifier *innot;
672 QSocketNotifier *outnot;
673 QSocketNotifier *errnot;
674
675 /**
676 * Lists the communication links that are activated for the child
677 * process. Should not be modified from derived classes.
678 */
679 Communication communication;
680
681 /**
682 * Called by "slotChildOutput" this function copies data arriving from the
683 * child process's stdout to the respective buffer and emits the signal
684 * "@ref receivedStderr".
685 */
686 int childOutput(int fdno);
687
688 /**
689 * Called by "slotChildOutput" this function copies data arriving from the
690 * child process's stdout to the respective buffer and emits the signal
691 * "@ref receivedStderr"
692 */
693 int childError(int fdno);
694
695 // information about the data that has to be sent to the child:
696
697 const char *input_data; // the buffer holding the data
698 int input_sent; // # of bytes already transmitted
699 int input_total; // total length of input_data
700
701 /**
702 * @ref KProcessController is a friend of KProcess because it has to have
703 * access to various data members.
704 */
705 friend class KProcessController;
706
707
708private:
709 /**
710 * Searches for a valid shell.
711 * Here is the algorithm used for finding an executable shell:
712 *
713 * @li Try the executable pointed to by the "SHELL" environment
714 * variable with white spaces stripped off
715 *
716 * @li If your process runs with uid != euid or gid != egid, a shell
717 * not listed in /etc/shells will not used.
718 *
719 * @li If no valid shell could be found, "/bin/sh" is used as a last resort.
720 */
721 QCString searchShell();
722
723 /**
724 * Used by @ref searchShell in order to find out whether the shell found
725 * is actually executable at all.
726 */
727 bool isExecutable(const QCString &filename);
728
729 // Disallow assignment and copy-construction
730 KProcess( const KProcess& );
731 KProcess& operator= ( const KProcess& );
732
733protected:
734 virtual void virtual_hook( int id, void* data );
735private:
736 KProcessPrivate *d;
737};
738
739class KShellProcessPrivate;
740
741/**
742* @obsolete
743*
744* This class is obsolete. Use KProcess and KProcess::setUseShell(true)
745* instead.
746*
747* @short A class derived from @ref KProcess to start child
748 * processes through a shell.
749* @author Christian Czezakte <e9025461@student.tuwien.ac.at>
750* @version $Id$
751*/
752class KShellProcess: public KProcess
753{
754 Q_OBJECT
755
756public:
757
758 /**
759 * Constructor
760 *
761 * By specifying the name of a shell (like "/bin/bash") you can override
762 * the mechanism for finding a valid shell as described in KProcess::searchShell()
763 */
764 KShellProcess(const char *shellname=0);
765
766 /**
767 * Destructor.
768 */
769 ~KShellProcess();
770
771 /**
772 * Starts up the process. -- For a detailed description
773 * have a look at the "start" member function and the detailed
774 * description of @ref KProcess .
775 */
776 virtual bool start(RunMode runmode = NotifyOnExit,
777 Communication comm = NoCommunication);
778
779 /**
780 * This function can be used to quote an argument string such that
781 * the shell processes it properly. This is e. g. necessary for
782 * user-provided file names which may contain spaces or quotes.
783 * It also prevents expansion of wild cards and environment variables.
784 */
785 static QString quote(const QString &arg);
786
787private:
788
789 QCString shell;
790
791 // Disallow assignment and copy-construction
792 KShellProcess( const KShellProcess& );
793 KShellProcess& operator= ( const KShellProcess& );
794
795protected:
796 virtual void virtual_hook( int id, void* data );
797private:
798 KShellProcessPrivate *d;
799};
800
801
802
803#endif
804