klauncher.cpp
00001 /* 00002 This file is part of the KDE libraries 00003 Copyright (c) 1999 Waldo Bastian <bastian@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License version 2 as published by the Free Software Foundation. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 #ifdef HAVE_CONFIG_H 00020 #include <config.h> 00021 #endif 00022 00023 #include <stdio.h> 00024 #include <unistd.h> 00025 #include <stdlib.h> 00026 #include <errno.h> 00027 #include <signal.h> 00028 #include <sys/time.h> 00029 00030 #include <qfile.h> 00031 00032 #include <kconfig.h> 00033 #include <kdebug.h> 00034 #include <klibloader.h> 00035 #include <klocale.h> 00036 #include <kprotocolmanager.h> 00037 #include <kprotocolinfo.h> 00038 #include <krun.h> 00039 #include <kstandarddirs.h> 00040 #include <ktempfile.h> 00041 #include <kurl.h> 00042 00043 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 00044 #include <kstartupinfo.h> // schroder 00045 #endif 00046 00047 00048 #include "kio/global.h" 00049 #include "kio/connection.h" 00050 #include "kio/slaveinterface.h" 00051 00052 #include "klauncher.h" 00053 #include "klauncher_cmds.h" 00054 00055 //#if defined Q_WS_X11 && ! defined K_WS_QTONLY 00056 #ifdef Q_WS_X11 00057 //#undef K_WS_QTONLY 00058 #include <X11/Xlib.h> // schroder 00059 #endif 00060 00061 // Dispose slaves after being idle for SLAVE_MAX_IDLE seconds 00062 #define SLAVE_MAX_IDLE 30 00063 00064 using namespace KIO; 00065 00066 template class QPtrList<KLaunchRequest>; 00067 template class QPtrList<IdleSlave>; 00068 00069 IdleSlave::IdleSlave(KSocket *socket) 00070 { 00071 mConn.init(socket); 00072 mConn.connect(this, SLOT(gotInput())); 00073 mConn.send( CMD_SLAVE_STATUS ); 00074 mPid = 0; 00075 mBirthDate = time(0); 00076 mOnHold = false; 00077 } 00078 00079 void 00080 IdleSlave::gotInput() 00081 { 00082 int cmd; 00083 QByteArray data; 00084 if (mConn.read( &cmd, data) == -1) 00085 { 00086 // Communication problem with slave. 00087 kdError(7016) << "SlavePool: No communication with slave." << endl; 00088 delete this; 00089 } 00090 else if (cmd == MSG_SLAVE_ACK) 00091 { 00092 delete this; 00093 } 00094 else if (cmd != MSG_SLAVE_STATUS) 00095 { 00096 kdError(7016) << "SlavePool: Unexpected data from slave." << endl; 00097 delete this; 00098 } 00099 else 00100 { 00101 QDataStream stream( data, IO_ReadOnly ); 00102 pid_t pid; 00103 QCString protocol; 00104 QString host; 00105 Q_INT8 b; 00106 stream >> pid >> protocol >> host >> b; 00107 // Overload with (bool) onHold, (KURL) url. 00108 if (!stream.atEnd()) 00109 { 00110 KURL url; 00111 stream >> url; 00112 mOnHold = true; 00113 mUrl = url; 00114 } 00115 00116 mPid = pid; 00117 mConnected = (b != 0); 00118 mProtocol = protocol; 00119 mHost = host; 00120 emit statusUpdate(this); 00121 } 00122 } 00123 00124 void 00125 IdleSlave::connect(const QString &app_socket) 00126 { 00127 QByteArray data; 00128 QDataStream stream( data, IO_WriteOnly); 00129 stream << app_socket; 00130 mConn.send( CMD_SLAVE_CONNECT, data ); 00131 // Timeout! 00132 } 00133 00134 void 00135 IdleSlave::reparseConfiguration() 00136 { 00137 mConn.send( CMD_REPARSECONFIGURATION ); 00138 } 00139 00140 bool 00141 IdleSlave::match(const QString &protocol, const QString &host, bool connected) 00142 { 00143 if (mOnHold) return false; 00144 if (protocol != mProtocol) return false; 00145 if (host.isEmpty()) return true; 00146 if (host != mHost) return false; 00147 if (!connected) return true; 00148 if (!mConnected) return false; 00149 return true; 00150 } 00151 00152 bool 00153 IdleSlave::onHold(const KURL &url) 00154 { 00155 if (!mOnHold) return false; 00156 return (url == mUrl); 00157 } 00158 00159 int 00160 IdleSlave::age(time_t now) 00161 { 00162 return (int) difftime(now, mBirthDate); 00163 } 00164 00165 KLauncher::KLauncher(int _kdeinitSocket, bool new_startup) 00166 : KApplication( false, false ), // No Styles, No GUI 00167 DCOPObject("klauncher"), 00168 kdeinitSocket(_kdeinitSocket), mAutoStart( new_startup ), 00169 dontBlockReading(false), newStartup( new_startup ) 00170 { 00171 #ifdef Q_WS_X11 00172 mCached_dpy = NULL; 00173 #endif 00174 connect(&mAutoTimer, SIGNAL(timeout()), this, SLOT(slotAutoStart())); 00175 requestList.setAutoDelete(true); 00176 mSlaveWaitRequest.setAutoDelete(true); 00177 dcopClient()->setNotifications( true ); 00178 connect(dcopClient(), SIGNAL( applicationRegistered( const QCString &)), 00179 this, SLOT( slotAppRegistered( const QCString &))); 00180 dcopClient()->connectDCOPSignal( "DCOPServer", "", "terminateKDE()", 00181 objId(), "terminateKDE()", false ); 00182 00183 QString prefix = locateLocal("socket", "klauncher"); 00184 KTempFile domainname(prefix, QString::fromLatin1(".slave-socket")); 00185 if (domainname.status() != 0) 00186 { 00187 // Sever error! 00188 qDebug("KLauncher: Fatal error, can't create tempfile!"); 00189 ::exit(1); 00190 } 00191 mPoolSocketName = domainname.name(); 00192 #ifdef __CYGWIN__ 00193 domainname.close(); 00194 domainname.unlink(); 00195 #endif 00196 mPoolSocket = new KServerSocket(QFile::encodeName(mPoolSocketName)); 00197 connect(mPoolSocket, SIGNAL(accepted( KSocket *)), 00198 SLOT(acceptSlave(KSocket *))); 00199 00200 connect(&mTimer, SIGNAL(timeout()), SLOT(idleTimeout())); 00201 00202 kdeinitNotifier = new QSocketNotifier(kdeinitSocket, QSocketNotifier::Read); 00203 connect(kdeinitNotifier, SIGNAL( activated( int )), 00204 this, SLOT( slotKDEInitData( int ))); 00205 kdeinitNotifier->setEnabled( true ); 00206 lastRequest = 0; 00207 bProcessingQueue = false; 00208 00209 mSlaveDebug = getenv("KDE_SLAVE_DEBUG_WAIT"); 00210 if (!mSlaveDebug.isEmpty()) 00211 { 00212 qWarning("Klauncher running in slave-debug mode for slaves of protocol '%s'", mSlaveDebug.data()); 00213 } 00214 mSlaveValgrind = getenv("KDE_SLAVE_VALGRIND"); 00215 if (!mSlaveValgrind.isEmpty()) 00216 { 00217 mSlaveValgrindSkin = getenv("KDE_SLAVE_VALGRIND_SKIN"); 00218 qWarning("Klauncher running slaves through valgrind for slaves of protocol '%s'", mSlaveValgrind.data()); 00219 } 00220 klauncher_header request_header; 00221 request_header.cmd = LAUNCHER_OK; 00222 request_header.arg_length = 0; 00223 write(kdeinitSocket, &request_header, sizeof(request_header)); 00224 } 00225 00226 KLauncher::~KLauncher() 00227 { 00228 close(); 00229 } 00230 00231 void KLauncher::close() 00232 { 00233 if (!mPoolSocketName.isEmpty()) 00234 { 00235 QCString filename = QFile::encodeName(mPoolSocketName); 00236 unlink(filename.data()); 00237 } 00238 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 00239 //#ifdef Q_WS_X11 00240 if( mCached_dpy != NULL ) 00241 XCloseDisplay( mCached_dpy ); 00242 #endif 00243 } 00244 00245 void 00246 KLauncher::destruct(int exit_code) 00247 { 00248 if (kapp) ((KLauncher*)kapp)->close(); 00249 // We don't delete kapp here, that's intentional. 00250 ::exit(exit_code); 00251 } 00252 00253 bool 00254 KLauncher::process(const QCString &fun, const QByteArray &data, 00255 QCString &replyType, QByteArray &replyData) 00256 { 00257 if ((fun == "exec_blind(QCString,QValueList<QCString>)") 00258 || (fun == "exec_blind(QCString,QValueList<QCString>,QValueList<QCString>,QCString)")) 00259 { 00260 QDataStream stream(data, IO_ReadOnly); 00261 replyType = "void"; 00262 QCString name; 00263 QValueList<QCString> arg_list; 00264 QCString startup_id = "0"; 00265 QValueList<QCString> envs; 00266 stream >> name >> arg_list; 00267 if( fun == "exec_blind(QCString,QValueList<QCString>,QValueList<QCString>,QCString)" ) 00268 stream >> envs >> startup_id; 00269 kdDebug(7016) << "KLauncher: Got exec_blind('" << name << "', ...)" << endl; 00270 exec_blind( name, arg_list, envs, startup_id); 00271 return true; 00272 } 00273 if ((fun == "start_service_by_name(QString,QStringList)") || 00274 (fun == "start_service_by_desktop_path(QString,QStringList)")|| 00275 (fun == "start_service_by_desktop_name(QString,QStringList)")|| 00276 (fun == "kdeinit_exec(QString,QStringList)") || 00277 (fun == "kdeinit_exec_wait(QString,QStringList)") || 00278 (fun == "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString)") || 00279 (fun == "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString)")|| 00280 (fun == "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString)") || 00281 (fun == "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString,bool)") || 00282 (fun == "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString,bool)")|| 00283 (fun == "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString,bool)") || 00284 (fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>)") || 00285 (fun == "kdeinit_exec_wait(QString,QStringList,QValueList<QCString>)") || 00286 (fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>,QCString)") || 00287 (fun == "kdeinit_exec_wait(QString,QStringList,QValueList<QCString>,QCString)")) 00288 { 00289 QDataStream stream(data, IO_ReadOnly); 00290 bool bNoWait = false; 00291 QString serviceName; 00292 QStringList urls; 00293 QValueList<QCString> envs; 00294 QCString startup_id = ""; 00295 DCOPresult.result = -1; 00296 DCOPresult.dcopName = 0; 00297 DCOPresult.error = QString::null; 00298 DCOPresult.pid = 0; 00299 stream >> serviceName >> urls; 00300 if ((fun == "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString,bool)") || 00301 (fun == "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString,bool)")|| 00302 (fun == "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString,bool)")) 00303 stream >> envs >> startup_id >> bNoWait; 00304 else if ((fun == "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString)") || 00305 (fun == "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString)")|| 00306 (fun == "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString)")) 00307 stream >> envs >> startup_id; 00308 else if ((fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>)") || 00309 (fun == "kdeinit_exec_wait(QString,QStringList,QValueList<QCString>)")) 00310 stream >> envs; 00311 else if ((fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>,QCString)") || 00312 (fun == "kdeinit_exec_wait(QString,QStringList,QValueList<QCString>,QCString)")) 00313 stream >> envs >> startup_id; 00314 bool finished; 00315 if (strncmp(fun, "start_service_by_name(", 22) == 0) 00316 { 00317 kdDebug(7016) << "KLauncher: Got start_service_by_name('" << serviceName << "', ...)" << endl; 00318 finished = start_service_by_name(serviceName, urls, envs, startup_id, bNoWait); 00319 } 00320 else if (strncmp(fun, "start_service_by_desktop_path(", 30) == 0) 00321 { 00322 kdDebug(7016) << "KLauncher: Got start_service_by_desktop_path('" << serviceName << "', ...)" << endl; 00323 finished = start_service_by_desktop_path(serviceName, urls, envs, startup_id, bNoWait); 00324 } 00325 else if (strncmp(fun, "start_service_by_desktop_name(", 30) == 0) 00326 { 00327 kdDebug(7016) << "KLauncher: Got start_service_by_desktop_name('" << serviceName << "', ...)" << endl; 00328 finished = start_service_by_desktop_name(serviceName, urls, envs, startup_id, bNoWait ); 00329 } 00330 else if ((fun == "kdeinit_exec(QString,QStringList)") 00331 || (fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>)") 00332 || (fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>,QCString)")) 00333 { 00334 kdDebug(7016) << "KLauncher: Got kdeinit_exec('" << serviceName << "', ...)" << endl; 00335 finished = kdeinit_exec(serviceName, urls, envs, startup_id, false); 00336 } 00337 else 00338 { 00339 kdDebug(7016) << "KLauncher: Got kdeinit_exec_wait('" << serviceName << "', ...)" << endl; 00340 finished = kdeinit_exec(serviceName, urls, envs, startup_id, true); 00341 } 00342 if (!finished) 00343 { 00344 replyType = "serviceResult"; 00345 QDataStream stream2(replyData, IO_WriteOnly); 00346 stream2 << DCOPresult.result << DCOPresult.dcopName << DCOPresult.error << DCOPresult.pid; 00347 } 00348 return true; 00349 } 00350 else if (fun == "requestSlave(QString,QString,QString)") 00351 { 00352 QDataStream stream(data, IO_ReadOnly); 00353 QString protocol; 00354 QString host; 00355 QString app_socket; 00356 stream >> protocol >> host >> app_socket; 00357 replyType = "QString"; 00358 QString error; 00359 pid_t pid = requestSlave(protocol, host, app_socket, error); 00360 QDataStream stream2(replyData, IO_WriteOnly); 00361 stream2 << pid << error; 00362 return true; 00363 } 00364 else if (fun == "requestHoldSlave(KURL,QString)") 00365 { 00366 QDataStream stream(data, IO_ReadOnly); 00367 KURL url; 00368 QString app_socket; 00369 stream >> url >> app_socket; 00370 replyType = "pid_t"; 00371 pid_t pid = requestHoldSlave(url, app_socket); 00372 QDataStream stream2(replyData, IO_WriteOnly); 00373 stream2 << pid; 00374 return true; 00375 } 00376 else if (fun == "waitForSlave(pid_t)") 00377 { 00378 QDataStream stream(data, IO_ReadOnly); 00379 pid_t pid; 00380 stream >> pid; 00381 waitForSlave(pid); 00382 replyType = "void"; 00383 return true; 00384 00385 } 00386 else if (fun == "setLaunchEnv(QCString,QCString)") 00387 { 00388 QDataStream stream(data, IO_ReadOnly); 00389 QCString name; 00390 QCString value; 00391 stream >> name >> value; 00392 setLaunchEnv(name, value); 00393 replyType = "void"; 00394 return true; 00395 } 00396 else if (fun == "reparseConfiguration()") 00397 { 00398 KGlobal::config()->reparseConfiguration(); 00399 kdDebug(7016) << "KLauncher::process : reparseConfiguration" << endl; 00400 KProtocolManager::reparseConfiguration(); 00401 IdleSlave *slave; 00402 for(slave = mSlaveList.first(); slave; slave = mSlaveList.next()) 00403 slave->reparseConfiguration(); 00404 replyType = "void"; 00405 return true; 00406 } 00407 else if (fun == "terminateKDE()") 00408 { 00409 ::signal( SIGHUP, SIG_IGN); 00410 ::signal( SIGTERM, SIG_IGN); 00411 kdDebug() << "KLauncher::process ---> terminateKDE" << endl; 00412 klauncher_header request_header; 00413 request_header.cmd = LAUNCHER_TERMINATE_KDE; 00414 request_header.arg_length = 0; 00415 write(kdeinitSocket, &request_header, sizeof(request_header)); 00416 destruct(0); 00417 } 00418 else if (fun == "autoStart()") 00419 { 00420 kdDebug() << "KLauncher::process ---> autoStart" << endl; 00421 autoStart(1); 00422 replyType = "void"; 00423 return true; 00424 } 00425 else if (fun == "autoStart(int)") 00426 { 00427 kdDebug() << "KLauncher::process ---> autoStart(int)" << endl; 00428 QDataStream stream(data, IO_ReadOnly); 00429 int phase; 00430 stream >> phase; 00431 autoStart(phase); 00432 replyType = "void"; 00433 return true; 00434 } 00435 00436 if (DCOPObject::process(fun, data, replyType, replyData)) 00437 { 00438 return true; 00439 } 00440 kdWarning(7016) << "Got unknown DCOP function: " << fun << endl; 00441 return false; 00442 } 00443 00444 QCStringList 00445 KLauncher::interfaces() 00446 { 00447 QCStringList ifaces = DCOPObject::interfaces(); 00448 ifaces += "KLauncher"; 00449 return ifaces; 00450 } 00451 00452 QCStringList 00453 KLauncher::functions() 00454 { 00455 QCStringList funcs = DCOPObject::functions(); 00456 funcs << "void exec_blind(QCString,QValueList<QCString>)"; 00457 funcs << "void exec_blind(QCString,QValueList<QCString>,QValueList<QCString>,QCString)"; 00458 funcs << "serviceResult start_service_by_name(QString,QStringList)"; 00459 funcs << "serviceResult start_service_by_desktop_path(QString,QStringList)"; 00460 funcs << "serviceResult start_service_by_desktop_name(QString,QStringList)"; 00461 funcs << "serviceResult kdeinit_exec(QString,QStringList)"; 00462 funcs << "serviceResult kdeinit_exec_wait(QString,QStringList)"; 00463 funcs << "serviceResult start_service_by_name(QString,QStringList,QValueList<QCString>,QCString)"; 00464 funcs << "serviceResult start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString)"; 00465 funcs << "serviceResult start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString)"; 00466 funcs << "serviceResult start_service_by_name(QString,QStringList,QValueList<QCString>,QCString,bool)"; 00467 funcs << "serviceResult start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString,bool)"; 00468 funcs << "serviceResult start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString,bool)"; 00469 funcs << "serviceResult kdeinit_exec(QString,QStringList,QValueList<QCString>)"; 00470 funcs << "serviceResult kdeinit_exec_wait(QString,QStringList,QValueList<QCString>)"; 00471 funcs << "QString requestSlave(QString,QString,QString)"; 00472 funcs << "pid_t requestHoldSlave(KURL,QString)"; 00473 funcs << "void waitForSlave(pid_t)"; 00474 funcs << "void setLaunchEnv(QCString,QCString)"; 00475 funcs << "void reparseConfiguration()"; 00476 // funcs << "void terminateKDE()"; 00477 funcs << "void autoStart()"; 00478 funcs << "void autoStart(int)"; 00479 return funcs; 00480 } 00481 00482 void KLauncher::setLaunchEnv(const QCString &name, const QCString &_value) 00483 { 00484 QCString value(_value); 00485 if (value.isNull()) 00486 value = ""; 00487 klauncher_header request_header; 00488 QByteArray requestData(name.length()+value.length()+2); 00489 memcpy(requestData.data(), name.data(), name.length()+1); 00490 memcpy(requestData.data()+name.length()+1, value.data(), value.length()+1); 00491 request_header.cmd = LAUNCHER_SETENV; 00492 request_header.arg_length = requestData.size(); 00493 write(kdeinitSocket, &request_header, sizeof(request_header)); 00494 write(kdeinitSocket, requestData.data(), request_header.arg_length); 00495 } 00496 00497 /* 00498 * Read 'len' bytes from 'sock' into buffer. 00499 * returns -1 on failure, 0 on no data. 00500 */ 00501 static int 00502 read_socket(int sock, char *buffer, int len) 00503 { 00504 ssize_t result; 00505 int bytes_left = len; 00506 while ( bytes_left > 0) 00507 { 00508 result = read(sock, buffer, bytes_left); 00509 if (result > 0) 00510 { 00511 buffer += result; 00512 bytes_left -= result; 00513 } 00514 else if (result == 0) 00515 return -1; 00516 else if ((result == -1) && (errno != EINTR)) 00517 return -1; 00518 } 00519 return 0; 00520 } 00521 00522 00523 void 00524 KLauncher::slotKDEInitData(int) 00525 { 00526 klauncher_header request_header; 00527 QByteArray requestData; 00528 if( dontBlockReading ) 00529 { 00530 // in case we get a request to start an application and data arrive 00531 // to kdeinitSocket at the same time, requestStart() will already 00532 // call slotKDEInitData(), so we must check there's still something 00533 // to read, otherwise this would block 00534 fd_set in; 00535 timeval tm = { 0, 0 }; 00536 FD_ZERO ( &in ); 00537 FD_SET( kdeinitSocket, &in ); 00538 select( kdeinitSocket + 1, &in, 0, 0, &tm ); 00539 if( !FD_ISSET( kdeinitSocket, &in )) 00540 return; 00541 } 00542 dontBlockReading = false; 00543 int result = read_socket(kdeinitSocket, (char *) &request_header, 00544 sizeof( request_header)); 00545 if (result == -1) 00546 { 00547 kdDebug() << "Exiting on read_socket errno: " << errno << endl; 00548 ::signal( SIGHUP, SIG_IGN); 00549 ::signal( SIGTERM, SIG_IGN); 00550 destruct(255); // Exit! 00551 } 00552 requestData.resize(request_header.arg_length); 00553 result = read_socket(kdeinitSocket, (char *) requestData.data(), 00554 request_header.arg_length); 00555 00556 if (request_header.cmd == LAUNCHER_DIED) 00557 { 00558 long *request_data; 00559 request_data = (long *) requestData.data(); 00560 processDied(request_data[0], request_data[1]); 00561 return; 00562 } 00563 if (lastRequest && (request_header.cmd == LAUNCHER_OK)) 00564 { 00565 long *request_data; 00566 request_data = (long *) requestData.data(); 00567 lastRequest->pid = (pid_t) (*request_data); 00568 kdDebug(7016) << lastRequest->name << " (pid " << lastRequest->pid << 00569 ") up and running." << endl; 00570 switch(lastRequest->dcop_service_type) 00571 { 00572 case KService::DCOP_None: 00573 { 00574 lastRequest->status = KLaunchRequest::Running; 00575 break; 00576 } 00577 00578 case KService::DCOP_Unique: 00579 { 00580 lastRequest->status = KLaunchRequest::Launching; 00581 break; 00582 } 00583 00584 case KService::DCOP_Wait: 00585 { 00586 lastRequest->status = KLaunchRequest::Launching; 00587 break; 00588 } 00589 00590 case KService::DCOP_Multi: 00591 { 00592 lastRequest->status = KLaunchRequest::Launching; 00593 break; 00594 } 00595 } 00596 lastRequest = 0; 00597 return; 00598 } 00599 if (lastRequest && (request_header.cmd == LAUNCHER_ERROR)) 00600 { 00601 lastRequest->status = KLaunchRequest::Error; 00602 if (!requestData.isEmpty()) 00603 lastRequest->errorMsg = QString::fromUtf8((char *) requestData.data()); 00604 lastRequest = 0; 00605 return; 00606 } 00607 00608 kdWarning(7016) << "Unexpected command from KDEInit (" << (unsigned int) request_header.cmd 00609 << ")" << endl; 00610 } 00611 00612 void 00613 KLauncher::processDied(pid_t pid, long /* exitStatus */) 00614 { 00615 KLaunchRequest *request = requestList.first(); 00616 for(; request; request = requestList.next()) 00617 { 00618 if (request->pid == pid) 00619 { 00620 if (request->dcop_service_type == KService::DCOP_Wait) 00621 request->status = KLaunchRequest::Done; 00622 else if ((request->dcop_service_type == KService::DCOP_Unique) && 00623 (dcopClient()->isApplicationRegistered(request->dcop_name))) 00624 request->status = KLaunchRequest::Running; 00625 else 00626 request->status = KLaunchRequest::Error; 00627 requestDone(request); 00628 return; 00629 } 00630 } 00631 } 00632 00633 void 00634 KLauncher::slotAppRegistered(const QCString &appId) 00635 { 00636 const char *cAppId = appId.data(); 00637 if (!cAppId) return; 00638 00639 KLaunchRequest *request = requestList.first(); 00640 KLaunchRequest *nextRequest; 00641 for(; request; request = nextRequest) 00642 { 00643 nextRequest = requestList.next(); 00644 if (request->status != KLaunchRequest::Launching) 00645 continue; 00646 00647 // For unique services check the requested service name first 00648 if ((request->dcop_service_type == KService::DCOP_Unique) && 00649 ((appId == request->dcop_name) || 00650 dcopClient()->isApplicationRegistered(request->dcop_name))) 00651 { 00652 request->status = KLaunchRequest::Running; 00653 requestDone(request); 00654 continue; 00655 } 00656 00657 const char *rAppId = request->dcop_name.data(); 00658 if (!rAppId) continue; 00659 00660 int l = strlen(rAppId); 00661 if ((strncmp(rAppId, cAppId, l) == 0) && 00662 ((cAppId[l] == '\0') || (cAppId[l] == '-'))) 00663 { 00664 request->dcop_name = appId; 00665 request->status = KLaunchRequest::Running; 00666 requestDone(request); 00667 continue; 00668 } 00669 } 00670 } 00671 00672 void 00673 KLauncher::autoStart(int phase) 00674 { 00675 if( mAutoStart.phase() >= phase ) 00676 return; 00677 mAutoStart.setPhase(phase); 00678 if( newStartup ) 00679 { 00680 if (phase == 0) 00681 mAutoStart.loadAutoStartList(); 00682 } 00683 else 00684 { 00685 if (phase == 1) 00686 mAutoStart.loadAutoStartList(); 00687 } 00688 mAutoTimer.start(0, true); 00689 } 00690 00691 void 00692 KLauncher::slotAutoStart() 00693 { 00694 KService::Ptr s; 00695 do 00696 { 00697 QString service = mAutoStart.startService(); 00698 if (service.isEmpty()) 00699 { 00700 // Done 00701 if( !mAutoStart.phaseDone()) 00702 { 00703 mAutoStart.setPhaseDone(); 00704 // Emit signal 00705 if( newStartup ) 00706 { 00707 QCString autoStartSignal; 00708 autoStartSignal.sprintf( "autoStart%dDone()", mAutoStart.phase()); 00709 emitDCOPSignal(autoStartSignal, QByteArray()); 00710 } 00711 else 00712 { 00713 QCString autoStartSignal( "autoStartDone()" ); 00714 int phase = mAutoStart.phase(); 00715 if ( phase > 1 ) 00716 autoStartSignal.sprintf( "autoStart%dDone()", phase ); 00717 emitDCOPSignal(autoStartSignal, QByteArray()); 00718 } 00719 } 00720 return; 00721 } 00722 s = new KService(service); 00723 } 00724 while (!start_service(s, QStringList(), QValueList<QCString>(), "0", false, true)); 00725 // Loop till we find a service that we can start. 00726 } 00727 00728 void 00729 KLauncher::requestDone(KLaunchRequest *request) 00730 { 00731 if ((request->status == KLaunchRequest::Running) || 00732 (request->status == KLaunchRequest::Done)) 00733 { 00734 DCOPresult.result = 0; 00735 DCOPresult.dcopName = request->dcop_name; 00736 DCOPresult.error = QString::null; 00737 DCOPresult.pid = request->pid; 00738 } 00739 else 00740 { 00741 DCOPresult.result = 1; 00742 DCOPresult.dcopName = ""; 00743 DCOPresult.error = i18n("KDEInit could not launch '%1'.").arg(request->name); 00744 if (!request->errorMsg.isEmpty()) 00745 DCOPresult.error += ":\n" + request->errorMsg; 00746 DCOPresult.pid = 0; 00747 00748 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 00749 //#ifdef Q_WS_X11 00750 if (!request->startup_dpy.isEmpty()) 00751 { 00752 Display* dpy = NULL; 00753 if( (mCached_dpy != NULL) && 00754 (request->startup_dpy == XDisplayString( mCached_dpy ))) 00755 dpy = mCached_dpy; 00756 if( dpy == NULL ) 00757 dpy = XOpenDisplay( request->startup_dpy ); 00758 if( dpy ) 00759 { 00760 KStartupInfoId id; 00761 id.initId( request->startup_id ); 00762 KStartupInfo::sendFinishX( dpy, id ); 00763 if( mCached_dpy != dpy && mCached_dpy != NULL ) 00764 XCloseDisplay( mCached_dpy ); 00765 mCached_dpy = dpy; 00766 } 00767 } 00768 #endif 00769 } 00770 00771 if (request->autoStart) 00772 { 00773 mAutoTimer.start(0, true); 00774 } 00775 00776 if (request->transaction) 00777 { 00778 QByteArray replyData; 00779 QCString replyType; 00780 replyType = "serviceResult"; 00781 QDataStream stream2(replyData, IO_WriteOnly); 00782 stream2 << DCOPresult.result << DCOPresult.dcopName << DCOPresult.error << DCOPresult.pid; 00783 dcopClient()->endTransaction( request->transaction, 00784 replyType, replyData); 00785 } 00786 requestList.removeRef( request ); 00787 } 00788 00789 void 00790 KLauncher::requestStart(KLaunchRequest *request) 00791 { 00792 requestList.append( request ); 00793 // Send request to kdeinit. 00794 klauncher_header request_header; 00795 QByteArray requestData; 00796 int length = 0; 00797 length += sizeof(long); // Nr of. Args 00798 length += request->name.length() + 1; // Cmd 00799 for(QValueList<QCString>::Iterator it = request->arg_list.begin(); 00800 it != request->arg_list.end(); 00801 it++) 00802 { 00803 length += (*it).length() + 1; // Args... 00804 } 00805 length += sizeof(long); // Nr of. envs 00806 for(QValueList<QCString>::ConstIterator it = request->envs.begin(); 00807 it != request->envs.end(); 00808 it++) 00809 { 00810 length += (*it).length() + 1; // Envs... 00811 } 00812 length += sizeof( long ); // avoid_loops 00813 #ifdef Q_WS_X11 00814 bool startup_notify = !request->startup_id.isNull() && request->startup_id != "0"; 00815 if( startup_notify ) 00816 length += request->startup_id.length() + 1; 00817 #endif 00818 if (!request->cwd.isEmpty()) 00819 length += request->cwd.length() + 1; 00820 00821 requestData.resize( length ); 00822 00823 char *p = requestData.data(); 00824 long l = request->arg_list.count()+1; 00825 memcpy(p, &l, sizeof(long)); 00826 p += sizeof(long); 00827 strcpy(p, request->name.data()); 00828 p += strlen(p) + 1; 00829 for(QValueList<QCString>::Iterator it = request->arg_list.begin(); 00830 it != request->arg_list.end(); 00831 it++) 00832 { 00833 strcpy(p, (*it).data()); 00834 p += strlen(p) + 1; 00835 } 00836 l = request->envs.count(); 00837 memcpy(p, &l, sizeof(long)); 00838 p += sizeof(long); 00839 for(QValueList<QCString>::ConstIterator it = request->envs.begin(); 00840 it != request->envs.end(); 00841 it++) 00842 { 00843 strcpy(p, (*it).data()); 00844 p += strlen(p) + 1; 00845 } 00846 l = 0; // avoid_loops, always false here 00847 memcpy(p, &l, sizeof(long)); 00848 p += sizeof(long); 00849 #ifdef Q_WS_X11 00850 if( startup_notify ) 00851 { 00852 strcpy(p, request->startup_id.data()); 00853 p += strlen( p ) + 1; 00854 } 00855 #endif 00856 if (!request->cwd.isEmpty()) 00857 { 00858 strcpy(p, request->cwd.data()); 00859 p += strlen( p ) + 1; 00860 } 00861 #ifdef Q_WS_X11 00862 request_header.cmd = startup_notify ? LAUNCHER_EXT_EXEC : LAUNCHER_EXEC_NEW; 00863 #else 00864 request_header.cmd = LAUNCHER_EXEC_NEW; 00865 #endif 00866 request_header.arg_length = length; 00867 write(kdeinitSocket, &request_header, sizeof(request_header)); 00868 write(kdeinitSocket, requestData.data(), request_header.arg_length); 00869 00870 // Wait for pid to return. 00871 lastRequest = request; 00872 dontBlockReading = false; 00873 do { 00874 slotKDEInitData( kdeinitSocket ); 00875 } 00876 while (lastRequest != 0); 00877 dontBlockReading = true; 00878 } 00879 00880 void 00881 KLauncher::exec_blind( const QCString &name, const QValueList<QCString> &arg_list, 00882 const QValueList<QCString> &envs, const QCString& startup_id ) 00883 { 00884 KLaunchRequest *request = new KLaunchRequest; 00885 request->autoStart = false; 00886 request->name = name; 00887 request->arg_list = arg_list; 00888 request->dcop_name = 0; 00889 request->dcop_service_type = KService::DCOP_None; 00890 request->pid = 0; 00891 request->status = KLaunchRequest::Launching; 00892 request->transaction = 0; // No confirmation is send 00893 request->envs = envs; 00894 // Find service, if any - strip path if needed 00895 KService::Ptr service = KService::serviceByDesktopName( name.mid( name.findRev( '/' ) + 1 )); 00896 if (service != NULL) 00897 send_service_startup_info( request, service, 00898 startup_id, QValueList< QCString >()); 00899 else // no .desktop file, no startup info 00900 cancel_service_startup_info( request, startup_id, envs ); 00901 00902 requestStart(request); 00903 // We don't care about this request any longer.... 00904 requestDone(request); 00905 } 00906 00907 00908 bool 00909 KLauncher::start_service_by_name(const QString &serviceName, const QStringList &urls, 00910 const QValueList<QCString> &envs, const QCString& startup_id, bool blind) 00911 { 00912 KService::Ptr service = 0; 00913 // Find service 00914 service = KService::serviceByName(serviceName); 00915 if (!service) 00916 { 00917 DCOPresult.result = ENOENT; 00918 DCOPresult.error = i18n("Could not find service '%1'.").arg(serviceName); 00919 cancel_service_startup_info( NULL, startup_id, envs ); // cancel it if any 00920 return false; 00921 } 00922 return start_service(service, urls, envs, startup_id, blind); 00923 } 00924 00925 bool 00926 KLauncher::start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, 00927 const QValueList<QCString> &envs, const QCString& startup_id, bool blind) 00928 { 00929 KService::Ptr service = 0; 00930 // Find service 00931 if (serviceName[0] == '/') 00932 { 00933 // Full path 00934 service = new KService(serviceName); 00935 } 00936 else 00937 { 00938 service = KService::serviceByDesktopPath(serviceName); 00939 } 00940 if (!service) 00941 { 00942 DCOPresult.result = ENOENT; 00943 DCOPresult.error = i18n("Could not find service '%1'.").arg(serviceName); 00944 cancel_service_startup_info( NULL, startup_id, envs ); // cancel it if any 00945 return false; 00946 } 00947 return start_service(service, urls, envs, startup_id, blind); 00948 } 00949 00950 bool 00951 KLauncher::start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, 00952 const QValueList<QCString> &envs, const QCString& startup_id, bool blind) 00953 { 00954 KService::Ptr service = 0; 00955 // Find service 00956 service = KService::serviceByDesktopName(serviceName); 00957 if (!service) 00958 { 00959 DCOPresult.result = ENOENT; 00960 DCOPresult.error = i18n("Could not find service '%1'.").arg(serviceName); 00961 cancel_service_startup_info( NULL, startup_id, envs ); // cancel it if any 00962 return false; 00963 } 00964 return start_service(service, urls, envs, startup_id, blind); 00965 } 00966 00967 bool 00968 KLauncher::start_service(KService::Ptr service, const QStringList &_urls, 00969 const QValueList<QCString> &envs, const QCString& startup_id, bool blind, bool autoStart) 00970 { 00971 QStringList urls = _urls; 00972 if (!service->isValid()) 00973 { 00974 DCOPresult.result = ENOEXEC; 00975 DCOPresult.error = i18n("Service '%1' is malformatted.").arg(service->desktopEntryPath()); 00976 cancel_service_startup_info( NULL, startup_id, envs ); // cancel it if any 00977 return false; 00978 } 00979 KLaunchRequest *request = new KLaunchRequest; 00980 request->autoStart = autoStart; 00981 00982 if ((urls.count() > 1) && !service->allowMultipleFiles()) 00983 { 00984 // We need to launch the application N times. That sucks. 00985 // We ignore the result for application 2 to N. 00986 // For the first file we launch the application in the 00987 // usual way. The reported result is based on this 00988 // application. 00989 QStringList::ConstIterator it = urls.begin(); 00990 for(++it; 00991 it != urls.end(); 00992 ++it) 00993 { 00994 QStringList singleUrl; 00995 singleUrl.append(*it); 00996 QCString startup_id2 = startup_id; 00997 if( !startup_id2.isEmpty() && startup_id2 != "0" ) 00998 startup_id2 = "0"; // can't use the same startup_id several times 00999 start_service( service, singleUrl, envs, startup_id2, true); 01000 } 01001 QString firstURL = *(urls.begin()); 01002 urls.clear(); 01003 urls.append(firstURL); 01004 } 01005 createArgs(request, service, urls); 01006 01007 // We must have one argument at least! 01008 if (!request->arg_list.count()) 01009 { 01010 DCOPresult.result = ENOEXEC; 01011 DCOPresult.error = i18n("Service '%1' is malformatted.").arg(service->desktopEntryPath()); 01012 delete request; 01013 cancel_service_startup_info( NULL, startup_id, envs ); 01014 return false; 01015 } 01016 01017 request->name = request->arg_list.first(); 01018 request->arg_list.remove(request->arg_list.begin()); 01019 01020 request->dcop_service_type = service->DCOPServiceType(); 01021 01022 if ((request->dcop_service_type == KService::DCOP_Unique) || 01023 (request->dcop_service_type == KService::DCOP_Multi)) 01024 { 01025 QVariant v = service->property("X-DCOP-ServiceName"); 01026 if (v.isValid()) 01027 request->dcop_name = v.toString().utf8(); 01028 if (request->dcop_name.isEmpty()) 01029 { 01030 request->dcop_name = QFile::encodeName(KRun::binaryName(service->exec(), true)); 01031 } 01032 } 01033 01034 request->pid = 0; 01035 request->transaction = 0; 01036 request->envs = envs; 01037 send_service_startup_info( request, service, startup_id, envs ); 01038 01039 // Request will be handled later. 01040 if (!blind && !autoStart) 01041 { 01042 request->transaction = dcopClient()->beginTransaction(); 01043 } 01044 queueRequest(request); 01045 return true; 01046 } 01047 01048 void 01049 KLauncher::send_service_startup_info( KLaunchRequest *request, KService::Ptr service, const QCString& startup_id, 01050 const QValueList<QCString> &envs ) 01051 { 01052 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 01053 //#ifdef Q_WS_X11 // KStartup* isn't implemented for Qt/Embedded yet 01054 request->startup_id = "0"; 01055 if( startup_id == "0" ) 01056 return; 01057 bool silent; 01058 QCString wmclass; 01059 if( !KRun::checkStartupNotify( QString::null, service, &silent, &wmclass )) 01060 return; 01061 KStartupInfoId id; 01062 id.initId( startup_id ); 01063 const char* dpy_str = NULL; 01064 for( QValueList<QCString>::ConstIterator it = envs.begin(); 01065 it != envs.end(); 01066 ++it ) 01067 if( strncmp( *it, "DISPLAY=", 8 ) == 0 ) 01068 dpy_str = static_cast< const char* >( *it ) + 8; 01069 Display* dpy = NULL; 01070 if( dpy_str != NULL && mCached_dpy != NULL 01071 && qstrcmp( dpy_str, XDisplayString( mCached_dpy )) == 0 ) 01072 dpy = mCached_dpy; 01073 if( dpy == NULL ) 01074 dpy = XOpenDisplay( dpy_str ); 01075 request->startup_id = id.id(); 01076 if( dpy == NULL ) 01077 { 01078 cancel_service_startup_info( request, startup_id, envs ); 01079 return; 01080 } 01081 01082 request->startup_dpy = dpy_str; 01083 01084 KStartupInfoData data; 01085 data.setName( service->name()); 01086 data.setIcon( service->icon()); 01087 data.setDescription( i18n( "Launching %1" ).arg( service->name())); 01088 if( !wmclass.isEmpty()) 01089 data.setWMClass( wmclass ); 01090 if( silent ) 01091 data.setSilent( KStartupInfoData::Yes ); 01092 // the rest will be sent by kdeinit 01093 KStartupInfo::sendStartupX( dpy, id, data ); 01094 if( mCached_dpy != dpy && mCached_dpy != NULL ) 01095 XCloseDisplay( mCached_dpy ); 01096 mCached_dpy = dpy; 01097 return; 01098 #else 01099 return; 01100 #endif 01101 } 01102 01103 void 01104 KLauncher::cancel_service_startup_info( KLaunchRequest* request, const QCString& startup_id, 01105 const QValueList<QCString> &envs ) 01106 { 01107 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 01108 //#ifdef Q_WS_X11 // KStartup* isn't implemented for Qt/Embedded yet 01109 if( request != NULL ) 01110 request->startup_id = "0"; 01111 if( !startup_id.isEmpty() && startup_id != "0" ) 01112 { 01113 const char* dpy_str = NULL; 01114 for( QValueList<QCString>::ConstIterator it = envs.begin(); 01115 it != envs.end(); 01116 ++it ) 01117 if( strncmp( *it, "DISPLAY=", 8 ) == 0 ) 01118 dpy_str = static_cast< const char* >( *it ) + 8; 01119 Display* dpy = NULL; 01120 if( dpy_str != NULL && mCached_dpy != NULL 01121 && qstrcmp( dpy_str, XDisplayString( mCached_dpy )) == 0 ) 01122 dpy = mCached_dpy; 01123 if( dpy == NULL ) 01124 dpy = XOpenDisplay( dpy_str ); 01125 if( dpy == NULL ) 01126 return; 01127 KStartupInfoId id; 01128 id.initId( startup_id ); 01129 KStartupInfo::sendFinishX( dpy, id ); 01130 if( mCached_dpy != dpy && mCached_dpy != NULL ) 01131 XCloseDisplay( mCached_dpy ); 01132 mCached_dpy = dpy; 01133 } 01134 #endif 01135 } 01136 01137 bool 01138 KLauncher::kdeinit_exec(const QString &app, const QStringList &args, 01139 const QValueList<QCString> &envs, QCString startup_id, bool wait) 01140 { 01141 KLaunchRequest *request = new KLaunchRequest; 01142 request->autoStart = false; 01143 01144 for(QStringList::ConstIterator it = args.begin(); 01145 it != args.end(); 01146 it++) 01147 { 01148 QString arg = *it; 01149 request->arg_list.append(arg.local8Bit()); 01150 } 01151 01152 request->name = app.local8Bit(); 01153 01154 if (wait) 01155 request->dcop_service_type = KService::DCOP_Wait; 01156 else 01157 request->dcop_service_type = KService::DCOP_None; 01158 request->dcop_name = 0; 01159 request->pid = 0; 01160 #ifdef Q_WS_X11 01161 request->startup_id = startup_id; 01162 #endif 01163 request->envs = envs; 01164 if( app != "kbuildsycoca" ) // avoid stupid loop 01165 { 01166 // Find service, if any - strip path if needed 01167 KService::Ptr service = KService::serviceByDesktopName( app.mid( app.findRev( '/' ) + 1 )); 01168 if (service != NULL) 01169 send_service_startup_info( request, service, 01170 startup_id, QValueList< QCString >()); 01171 else // no .desktop file, no startup info 01172 cancel_service_startup_info( request, startup_id, envs ); 01173 } 01174 request->transaction = dcopClient()->beginTransaction(); 01175 queueRequest(request); 01176 return true; 01177 } 01178 01179 void 01180 KLauncher::queueRequest(KLaunchRequest *request) 01181 { 01182 requestQueue.append( request ); 01183 if (!bProcessingQueue) 01184 { 01185 bProcessingQueue = true; 01186 QTimer::singleShot(0, this, SLOT( slotDequeue() )); 01187 } 01188 } 01189 01190 void 01191 KLauncher::slotDequeue() 01192 { 01193 do { 01194 KLaunchRequest *request = requestQueue.take(0); 01195 // process request 01196 request->status = KLaunchRequest::Launching; 01197 requestStart(request); 01198 if (request->status != KLaunchRequest::Launching) 01199 { 01200 // Request handled. 01201 requestDone( request ); 01202 continue; 01203 } 01204 } while(requestQueue.count()); 01205 bProcessingQueue = false; 01206 } 01207 01208 void 01209 KLauncher::createArgs( KLaunchRequest *request, const KService::Ptr service , 01210 const QStringList &urls) 01211 { 01212 QStringList params = KRun::processDesktopExec(*service, urls, false); 01213 01214 for(QStringList::ConstIterator it = params.begin(); 01215 it != params.end(); ++it) 01216 { 01217 request->arg_list.append((*it).local8Bit()); 01218 } 01219 request->cwd = QFile::encodeName(service->path()); 01220 } 01221 01223 01224 pid_t 01225 KLauncher::requestHoldSlave(const KURL &url, const QString &app_socket) 01226 { 01227 IdleSlave *slave; 01228 for(slave = mSlaveList.first(); slave; slave = mSlaveList.next()) 01229 { 01230 if (slave->onHold(url)) 01231 break; 01232 } 01233 if (slave) 01234 { 01235 mSlaveList.removeRef(slave); 01236 slave->connect(app_socket); 01237 return slave->pid(); 01238 } 01239 return 0; 01240 } 01241 01242 01243 pid_t 01244 KLauncher::requestSlave(const QString &protocol, 01245 const QString &host, 01246 const QString &app_socket, 01247 QString &error) 01248 { 01249 IdleSlave *slave; 01250 for(slave = mSlaveList.first(); slave; slave = mSlaveList.next()) 01251 { 01252 if (slave->match(protocol, host, true)) 01253 break; 01254 } 01255 if (!slave) 01256 { 01257 for(slave = mSlaveList.first(); slave; slave = mSlaveList.next()) 01258 { 01259 if (slave->match(protocol, host, false)) 01260 break; 01261 } 01262 } 01263 if (!slave) 01264 { 01265 for(slave = mSlaveList.first(); slave; slave = mSlaveList.next()) 01266 { 01267 if (slave->match(protocol, QString::null, false)) 01268 break; 01269 } 01270 } 01271 if (slave) 01272 { 01273 mSlaveList.removeRef(slave); 01274 slave->connect(app_socket); 01275 return slave->pid(); 01276 } 01277 01278 QString _name = KProtocolInfo::exec(protocol); 01279 if (_name.isEmpty()) 01280 { 01281 error = i18n("Unknown protocol '%1'.\n").arg(protocol); 01282 return 0; 01283 } 01284 01285 QCString name = _name.latin1(); // ex: "kio_ftp" 01286 QCString arg1 = protocol.latin1(); 01287 QCString arg2 = QFile::encodeName(mPoolSocketName); 01288 QCString arg3 = QFile::encodeName(app_socket); 01289 QValueList<QCString> arg_list; 01290 arg_list.append(arg1); 01291 arg_list.append(arg2); 01292 arg_list.append(arg3); 01293 01294 // kdDebug(7016) << "KLauncher: launching new slave " << _name << " with protocol=" << protocol << endl; 01295 if (mSlaveDebug == arg1) 01296 { 01297 klauncher_header request_header; 01298 request_header.cmd = LAUNCHER_DEBUG_WAIT; 01299 request_header.arg_length = 0; 01300 write(kdeinitSocket, &request_header, sizeof(request_header)); 01301 } 01302 if (mSlaveValgrind == arg1) 01303 { 01304 arg_list.prepend(QFile::encodeName(KLibLoader::findLibrary(name))); 01305 arg_list.prepend(QFile::encodeName(locate("exe", "kioslave"))); 01306 name = "valgrind"; 01307 if (!mSlaveValgrindSkin.isEmpty()) { 01308 arg_list.prepend(QCString("--tool=") + mSlaveValgrindSkin); 01309 } else 01310 arg_list.prepend("--tool=memcheck"); 01311 } 01312 01313 KLaunchRequest *request = new KLaunchRequest; 01314 request->autoStart = false; 01315 request->name = name; 01316 request->arg_list = arg_list; 01317 request->dcop_name = 0; 01318 request->dcop_service_type = KService::DCOP_None; 01319 request->pid = 0; 01320 #ifdef Q_WS_X11 01321 request->startup_id = "0"; 01322 #endif 01323 request->status = KLaunchRequest::Launching; 01324 request->transaction = 0; // No confirmation is send 01325 requestStart(request); 01326 pid_t pid = request->pid; 01327 01328 // kdDebug(7016) << "Slave launched, pid = " << pid << endl; 01329 01330 // We don't care about this request any longer.... 01331 requestDone(request); 01332 if (!pid) 01333 { 01334 error = i18n("Error loading '%1'.\n").arg(name); 01335 } 01336 return pid; 01337 } 01338 01339 void 01340 KLauncher::waitForSlave(pid_t pid) 01341 { 01342 IdleSlave *slave; 01343 for(slave = mSlaveList.first(); slave; slave = mSlaveList.next()) 01344 { 01345 if (slave->pid() == pid) 01346 return; // Already here. 01347 } 01348 SlaveWaitRequest *waitRequest = new SlaveWaitRequest; 01349 waitRequest->transaction = dcopClient()->beginTransaction(); 01350 waitRequest->pid = pid; 01351 mSlaveWaitRequest.append(waitRequest); 01352 } 01353 01354 void 01355 KLauncher::acceptSlave(KSocket *slaveSocket) 01356 { 01357 IdleSlave *slave = new IdleSlave(slaveSocket); 01358 // Send it a SLAVE_STATUS command. 01359 mSlaveList.append(slave); 01360 connect(slave, SIGNAL(destroyed()), this, SLOT(slotSlaveGone())); 01361 connect(slave, SIGNAL(statusUpdate(IdleSlave *)), 01362 this, SLOT(slotSlaveStatus(IdleSlave *))); 01363 if (!mTimer.isActive()) 01364 { 01365 mTimer.start(1000*10); 01366 } 01367 } 01368 01369 void 01370 KLauncher::slotSlaveStatus(IdleSlave *slave) 01371 { 01372 SlaveWaitRequest *waitRequest = mSlaveWaitRequest.first(); 01373 while(waitRequest) 01374 { 01375 if (waitRequest->pid == slave->pid()) 01376 { 01377 QByteArray replyData; 01378 QCString replyType; 01379 replyType = "void"; 01380 dcopClient()->endTransaction( waitRequest->transaction, replyType, replyData); 01381 mSlaveWaitRequest.removeRef(waitRequest); 01382 waitRequest = mSlaveWaitRequest.current(); 01383 } 01384 else 01385 { 01386 waitRequest = mSlaveWaitRequest.next(); 01387 } 01388 } 01389 } 01390 01391 void 01392 KLauncher::slotSlaveGone() 01393 { 01394 IdleSlave *slave = (IdleSlave *) sender(); 01395 mSlaveList.removeRef(slave); 01396 if ((mSlaveList.count() == 0) && (mTimer.isActive())) 01397 { 01398 mTimer.stop(); 01399 } 01400 } 01401 01402 void 01403 KLauncher::idleTimeout() 01404 { 01405 bool keepOneFileSlave=true; 01406 time_t now = time(0); 01407 IdleSlave *slave; 01408 for(slave = mSlaveList.first(); slave; slave = mSlaveList.next()) 01409 { 01410 if ((slave->protocol()=="file") && (keepOneFileSlave)) 01411 keepOneFileSlave=false; 01412 else if (slave->age(now) > SLAVE_MAX_IDLE) 01413 { 01414 // killing idle slave 01415 delete slave; 01416 } 01417 } 01418 } 01419 01420 #include "klauncher.moc"