summaryrefslogtreecommitdiffabout
path: root/microkde/oprocess.cpp
Unidiff
Diffstat (limited to 'microkde/oprocess.cpp') (more/less context) (show whitespace changes)
-rw-r--r--microkde/oprocess.cpp951
1 files changed, 951 insertions, 0 deletions
diff --git a/microkde/oprocess.cpp b/microkde/oprocess.cpp
new file mode 100644
index 0000000..95e3e4b
--- a/dev/null
+++ b/microkde/oprocess.cpp
@@ -0,0 +1,951 @@
1/*
2                This file is part of the Opie Project
3             Copyright (C) 2002-2004 Holger Freyther <zecke@handhelds.org>
4 and The Opie Team <opie-devel@handhelds.org>
5 =. Based on KProcess (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at)
6 .=l.
7          .>+-=
8_;:,     .>    :=|. This program is free software; you can
9.> <`_,   >  .   <= redistribute it and/or modify it under
10:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
11.="- .-=="i,     .._ License as published by the Free Software
12- .   .-<_>     .<> Foundation; either version 2 of the License,
13    ._= =}       : or (at your option) any later version.
14   .%`+i>       _;_.
15   .i_,=:_.      -<s. This program is distributed in the hope that
16    +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
17   : ..    .:,     . . . without even the implied warranty of
18   =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
19 _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
20..}^=.=       =       ; Library General Public License for more
21++=   -.     .`     .: details.
22:     =  ...= . :.=-
23-.   .:....=;==+<; You should have received a copy of the GNU
24 -_. . .   )=.  = Library General Public License along with
25   --        :-=` this library; see the file COPYING.LIB.
26 If not, write to the Free Software Foundation,
27 Inc., 59 Temple Place - Suite 330,
28 Boston, MA 02111-1307, USA.
29*/
30
31#include "oprocctrl.h"
32
33/* OPIE */
34#include <oprocess.h>
35
36/* QT */
37
38#include <qapplication.h>
39#include <qdir.h>
40#include <qmap.h>
41#include <qsocketnotifier.h>
42#include <qtextstream.h>
43
44/* STD */
45#include <errno.h>
46#include <fcntl.h>
47#include <pwd.h>
48#include <stdlib.h>
49#include <signal.h>
50#include <stdio.h>
51#include <string.h>
52#include <sys/time.h>
53#include <sys/types.h>
54#include <sys/stat.h>
55#include <sys/socket.h>
56#include <unistd.h>
57#ifdef HAVE_SYS_SELECT_H
58#include <sys/select.h>
59#endif
60#ifdef HAVE_INITGROUPS
61#include <grp.h>
62#endif
63
64using namespace Opie::Core::Internal;
65
66namespace Opie {
67namespace Core {
68namespace Internal {
69class OProcessPrivate
70{
71public:
72 OProcessPrivate() : useShell( false )
73 { }
74
75 bool useShell;
76 QMap<QString, QString> env;
77 QString wd;
78 QCString shell;
79};
80}
81
82OProcess::OProcess( QObject *parent, const char *name )
83 : QObject( parent, name )
84{
85 init ( );
86}
87
88OProcess::OProcess( const QString &arg0, QObject *parent, const char *name )
89 : QObject( parent, name )
90{
91 init ( );
92 *this << arg0;
93}
94
95OProcess::OProcess( const QStringList &args, QObject *parent, const char *name )
96 : QObject( parent, name )
97{
98 init ( );
99 *this << args;
100}
101
102void OProcess::init ( )
103{
104 run_mode = NotifyOnExit;
105 runs = false;
106 pid_ = 0;
107 status = 0;
108 keepPrivs = false;
109 innot = 0;
110 outnot = 0;
111 errnot = 0;
112 communication = NoCommunication;
113 input_data = 0;
114 input_sent = 0;
115 input_total = 0;
116 d = 0;
117
118 if ( 0 == OProcessController::theOProcessController )
119 {
120 ( void ) new OProcessController();
121 CHECK_PTR( OProcessController::theOProcessController );
122 }
123
124 OProcessController::theOProcessController->addOProcess( this );
125 out[ 0 ] = out[ 1 ] = -1;
126 in[ 0 ] = in[ 1 ] = -1;
127 err[ 0 ] = err[ 1 ] = -1;
128}
129
130void OProcess::setEnvironment( const QString &name, const QString &value )
131{
132 if ( !d )
133 d = new OProcessPrivate;
134 d->env.insert( name, value );
135}
136
137void OProcess::setWorkingDirectory( const QString &dir )
138{
139 if ( !d )
140 d = new OProcessPrivate;
141 d->wd = dir;
142}
143
144void OProcess::setupEnvironment()
145{
146 if ( d )
147 {
148 QMap<QString, QString>::Iterator it;
149 for ( it = d->env.begin(); it != d->env.end(); ++it )
150 setenv( QFile::encodeName( it.key() ).data(),
151 QFile::encodeName( it.data() ).data(), 1 );
152 if ( !d->wd.isEmpty() )
153 chdir( QFile::encodeName( d->wd ).data() );
154 }
155}
156
157void OProcess::setRunPrivileged( bool keepPrivileges )
158{
159 keepPrivs = keepPrivileges;
160}
161
162bool OProcess::runPrivileged() const
163{
164 return keepPrivs;
165}
166
167OProcess::~OProcess()
168{
169 // destroying the OProcess instance sends a SIGKILL to the
170 // child process (if it is running) after removing it from the
171 // list of valid processes (if the process is not started as
172 // "DontCare")
173
174 OProcessController::theOProcessController->removeOProcess( this );
175 // this must happen before we kill the child
176 // TODO: block the signal while removing the current process from the process list
177
178 if ( runs && ( run_mode != DontCare ) )
179 kill( SIGKILL );
180
181 // Clean up open fd's and socket notifiers.
182 closeStdin();
183 closeStdout();
184 closeStderr();
185
186 // TODO: restore SIGCHLD and SIGPIPE handler if this is the last OProcess
187 delete d;
188}
189
190void OProcess::detach()
191{
192 OProcessController::theOProcessController->removeOProcess( this );
193
194 runs = false;
195 pid_ = 0;
196
197 // Clean up open fd's and socket notifiers.
198 closeStdin();
199 closeStdout();
200 closeStderr();
201}
202
203bool OProcess::setExecutable( const QString& proc )
204{
205 if ( runs )
206 return false;
207
208 if ( proc.isEmpty() )
209 return false;
210
211 if ( !arguments.isEmpty() )
212 arguments.remove( arguments.begin() );
213 arguments.prepend( QFile::encodeName( proc ) );
214
215 return true;
216}
217
218OProcess &OProcess::operator<<( const QStringList& args )
219{
220 QStringList::ConstIterator it = args.begin();
221 for ( ; it != args.end() ; ++it )
222 arguments.append( QFile::encodeName( *it ) );
223 return *this;
224}
225
226OProcess &OProcess::operator<<( const QCString& arg )
227{
228 return operator<< ( arg.data() );
229}
230
231OProcess &OProcess::operator<<( const char* arg )
232{
233 arguments.append( arg );
234 return *this;
235}
236
237OProcess &OProcess::operator<<( const QString& arg )
238{
239 arguments.append( QFile::encodeName( arg ) );
240 return *this;
241}
242
243void OProcess::clearArguments()
244{
245 arguments.clear();
246}
247
248bool OProcess::start( RunMode runmode, Communication comm )
249{
250 uint i;
251 uint n = arguments.count();
252 char **arglist;
253
254 if ( runs || ( 0 == n ) )
255 {
256 return false; // cannot start a process that is already running
257 // or if no executable has been assigned
258 }
259 run_mode = runmode;
260 status = 0;
261
262 QCString shellCmd;
263 if ( d && d->useShell )
264 {
265 if ( d->shell.isEmpty() )
266 {
267 qWarning( "Could not find a valid shell" );
268 return false;
269 }
270
271 arglist = static_cast<char **>( malloc( ( 4 ) * sizeof( char * ) ) );
272 for ( i = 0; i < n; i++ )
273 {
274 shellCmd += arguments[ i ];
275 shellCmd += " "; // CC: to separate the arguments
276 }
277
278 arglist[ 0 ] = d->shell.data();
279 arglist[ 1 ] = ( char * ) "-c";
280 arglist[ 2 ] = shellCmd.data();
281 arglist[ 3 ] = 0;
282 }
283 else
284 {
285 arglist = static_cast<char **>( malloc( ( n + 1 ) * sizeof( char * ) ) );
286 for ( i = 0; i < n; i++ )
287 arglist[ i ] = arguments[ i ].data();
288 arglist[ n ] = 0;
289 }
290
291 if ( !setupCommunication( comm ) )
292 qWarning( "Could not setup Communication!" );
293
294 // We do this in the parent because if we do it in the child process
295 // gdb gets confused when the application runs from gdb.
296 uid_t uid = getuid();
297 gid_t gid = getgid();
298#ifdef HAVE_INITGROUPS
299
300 struct passwd *pw = getpwuid( uid );
301#endif
302
303 int fd[ 2 ];
304 if ( 0 > pipe( fd ) )
305 {
306 fd[ 0 ] = fd[ 1 ] = 0; // Pipe failed.. continue
307 }
308
309 runs = true;
310
311 QApplication::flushX();
312
313 // WABA: Note that we use fork() and not vfork() because
314 // vfork() has unclear semantics and is not standardized.
315 pid_ = fork();
316
317 if ( 0 == pid_ )
318 {
319 if ( fd[ 0 ] )
320 close( fd[ 0 ] );
321 if ( !runPrivileged() )
322 {
323 setgid( gid );
324#if defined( HAVE_INITGROUPS)
325
326 if ( pw )
327 initgroups( pw->pw_name, pw->pw_gid );
328#endif
329
330 setuid( uid );
331 }
332 // The child process
333 if ( !commSetupDoneC() )
334 qWarning( "Could not finish comm setup in child!" );
335
336 setupEnvironment();
337
338 // Matthias
339 if ( run_mode == DontCare )
340 setpgid( 0, 0 );
341 // restore default SIGPIPE handler (Harri)
342 struct sigaction act;
343 sigemptyset( &( act.sa_mask ) );
344 sigaddset( &( act.sa_mask ), SIGPIPE );
345 act.sa_handler = SIG_DFL;
346 act.sa_flags = 0;
347 sigaction( SIGPIPE, &act, 0L );
348
349 // We set the close on exec flag.
350 // Closing of fd[1] indicates that the execvp succeeded!
351 if ( fd[ 1 ] )
352 fcntl( fd[ 1 ], F_SETFD, FD_CLOEXEC );
353 execvp( arglist[ 0 ], arglist );
354 char resultByte = 1;
355 if ( fd[ 1 ] )
356 write( fd[ 1 ], &resultByte, 1 );
357 _exit( -1 );
358 }
359 else if ( -1 == pid_ )
360 {
361 // forking failed
362
363 runs = false;
364 free( arglist );
365 return false;
366 }
367 else
368 {
369 if ( fd[ 1 ] )
370 close( fd[ 1 ] );
371 // the parent continues here
372
373 // Discard any data for stdin that might still be there
374 input_data = 0;
375
376 // Check whether client could be started.
377 if ( fd[ 0 ] )
378 for ( ;; )
379 {
380 char resultByte;
381 int n = ::read( fd[ 0 ], &resultByte, 1 );
382 if ( n == 1 )
383 {
384 // Error
385 runs = false;
386 close( fd[ 0 ] );
387 free( arglist );
388 pid_ = 0;
389 return false;
390 }
391 if ( n == -1 )
392 {
393 if ( ( errno == ECHILD ) || ( errno == EINTR ) )
394 continue; // Ignore
395 }
396 break; // success
397 }
398 if ( fd[ 0 ] )
399 close( fd[ 0 ] );
400
401 if ( !commSetupDoneP() ) // finish communication socket setup for the parent
402 qWarning( "Could not finish comm setup in parent!" );
403
404 if ( run_mode == Block )
405 {
406 commClose();
407
408 // The SIGCHLD handler of the process controller will catch
409 // the exit and set the status
410 while ( runs )
411 {
412 OProcessController::theOProcessController->
413 slotDoHousekeeping( 0 );
414 }
415 runs = FALSE;
416 emit processExited( this );
417 }
418 }
419 free( arglist );
420 return true;
421}
422
423
424
425bool OProcess::kill( int signo )
426{
427 bool rv = false;
428
429 if ( 0 != pid_ )
430 rv = ( -1 != ::kill( pid_, signo ) );
431 // probably store errno somewhere...
432 return rv;
433}
434
435bool OProcess::isRunning() const
436{
437 return runs;
438}
439
440pid_t OProcess::pid() const
441{
442 return pid_;
443}
444
445bool OProcess::normalExit() const
446{
447 int _status = status;
448 return ( pid_ != 0 ) && ( !runs ) && ( WIFEXITED( ( _status ) ) );
449}
450
451int OProcess::exitStatus() const
452{
453 int _status = status;
454 return WEXITSTATUS( ( _status ) );
455}
456
457bool OProcess::writeStdin( const char *buffer, int buflen )
458{
459 bool rv;
460
461 // if there is still data pending, writing new data
462 // to stdout is not allowed (since it could also confuse
463 // kprocess...
464 if ( 0 != input_data )
465 return false;
466
467 if ( runs && ( communication & Stdin ) )
468 {
469 input_data = buffer;
470 input_sent = 0;
471 input_total = buflen;
472 slotSendData( 0 );
473 innot->setEnabled( true );
474 rv = true;
475 }
476 else
477 rv = false;
478 return rv;
479}
480
481void OProcess::flushStdin ( )
482{
483 if ( !input_data || ( input_sent == input_total ) )
484 return ;
485
486 int d1, d2;
487
488 do
489 {
490 d1 = input_total - input_sent;
491 slotSendData ( 0 );
492 d2 = input_total - input_sent;
493 }
494 while ( d2 <= d1 );
495}
496
497void OProcess::suspend()
498{
499 if ( ( communication & Stdout ) && outnot )
500 outnot->setEnabled( false );
501}
502
503void OProcess::resume()
504{
505 if ( ( communication & Stdout ) && outnot )
506 outnot->setEnabled( true );
507}
508
509bool OProcess::closeStdin()
510{
511 bool rv;
512
513 if ( communication & Stdin )
514 {
515 communication = ( Communication ) ( communication & ~Stdin );
516 delete innot;
517 innot = 0;
518 close( in[ 1 ] );
519 rv = true;
520 }
521 else
522 rv = false;
523 return rv;
524}
525
526bool OProcess::closeStdout()
527{
528 bool rv;
529
530 if ( communication & Stdout )
531 {
532 communication = ( Communication ) ( communication & ~Stdout );
533 delete outnot;
534 outnot = 0;
535 close( out[ 0 ] );
536 rv = true;
537 }
538 else
539 rv = false;
540 return rv;
541}
542
543bool OProcess::closeStderr()
544{
545 bool rv;
546
547 if ( communication & Stderr )
548 {
549 communication = static_cast<Communication>( communication & ~Stderr );
550 delete errnot;
551 errnot = 0;
552 close( err[ 0 ] );
553 rv = true;
554 }
555 else
556 rv = false;
557 return rv;
558}
559
560void OProcess::slotChildOutput( int fdno )
561{
562 if ( !childOutput( fdno ) )
563 closeStdout();
564}
565
566void OProcess::slotChildError( int fdno )
567{
568 if ( !childError( fdno ) )
569 closeStderr();
570}
571
572void OProcess::slotSendData( int )
573{
574 if ( input_sent == input_total )
575 {
576 innot->setEnabled( false );
577 input_data = 0;
578 emit wroteStdin( this );
579 }
580 else
581 input_sent += ::write( in[ 1 ], input_data + input_sent, input_total - input_sent );
582}
583
584void OProcess::processHasExited( int state )
585{
586 if ( runs )
587 {
588 runs = false;
589 status = state;
590
591 commClose(); // cleanup communication sockets
592
593 // also emit a signal if the process was run Blocking
594 if ( DontCare != run_mode )
595 {
596 emit processExited( this );
597 }
598 }
599}
600
601int OProcess::childOutput( int fdno )
602{
603 if ( communication & NoRead )
604 {
605 int len = -1;
606 emit receivedStdout( fdno, len );
607 errno = 0; // Make sure errno doesn't read "EAGAIN"
608 return len;
609 }
610 else
611 {
612 char buffer[ 1024 ];
613 int len;
614
615 len = ::read( fdno, buffer, 1024 );
616
617 if ( 0 < len )
618 {
619 emit receivedStdout( this, buffer, len );
620 }
621 return len;
622 }
623}
624
625int OProcess::childError( int fdno )
626{
627 char buffer[ 1024 ];
628 int len;
629
630 len = ::read( fdno, buffer, 1024 );
631
632 if ( 0 < len )
633 emit receivedStderr( this, buffer, len );
634 return len;
635}
636
637int OProcess::setupCommunication( Communication comm )
638{
639 int ok;
640
641 communication = comm;
642
643 ok = 1;
644 if ( comm & Stdin )
645 ok &= socketpair( AF_UNIX, SOCK_STREAM, 0, in ) >= 0;
646
647 if ( comm & Stdout )
648 ok &= socketpair( AF_UNIX, SOCK_STREAM, 0, out ) >= 0;
649
650 if ( comm & Stderr )
651 ok &= socketpair( AF_UNIX, SOCK_STREAM, 0, err ) >= 0;
652
653 return ok;
654}
655
656int OProcess::commSetupDoneP()
657{
658 int ok = 1;
659
660 if ( communication != NoCommunication )
661 {
662 if ( communication & Stdin )
663 close( in[ 0 ] );
664 if ( communication & Stdout )
665 close( out[ 1 ] );
666 if ( communication & Stderr )
667 close( err[ 1 ] );
668
669 // Don't create socket notifiers and set the sockets non-blocking if
670 // blocking is requested.
671 if ( run_mode == Block )
672 return ok;
673
674 if ( communication & Stdin )
675 {
676 // ok &= (-1 != fcntl(in[1], F_SETFL, O_NONBLOCK));
677 innot = new QSocketNotifier( in[ 1 ], QSocketNotifier::Write, this );
678 CHECK_PTR( innot );
679 innot->setEnabled( false ); // will be enabled when data has to be sent
680 QObject::connect( innot, SIGNAL( activated(int) ),
681 this, SLOT( slotSendData(int) ) );
682 }
683
684 if ( communication & Stdout )
685 {
686 // ok &= (-1 != fcntl(out[0], F_SETFL, O_NONBLOCK));
687 outnot = new QSocketNotifier( out[ 0 ], QSocketNotifier::Read, this );
688 CHECK_PTR( outnot );
689 QObject::connect( outnot, SIGNAL( activated(int) ),
690 this, SLOT( slotChildOutput(int) ) );
691 if ( communication & NoRead )
692 suspend();
693 }
694
695 if ( communication & Stderr )
696 {
697 // ok &= (-1 != fcntl(err[0], F_SETFL, O_NONBLOCK));
698 errnot = new QSocketNotifier( err[ 0 ], QSocketNotifier::Read, this );
699 CHECK_PTR( errnot );
700 QObject::connect( errnot, SIGNAL( activated(int) ),
701 this, SLOT( slotChildError(int) ) );
702 }
703 }
704 return ok;
705}
706
707int OProcess::commSetupDoneC()
708{
709 int ok = 1;
710 struct linger so;
711 memset( &so, 0, sizeof( so ) );
712
713 if ( communication & Stdin )
714 close( in[ 1 ] );
715 if ( communication & Stdout )
716 close( out[ 0 ] );
717 if ( communication & Stderr )
718 close( err[ 0 ] );
719
720 if ( communication & Stdin )
721 ok &= dup2( in[ 0 ], STDIN_FILENO ) != -1;
722 else
723 {
724 int null_fd = open( "/dev/null", O_RDONLY );
725 ok &= dup2( null_fd, STDIN_FILENO ) != -1;
726 close( null_fd );
727 }
728 if ( communication & Stdout )
729 {
730 ok &= dup2( out[ 1 ], STDOUT_FILENO ) != -1;
731 ok &= !setsockopt( out[ 1 ], SOL_SOCKET, SO_LINGER, ( char* ) & so, sizeof( so ) );
732 }
733 else
734 {
735 int null_fd = open( "/dev/null", O_WRONLY );
736 ok &= dup2( null_fd, STDOUT_FILENO ) != -1;
737 close( null_fd );
738 }
739 if ( communication & Stderr )
740 {
741 ok &= dup2( err[ 1 ], STDERR_FILENO ) != -1;
742 ok &= !setsockopt( err[ 1 ], SOL_SOCKET, SO_LINGER, reinterpret_cast<char *>( &so ), sizeof( so ) );
743 }
744 else
745 {
746 int null_fd = open( "/dev/null", O_WRONLY );
747 ok &= dup2( null_fd, STDERR_FILENO ) != -1;
748 close( null_fd );
749 }
750 return ok;
751}
752
753void OProcess::commClose()
754{
755 if ( NoCommunication != communication )
756 {
757 bool b_in = ( communication & Stdin );
758 bool b_out = ( communication & Stdout );
759 bool b_err = ( communication & Stderr );
760 if ( b_in )
761 delete innot;
762
763 if ( b_out || b_err )
764 {
765 // If both channels are being read we need to make sure that one socket buffer
766 // doesn't fill up whilst we are waiting for data on the other (causing a deadlock).
767 // Hence we need to use select.
768
769 // Once one or other of the channels has reached EOF (or given an error) go back
770 // to the usual mechanism.
771
772 int fds_ready = 1;
773 fd_set rfds;
774
775 int max_fd = 0;
776 if ( b_out )
777 {
778 fcntl( out[ 0 ], F_SETFL, O_NONBLOCK );
779 if ( out[ 0 ] > max_fd )
780 max_fd = out[ 0 ];
781 delete outnot;
782 outnot = 0;
783 }
784 if ( b_err )
785 {
786 fcntl( err[ 0 ], F_SETFL, O_NONBLOCK );
787 if ( err[ 0 ] > max_fd )
788 max_fd = err[ 0 ];
789 delete errnot;
790 errnot = 0;
791 }
792
793
794 while ( b_out || b_err )
795 {
796 // * If the process is still running we block until we
797 // receive data. (p_timeout = 0, no timeout)
798 // * If the process has already exited, we only check
799 // the available data, we don't wait for more.
800 // (p_timeout = &timeout, timeout immediately)
801 struct timeval timeout;
802 timeout.tv_sec = 0;
803 timeout.tv_usec = 0;
804 struct timeval *p_timeout = runs ? 0 : &timeout;
805
806 FD_ZERO( &rfds );
807 if ( b_out )
808 FD_SET( out[ 0 ], &rfds );
809
810 if ( b_err )
811 FD_SET( err[ 0 ], &rfds );
812
813 fds_ready = select( max_fd + 1, &rfds, 0, 0, p_timeout );
814 if ( fds_ready <= 0 )
815 break;
816
817 if ( b_out && FD_ISSET( out[ 0 ], &rfds ) )
818 {
819 int ret = 1;
820 while ( ret > 0 )
821 ret = childOutput( out[ 0 ] );
822 if ( ( ret == -1 && errno != EAGAIN ) || ret == 0 )
823 b_out = false;
824 }
825
826 if ( b_err && FD_ISSET( err[ 0 ], &rfds ) )
827 {
828 int ret = 1;
829 while ( ret > 0 )
830 ret = childError( err[ 0 ] );
831 if ( ( ret == -1 && errno != EAGAIN ) || ret == 0 )
832 b_err = false;
833 }
834 }
835 }
836
837 if ( b_in )
838 {
839 communication = ( Communication ) ( communication & ~Stdin );
840 close( in[ 1 ] );
841 }
842 if ( b_out )
843 {
844 communication = ( Communication ) ( communication & ~Stdout );
845 close( out[ 0 ] );
846 }
847 if ( b_err )
848 {
849 communication = ( Communication ) ( communication & ~Stderr );
850 close( err[ 0 ] );
851 }
852 }
853}
854
855void OProcess::setUseShell( bool useShell, const char *shell )
856{
857 if ( !d )
858 d = new OProcessPrivate;
859 d->useShell = useShell;
860 d->shell = shell;
861 if ( d->shell.isEmpty() )
862 d->shell = searchShell();
863}
864
865QString OProcess::quote( const QString &arg )
866{
867 QString res = arg;
868 res.replace( QRegExp( QString::fromLatin1( "\'" ) ),
869 QString::fromLatin1( "'\"'\"'" ) );
870 res.prepend( '\'' );
871 res.append( '\'' );
872 return res;
873}
874
875QCString OProcess::searchShell()
876{
877 QCString tmpShell = QCString( getenv( "SHELL" ) ).stripWhiteSpace();
878 if ( !isExecutable( tmpShell ) )
879 {
880 tmpShell = "/bin/sh";
881 }
882
883 return tmpShell;
884}
885
886bool OProcess::isExecutable( const QCString &filename )
887{
888 struct stat fileinfo;
889
890 if ( filename.isEmpty() )
891 return false;
892
893 // CC: we've got a valid filename, now let's see whether we can execute that file
894
895 if ( -1 == stat( filename.data(), &fileinfo ) )
896 return false;
897 // CC: return false if the file does not exist
898
899 // CC: anyway, we cannot execute directories, block/character devices, fifos or sockets
900 if ( ( S_ISDIR( fileinfo.st_mode ) ) ||
901 ( S_ISCHR( fileinfo.st_mode ) ) ||
902 ( S_ISBLK( fileinfo.st_mode ) ) ||
903#ifdef S_ISSOCK
904 // CC: SYSVR4 systems don't have that macro
905 ( S_ISSOCK( fileinfo.st_mode ) ) ||
906#endif
907 ( S_ISFIFO( fileinfo.st_mode ) ) ||
908 ( S_ISDIR( fileinfo.st_mode ) ) )
909 {
910 return false;
911 }
912
913 // CC: now check for permission to execute the file
914 if ( access( filename.data(), X_OK ) != 0 )
915 return false;
916
917 // CC: we've passed all the tests...
918 return true;
919}
920
921int OProcess::processPID( const QString& process )
922{
923 QString line;
924 QDir d = QDir( "/proc" );
925 QStringList dirs = d.entryList( QDir::Dirs );
926 QStringList::Iterator it;
927 for ( it = dirs.begin(); it != dirs.end(); ++it )
928 {
929 //qDebug( "next entry: %s", (const char*) *it );
930 QFile file( "/proc/"+*it+"/cmdline" );
931 file.open( IO_ReadOnly );
932 if ( !file.isOpen() ) continue;
933 QTextStream t( &file );
934 line = t.readLine();
935 //qDebug( "cmdline = %s", (const char*) line );
936 if ( line.contains( process ) ) break; //FIXME: That may find also other process, if the name is not long enough ;)
937 }
938 if ( line.contains( process ) )
939 {
940 //qDebug( "found process id #%d", (*it).toInt() );
941 return (*it).toInt();
942 }
943 else
944 {
945 //qDebug( "process '%s' not found", (const char*) process );
946 return 0;
947 }
948}
949
950}
951}