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
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"
QString i18n(const char *text)
bool start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, const QDBusMessage &msg)
Start a service by desktop path.
QList< KLaunchRequest * > requestList
serviceResult requestResult
#define LAUNCHER_EXT_EXEC
void cancel_service_startup_info(KLaunchRequest *request, const QByteArray &startup_id, const QStringList &envs)
int age(time_t now) const
void slotSlaveStatus(IdleSlave *)
bool onHold(const KUrl &url) const
void autoStart(int phase=1)
static Ptr serviceByDesktopName(const QString &_name)
bool checkForHeldSlave(const QString &url)
Return true of there is a slave held for url.
static QString locate(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
pid_t requestHoldSlave(const KUrl &url, const QString &app_socket)
void connect(const QString &app_socket)
KIO::ConnectionServer mConnectionServer
void exec_blind(const QString &name, const QStringList &arg_list, const QStringList &envs, const QString &startup_id)
Starts a program.
QVariant property(const QString &_name, QVariant::Type t) const
bool kdeinit_exec(const QString &app, const QStringList &args, const QString &workdir, const QStringList &envs, const QString &startup_id, bool wait, const QDBusMessage &msg)
static KLauncher * g_klauncher_self
void reparseConfiguration()
void reparseConfiguration()
static QDebug kError(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
IdleSlave(QObject *parent)
void setOutputChannelMode(OutputChannelMode mode)
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
static void appendLong(QByteArray &ba, long l)
void send_service_startup_info(KLaunchRequest *request, KService::Ptr service, const QByteArray &startup_id, const QStringList &envs)
QList< SlaveWaitRequest * > mSlaveWaitRequest
KLaunchRequest * lastRequest
static bool isAuthorizedDesktopFile(const QString &path)
void slotFinished(int exitCode, QProcess::ExitStatus exitStatus)
#define LAUNCHER_EXEC_NEW
#define LAUNCHER_DEBUG_WAIT
KService::DBusStartupType dbus_startup_type
DBusStartupType dbusStartupType() const
bool start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, const QDBusMessage &msg)
Start a service by desktop name.
pid_t requestSlave(const QString &protocol, const QString &host, const QString &app_socket, QString &error)
const char * commandToString(int command)
bool start_service_by_name(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, const QDBusMessage &msg)
Start a service by (translated) name - deprecated.
#define LAUNCHER_CHILD_DIED
void statusUpdate(IdleSlave *)
#define LAUNCHER_TERMINATE_KDEINIT
static bool matchesPendingRequest(const QString &appId, const QString &pendingAppId)
static const char *const s_DBusStartupTypeToString[]
void processDied(pid_t pid, long exitStatus)
static Ptr serviceByDesktopPath(const QString &_path)
QList< IdleSlave * > mSlaveList
bool allowMultipleFiles() const
void setLaunchEnv(const QString &name, const QString &value)
bool match(const QString &protocol, const QString &host, bool connected) const
QList< KLaunchRequest * > requestQueue
QString tolerant_dbus_name
static QString exec(const QString &protocol)
void waitForSlave(int pid, const QDBusMessage &msg)
void slotKDEInitData(int)
static Ptr serviceByName(const QString &_name)
#define K_EINTR_LOOP(var, cmd)
void requestDone(KLaunchRequest *request)
void requestStart(KLaunchRequest *request)
static int read_socket(int sock, char *buffer, int len)
static QString findExe(const QString &appname, const QString &pathstr=QString(), SearchOptions options=NoSearchOptions)
const KComponentData & mainComponent()
void processRequestReturn(int status, const QByteArray &requestData)
void queueRequest(KLaunchRequest *)
static QDebug kWarning(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
bool start_service(KService::Ptr service, const QStringList &urls, const QStringList &envs, const QByteArray &startup_id, bool blind, bool autoStart, const QDBusMessage &msg)
void createArgs(KLaunchRequest *request, const KService::Ptr service, const QStringList &url)
QString mSlaveValgrindSkin
void slotNameOwnerChanged(const QString &name, const QString &oldOnwer, const QString &newOwner)
void setProgram(const QString &exe, const QStringList &args=QStringList())
ssize_t kde_safe_write(int fd, const void *buf, size_t count)