20 #define QT_NO_CAST_FROM_ASCII
36 #include <kstartupinfo.h>
40 #include <QtCore/QFile>
47 #include <kprotocolmanager.h>
55 #include <kio/global.h>
56 #include <kio/connection.h>
57 #include <kio/slaveinterface.h>
60 #define SLAVE_MAX_IDLE 30
65 {
"DBusNone",
"DBusUnique",
"DBusMulti",
"DBusWait",
"ERROR" };
74 mConn.send( CMD_SLAVE_STATUS );
80 template<
int T>
struct PIDType {
typedef pid_t PID_t; } ;
81 template<>
struct PIDType<2> {
typedef qint16 PID_t; } ;
82 template<>
struct PIDType<4> {
typedef qint32 PID_t; } ;
89 if (
mConn.read( &cmd, data) == -1)
95 else if (cmd == MSG_SLAVE_ACK)
99 else if (cmd != MSG_SLAVE_STATUS)
101 kError(7016) <<
"SlavePool: Unexpected data from slave." << endl;
106 QDataStream stream( data );
107 PIDType<sizeof(pid_t)>::PID_t stream_pid;
112 stream >> stream_pid >> protocol >> host >> b;
125 mProtocol = QString::fromLatin1(protocol);
135 QDataStream stream( &data, QIODevice::WriteOnly);
136 stream << app_socket;
137 mConn.send( CMD_SLAVE_CONNECT, data );
144 mConn.send( CMD_REPARSECONFIGURATION );
153 if (host.isEmpty()) {
163 return (url ==
mUrl);
174 #ifndef USE_KPROCESS_FOR_KIOSLAVES
177 kdeinitSocket(_kdeinitSocket)
189 mAutoTimer.setSingleShot(
true);
191 QDBusConnection::sessionBus().registerObject(QLatin1String(
"/KLauncher"),
this);
193 connect(&mAutoTimer, SIGNAL(
timeout()),
this, SLOT(slotAutoStart()));
194 connect(QDBusConnection::sessionBus().interface(),
198 mConnectionServer.listenForRemote();
199 connect(&mConnectionServer, SIGNAL(newConnection()), SLOT(acceptSlave()));
200 if (!mConnectionServer.isListening())
203 qDebug(
"KLauncher: Fatal error, can't create tempfile!");
207 connect(&mTimer, SIGNAL(
timeout()), SLOT(idleTimeout()));
209 #ifndef USE_KPROCESS_FOR_KIOSLAVES
210 kdeinitNotifier =
new QSocketNotifier(kdeinitSocket, QSocketNotifier::Read);
211 connect(kdeinitNotifier, SIGNAL(activated(
int)),
212 this, SLOT(slotKDEInitData(
int)));
213 kdeinitNotifier->setEnabled(
true );
216 bProcessingQueue =
false;
218 mSlaveDebug = QString::fromLocal8Bit(qgetenv(
"KDE_SLAVE_DEBUG_WAIT"));
219 if (!mSlaveDebug.isEmpty())
221 qWarning(
"Klauncher running in slave-debug mode for slaves of protocol '%s'", qPrintable(mSlaveDebug));
223 mSlaveValgrind = QString::fromLocal8Bit(qgetenv(
"KDE_SLAVE_VALGRIND"));
224 if (!mSlaveValgrind.isEmpty())
226 mSlaveValgrindSkin = QString::fromLocal8Bit(qgetenv(
"KDE_SLAVE_VALGRIND_SKIN"));
227 qWarning(
"Klauncher running slaves through valgrind for slaves of protocol '%s'", qPrintable(mSlaveValgrind));
229 #ifdef USE_KPROCESS_FOR_KIOSLAVES
230 kDebug(7016) <<
"LAUNCHER_OK";
235 write(kdeinitSocket, &request_header,
sizeof(request_header));
267 #ifndef USE_KPROCESS_FOR_KIOSLAVES
269 QByteArray requestData;
270 requestData.append(name.toLocal8Bit()).append(
'\0').append(value.toLocal8Bit()).append(
'\0');
272 request_header.
arg_length = requestData.size();
273 write(kdeinitSocket, &request_header,
sizeof(request_header));
274 write(kdeinitSocket, requestData.data(), request_header.
arg_length);
281 #ifndef USE_KPROCESS_FOR_KIOSLAVES
290 int bytes_left = len;
291 while (bytes_left > 0) {
300 timeval tm = { 30, 0 };
303 select( sock + 1, &in, 0, 0, &tm );
304 if( !FD_ISSET( sock, &in )) {
305 kDebug(7016) <<
"read_socket" << sock <<
"nothing to read, kdeinit4 must be dead";
309 result = read(sock, buffer, bytes_left);
315 else if (result == 0)
317 else if ((result == -1) && (errno != EINTR))
327 #ifndef USE_KPROCESS_FOR_KIOSLAVES
329 QByteArray requestData;
331 int result =
read_socket(kdeinitSocket, (
char *) &request_header,
332 sizeof( request_header));
335 kDebug(7016) <<
"Exiting on read_socket errno:" << errno;
336 KDE_signal( SIGHUP, SIG_IGN);
337 KDE_signal( SIGTERM, SIG_IGN);
340 requestData.resize(request_header.
arg_length);
341 result =
read_socket(kdeinitSocket, (
char *) requestData.data(),
353 request_data = (
long *) requestData.data();
360 request_data = (
long *) requestData.data();
382 if (!requestData.isEmpty())
388 kWarning(7016)<<
"Unexpected request return" << (
unsigned int) status;
394 #ifdef KLAUNCHER_VERBOSE_OUTPUT
395 kDebug(7016) << pid <<
"exitStatus=" << exitStatus;
397 Q_UNUSED(exitStatus);
402 #ifdef KLAUNCHER_VERBOSE_OUTPUT
403 kDebug(7016) <<
" had pending request" << request->
pid;
405 if (request->
pid == pid)
410 && QDBusConnection::sessionBus().interface()->isServiceRegistered(request->
dbus_name)) {
412 #ifdef KLAUNCHER_VERBOSE_OUTPUT
413 kDebug(7016) << pid <<
"running as a unique app";
417 #ifdef KLAUNCHER_VERBOSE_OUTPUT
418 kDebug(7016) << pid <<
"died, requestDone. status=" << request->
status;
425 #ifdef KLAUNCHER_VERBOSE_OUTPUT
426 kDebug(7016) <<
"found no pending requests for PID" << pid;
435 const QString newAppId = appId.left(appId.lastIndexOf(QLatin1Char(
'-')));
439 if (pendingAppId.startsWith(QLatin1String(
"*."))) {
440 const QString pendingName = pendingAppId.mid(2);
441 const QString appName = newAppId.mid(newAppId.lastIndexOf(QLatin1Char(
'.'))+1);
443 return appName == pendingName;
446 return newAppId == pendingAppId;
454 if (appId.isEmpty() || newOwner.isEmpty())
457 #ifdef KLAUNCHER_VERBOSE_OUTPUT
458 kDebug(7016) <<
"new app" << appId;
465 #ifdef KLAUNCHER_VERBOSE_OUTPUT
471 QDBusConnection::sessionBus().interface()->isServiceRegistered(request->
dbus_name)) {
473 #ifdef KLAUNCHER_VERBOSE_OUTPUT
474 kDebug(7016) <<
"OK, unique app" << request->
dbus_name <<
"is running";
479 #ifdef KLAUNCHER_VERBOSE_OUTPUT
480 kDebug(7016) <<
"unique app" << request->
dbus_name <<
"not running yet";
486 #ifdef KLAUNCHER_VERBOSE_OUTPUT
489 if (rAppId.isEmpty())
493 #ifdef KLAUNCHER_VERBOSE_OUTPUT
494 kDebug(7016) <<
"ok, request done";
522 if (service.isEmpty())
582 KStartupInfo::sendFinishX( dpy,
id );
596 if (request->
transaction.type() != QDBusMessage::InvalidMessage)
607 #ifdef KLAUNCHER_VERBOSE_OUTPUT
608 kDebug(7016) <<
"removing done request" << request->
name <<
"PID" << request->
pid;
617 const int sz = ba.size();
618 ba.resize(sz +
sizeof(
long));
619 memcpy(ba.data() + sz, &l,
sizeof(long));
625 #ifdef USE_KPROCESS_FOR_KIOSLAVES
631 connect(process ,SIGNAL(readyReadStandardOutput()),
this, SLOT(
slotGotOutput()) );
632 connect(process ,SIGNAL(finished(
int,QProcess::ExitStatus)),
this, SLOT(
slotFinished(
int,QProcess::ExitStatus)) );
643 if (!bundlepath.isEmpty())
644 executable = bundlepath;
649 if (!process->waitForStarted())
655 request->
pid = process->
pid();
656 QByteArray data((
char *)&request->
pid,
sizeof(
int));
665 QByteArray requestData;
666 requestData.reserve(1024);
669 requestData.append(request->
name.toLocal8Bit());
670 requestData.append(
'\0');
672 requestData.append(arg.toLocal8Bit()).append(
'\0');
675 requestData.append(env.toLocal8Bit()).append(
'\0');
680 requestData.append(request->
startup_id).append(
'\0');
682 if (!request->
cwd.isEmpty())
683 requestData.append(QFile::encodeName(request->
cwd)).append(
'\0');
690 request_header.
arg_length = requestData.length();
692 #ifdef KLAUNCHER_VERBOSE_OUTPUT
697 write(kdeinitSocket, &request_header,
sizeof(request_header));
698 write(kdeinitSocket, requestData.data(), requestData.length());
705 while (lastRequest != 0);
713 request->
name = name;
718 request->
envs = envs;
735 const QStringList &envs,
const QString& startup_id,
bool blind,
const QDBusMessage &msg)
739 #ifndef KDE_NO_DEPRECATED
749 return start_service(service, urls, envs, startup_id.toLocal8Bit(), blind,
false, msg);
754 const QStringList &envs,
const QString& startup_id,
bool blind,
const QDBusMessage &msg)
758 const QFileInfo fi(serviceName);
759 if (fi.isAbsolute() && fi.exists())
762 service =
new KService(serviceName);
778 return start_service(service, urls, envs, startup_id.toLocal8Bit(), blind,
false, msg);
783 const QStringList &envs,
const QString& startup_id,
bool blind,
const QDBusMessage &msg)
793 return start_service(service, urls, envs, startup_id.toLocal8Bit(), blind,
false, msg);
798 const QStringList &envs,
const QByteArray &startup_id,
799 bool blind,
bool autoStart,
const QDBusMessage &msg)
804 if (!service->
isValid() || !runPermitted)
824 QStringList::ConstIterator it = urls.constBegin();
826 it != urls.constEnd();
830 singleUrl.append(*it);
831 QByteArray startup_id2 = startup_id;
832 if( !startup_id2.isEmpty() && startup_id2 !=
"0" )
834 start_service( service, singleUrl, envs, startup_id2,
true,
false, msg);
836 QString firstURL = *(urls.begin());
838 urls.append(firstURL);
854 if (request->
name.endsWith(QLatin1String(
"/kioexec"))) {
860 request->
dbus_name = QString::fromLatin1(
"org.kde.kioexec");
871 const QString binName = KRun::binaryName(service->
exec(),
true);
872 request->
dbus_name = QString::fromLatin1(
"org.kde.") + binName;
878 #ifdef KLAUNCHER_VERBOSE_OUTPUT
884 request->
envs = envs;
888 if (!blind && !autoStart)
890 msg.setDelayedReply(
true);
903 if (startup_id ==
"0")
907 if( !KRun::checkStartupNotify(
QString(), service.
data(), &silent, &wmclass ))
910 id.initId(startup_id);
912 foreach (
const QString &env, envs) {
913 if (env.startsWith(QLatin1String(
"DISPLAY=")))
914 dpy_str = env.mid(8).toLocal8Bit();
920 dpy = XOpenDisplay(dpy_str);
929 KStartupInfoData data;
930 data.setName( service->
name());
931 data.setIcon( service->
icon());
932 data.setDescription(
i18n(
"Launching %1" , service->
name()));
933 if( !wmclass.isEmpty())
934 data.setWMClass( wmclass );
936 data.setSilent( KStartupInfoData::Yes );
937 data.setApplicationId( service->
entryPath());
939 KStartupInfo::sendStartupX( dpy,
id, data );
954 if( request != NULL )
956 if( !startup_id.isEmpty() && startup_id !=
"0" )
959 foreach (
const QString &env, envs) {
960 if (env.startsWith(QLatin1String(
"DISPLAY=")))
961 dpy_str = env.mid(8);
965 && dpy_str != QLatin1String(XDisplayString(
mCached_dpy )) )
968 dpy = XOpenDisplay( dpy_str.toLatin1().constData() );
972 id.initId(startup_id);
973 KStartupInfo::sendFinishX( dpy,
id );
984 const QString &startup_id,
bool wait,
const QDBusMessage &msg)
996 request->
startup_id = startup_id.toLocal8Bit();
998 request->
envs = envs;
999 request->
cwd = workdir;
1001 if (!app.endsWith(QLatin1String(
"kbuildsycoca4"))) {
1003 const QString desktopName = app.mid(app.lastIndexOf(QLatin1Char(
'/')) + 1);
1012 msg.setDelayedReply(
true);
1040 #ifdef KLAUNCHER_VERBOSE_OUTPUT
1041 kDebug(7016) <<
"Request handled already";
1054 const QStringList params = KRun::processDesktopExec(*service, urls);
1056 for(QStringList::ConstIterator it = params.begin();
1057 it != params.end(); ++it)
1061 request->
cwd = service->
path();
1082 return slave->
pid();
1096 if (p->
match(protocol, host,
true))
1106 if (p->
match(protocol, host,
false))
1128 return slave->
pid();
1134 error =
i18n(
"Unknown protocol '%1'.\n", protocol);
1139 #ifdef USE_KPROCESS_FOR_KIOSLAVES
1141 arg_list << protocol;
1143 arg_list << app_socket;
1149 arg_list.append(arg1);
1150 arg_list.append(arg2);
1151 arg_list.append(arg3);
1154 kDebug(7016) <<
"KLauncher: launching new slave " << name <<
" with protocol=" << protocol
1155 <<
" args=" << arg_list << endl;
1160 #ifndef USE_KPROCESS_FOR_KIOSLAVES
1164 write(kdeinitSocket, &request_header,
sizeof(request_header));
1166 name = QString::fromLatin1(
"gdb");
1170 #ifndef USE_KPROCESS_FOR_KIOSLAVES // otherwise we've already done this
1175 name = QString::fromLatin1(
"valgrind");
1180 arg_list.prepend(QLatin1String(
"--tool=memcheck"));
1185 request->
name = name;
1194 pid_t pid = request->
pid;
1202 error =
i18n(
"Error loading '%1'.\n", name);
1222 if (slave->
pid() ==
static_cast<pid_t
>(pid))
1226 msg.setDelayedReply(
true);
1228 waitRequest->
pid =
static_cast<pid_t
>(pid);
1238 connect(slave, SIGNAL(destroyed()),
this, SLOT(
slotSlaveGone()));
1239 connect(slave, SIGNAL(statusUpdate(
IdleSlave*)),
1254 if (waitRequest->
pid == slave->
pid())
1256 QDBusConnection::sessionBus().send(waitRequest->
transaction.createReply());
1277 bool keepOneFileSlave=
true;
1278 time_t now = time(0);
1281 if ((slave->
protocol()==QLatin1String(
"file")) && (keepOneFileSlave))
1282 keepOneFileSlave=
false;
1302 #ifdef USE_KPROCESS_FOR_KIOSLAVES
1304 QByteArray _stdout = p->readAllStandardOutput();
1305 kDebug(7016) << _stdout.data();
1312 #ifdef USE_KPROCESS_FOR_KIOSLAVES
1314 kDebug(7016) <<
"process finished exitcode=" << exitCode <<
"exitStatus=" << exitStatus;
1320 #ifdef KLAUNCHER_VERBOSE_OUTPUT
1321 kDebug(7016) <<
"found KProcess, request done";
1323 if (exitCode == 0 && exitStatus == QProcess::NormalExit)
1334 Q_UNUSED(exitStatus);
1342 #ifndef USE_KPROCESS_FOR_KIOSLAVES
1346 write(kdeinitSocket, &request_header,
sizeof(request_header));
1350 #include "klauncher.moc"