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], "--version") == 0)
00341 {
00342 printf("Qt: %s\n",qVersion());
00343 printf("KDE: %s\n", KDE_VERSION_STRING);
00344 exit(0);
00345 }
00346 if (strcmp(safe_argv[i], "--help") == 0)
00347 {
00348 printf("Usage: kdeinit4 [options]\n");
00349 #ifdef ENABLE_EXIT
00350 printf(" --exit Terminate when kded has run\n");
00351 #endif
00352 printf(" --help this help page\n");
00353 printf(" --list list kde processes\n");
00354 printf(" --list-dbus-apps list all applications registered in dbus\n");
00355 printf(" --quit-over-dbus quit all application registered in dbus\n");
00356 printf(" --no-dbus do not start dbus-daemon\n");
00357 printf(" --no-klauncher do not start klauncher\n");
00358 printf(" --no-kded do not start kded\n");
00359 printf(" --shutdown safe shutdown of all running kde processes\n");
00360 printf(" first over dbus, then using hard kill\n");
00361 #ifdef ENABLE_SUICIDE
00362 printf(" --suicide terminate when no KDE applications are left running\n");
00363 #endif
00364 printf(" --terminate hard kill of *all* running kde processes\n");
00365 printf(" --verbose print verbose messages\n");
00366 printf(" --version Show version information\n");
00367 exit(0);
00368 }
00369 if (strcmp(safe_argv[i], "--list") == 0)
00370 listProcesses = true;
00371 if (strcmp(safe_argv[i], "--shutdown") == 0)
00372 shutdown = true;
00373 if (strcmp(safe_argv[i], "--terminate") == 0 || strcmp(safe_argv[i], "--kill") == 0)
00374 killProcesses = true;
00375 if (strcmp(safe_argv[i], "--list-dbus-apps") == 0)
00376 listAppsInDBus = true;
00377 if (strcmp(safe_argv[i], "--quit-over-dbus") == 0)
00378 quitAppsOverDBus = true;
00379 }
00380
00381 ProcessList processList;
00382
00383 if (listProcesses) {
00384 listAllRunningKDEProcesses(processList);
00385 return 0;
00386 }
00387 else if (killProcesses) {
00388 terminateAllRunningKDEProcesses(processList);
00389 return 0;
00390 }
00391 else if (listAppsInDBus) {
00392 listAllNamedAppsInDBus();
00393 return 0;
00394 }
00395 else if (quitAppsOverDBus) {
00396 quitApplicationsOverDBus();
00397 return 0;
00398 }
00399 else if (shutdown) {
00400 quitApplicationsOverDBus();
00401 Sleep(2000);
00402 terminateAllRunningKDEProcesses(processList);
00403 }
00404
00406 s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration);
00407
00408 if (launch_dbus && !processList.hasProcessInList("dbus-daemon"))
00409 {
00410 pid = launch("dbus-launch.exe");
00411 if (!pid)
00412 pid = launch("dbus-launch.bat");
00413 if (!pid)
00414 exit(1);
00415 }
00416
00417 if (launch_klauncher && !processList.hasProcessInList("klauncher"))
00418 {
00419 pid = launch("klauncher");
00420 if (!pid || !checkIfRegisteredInDBus("org.kde.klauncher",10))
00421 exit(1);
00422 }
00423
00424
00425 if (launch_kded && !processList.hasProcessInList(KDED_EXENAME))
00426 {
00427 pid = launch(KDED_EXENAME);
00428 if (!pid || !checkIfRegisteredInDBus("org.kde.kded",10))
00429 exit(1);
00430 }
00431
00432 for(int i = 1; i < argc; i++)
00433 {
00434 if (safe_argv[i][0] == '+')
00435 {
00436 pid = launch(safe_argv[i]+1);
00437 }
00438 else if (safe_argv[i][0] == '-')
00439 {
00440
00441 }
00442 else
00443 {
00444 pid = launch( safe_argv[i]);
00445 }
00446 }
00447
00449 for(int i = 0; i < argc; i++)
00450 {
00451 free(safe_argv[i]);
00452 }
00453 free (safe_argv);
00454
00456 #ifdef ENABLE_SUICIDE
00457 if (suicide) {
00458 QProcess *proc;
00459 int can_exit=1;
00460 do {
00461 foreach(proc,startedProcesses) {
00462 if (proc->state() != QProcess::NotRunning)
00463 can_exit = 0;
00464 }
00465 if (!can_exit)
00466 Sleep(2000);
00467 } while(!can_exit);
00468 return 0;
00469 }
00470 #endif
00471 return 0;
00472 }