summaryrefslogtreecommitdiff
path: root/noncore/net/opietooth/lib/kprocess.cpp
Unidiff
Diffstat (limited to 'noncore/net/opietooth/lib/kprocess.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/net/opietooth/lib/kprocess.cpp915
1 files changed, 915 insertions, 0 deletions
diff --git a/noncore/net/opietooth/lib/kprocess.cpp b/noncore/net/opietooth/lib/kprocess.cpp
new file mode 100644
index 0000000..ce7ed3e
--- a/dev/null
+++ b/noncore/net/opietooth/lib/kprocess.cpp
@@ -0,0 +1,915 @@
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"