20 #define QT_NO_CAST_FROM_ASCII
36 #include <kstartupinfo.h>
40 #include <QtCore/QFile>
41 #include <qplatformdefs.h>
48 #include <kprotocolmanager.h>
56 #include <kio/global.h>
57 #include <kio/connection.h>
58 #include <kio/slaveinterface.h>
61 #define SLAVE_MAX_IDLE 30
66 {
"DBusNone",
"DBusUnique",
"DBusMulti",
"DBusWait",
"ERROR" };
73 QObject::connect(&
mConn, SIGNAL(readyRead()),
this, SLOT(
gotInput()));
75 mConn.send( CMD_SLAVE_STATUS );
81 template<
int T>
struct PIDType {
typedef pid_t PID_t; } ;
82 template<>
struct PIDType<2> {
typedef qint16 PID_t; } ;
83 template<>
struct PIDType<4> {
typedef qint32 PID_t; } ;
90 if (
mConn.read( &cmd, data) == -1)
96 else if (cmd == MSG_SLAVE_ACK)
100 else if (cmd != MSG_SLAVE_STATUS)
102 kError(7016) <<
"SlavePool: Unexpected data from slave." << endl;
107 QDataStream stream( data );
108 PIDType<sizeof(pid_t)>::PID_t stream_pid;
113 stream >> stream_pid >> protocol >> host >> b;
126 mProtocol = QString::fromLatin1(protocol);
136 QDataStream stream( &data, QIODevice::WriteOnly);
137 stream << app_socket;
138 mConn.send( CMD_SLAVE_CONNECT, data );
145 mConn.send( CMD_REPARSECONFIGURATION );
154 if (host.isEmpty()) {
164 return (url ==
mUrl);
177 #define K_EINTR_LOOP(var, cmd) \
180 } while (var == -1 && errno == EINTR)
187 qWarning() <<
"write failed:" << strerror(errno);
191 #ifndef USE_KPROCESS_FOR_KIOSLAVES
194 kdeinitSocket(_kdeinitSocket)
206 mAutoTimer.setSingleShot(
true);
208 QDBusConnection::sessionBus().registerObject(QLatin1String(
"/KLauncher"),
this);
210 connect(&mAutoTimer, SIGNAL(
timeout()),
this, SLOT(slotAutoStart()));
211 connect(QDBusConnection::sessionBus().interface(),
215 mConnectionServer.listenForRemote();
216 connect(&mConnectionServer, SIGNAL(newConnection()), SLOT(acceptSlave()));
217 if (!mConnectionServer.isListening())
220 qDebug(
"KLauncher: Fatal error, can't create tempfile!");
224 connect(&mTimer, SIGNAL(
timeout()), SLOT(idleTimeout()));
226 #ifndef USE_KPROCESS_FOR_KIOSLAVES
227 kdeinitNotifier =
new QSocketNotifier(kdeinitSocket, QSocketNotifier::Read);
228 connect(kdeinitNotifier, SIGNAL(activated(
int)),
229 this, SLOT(slotKDEInitData(
int)));
230 kdeinitNotifier->setEnabled(
true );
233 bProcessingQueue =
false;
235 mSlaveDebug = QString::fromLocal8Bit(qgetenv(
"KDE_SLAVE_DEBUG_WAIT"));
236 if (!mSlaveDebug.isEmpty())
238 qWarning(
"Klauncher running in slave-debug mode for slaves of protocol '%s'", qPrintable(mSlaveDebug));
240 mSlaveValgrind = QString::fromLocal8Bit(qgetenv(
"KDE_SLAVE_VALGRIND"));
241 if (!mSlaveValgrind.isEmpty())
243 mSlaveValgrindSkin = QString::fromLocal8Bit(qgetenv(
"KDE_SLAVE_VALGRIND_SKIN"));
244 qWarning(
"Klauncher running slaves through valgrind for slaves of protocol '%s'", qPrintable(mSlaveValgrind));
246 #ifdef USE_KPROCESS_FOR_KIOSLAVES
247 kDebug(7016) <<
"LAUNCHER_OK";
252 kde_safe_write(kdeinitSocket, &request_header,
sizeof(request_header));
284 #ifndef USE_KPROCESS_FOR_KIOSLAVES
286 QByteArray requestData;
287 requestData.append(name.toLocal8Bit()).append(
'\0').append(value.toLocal8Bit()).append(
'\0');
289 request_header.
arg_length = requestData.size();
290 kde_safe_write(kdeinitSocket, &request_header,
sizeof(request_header));
298 #ifndef USE_KPROCESS_FOR_KIOSLAVES
307 int bytes_left = len;
308 while (bytes_left > 0) {
317 timeval tm = { 30, 0 };
320 select( sock + 1, &in, 0, 0, &tm );
321 if( !FD_ISSET( sock, &in )) {
322 kDebug(7016) <<
"read_socket" << sock <<
"nothing to read, kdeinit4 must be dead";
326 result = read(sock, buffer, bytes_left);
332 else if (result == 0)
334 else if ((result == -1) && (errno != EINTR))
344 #ifndef USE_KPROCESS_FOR_KIOSLAVES
346 QByteArray requestData;
348 int result =
read_socket(kdeinitSocket, (
char *) &request_header,
349 sizeof( request_header));
352 kDebug(7016) <<
"Exiting on read_socket errno:" << errno;
353 KDE_signal( SIGHUP, SIG_IGN);
354 KDE_signal( SIGTERM, SIG_IGN);
357 requestData.resize(request_header.
arg_length);
358 result =
read_socket(kdeinitSocket, (
char *) requestData.data(),
370 request_data = (
long *) requestData.data();
377 request_data = (
long *) requestData.data();
399 if (!requestData.isEmpty())
405 kWarning(7016)<<
"Unexpected request return" << (
unsigned int) status;
411 #ifdef KLAUNCHER_VERBOSE_OUTPUT
412 kDebug(7016) << pid <<
"exitStatus=" << exitStatus;
414 Q_UNUSED(exitStatus);
419 #ifdef KLAUNCHER_VERBOSE_OUTPUT
420 kDebug(7016) <<
" had pending request" << request->
pid;
422 if (request->
pid == pid)
427 && QDBusConnection::sessionBus().interface()->isServiceRegistered(request->
dbus_name)) {
429 #ifdef KLAUNCHER_VERBOSE_OUTPUT
430 kDebug(7016) << pid <<
"running as a unique app";
434 #ifdef KLAUNCHER_VERBOSE_OUTPUT
435 kDebug(7016) << pid <<
"died, requestDone. status=" << request->
status;
442 #ifdef KLAUNCHER_VERBOSE_OUTPUT
443 kDebug(7016) <<
"found no pending requests for PID" << pid;
452 const QString newAppId = appId.left(appId.lastIndexOf(QLatin1Char(
'-')));
456 if (pendingAppId.startsWith(QLatin1String(
"*."))) {
457 const QString pendingName = pendingAppId.mid(2);
458 const QString appName = newAppId.mid(newAppId.lastIndexOf(QLatin1Char(
'.'))+1);
460 return appName == pendingName;
463 return newAppId == pendingAppId;
471 if (appId.isEmpty() || newOwner.isEmpty())
474 #ifdef KLAUNCHER_VERBOSE_OUTPUT
475 kDebug(7016) <<
"new app" << appId;
482 #ifdef KLAUNCHER_VERBOSE_OUTPUT
488 QDBusConnection::sessionBus().interface()->isServiceRegistered(request->
dbus_name)) {
490 #ifdef KLAUNCHER_VERBOSE_OUTPUT
491 kDebug(7016) <<
"OK, unique app" << request->
dbus_name <<
"is running";
496 #ifdef KLAUNCHER_VERBOSE_OUTPUT
497 kDebug(7016) <<
"unique app" << request->
dbus_name <<
"not running yet";
503 #ifdef KLAUNCHER_VERBOSE_OUTPUT
506 if (rAppId.isEmpty())
510 #ifdef KLAUNCHER_VERBOSE_OUTPUT
511 kDebug(7016) <<
"ok, request done";
539 if (service.isEmpty())
599 KStartupInfo::sendFinishX( dpy,
id );
613 if (request->
transaction.type() != QDBusMessage::InvalidMessage)
624 #ifdef KLAUNCHER_VERBOSE_OUTPUT
625 kDebug(7016) <<
"removing done request" << request->
name <<
"PID" << request->
pid;
634 const int sz = ba.size();
635 ba.resize(sz +
sizeof(
long));
636 memcpy(ba.data() + sz, &l,
sizeof(long));
642 #ifdef USE_KPROCESS_FOR_KIOSLAVES
648 connect(process ,SIGNAL(readyReadStandardOutput()),
this, SLOT(
slotGotOutput()) );
649 connect(process ,SIGNAL(finished(
int,QProcess::ExitStatus)),
this, SLOT(
slotFinished(
int,QProcess::ExitStatus)) );
660 if (!bundlepath.isEmpty())
661 executable = bundlepath;
666 if (!process->waitForStarted())
672 request->
pid = process->
pid();
673 QByteArray data((
char *)&request->
pid,
sizeof(
int));
682 QByteArray requestData;
683 requestData.reserve(1024);
686 requestData.append(request->
name.toLocal8Bit());
687 requestData.append(
'\0');
689 requestData.append(arg.toLocal8Bit()).append(
'\0');
692 requestData.append(env.toLocal8Bit()).append(
'\0');
697 requestData.append(request->
startup_id).append(
'\0');
699 if (!request->
cwd.isEmpty())
700 requestData.append(QFile::encodeName(request->
cwd)).append(
'\0');
707 request_header.
arg_length = requestData.length();
709 #ifdef KLAUNCHER_VERBOSE_OUTPUT
714 kde_safe_write(kdeinitSocket, &request_header,
sizeof(request_header));
715 kde_safe_write(kdeinitSocket, requestData.data(), requestData.length());
722 while (lastRequest != 0);
730 request->
name = name;
735 request->
envs = envs;
752 const QStringList &envs,
const QString& startup_id,
bool blind,
const QDBusMessage &msg)
756 #ifndef KDE_NO_DEPRECATED
766 return start_service(service, urls, envs, startup_id.toLocal8Bit(), blind,
false, msg);
771 const QStringList &envs,
const QString& startup_id,
bool blind,
const QDBusMessage &msg)
775 const QFileInfo fi(serviceName);
776 if (fi.isAbsolute() && fi.exists())
779 service =
new KService(serviceName);
795 return start_service(service, urls, envs, startup_id.toLocal8Bit(), blind,
false, msg);
800 const QStringList &envs,
const QString& startup_id,
bool blind,
const QDBusMessage &msg)
810 return start_service(service, urls, envs, startup_id.toLocal8Bit(), blind,
false, msg);
815 const QStringList &envs,
const QByteArray &startup_id,
816 bool blind,
bool autoStart,
const QDBusMessage &msg)
821 if (!service->isValid() || !runPermitted)
824 if (service->isValid())
841 QStringList::ConstIterator it = urls.constBegin();
843 it != urls.constEnd();
847 singleUrl.append(*it);
848 QByteArray startup_id2 = startup_id;
849 if( !startup_id2.isEmpty() && startup_id2 !=
"0" )
851 start_service( service, singleUrl, envs, startup_id2,
true,
false, msg);
853 QString firstURL = *(urls.begin());
855 urls.append(firstURL);
871 if (request->
name.endsWith(QLatin1String(
"/kioexec"))) {
877 request->
dbus_name = QString::fromLatin1(
"org.kde.kioexec");
888 const QString binName = KRun::binaryName(service->
exec(),
true);
889 request->
dbus_name = QString::fromLatin1(
"org.kde.") + binName;
895 #ifdef KLAUNCHER_VERBOSE_OUTPUT
901 request->
envs = envs;
905 if (!blind && !autoStart)
907 msg.setDelayedReply(
true);
920 if (startup_id ==
"0")
924 if( !KRun::checkStartupNotify(
QString(), service.
data(), &silent, &wmclass ))
927 id.initId(startup_id);
929 foreach (
const QString &env, envs) {
930 if (env.startsWith(QLatin1String(
"DISPLAY=")))
931 dpy_str = env.mid(8).toLocal8Bit();
937 dpy = XOpenDisplay(dpy_str);
946 KStartupInfoData data;
947 data.setName( service->name());
948 data.setIcon( service->
icon());
949 data.setDescription(
i18n(
"Launching %1" , service->name()));
950 if( !wmclass.isEmpty())
951 data.setWMClass( wmclass );
953 data.setSilent( KStartupInfoData::Yes );
954 data.setApplicationId( service->entryPath());
956 KStartupInfo::sendStartupX( dpy,
id, data );
971 if( request != NULL )
973 if( !startup_id.isEmpty() && startup_id !=
"0" )
976 foreach (
const QString &env, envs) {
977 if (env.startsWith(QLatin1String(
"DISPLAY=")))
978 dpy_str = env.mid(8);
982 && dpy_str != QLatin1String(XDisplayString(
mCached_dpy )) )
985 dpy = XOpenDisplay( dpy_str.toLatin1().constData() );
989 id.initId(startup_id);
990 KStartupInfo::sendFinishX( dpy,
id );
1001 const QString &startup_id,
bool wait,
const QDBusMessage &msg)
1006 request->
name = app;
1013 request->
startup_id = startup_id.toLocal8Bit();
1015 request->
envs = envs;
1016 request->
cwd = workdir;
1018 if (!app.endsWith(QLatin1String(
"kbuildsycoca4"))) {
1020 const QString desktopName = app.mid(app.lastIndexOf(QLatin1Char(
'/')) + 1);
1029 msg.setDelayedReply(
true);
1057 #ifdef KLAUNCHER_VERBOSE_OUTPUT
1058 kDebug(7016) <<
"Request handled already";
1071 const QStringList params = KRun::processDesktopExec(*service, urls);
1073 for(QStringList::ConstIterator it = params.begin();
1074 it != params.end(); ++it)
1078 request->
cwd = service->
path();
1099 return slave->
pid();
1113 if (p->
match(protocol, host,
true))
1123 if (p->
match(protocol, host,
false))
1145 return slave->
pid();
1151 error =
i18n(
"Unknown protocol '%1'.\n", protocol);
1156 #ifdef USE_KPROCESS_FOR_KIOSLAVES
1158 arg_list << protocol;
1160 arg_list << app_socket;
1166 arg_list.append(arg1);
1167 arg_list.append(arg2);
1168 arg_list.append(arg3);
1171 kDebug(7016) <<
"KLauncher: launching new slave " << name <<
" with protocol=" << protocol
1172 <<
" args=" << arg_list << endl;
1177 #ifndef USE_KPROCESS_FOR_KIOSLAVES
1181 kde_safe_write(kdeinitSocket, &request_header,
sizeof(request_header));
1183 name = QString::fromLatin1(
"gdb");
1187 #ifndef USE_KPROCESS_FOR_KIOSLAVES // otherwise we've already done this
1188 KLibrary lib(name, KGlobal::mainComponent());
1192 name = QString::fromLatin1(
"valgrind");
1197 arg_list.prepend(QLatin1String(
"--tool=memcheck"));
1202 request->
name = name;
1211 pid_t pid = request->
pid;
1219 error =
i18n(
"Error loading '%1'.\n", name);
1239 if (slave->
pid() ==
static_cast<pid_t
>(pid))
1243 msg.setDelayedReply(
true);
1245 waitRequest->
pid =
static_cast<pid_t
>(pid);
1255 connect(slave, SIGNAL(destroyed()),
this, SLOT(
slotSlaveGone()));
1256 connect(slave, SIGNAL(statusUpdate(
IdleSlave*)),
1271 if (waitRequest->
pid == slave->
pid())
1273 QDBusConnection::sessionBus().send(waitRequest->
transaction.createReply());
1294 bool keepOneFileSlave=
true;
1295 time_t now = time(0);
1298 if ((slave->
protocol()==QLatin1String(
"file")) && (keepOneFileSlave))
1299 keepOneFileSlave=
false;
1310 KProtocolManager::reparseConfiguration();
1319 #ifdef USE_KPROCESS_FOR_KIOSLAVES
1321 QByteArray _stdout = p->readAllStandardOutput();
1322 kDebug(7016) << _stdout.data();
1329 #ifdef USE_KPROCESS_FOR_KIOSLAVES
1331 kDebug(7016) <<
"process finished exitcode=" << exitCode <<
"exitStatus=" << exitStatus;
1337 #ifdef KLAUNCHER_VERBOSE_OUTPUT
1338 kDebug(7016) <<
"found KProcess, request done";
1340 if (exitCode == 0 && exitStatus == QProcess::NormalExit)
1351 Q_UNUSED(exitStatus);
1359 #ifndef USE_KPROCESS_FOR_KIOSLAVES
1363 kde_safe_write(kdeinitSocket, &request_header,
sizeof(request_header));
1367 #include "klauncher.moc"