00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <config.h>
00024
00025
00026 #include <errno.h>
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030
00031 #include <windows.h>
00032 #include <psapi.h>
00033
00034
00035 #include <QtCore/QProcess>
00036 #include <QtCore/QFileInfo>
00037 #include <QtDBus/QtDBus>
00038
00039 #include <kcomponentdata.h>
00040 #include <kstandarddirs.h>
00041 #include <kapplication.h>
00042 #include <kdeversion.h>
00043
00044
00045
00046
00047 #define KDED_EXENAME "kded4"
00048
00049 static KComponentData *s_instance = 0;
00050
00051
00052 int verbose=0;
00053
00055 QList<QProcess*> startedProcesses;
00056
00057 class ProcessListEntry {
00058 public:
00059 ProcessListEntry(HANDLE _handle,char *_path, int _pid )
00060 {
00061 QFileInfo p(_path);
00062 path = p.absolutePath();
00063 name = p.baseName();
00064 handle = _handle;
00065 pid = _pid;
00066 }
00067 QString name;
00068 QString path;
00069 int pid;
00070 HANDLE handle;
00071 friend QDebug operator <<(QDebug out, const ProcessListEntry &c);
00072 };
00073
00074 QDebug operator <<(QDebug out, const ProcessListEntry &c)
00075 {
00076 out << "(ProcessListEntry"
00077 << "name" << c.name
00078 << "path" << c.path
00079 << "pid" << c.pid
00080 << "handle" << c.handle
00081 << ")";
00082 return out;
00083 }
00084
00088 class ProcessList {
00089 public:
00090 ProcessList() {initProcessList(); }
00091 ~ProcessList();
00092 ProcessListEntry *hasProcessInList(const QString &name);
00093 bool terminateProcess(const QString &name);
00094 QList<ProcessListEntry *> &list() { return processList; }
00095 private:
00096 void initProcessList();
00097 void getProcessNameAndID( DWORD processID );
00098 QList<ProcessListEntry *> processList;
00099 };
00100
00101
00102 void ProcessList::getProcessNameAndID( DWORD processID )
00103 {
00104 char szProcessName[MAX_PATH];
00105
00106
00107
00108 HANDLE hProcess = OpenProcess( SYNCHRONIZE|PROCESS_QUERY_INFORMATION |
00109 PROCESS_VM_READ | PROCESS_TERMINATE,
00110 false, processID );
00111
00112
00113 int ret;
00114
00115 if (NULL != hProcess )
00116 {
00117 HMODULE hMod;
00118 DWORD cbNeeded;
00119
00120 if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod),
00121 &cbNeeded) )
00122 {
00123 ret = GetModuleFileNameExA( hProcess, hMod, szProcessName,
00124 sizeof(szProcessName)/sizeof(TCHAR) );
00125 }
00126 }
00127 if (ret > 0)
00128 {
00129 processList << new ProcessListEntry(hProcess,szProcessName,processID );
00130 }
00131 }
00132
00133
00137 void ProcessList::initProcessList()
00138 {
00139
00140
00141 DWORD aProcesses[1024], cbNeeded, cProcesses;
00142 unsigned int i;
00143
00144 if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
00145 return;
00146
00147
00148
00149 cProcesses = cbNeeded / sizeof(DWORD);
00150
00151
00152
00153 for ( i = 0; i < cProcesses; i++ )
00154 if( aProcesses[i] != 0 )
00155 getProcessNameAndID( aProcesses[i] );
00156 }
00157
00158
00159 ProcessList::~ProcessList()
00160 {
00161 ProcessListEntry *ple;
00162 foreach(ple,processList) {
00163 CloseHandle(ple->handle);
00164 delete ple;
00165 }
00166 }
00167
00171 ProcessListEntry *ProcessList::hasProcessInList(const QString &name)
00172 {
00173 ProcessListEntry *ple;
00174 foreach(ple,processList) {
00175 if (ple->name == name || ple->name == name + ".exe") {
00176 return ple;
00177 }
00178 }
00179 return NULL;
00180 }
00181
00185 bool ProcessList::terminateProcess(const QString &name)
00186 {
00187 ProcessListEntry *p = hasProcessInList(name);
00188 if (!p)
00189 return false;
00190 return TerminateProcess(p->handle,0) ? true : false;
00191 }
00192
00193
00194 int launch(const QString &cmd)
00195 {
00196 QProcess *proc = new QProcess();
00197 proc->start(cmd);
00198 proc->waitForStarted();
00199 startedProcesses << proc;
00200 _PROCESS_INFORMATION* _pid = proc->pid();
00201 int pid = _pid ? _pid->dwProcessId : 0;
00202 if (verbose) {
00203 fprintf(stderr,"%s",proc->readAllStandardError().constData());
00204 fprintf(stderr,"%s",proc->readAllStandardOutput().constData());
00205 }
00206 if (pid) {
00207 if (verbose)
00208 fprintf(stderr, "kdeinit4: Launched %s, pid = %ld\n", qPrintable(cmd),(long) pid);
00209 }
00210 else {
00211 if (verbose)
00212 fprintf(stderr, "kdeinit4: could not launch %s, exiting",qPrintable(cmd));
00213 }
00214 return pid;
00215 }
00216
00218 bool checkIfRegisteredInDBus(const QString &name, int _timeout=10)
00219 {
00220 int timeout = _timeout * 5;
00221 while(timeout) {
00222 if ( QDBusConnection::sessionBus().interface()->isServiceRegistered( name ) )
00223 break;
00224 Sleep(200);
00225 timeout--;
00226 }
00227 if (!timeout) {
00228 if (verbose)
00229 fprintf(stderr,"not registered %s in dbus after %d secs\n",qPrintable(name),_timeout);
00230 return false;
00231 }
00232 if (verbose)
00233 fprintf(stderr,"%s is registered in dbus\n",qPrintable(name));
00234 return true;
00235 }
00236
00237 void listAllRunningKDEProcesses(ProcessList &processList)
00238 {
00239 ProcessListEntry *ple;
00240 QString installPrefix = KStandardDirs::installPath("kdedir");
00241
00242 foreach(ple,processList.list())
00243 {
00244 if (ple->path.toLower().startsWith(installPrefix.toLower()))
00245 fprintf(stderr,"path: %s name: %s pid: %u\n", ple->path.toLatin1().data(), ple->name.toLatin1().data(), ple->pid);
00246 }
00247 }
00248
00249 void terminateAllRunningKDEProcesses(ProcessList &processList)
00250 {
00251 ProcessListEntry *ple;
00252 QString installPrefix = KStandardDirs::installPath("kdedir");
00253
00254 foreach(ple,processList.list())
00255 {
00256 if (ple->path.toLower().startsWith(installPrefix.toLower()))
00257 {
00258 if (verbose)
00259 fprintf(stderr,"terminating path: %s name: %s pid: %u\n", ple->path.toLatin1().data(), ple->name.toLatin1().data(), ple->pid);
00260 processList.terminateProcess(ple->name);
00261 }
00262 }
00263 }
00264
00265 void listAllNamedAppsInDBus()
00266 {
00267 QDBusConnection connection = QDBusConnection::sessionBus();
00268 QDBusConnectionInterface *bus = connection.interface();
00269 const QStringList services = bus->registeredServiceNames();
00270 foreach(const QString &service, services) {
00271 if (service.startsWith("org.freedesktop.DBus") || service.startsWith(':'))
00272 continue;
00273 fprintf(stderr, "%s \n", service.toLatin1().data());
00274 }
00275 }
00276
00277 void quitApplicationsOverDBus()
00278 {
00279 QDBusConnection connection = QDBusConnection::sessionBus();
00280 QDBusConnectionInterface *bus = connection.interface();
00281 const QStringList services = bus->registeredServiceNames();
00282 foreach(const QString &service, services) {
00283 if (service.startsWith("org.freedesktop.DBus") || service.startsWith(':'))
00284 continue;
00285 QDBusInterface *iface = new QDBusInterface(service,
00286 QLatin1String("/MainApplication"),
00287
00288 #if QT_VERSION < 0x040402
00289 QLatin1String(""),
00290 #else
00291 QLatin1String("org.kde.KApplication"),
00292 #endif
00293 connection);
00294 if (!iface->isValid()) {
00295 if (verbose)
00296 fprintf(stderr, "invalid interface of service %s\n", service.toLatin1().data());
00297 continue;
00298 }
00299 iface->call("quit");
00300 if (iface->lastError().isValid()) {
00301 if (verbose)
00302 fprintf(stderr,"killing %s with result\n", iface->lastError().message().toLatin1().data());
00303 }
00304 delete iface;
00305 }
00306 }
00307
00308 int main(int argc, char **argv, char **envp)
00309 {
00310 pid_t pid;
00311 bool launch_dbus = true;
00312 bool launch_klauncher = true;
00313 bool launch_kded = true;
00314 bool suicide = false;
00315 bool listProcesses = false;
00316 bool killProcesses = false;
00317 bool listAppsInDBus = false;
00318 bool quitAppsOverDBus = false;
00319 bool shutdown = false;
00320
00322 char **safe_argv = (char **) malloc( sizeof(char *) * argc);
00323 for(int i = 0; i < argc; i++)
00324 {
00325 safe_argv[i] = strcpy((char*)malloc(strlen(argv[i])+1), argv[i]);
00326 if (strcmp(safe_argv[i], "--no-dbus") == 0)
00327 launch_dbus = false;
00328 if (strcmp(safe_argv[i], "--no-klauncher") == 0)
00329 launch_klauncher = false;
00330 if (strcmp(safe_argv[i], "--no-kded") == 0)
00331 launch_kded = false;
00332 if (strcmp(safe_argv[i], "--suicide") == 0)
00333 suicide = true;
00334 #ifdef ENABLE_EXIT
00335 if (strcmp(safe_argv[i], "--exit") == 0)
00336 keep_running = 0;
00337 #endif
00338 if (strcmp(safe_argv[i], "--verbose") == 0)
00339 verbose = 1;
00340 if (strcmp(safe_argv[i], "--help") == 0)
00341 {
00342 printf("Usage: kdeinit4 [options]\n");
00343 #ifdef ENABLE_EXIT
00344 printf(" --exit Terminate when kded has run\n");
00345 #endif
00346 printf(" --help this help page\n");
00347 printf(" --list list kde processes\n");
00348 printf(" --list-dbus-apps list all applications registered in dbus\n");
00349 printf(" --quit-over-dbus quit all application registered in dbus\n");
00350 printf(" --no-dbus do not start dbus-daemon\n");
00351 printf(" --no-klauncher do not start klauncher\n");
00352 printf(" --no-kded do not start kded\n");
00353 printf(" --shutdown safe shutdown of all running kde processes\n");
00354 printf(" first over dbus, then using hard kill\n");
00355 #ifdef ENABLE_SUICIDE
00356 printf(" --suicide terminate when no KDE applications are left running\n");
00357 #endif
00358 printf(" --terminate hard kill of *all* running kde processes\n");
00359 printf(" --verbose print verbose messages\n");
00360 exit(0);
00361 }
00362 if (strcmp(safe_argv[i], "--list") == 0)
00363 listProcesses = true;
00364 if (strcmp(safe_argv[i], "--shutdown") == 0)
00365 shutdown = true;
00366 if (strcmp(safe_argv[i], "--terminate") == 0 || strcmp(safe_argv[i], "--kill") == 0)
00367 killProcesses = true;
00368 if (strcmp(safe_argv[i], "--list-dbus-apps") == 0)
00369 listAppsInDBus = true;
00370 if (strcmp(safe_argv[i], "--quit-over-dbus") == 0)
00371 quitAppsOverDBus = true;
00372 }
00373
00374 ProcessList processList;
00375
00376 if (listProcesses) {
00377 listAllRunningKDEProcesses(processList);
00378 return 0;
00379 }
00380 else if (killProcesses) {
00381 terminateAllRunningKDEProcesses(processList);
00382 return 0;
00383 }
00384 else if (listAppsInDBus) {
00385 listAllNamedAppsInDBus();
00386 return 0;
00387 }
00388 else if (quitAppsOverDBus) {
00389 quitApplicationsOverDBus();
00390 return 0;
00391 }
00392 else if (shutdown) {
00393 quitApplicationsOverDBus();
00394 Sleep(2000);
00395 terminateAllRunningKDEProcesses(processList);
00396 }
00397
00399 s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration);
00400
00401 if (launch_dbus && !processList.hasProcessInList("dbus-daemon"))
00402 {
00403 pid = launch("dbus-launch.exe");
00404 if (!pid)
00405 pid = launch("dbus-launch.bat");
00406 if (!pid)
00407 exit(1);
00408 }
00409
00410 if (launch_klauncher && !processList.hasProcessInList("klauncher"))
00411 {
00412 pid = launch("klauncher");
00413 if (!pid || !checkIfRegisteredInDBus("org.kde.klauncher",10))
00414 exit(1);
00415 }
00416
00417
00418 if (launch_kded && !processList.hasProcessInList(KDED_EXENAME))
00419 {
00420 pid = launch(KDED_EXENAME);
00421 if (!pid || !checkIfRegisteredInDBus("org.kde.kded",10))
00422 exit(1);
00423 }
00424
00425 for(int i = 1; i < argc; i++)
00426 {
00427 if (safe_argv[i][0] == '+')
00428 {
00429 pid = launch(safe_argv[i]+1);
00430 }
00431 else if (safe_argv[i][0] == '-')
00432 {
00433
00434 }
00435 else
00436 {
00437 pid = launch( safe_argv[i]);
00438 }
00439 }
00440
00442 for(int i = 0; i < argc; i++)
00443 {
00444 free(safe_argv[i]);
00445 }
00446 free (safe_argv);
00447
00449 #ifdef ENABLE_SUICIDE
00450 if (suicide) {
00451 QProcess *proc;
00452 int can_exit=1;
00453 do {
00454 foreach(proc,startedProcesses) {
00455 if (proc->state() != QProcess::NotRunning)
00456 can_exit = 0;
00457 }
00458 if (!can_exit)
00459 Sleep(2000);
00460 } while(!can_exit);
00461 return 0;
00462 }
00463 #endif
00464 return 0;
00465 }