00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "klauncher.h"
00021 #include "klauncher_cmds.h"
00022 #include "klauncher_adaptor.h"
00023
00024 #include <config.h>
00025
00026 #include <stdio.h>
00027 #include <unistd.h>
00028 #include <stdlib.h>
00029 #include <errno.h>
00030 #include <signal.h>
00031 #include <sys/time.h>
00032
00033 #ifdef Q_WS_X11
00034 #include <kstartupinfo.h>
00035 #include <X11/Xlib.h>
00036 #endif
00037
00038 #include <QtCore/QFile>
00039
00040 #include <kconfig.h>
00041 #include <kdebug.h>
00042 #include <kde_file.h>
00043 #include <klibloader.h>
00044 #include <klocale.h>
00045 #include <kprotocolmanager.h>
00046 #include <kprotocolinfo.h>
00047 #include <krun.h>
00048 #include <kstandarddirs.h>
00049 #include <ktemporaryfile.h>
00050 #include <kurl.h>
00051
00052 #include <kio/global.h>
00053 #include <kio/connection.h>
00054 #include <kio/slaveinterface.h>
00055
00056
00057 #define SLAVE_MAX_IDLE 30
00058
00059 using namespace KIO;
00060
00061 IdleSlave::IdleSlave(QObject *parent)
00062 : QObject(parent)
00063 {
00064 QObject::connect(&mConn, SIGNAL(readyRead()), this, SLOT(gotInput()));
00065
00066 mConn.send( CMD_SLAVE_STATUS );
00067 mPid = 0;
00068 mBirthDate = time(0);
00069 mOnHold = false;
00070 }
00071
00072 template<int T> struct PIDType { typedef pid_t PID_t; } ;
00073 template<> struct PIDType<2> { typedef qint16 PID_t; } ;
00074 template<> struct PIDType<4> { typedef qint32 PID_t; } ;
00075
00076 void
00077 IdleSlave::gotInput()
00078 {
00079 int cmd;
00080 QByteArray data;
00081 if (mConn.read( &cmd, data) == -1)
00082 {
00083
00084 kError(7016) << "SlavePool: No communication with slave." << endl;
00085 delete this;
00086 }
00087 else if (cmd == MSG_SLAVE_ACK)
00088 {
00089 delete this;
00090 }
00091 else if (cmd != MSG_SLAVE_STATUS)
00092 {
00093 kError(7016) << "SlavePool: Unexpected data from slave." << endl;
00094 delete this;
00095 }
00096 else
00097 {
00098 QDataStream stream( data );
00099 PIDType<sizeof(pid_t)>::PID_t stream_pid;
00100 pid_t pid;
00101 QByteArray protocol;
00102 QString host;
00103 qint8 b;
00104 stream >> stream_pid >> protocol >> host >> b;
00105 pid = stream_pid;
00106
00107 if (!stream.atEnd())
00108 {
00109 KUrl url;
00110 stream >> url;
00111 mOnHold = true;
00112 mUrl = url;
00113 }
00114
00115 mPid = pid;
00116 mConnected = (b != 0);
00117 mProtocol = QString::fromLatin1(protocol);
00118 mHost = host;
00119 emit statusUpdate(this);
00120 }
00121 }
00122
00123 void
00124 IdleSlave::connect(const QString &app_socket)
00125 {
00126 QByteArray data;
00127 QDataStream stream( &data, QIODevice::WriteOnly);
00128 stream << app_socket;
00129 mConn.send( CMD_SLAVE_CONNECT, data );
00130
00131 }
00132
00133 void
00134 IdleSlave::reparseConfiguration()
00135 {
00136 mConn.send( CMD_REPARSECONFIGURATION );
00137 }
00138
00139 bool
00140 IdleSlave::match(const QString &protocol, const QString &host, bool connected)
00141 {
00142 if (mOnHold) return false;
00143 if (protocol != mProtocol) return false;
00144 if (host.isEmpty()) return true;
00145 if (host != mHost) return false;
00146 if (!connected) return true;
00147 if (!mConnected) return false;
00148 return true;
00149 }
00150
00151 bool
00152 IdleSlave::onHold(const KUrl &url)
00153 {
00154 if (!mOnHold) return false;
00155 return (url == mUrl);
00156 }
00157
00158 int
00159 IdleSlave::age(time_t now)
00160 {
00161 return (int) difftime(now, mBirthDate);
00162 }
00163
00164 static KLauncher* g_klauncher_self;
00165
00166 KLauncher::KLauncher(int _kdeinitSocket)
00167 : QObject(0),
00168 kdeinitSocket(_kdeinitSocket), dontBlockReading(false)
00169 {
00170 #ifdef Q_WS_X11
00171 mCached_dpy = NULL;
00172 #endif
00173 Q_ASSERT( g_klauncher_self == NULL );
00174 g_klauncher_self = this;
00175
00176 mAutoTimer.setSingleShot(true);
00177 new KLauncherAdaptor(this);
00178 QDBusConnection::sessionBus().registerObject("/KLauncher", this);
00179
00180 connect(&mAutoTimer, SIGNAL(timeout()), this, SLOT(slotAutoStart()));
00181 connect(QDBusConnection::sessionBus().interface(),
00182 SIGNAL(serviceOwnerChanged(QString,QString,QString)),
00183 SLOT(slotNameOwnerChanged(QString,QString,QString)));
00184
00185 mConnectionServer.listenForRemote();
00186 connect(&mConnectionServer, SIGNAL(newConnection()), SLOT(acceptSlave()));
00187 if (!mConnectionServer.isListening())
00188 {
00189
00190 qDebug("KLauncher: Fatal error, can't create tempfile!");
00191 ::_exit(1);
00192 }
00193
00194 connect(&mTimer, SIGNAL(timeout()), SLOT(idleTimeout()));
00195
00196 #ifndef Q_WS_WIN
00197 kdeinitNotifier = new QSocketNotifier(kdeinitSocket, QSocketNotifier::Read);
00198 connect(kdeinitNotifier, SIGNAL( activated( int )),
00199 this, SLOT( slotKDEInitData( int )));
00200 kdeinitNotifier->setEnabled( true );
00201 #endif
00202 lastRequest = 0;
00203 bProcessingQueue = false;
00204
00205 mSlaveDebug = QString::fromLocal8Bit(qgetenv("KDE_SLAVE_DEBUG_WAIT"));
00206 if (!mSlaveDebug.isEmpty())
00207 {
00208 qWarning("Klauncher running in slave-debug mode for slaves of protocol '%s'", qPrintable(mSlaveDebug));
00209 }
00210 mSlaveValgrind = QString::fromLocal8Bit(qgetenv("KDE_SLAVE_VALGRIND"));
00211 if (!mSlaveValgrind.isEmpty())
00212 {
00213 mSlaveValgrindSkin = QString::fromLocal8Bit(qgetenv("KDE_SLAVE_VALGRIND_SKIN"));
00214 qWarning("Klauncher running slaves through valgrind for slaves of protocol '%s'", qPrintable(mSlaveValgrind));
00215 }
00216 #ifdef Q_WS_WIN
00217 kDebug(7016) << "LAUNCHER_OK";
00218 #else
00219 klauncher_header request_header;
00220 request_header.cmd = LAUNCHER_OK;
00221 request_header.arg_length = 0;
00222 write(kdeinitSocket, &request_header, sizeof(request_header));
00223 #endif
00224 }
00225
00226 KLauncher::~KLauncher()
00227 {
00228 close();
00229 g_klauncher_self = NULL;
00230 }
00231
00232 void KLauncher::close()
00233 {
00234 #ifdef Q_WS_X11
00235 if( mCached_dpy != NULL )
00236 {
00237 XCloseDisplay( mCached_dpy );
00238 mCached_dpy = NULL;
00239 }
00240 #endif
00241 }
00242
00243 void
00244 KLauncher::destruct()
00245 {
00246 if (g_klauncher_self)
00247 g_klauncher_self->close();
00248
00249 ::_exit(255);
00250 }
00251
00252 void KLauncher::setLaunchEnv(const QString &name, const QString &value)
00253 {
00254 #ifdef Q_WS_WIN
00255
00256 #else
00257 klauncher_header request_header;
00258 QByteArray requestData;
00259 requestData.append(name.toLocal8Bit()).append('\0').append(value.toLocal8Bit()).append('\0');
00260 request_header.cmd = LAUNCHER_SETENV;
00261 request_header.arg_length = requestData.size();
00262 write(kdeinitSocket, &request_header, sizeof(request_header));
00263 write(kdeinitSocket, requestData.data(), request_header.arg_length);
00264 #endif
00265 }
00266
00267 #ifndef Q_WS_WIN
00268
00269
00270
00271
00272 static int
00273 read_socket(int sock, char *buffer, int len)
00274 {
00275 ssize_t result;
00276 int bytes_left = len;
00277 while ( bytes_left > 0)
00278 {
00279 result = read(sock, buffer, bytes_left);
00280 if (result > 0)
00281 {
00282 buffer += result;
00283 bytes_left -= result;
00284 }
00285 else if (result == 0)
00286 return -1;
00287 else if ((result == -1) && (errno != EINTR))
00288 return -1;
00289 }
00290 return 0;
00291 }
00292
00293
00294 void
00295 KLauncher::slotKDEInitData(int)
00296 {
00297 klauncher_header request_header;
00298 QByteArray requestData;
00299 if( dontBlockReading )
00300 {
00301
00302
00303
00304
00305 fd_set in;
00306 timeval tm = { 0, 0 };
00307 FD_ZERO ( &in );
00308 FD_SET( kdeinitSocket, &in );
00309 select( kdeinitSocket + 1, &in, 0, 0, &tm );
00310 if( !FD_ISSET( kdeinitSocket, &in ))
00311 return;
00312 }
00313 dontBlockReading = false;
00314 int result = read_socket(kdeinitSocket, (char *) &request_header,
00315 sizeof( request_header));
00316 if (result == -1)
00317 {
00318 kDebug(7016) << "Exiting on read_socket errno:" << errno;
00319 KDE_signal( SIGHUP, SIG_IGN);
00320 KDE_signal( SIGTERM, SIG_IGN);
00321 destruct();
00322 }
00323 requestData.resize(request_header.arg_length);
00324 result = read_socket(kdeinitSocket, (char *) requestData.data(),
00325 request_header.arg_length);
00326
00327 processRequestReturn(request_header.cmd,requestData);
00328
00329 }
00330 #endif
00331
00332 void KLauncher::processRequestReturn(int status, const QByteArray &requestData)
00333 {
00334 if (status == LAUNCHER_DIED)
00335 {
00336 long *request_data;
00337 request_data = (long *) requestData.data();
00338 processDied(request_data[0], request_data[1]);
00339 return;
00340 }
00341 if (lastRequest && (status == LAUNCHER_OK))
00342 {
00343 long *request_data;
00344 request_data = (long *) requestData.data();
00345 lastRequest->pid = (pid_t) (*request_data);
00346 kDebug(7016).nospace() << lastRequest->name << " (pid " << lastRequest->pid <<
00347 ") up and running.";
00348 switch(lastRequest->dbus_startup_type)
00349 {
00350 case KService::DBusNone:
00351 lastRequest->status = KLaunchRequest::Running;
00352 break;
00353 case KService::DBusUnique:
00354 case KService::DBusWait:
00355 case KService::DBusMulti:
00356 lastRequest->status = KLaunchRequest::Launching;
00357 break;
00358 }
00359 lastRequest = 0;
00360 return;
00361 }
00362 if (lastRequest && (status == LAUNCHER_ERROR))
00363 {
00364 lastRequest->status = KLaunchRequest::Error;
00365 kDebug(7016) << lastRequest->name << " failed." << endl;
00366 if (!requestData.isEmpty())
00367 lastRequest->errorMsg = QString::fromUtf8((char *) requestData.data());
00368 lastRequest = 0;
00369 return;
00370 }
00371
00372 kWarning(7016)<< "Unexpected request return" << (unsigned int) status;
00373 }
00374
00375 void
00376 KLauncher::processDied(pid_t pid, long )
00377 {
00378 foreach (KLaunchRequest *request, requestList)
00379 {
00380 if (request->pid == pid)
00381 {
00382 if (request->dbus_startup_type == KService::DBusWait)
00383 request->status = KLaunchRequest::Done;
00384 else if ((request->dbus_startup_type == KService::DBusUnique)
00385 && QDBusConnection::sessionBus().interface()->isServiceRegistered(request->dbus_name))
00386 request->status = KLaunchRequest::Running;
00387 else
00388 request->status = KLaunchRequest::Error;
00389 requestDone(request);
00390 return;
00391 }
00392 }
00393 }
00394
00395 void
00396 KLauncher::slotNameOwnerChanged(const QString &appId, const QString &oldOwner,
00397 const QString &newOwner)
00398 {
00399 Q_UNUSED(oldOwner);
00400 if (appId.isEmpty() || newOwner.isEmpty())
00401 return;
00402
00403 foreach (KLaunchRequest *request, requestList)
00404 {
00405 if (request->status != KLaunchRequest::Launching)
00406 continue;
00407
00408
00409 if ((request->dbus_startup_type == KService::DBusUnique) &&
00410 ((appId == request->dbus_name) ||
00411 QDBusConnection::sessionBus().interface()->isServiceRegistered(request->dbus_name)))
00412 {
00413 request->status = KLaunchRequest::Running;
00414 requestDone(request);
00415 continue;
00416 }
00417
00418 const QString rAppId = request->dbus_name;
00419 if (rAppId.isEmpty())
00420 return;
00421
00422
00423
00424 QChar c = appId.length() > rAppId.length() ? appId.at(rAppId.length()) : QChar();
00425 if (appId.startsWith(rAppId) && ((appId.length() == rAppId.length()) ||
00426 (c == QLatin1Char('-'))))
00427 {
00428 request->dbus_name = appId;
00429 request->status = KLaunchRequest::Running;
00430 requestDone(request);
00431 continue;
00432 }
00433 }
00434 }
00435
00436 void
00437 KLauncher::autoStart(int phase)
00438 {
00439 if( mAutoStart.phase() >= phase )
00440 return;
00441 mAutoStart.setPhase(phase);
00442 if (phase == 0)
00443 mAutoStart.loadAutoStartList();
00444 mAutoTimer.start(0);
00445 }
00446
00447 void
00448 KLauncher::slotAutoStart()
00449 {
00450 KService::Ptr s;
00451 do
00452 {
00453 QString service = mAutoStart.startService();
00454 if (service.isEmpty())
00455 {
00456
00457 if( !mAutoStart.phaseDone())
00458 {
00459 mAutoStart.setPhaseDone();
00460 switch( mAutoStart.phase())
00461 {
00462 case 0:
00463 emit autoStart0Done();
00464 break;
00465 case 1:
00466 emit autoStart1Done();
00467 break;
00468 case 2:
00469 emit autoStart2Done();
00470 break;
00471 }
00472 }
00473 return;
00474 }
00475 s = new KService(service);
00476 }
00477 while (!start_service(s, QStringList(), QStringList(), "0", false, true, QDBusMessage()));
00478
00479 }
00480
00481 void
00482 KLauncher::requestDone(KLaunchRequest *request)
00483 {
00484 if ((request->status == KLaunchRequest::Running) ||
00485 (request->status == KLaunchRequest::Done))
00486 {
00487 requestResult.result = 0;
00488 requestResult.dbusName = request->dbus_name;
00489 requestResult.error = "";
00490 requestResult.pid = request->pid;
00491 }
00492 else
00493 {
00494 requestResult.result = 1;
00495 requestResult.dbusName = "";
00496 requestResult.error = i18n("KDEInit could not launch '%1'.", request->name);
00497 if (!request->errorMsg.isEmpty())
00498 requestResult.error += ":\n" + request->errorMsg;
00499 requestResult.pid = 0;
00500
00501 #ifdef Q_WS_X11
00502 if (!request->startup_dpy.isEmpty())
00503 {
00504 Display* dpy = NULL;
00505 if( (mCached_dpy != NULL) &&
00506 (request->startup_dpy == XDisplayString( mCached_dpy )))
00507 dpy = mCached_dpy;
00508 if( dpy == NULL )
00509 dpy = XOpenDisplay( request->startup_dpy.toLocal8Bit() );
00510 if( dpy )
00511 {
00512 KStartupInfoId id;
00513 id.initId( request->startup_id.toLocal8Bit() );
00514 KStartupInfo::sendFinishX( dpy, id );
00515 if( mCached_dpy != dpy && mCached_dpy != NULL )
00516 XCloseDisplay( mCached_dpy );
00517 mCached_dpy = dpy;
00518 }
00519 }
00520 #endif
00521 }
00522
00523 if (request->autoStart)
00524 {
00525 mAutoTimer.start(0);
00526 }
00527
00528 if (request->transaction.type() != QDBusMessage::InvalidMessage)
00529 {
00530 if ( requestResult.dbusName.isNull() )
00531 requestResult.dbusName = "";
00532 Q_ASSERT( !requestResult.error.isNull() );
00533 PIDType<sizeof(pid_t)>::PID_t stream_pid = requestResult.pid;
00534 QDBusConnection::sessionBus().send(request->transaction.createReply(QVariantList() << requestResult.result
00535 << requestResult.dbusName
00536 << requestResult.error
00537 << stream_pid));
00538 }
00539 requestList.removeAll( request );
00540 delete request;
00541 }
00542
00543 static void appendLong(QByteArray &ba, long l)
00544 {
00545 const int sz = ba.size();
00546 ba.resize(sz + sizeof(long));
00547 memcpy(ba.data() + sz, &l, sizeof(long));
00548 }
00549
00550 void
00551 KLauncher::requestStart(KLaunchRequest *request)
00552 {
00553 #ifdef Q_WS_WIN
00554 requestList.append( request );
00555 lastRequest = request;
00556
00557 KProcess *process = new KProcess;
00558 process->setOutputChannelMode(KProcess::MergedChannels);
00559 connect(process ,SIGNAL(readyReadStandardOutput()),this, SLOT(slotGotOutput()) );
00560 connect(process ,SIGNAL(finished(int, QProcess::ExitStatus)),this, SLOT(slotFinished(int, QProcess::ExitStatus)) );
00561 request->process = process;
00562
00563
00564 QStringList args;
00565 foreach (const QString &arg, request->arg_list)
00566 args << arg;
00567
00568 process->setProgram(request->name,args);
00569 process->start();
00570
00571 if (!process->waitForStarted())
00572 {
00573 processRequestReturn(LAUNCHER_ERROR,"");
00574 }
00575 else
00576 {
00577 request->pid = process->pid();
00578 QByteArray data((char *)&request->pid, sizeof(int));
00579 processRequestReturn(LAUNCHER_OK,data);
00580 }
00581 return;
00582
00583 #else
00584 requestList.append( request );
00585
00586 klauncher_header request_header;
00587 QByteArray requestData;
00588 requestData.reserve(1024);
00589
00590 appendLong(requestData, request->arg_list.count() + 1);
00591 requestData.append(request->name.toLocal8Bit());
00592 requestData.append('\0');
00593 foreach (const QString &arg, request->arg_list)
00594 requestData.append(arg.toLocal8Bit()).append('\0');
00595 appendLong(requestData, request->envs.count());
00596 foreach (const QString &env, request->envs)
00597 requestData.append(env.toLocal8Bit()).append('\0');
00598 appendLong(requestData, 0);
00599 #ifdef Q_WS_X11
00600 bool startup_notify = !request->startup_id.isNull() && request->startup_id != "0";
00601 if( startup_notify )
00602 requestData.append(request->startup_id.toLocal8Bit()).append('\0');
00603 #endif
00604 if (!request->cwd.isEmpty())
00605 requestData.append(request->cwd.toLocal8Bit()).append('\0');
00606
00607 #ifdef Q_WS_X11
00608 request_header.cmd = startup_notify ? LAUNCHER_EXT_EXEC : LAUNCHER_EXEC_NEW;
00609 #else
00610 request_header.cmd = LAUNCHER_EXEC_NEW;
00611 #endif
00612 request_header.arg_length = requestData.length();
00613 write(kdeinitSocket, &request_header, sizeof(request_header));
00614 write(kdeinitSocket, requestData.data(), requestData.length());
00615
00616
00617 lastRequest = request;
00618 dontBlockReading = false;
00619 do {
00620 slotKDEInitData( kdeinitSocket );
00621 }
00622 while (lastRequest != 0);
00623 dontBlockReading = true;
00624 #endif
00625 }
00626
00627 void KLauncher::exec_blind(const QString &name, const QStringList &arg_list, const QStringList &envs, const QString &startup_id)
00628 {
00629 KLaunchRequest *request = new KLaunchRequest;
00630 request->autoStart = false;
00631 request->name = name;
00632 request->arg_list = arg_list;
00633 request->dbus_startup_type = KService::DBusNone;
00634 request->pid = 0;
00635 request->status = KLaunchRequest::Launching;
00636 request->envs = envs;
00637
00638 KService::Ptr service = KService::serviceByDesktopName( name.mid( name.lastIndexOf( '/' ) + 1 ));
00639 if (service)
00640 send_service_startup_info( request, service, startup_id, QStringList());
00641 else
00642 cancel_service_startup_info( request, startup_id, envs );
00643
00644 requestStart(request);
00645
00646 requestDone(request);
00647 }
00648
00649
00650
00651 bool
00652 KLauncher::start_service_by_name(const QString &serviceName, const QStringList &urls,
00653 const QStringList &envs, const QString& startup_id, bool blind, const QDBusMessage &msg)
00654 {
00655 KService::Ptr service;
00656
00657 service = KService::serviceByName(serviceName);
00658 if (!service)
00659 {
00660 requestResult.result = ENOENT;
00661 requestResult.error = i18n("Could not find service '%1'.", serviceName);
00662 cancel_service_startup_info( NULL, startup_id, envs );
00663 return false;
00664 }
00665 return start_service(service, urls, envs, startup_id, blind, false, msg);
00666 }
00667
00668 bool
00669 KLauncher::start_service_by_desktop_path(const QString &serviceName, const QStringList &urls,
00670 const QStringList &envs, const QString& startup_id, bool blind, const QDBusMessage &msg)
00671 {
00672 KService::Ptr service;
00673
00674 if (QFileInfo(serviceName).isAbsolute() )
00675 {
00676
00677 service = new KService(serviceName);
00678 }
00679 else
00680 {
00681 service = KService::serviceByDesktopPath(serviceName);
00682 }
00683 if (!service)
00684 {
00685 requestResult.result = ENOENT;
00686 requestResult.error = i18n("Could not find service '%1'.", serviceName);
00687 cancel_service_startup_info( NULL, startup_id, envs );
00688 return false;
00689 }
00690 return start_service(service, urls, envs, startup_id, blind, false, msg);
00691 }
00692
00693 bool
00694 KLauncher::start_service_by_desktop_name(const QString &serviceName, const QStringList &urls,
00695 const QStringList &envs, const QString& startup_id, bool blind, const QDBusMessage &msg)
00696 {
00697 KService::Ptr service = KService::serviceByDesktopName(serviceName);
00698 if (!service)
00699 {
00700 requestResult.result = ENOENT;
00701 requestResult.error = i18n("Could not find service '%1'.", serviceName);
00702 cancel_service_startup_info( NULL, startup_id, envs );
00703 return false;
00704 }
00705 return start_service(service, urls, envs, startup_id, blind, false, msg);
00706 }
00707
00708 bool
00709 KLauncher::start_service(KService::Ptr service, const QStringList &_urls,
00710 const QStringList &envs, const QString &startup_id,
00711 bool blind, bool autoStart, const QDBusMessage &msg)
00712 {
00713 QStringList urls = _urls;
00714 if (!service->isValid())
00715 {
00716 requestResult.result = ENOEXEC;
00717 requestResult.error = i18n("Service '%1' is malformatted.", service->entryPath());
00718 cancel_service_startup_info( NULL, startup_id, envs );
00719 return false;
00720 }
00721 KLaunchRequest *request = new KLaunchRequest;
00722 request->autoStart = autoStart;
00723
00724 if ((urls.count() > 1) && !service->allowMultipleFiles())
00725 {
00726
00727
00728
00729
00730
00731 QStringList::ConstIterator it = urls.begin();
00732 for(++it;
00733 it != urls.end();
00734 ++it)
00735 {
00736 QStringList singleUrl;
00737 singleUrl.append(*it);
00738 QString startup_id2 = startup_id;
00739 if( !startup_id2.isEmpty() && startup_id2 != "0" )
00740 startup_id2 = "0";
00741 start_service( service, singleUrl, envs, startup_id2, true, false, msg);
00742 }
00743 QString firstURL = *(urls.begin());
00744 urls.clear();
00745 urls.append(firstURL);
00746 }
00747 createArgs(request, service, urls);
00748
00749
00750 if (!request->arg_list.count())
00751 {
00752 requestResult.result = ENOEXEC;
00753 requestResult.error = i18n("Service '%1' is malformatted.", service->entryPath());
00754 delete request;
00755 cancel_service_startup_info( NULL, startup_id, envs );
00756 return false;
00757 }
00758
00759 request->name = request->arg_list.takeFirst();
00760 request->dbus_startup_type = service->dbusStartupType();
00761
00762 if ((request->dbus_startup_type == KService::DBusUnique) ||
00763 (request->dbus_startup_type == KService::DBusMulti))
00764 {
00765 QVariant v = service->property("X-DBUS-ServiceName");
00766 if (v.isValid())
00767 request->dbus_name = v.toString().toUtf8();
00768 if (request->dbus_name.isEmpty())
00769 {
00770 request->dbus_name = "org.kde." + QFile::encodeName(KRun::binaryName(service->exec(), true));
00771 }
00772 }
00773
00774 request->pid = 0;
00775 request->envs = envs;
00776 send_service_startup_info( request, service, startup_id, envs );
00777
00778
00779 if (!blind && !autoStart)
00780 {
00781 msg.setDelayedReply(true);
00782 request->transaction = msg;
00783 }
00784 queueRequest(request);
00785 return true;
00786 }
00787
00788 void
00789 KLauncher::send_service_startup_info( KLaunchRequest *request, KService::Ptr service, const QString& startup_id,
00790 const QStringList &envs )
00791 {
00792 #ifdef Q_WS_X11
00793 request->startup_id = "0";
00794 if( startup_id == "0" )
00795 return;
00796 bool silent;
00797 QByteArray wmclass;
00798 if( !KRun::checkStartupNotify( QString(), service.data(), &silent, &wmclass ))
00799 return;
00800 KStartupInfoId id;
00801 id.initId( startup_id.toLatin1() );
00802 QString dpy_str;
00803 foreach (const QString &env, envs) {
00804 if (env.startsWith(QLatin1String("DISPLAY=")))
00805 dpy_str = env.mid(8);
00806 }
00807 Display* dpy = NULL;
00808 if( !dpy_str.isEmpty() && mCached_dpy != NULL
00809 && dpy_str != QLatin1String(XDisplayString(mCached_dpy)) )
00810 dpy = mCached_dpy;
00811 if( dpy == NULL )
00812 dpy = XOpenDisplay( dpy_str.toLatin1().constData() );
00813 request->startup_id = id.id();
00814 if( dpy == NULL )
00815 {
00816 cancel_service_startup_info( request, startup_id, envs );
00817 return;
00818 }
00819
00820 request->startup_dpy = dpy_str;
00821
00822 KStartupInfoData data;
00823 data.setName( service->name());
00824 data.setIcon( service->icon());
00825 data.setDescription( i18n( "Launching %1" , service->name()));
00826 if( !wmclass.isEmpty())
00827 data.setWMClass( wmclass );
00828 if( silent )
00829 data.setSilent( KStartupInfoData::Yes );
00830
00831 KStartupInfo::sendStartupX( dpy, id, data );
00832 if( mCached_dpy != dpy && mCached_dpy != NULL )
00833 XCloseDisplay( mCached_dpy );
00834 mCached_dpy = dpy;
00835 return;
00836 #else
00837 return;
00838 #endif
00839 }
00840
00841 void
00842 KLauncher::cancel_service_startup_info( KLaunchRequest* request, const QString& startup_id,
00843 const QStringList &envs )
00844 {
00845 #ifdef Q_WS_X11
00846 if( request != NULL )
00847 request->startup_id = "0";
00848 if( !startup_id.isEmpty() && startup_id != "0" )
00849 {
00850 QString dpy_str;
00851 foreach (const QString &env, envs) {
00852 if (env.startsWith(QLatin1String("DISPLAY=")))
00853 dpy_str = env.mid(8);
00854 }
00855 Display* dpy = NULL;
00856 if( !dpy_str.isEmpty() && mCached_dpy != NULL
00857 && dpy_str != QLatin1String(XDisplayString( mCached_dpy )) )
00858 dpy = mCached_dpy;
00859 if( dpy == NULL )
00860 dpy = XOpenDisplay( dpy_str.toLatin1().constData() );
00861 if( dpy == NULL )
00862 return;
00863 KStartupInfoId id;
00864 id.initId( startup_id.toLatin1() );
00865 KStartupInfo::sendFinishX( dpy, id );
00866 if( mCached_dpy != dpy && mCached_dpy != NULL )
00867 XCloseDisplay( mCached_dpy );
00868 mCached_dpy = dpy;
00869 }
00870 #endif
00871 }
00872
00873 bool
00874 KLauncher::kdeinit_exec(const QString &app, const QStringList &args,
00875 const QString& workdir, const QStringList &envs,
00876 const QString &startup_id, bool wait, const QDBusMessage &msg)
00877 {
00878 KLaunchRequest *request = new KLaunchRequest;
00879 request->autoStart = false;
00880
00881 for(QStringList::ConstIterator it = args.begin();
00882 it != args.end();
00883 ++it)
00884 {
00885 QString arg = *it;
00886 request->arg_list.append(arg.toLocal8Bit());
00887 }
00888
00889 request->name = app.toLocal8Bit();
00890
00891 if (wait)
00892 request->dbus_startup_type = KService::DBusWait;
00893 else
00894 request->dbus_startup_type = KService::DBusNone;
00895 request->pid = 0;
00896 #ifdef Q_WS_X11
00897 request->startup_id = startup_id;
00898 #endif
00899 request->envs = envs;
00900 request->cwd = workdir;
00901 if( !app.endsWith("kbuildsycoca4") )
00902 {
00903
00904 KService::Ptr service = KService::serviceByDesktopName( app.mid( app.lastIndexOf( '/' ) + 1 ));
00905 if (service)
00906 send_service_startup_info( request, service,
00907 startup_id, QStringList());
00908 else
00909 cancel_service_startup_info( request, startup_id, envs );
00910 }
00911 msg.setDelayedReply(true);
00912 request->transaction = msg;
00913 queueRequest(request);
00914 return true;
00915 }
00916
00917 void
00918 KLauncher::queueRequest(KLaunchRequest *request)
00919 {
00920 requestQueue.append( request );
00921 if (!bProcessingQueue)
00922 {
00923 bProcessingQueue = true;
00924 QTimer::singleShot(0, this, SLOT( slotDequeue() ));
00925 }
00926 }
00927
00928 void
00929 KLauncher::slotDequeue()
00930 {
00931 do {
00932 KLaunchRequest *request = requestQueue.takeFirst();
00933
00934 request->status = KLaunchRequest::Launching;
00935 requestStart(request);
00936 if (request->status != KLaunchRequest::Launching)
00937 {
00938
00939 requestDone( request );
00940 continue;
00941 }
00942 } while(requestQueue.count());
00943 bProcessingQueue = false;
00944 }
00945
00946 void
00947 KLauncher::createArgs( KLaunchRequest *request, const KService::Ptr service ,
00948 const QStringList &urls)
00949 {
00950 const QStringList params = KRun::processDesktopExec(*service, urls);
00951
00952 for(QStringList::ConstIterator it = params.begin();
00953 it != params.end(); ++it)
00954 {
00955 request->arg_list.append(*it);
00956 }
00957 request->cwd = service->path();
00958 }
00959
00961
00962 pid_t
00963 KLauncher::requestHoldSlave(const KUrl &url, const QString &app_socket)
00964 {
00965 IdleSlave *slave = 0;
00966 foreach (IdleSlave *p, mSlaveList)
00967 {
00968 if (p->onHold(url))
00969 {
00970 slave = p;
00971 break;
00972 }
00973 }
00974 if (slave)
00975 {
00976 mSlaveList.removeAll(slave);
00977 slave->connect(app_socket);
00978 return slave->pid();
00979 }
00980 return 0;
00981 }
00982
00983
00984 pid_t
00985 KLauncher::requestSlave(const QString &protocol,
00986 const QString &host,
00987 const QString &app_socket,
00988 QString &error)
00989 {
00990 IdleSlave *slave = 0;
00991 foreach (IdleSlave *p, mSlaveList)
00992 {
00993 if (p->match(protocol, host, true))
00994 {
00995 slave = p;
00996 break;
00997 }
00998 }
00999 if (!slave)
01000 {
01001 foreach (IdleSlave *p, mSlaveList)
01002 {
01003 if (p->match(protocol, host, false))
01004 {
01005 slave = p;
01006 break;
01007 }
01008 }
01009 }
01010 if (!slave)
01011 {
01012 foreach (IdleSlave *p, mSlaveList)
01013 {
01014 if (p->match(protocol, QString(), false))
01015 {
01016 slave = p;
01017 break;
01018 }
01019 }
01020 }
01021 if (slave)
01022 {
01023 mSlaveList.removeAll(slave);
01024 slave->connect(app_socket);
01025 return slave->pid();
01026 }
01027
01028 QString name = KProtocolInfo::exec(protocol);
01029 if (name.isEmpty())
01030 {
01031 error = i18n("Unknown protocol '%1'.\n", protocol);
01032 return 0;
01033 }
01034
01035 QStringList arg_list;
01036 #ifdef Q_WS_WIN
01037 arg_list << name;
01038 arg_list << protocol;
01039 arg_list << mConnectionServer.address();
01040 arg_list << app_socket;
01041 name = KStandardDirs::findExe("kioslave");
01042 #else
01043 QString arg1 = protocol;
01044 QString arg2 = mConnectionServer.address();
01045 QString arg3 = app_socket;
01046 arg_list.append(arg1);
01047 arg_list.append(arg2);
01048 arg_list.append(arg3);
01049 #endif
01050
01051 kDebug(7016) << "KLauncher: launching new slave " << name << " with protocol=" << protocol
01052 << " args=" << arg_list << endl;
01053
01054 #ifdef Q_OS_UNIX
01055 if (mSlaveDebug == arg1)
01056 {
01057 klauncher_header request_header;
01058 request_header.cmd = LAUNCHER_DEBUG_WAIT;
01059 request_header.arg_length = 0;
01060 write(kdeinitSocket, &request_header, sizeof(request_header));
01061 }
01062 if (mSlaveValgrind == arg1)
01063 {
01064 arg_list.prepend(QFile::encodeName(KLibLoader::findLibrary(name.toLocal8Bit())));
01065 arg_list.prepend(QFile::encodeName(KStandardDirs::locate("exe", "kioslave")));
01066 name = "valgrind";
01067 if (!mSlaveValgrindSkin.isEmpty()) {
01068 arg_list.prepend(QLatin1String("--tool=") + mSlaveValgrindSkin);
01069 } else
01070 arg_list.prepend(QLatin1String("--tool=memcheck"));
01071 }
01072 #endif
01073 KLaunchRequest *request = new KLaunchRequest;
01074 request->autoStart = false;
01075 request->name = name;
01076 request->arg_list = arg_list;
01077 request->dbus_startup_type = KService::DBusNone;
01078 request->pid = 0;
01079 #ifdef Q_WS_X11
01080 request->startup_id = "0";
01081 #endif
01082 request->status = KLaunchRequest::Launching;
01083 requestStart(request);
01084 pid_t pid = request->pid;
01085
01086
01087
01088
01089 requestDone(request);
01090 if (!pid)
01091 {
01092 error = i18n("Error loading '%1'.\n", name);
01093 }
01094 return pid;
01095 }
01096
01097 void
01098 KLauncher::waitForSlave(int pid, const QDBusMessage &msg)
01099 {
01100 foreach (IdleSlave *slave, mSlaveList)
01101 {
01102 if (slave->pid() == static_cast<pid_t>(pid))
01103 return;
01104 }
01105 SlaveWaitRequest *waitRequest = new SlaveWaitRequest;
01106 msg.setDelayedReply(true);
01107 waitRequest->transaction = msg;
01108 waitRequest->pid = static_cast<pid_t>(pid);
01109 mSlaveWaitRequest.append(waitRequest);
01110 }
01111
01112 void
01113 KLauncher::acceptSlave()
01114 {
01115 IdleSlave *slave = new IdleSlave(this);
01116 mConnectionServer.setNextPendingConnection(&slave->mConn);
01117 mSlaveList.append(slave);
01118 connect(slave, SIGNAL(destroyed()), this, SLOT(slotSlaveGone()));
01119 connect(slave, SIGNAL(statusUpdate(IdleSlave *)),
01120 this, SLOT(slotSlaveStatus(IdleSlave *)));
01121 if (!mTimer.isActive())
01122 {
01123 mTimer.start(1000*10);
01124 }
01125 }
01126
01127 void
01128 KLauncher::slotSlaveStatus(IdleSlave *slave)
01129 {
01130 QMutableListIterator<SlaveWaitRequest *> it(mSlaveWaitRequest);
01131 while(it.hasNext())
01132 {
01133 SlaveWaitRequest *waitRequest = it.next();
01134 if (waitRequest->pid == slave->pid())
01135 {
01136 QDBusConnection::sessionBus().send(waitRequest->transaction.createReply());
01137 it.remove();
01138 delete waitRequest;
01139 }
01140 }
01141 }
01142
01143 void
01144 KLauncher::slotSlaveGone()
01145 {
01146 IdleSlave *slave = (IdleSlave *) sender();
01147 mSlaveList.removeAll(slave);
01148 if ((mSlaveList.count() == 0) && (mTimer.isActive()))
01149 {
01150 mTimer.stop();
01151 }
01152 }
01153
01154 void
01155 KLauncher::idleTimeout()
01156 {
01157 bool keepOneFileSlave=true;
01158 time_t now = time(0);
01159 foreach (IdleSlave *slave, mSlaveList)
01160 {
01161 if ((slave->protocol()=="file") && (keepOneFileSlave))
01162 keepOneFileSlave=false;
01163 else if (slave->age(now) > SLAVE_MAX_IDLE)
01164 {
01165
01166 delete slave;
01167 }
01168 }
01169 }
01170
01171 void KLauncher::reparseConfiguration()
01172 {
01173 KProtocolManager::reparseConfiguration();
01174 foreach (IdleSlave *slave, mSlaveList)
01175 slave->reparseConfiguration();
01176 }
01177
01178 #ifdef Q_WS_WIN
01179 void
01180 KLauncher::slotGotOutput()
01181 {
01182 KProcess *p = static_cast<KProcess *>(sender());
01183 QByteArray _stdout = p->readAllStandardOutput();
01184 kDebug(7016) << _stdout.data();
01185 }
01186
01187 void
01188 KLauncher::slotFinished(int exitCode, QProcess::ExitStatus exitStatus )
01189 {
01190 KProcess *p = static_cast<KProcess *>(sender());
01191 kDebug(7016) << "process finished exitcode=" << exitCode << "exitStatus=" << exitStatus;
01192
01193 foreach (KLaunchRequest *request, requestList)
01194 {
01195 if (request->process == p)
01196 {
01197 kDebug() << "found process setting to done";
01198 if (exitCode == 0 && exitStatus == QProcess::NormalExit)
01199 request->status = KLaunchRequest::Done;
01200 else
01201 request->status = KLaunchRequest::Error;
01202 requestDone(request);
01203 request->process = 0;
01204 }
01205 }
01206 delete p;
01207 }
01208 #endif
01209
01210 #include "klauncher.moc"