/* $Id$ * Bluetooth serial forwarder class implementation * * (c) Copyright 2006 GPL * * This software is provided under the GNU public license, incorporated * herein by reference. The software is provided without warranty or * support. */ #include "bt-serial.h" #include #include #include #include #include #include #include #include "forwarder.h" using namespace OpieTooth; using namespace Opie::Core; using namespace Opie::Core::Internal; SerialForwarder::SerialForwarder(QString& devName, int dspeed) : OProcess(), device(devName), speed(dspeed) { status = false; } SerialForwarder::~SerialForwarder() { stop(); } bool SerialForwarder::start(RunMode runmode, Communication comm) { int htmp; //temporary device int result; //call result if ( runs ) { return false; // cannot start a process that is already running // or if no executable has been assigned } //First, check if serial device is usable htmp = ::openSerial(device); if (htmp < 0) return false; close(htmp); run_mode = runmode; status = 0; if(::bt_serialStart() < 0) return false; if ( !setupCommunication( comm ) ) qWarning( "Could not setup Communication!" ); // We do this in the parent because if we do it in the child process // gdb gets confused when the application runs from gdb. uid_t uid = getuid(); gid_t gid = getgid(); #ifdef HAVE_INITGROUPS struct passwd *pw = getpwuid( uid ); #endif int fd[ 2 ]; if ( 0 > pipe( fd ) ) { fd[ 0 ] = fd[ 1 ] = 0; // Pipe failed.. continue } runs = true; QApplication::flushX(); // WABA: Note that we use fork() and not vfork() because // vfork() has unclear semantics and is not standardized. pid_ = fork(); if ( 0 == pid_ ) { if ( fd[ 0 ] ) close( fd[ 0 ] ); if ( !runPrivileged() ) { setgid( gid ); #if defined( HAVE_INITGROUPS) if ( pw ) initgroups( pw->pw_name, pw->pw_gid ); #endif setuid( uid ); } // The child process if ( !commSetupDoneC() ) qWarning( "Could not finish comm setup in child!" ); setupEnvironment(); // Matthias if ( run_mode == DontCare ) setpgid( 0, 0 ); // restore default SIGPIPE handler (Harri) struct sigaction act; sigemptyset( &( act.sa_mask ) ); sigaddset( &( act.sa_mask ), SIGPIPE ); act.sa_handler = SIG_DFL; act.sa_flags = 0; sigaction( SIGPIPE, &act, 0L ); // We set the close on exec flag. // Closing of fd[1] indicates that the execvp succeeded! if ( fd[ 1 ] ) fcntl( fd[ 1 ], F_SETFD, FD_CLOEXEC ); do { BTSerialConn conn; //Connection handler if ( fd[ 1 ] ) { ::close(fd[1]); fd[1] = 0; } result = ::bt_serialForward(&conn, device); } while(result == 0); char resultByte = 1; if ( fd[ 1 ] ) write( fd[ 1 ], &resultByte, 1 ); _exit( -1 ); } else if ( -1 == pid_ ) { // forking failed runs = false; return false; } else { if ( fd[ 1 ] ) close( fd[ 1 ] ); // the parent continues here // Discard any data for stdin that might still be there input_data = 0; // Check whether client could be started. if ( fd[ 0 ] ) for ( ;; ) { char resultByte; int n = ::read( fd[ 0 ], &resultByte, 1 ); if ( n == 1 ) { // Error runs = false; close( fd[ 0 ] ); pid_ = 0; return false; } if ( n == -1 ) { if ( ( errno == ECHILD ) || ( errno == EINTR ) ) continue; // Ignore } break; // success } if ( fd[ 0 ] ) close( fd[ 0 ] ); if ( !commSetupDoneP() ) // finish communication socket setup for the parent qWarning( "Could not finish comm setup in parent!" ); if ( run_mode == Block ) { commClose(); // The SIGCHLD handler of the process controller will catch // the exit and set the status while ( runs ) { OProcessController::theOProcessController-> slotDoHousekeeping( 0 ); } runs = FALSE; emit processExited( this ); } } return true; } /* * Stop forwarding process */ int SerialForwarder::stop() { kill(SIGTERM); ::bt_serialStop(); return 0; } //eof