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