KInit
kinit_win.cpp
Go to the documentation of this file.
00001 /* 00002 * This file is part of the KDE libraries 00003 * Copyright (c) 1999-2000 Waldo Bastian <bastian@kde.org> 00004 * (c) 1999 Mario Weilguni <mweilguni@sime.com> 00005 * (c) 2001 Lubos Lunak <l.lunak@kde.org> 00006 * (c) 2006 Ralf Habacker <ralf.habacker@freenet.de> 00007 * (c) 2009 Patrick Spendrin <ps_ml@gmx.de> 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Library General Public 00011 * License version 2 as published by the Free Software Foundation. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Library General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Library General Public License 00019 * along with this library; see the file COPYING.LIB. If not, write to 00020 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00021 * Boston, MA 02110-1301, USA. 00022 */ 00023 00024 #include <config.h> 00025 00026 00027 #include <errno.h> 00028 #include <stdio.h> 00029 #include <stdlib.h> 00030 #include <string.h> 00031 00032 #include <windows.h> 00033 #ifndef _WIN32_WCE 00034 #include <Sddl.h> 00035 #else 00036 #include <tlhelp32.h> 00037 #endif 00038 #include <psapi.h> 00039 00040 00041 #include <QtCore/QProcess> 00042 #include <QtCore/QFileInfo> 00043 // Under wince interface is defined, so undef it otherwise it breaks it 00044 #undef interface 00045 #include <QtDBus/QtDBus> 00046 00047 #include <kcomponentdata.h> 00048 #include <kstandarddirs.h> 00049 #include <kapplication.h> 00050 #include <kdeversion.h> 00051 #include <kuser.h> 00052 00053 //#define ENABLE_SUICIDE 00054 //#define ENABLE_EXIT 00055 00056 #define KDED_EXENAME "kded4" 00057 00058 static KComponentData *s_instance = 0; 00059 00060 // print verbose messages 00061 int verbose=0; 00062 00064 QList<QProcess*> startedProcesses; 00065 00066 class ProcessListEntry { 00067 public: 00068 ProcessListEntry( HANDLE _handle,char *_path, int _pid, K_UID _owner ) 00069 { 00070 QFileInfo p(_path); 00071 path = p.absolutePath(); 00072 name = p.baseName(); 00073 handle = _handle; 00074 pid = _pid; 00075 //There are no users under wince 00076 #ifndef _WIN32_WCE 00077 DWORD length = GetLengthSid(_owner); 00078 owner = (PSID) malloc(length); 00079 CopySid(length, owner, _owner); 00080 #else 00081 owner = 0; 00082 #endif 00083 } 00084 00085 ~ProcessListEntry() 00086 { 00087 //There are no users under wince 00088 #ifndef _WIN32_WCE 00089 free(owner); 00090 #endif 00091 owner = 0; 00092 } 00093 00094 QString name; 00095 QString path; 00096 int pid; 00097 HANDLE handle; 00098 K_UID owner; 00099 friend QDebug operator <<(QDebug out, const ProcessListEntry &c); 00100 }; 00101 00102 QDebug operator <<(QDebug out, const ProcessListEntry &c) 00103 { 00104 out << "(ProcessListEntry" 00105 << "name" << c.name 00106 << "path" << c.path 00107 << "pid" << c.pid 00108 << "handle" << c.handle 00109 << ")"; 00110 return out; 00111 } 00112 00116 class ProcessList { 00117 public: 00118 ProcessList() {initProcessList(); } 00119 ~ProcessList(); 00120 ProcessListEntry *hasProcessInList(const QString &name, K_UID owner=0 ); 00121 bool terminateProcess(const QString &name); 00122 QList<ProcessListEntry *> &list() { return processList; } 00123 QList<ProcessListEntry *> listProcesses(); 00124 private: 00125 void initProcessList(); 00126 void getProcessNameAndID( DWORD processID ); 00127 QList<ProcessListEntry *> processList; 00128 }; 00129 00130 00131 void ProcessList::getProcessNameAndID( DWORD processID ) 00132 { 00133 #ifndef _WIN32_WCE 00134 char szProcessName[MAX_PATH]; 00135 // by default use the current process' uid 00136 KUser user; 00137 K_UID processSid; 00138 K_UID userId = user.uid(); 00139 00140 if(userId == NULL) { 00141 return; 00142 } 00143 00144 if(!IsValidSid(userId)) 00145 { 00146 return; 00147 } 00148 00149 DWORD sidLength = GetLengthSid(user.uid()); 00150 processSid = (PSID) malloc(sidLength); 00151 CopySid(sidLength, processSid, user.uid()); 00152 00153 // Get a handle to the process. 00154 00155 HANDLE hProcess = OpenProcess( SYNCHRONIZE|PROCESS_QUERY_INFORMATION | 00156 PROCESS_VM_READ | PROCESS_TERMINATE, 00157 false, processID ); 00158 00159 // Get the process name. 00160 int ret = 0; 00161 00162 if (NULL != hProcess ) 00163 { 00164 HMODULE hMod; 00165 DWORD cbNeeded; 00166 00167 if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod), 00168 &cbNeeded) ) 00169 { 00170 ret = GetModuleFileNameExA( hProcess, hMod, szProcessName, 00171 sizeof(szProcessName)/sizeof(TCHAR) ); 00172 } 00173 00174 if (ret > 0) 00175 { 00176 HANDLE hToken = NULL; 00177 00178 OpenProcessToken(hProcess, TOKEN_READ, &hToken); 00179 if(hToken) 00180 { 00181 DWORD size; 00182 PTOKEN_USER userStruct; 00183 00184 // check how much space is needed 00185 GetTokenInformation(hToken, TokenUser, NULL, 0, &size); 00186 if( ERROR_INSUFFICIENT_BUFFER == GetLastError() ) 00187 { 00188 userStruct = reinterpret_cast<PTOKEN_USER>( new BYTE[size] ); 00189 GetTokenInformation(hToken, TokenUser, userStruct, size, &size); 00190 00191 sidLength = GetLengthSid(userStruct->User.Sid); 00192 free(processSid); 00193 processSid = 0; 00194 processSid = (PSID) malloc(sidLength); 00195 CopySid(sidLength, processSid, userStruct->User.Sid); 00196 00197 CloseHandle(hToken); 00198 delete [] userStruct; 00199 } 00200 } 00201 } 00202 } 00203 if (ret > 0) 00204 { 00205 processList << new ProcessListEntry( hProcess, szProcessName, processID, processSid ); 00206 } 00207 free(processSid); 00208 #endif 00209 } 00210 00211 00215 void ProcessList::initProcessList() 00216 { 00217 #ifndef _WIN32_WCE 00218 // Get the list of process identifiers. 00219 00220 DWORD aProcesses[1024], cbNeeded, cProcesses; 00221 unsigned int i; 00222 00223 if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) ) 00224 return; 00225 00226 // Calculate how many process identifiers were returned. 00227 00228 cProcesses = cbNeeded / sizeof(DWORD); 00229 00230 // Print the name and process identifier for each process. 00231 00232 for ( i = 0; i < cProcesses; i++ ) 00233 if( aProcesses[i] != 0 ) 00234 getProcessNameAndID( aProcesses[i] ); 00235 #else 00236 HANDLE h; 00237 PROCESSENTRY32 pe32; 00238 00239 h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 00240 if (h == INVALID_HANDLE_VALUE) { 00241 return; 00242 } 00243 pe32.dwSize = sizeof(PROCESSENTRY32); 00244 if (!Process32First( h, &pe32 )) 00245 return; 00246 00247 do 00248 { 00249 HANDLE hProcess = OpenProcess( SYNCHRONIZE|PROCESS_QUERY_INFORMATION | 00250 PROCESS_VM_READ | PROCESS_TERMINATE, 00251 false, pe32.th32ProcessID ); 00252 00253 processList << new ProcessListEntry( hProcess, QString::fromWCharArray(pe32.szExeFile).toAscii().data(), pe32.th32ProcessID, 0 ); 00254 00255 } while( Process32Next( h, &pe32 ) ); 00256 CloseToolhelp32Snapshot(h); 00257 #endif 00258 } 00259 00260 QList<ProcessListEntry*> ProcessList::listProcesses() 00261 { 00262 //FIXME: Under wince there is no EnumProcesses 00263 #ifndef _WIN32_WCE 00264 // Get the list of process identifiers. 00265 00266 DWORD aProcesses[1024], cbNeeded, cProcesses; 00267 unsigned int i; 00268 00269 if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) ) 00270 return QList<ProcessListEntry*>(); 00271 00272 // Calculate how many process identifiers were returned. 00273 00274 cProcesses = cbNeeded / sizeof(DWORD); 00275 00276 // Print the name and process identifier for each process. 00277 00278 processList.erase(processList.begin(), processList.end()); 00279 for ( i = 0; i < cProcesses; i++ ) 00280 if( aProcesses[i] != 0 ) 00281 getProcessNameAndID( aProcesses[i] ); 00282 00283 #endif 00284 return processList; 00285 } 00286 00287 00288 ProcessList::~ProcessList() 00289 { 00290 ProcessListEntry *ple; 00291 QList<ProcessListEntry*> l = listProcesses(); 00292 foreach(ple,l) { 00293 CloseHandle(ple->handle); 00294 delete ple; 00295 } 00296 } 00297 00301 ProcessListEntry *ProcessList::hasProcessInList(const QString &name, K_UID owner) 00302 { 00303 ProcessListEntry *ple; 00304 foreach(ple,processList) { 00305 if (ple->pid < 0) { 00306 qDebug() << "negative pid!"; 00307 continue; 00308 } 00309 00310 if (ple->name != name && ple->name != name + ".exe") { 00311 continue; 00312 } 00313 00314 if (!ple->path.isEmpty() && !ple->path.toLower().startsWith(KStandardDirs::installPath("kdedir").toLower())) { 00315 // process is outside of installation directory 00316 qDebug() << "path of the process" << name << "seems to be outside of the installPath:" << ple->path << KStandardDirs::installPath("kdedir"); 00317 continue; 00318 } 00319 00320 #ifndef _WIN32_WCE 00321 if(owner) 00322 { 00323 // owner is set 00324 if(EqualSid(owner, ple->owner)) return ple; 00325 } 00326 else 00327 { 00329 const QByteArray domain = qgetenv("USERDOMAIN"); 00330 const QByteArray host = qgetenv("COMPUTERNAME"); 00331 if (domain != host) 00332 return ple; 00333 00334 // no owner is set, use the owner of this process 00335 KUser user; 00336 if(EqualSid(user.uid(), ple->owner)) return ple; 00337 } 00338 #else 00339 return ple; 00340 #endif 00341 } 00342 return NULL; 00343 } 00344 00348 bool ProcessList::terminateProcess(const QString &name) 00349 { 00350 qDebug() << "going to terminate process" << name; 00351 ProcessListEntry *p = hasProcessInList(name); 00352 if (!p) { 00353 qDebug() << "could not find ProcessListEntry for process name" << name; 00354 return false; 00355 } 00356 00357 bool ret = TerminateProcess(p->handle,0); 00358 if (ret) { 00359 CloseHandle(p->handle); 00360 int i = processList.indexOf(p); 00361 if(i != -1) processList.removeAt(i); 00362 delete p; 00363 return true; 00364 } else { 00365 return false; 00366 } 00367 } 00368 00369 // internal launch function 00370 int launch(const QString &cmd) 00371 { 00372 QProcess *proc = new QProcess(); 00373 proc->start(cmd); 00374 proc->waitForStarted(); 00375 startedProcesses << proc; 00376 _PROCESS_INFORMATION* _pid = proc->pid(); 00377 int pid = _pid ? _pid->dwProcessId : 0; 00378 if (verbose) { 00379 fprintf(stderr,"%s",proc->readAllStandardError().constData()); 00380 fprintf(stderr,"%s",proc->readAllStandardOutput().constData()); 00381 } 00382 if (pid) { 00383 if (verbose) 00384 fprintf(stderr, "kdeinit4: Launched %s, pid = %ld\n", qPrintable(cmd),(long) pid); 00385 } 00386 else { 00387 if (verbose) 00388 fprintf(stderr, "kdeinit4: could not launch %s, exiting\n",qPrintable(cmd)); 00389 } 00390 return pid; 00391 } 00392 00394 bool checkIfRegisteredInDBus(const QString &name, int _timeout=10) 00395 { 00396 int timeout = _timeout * 5; 00397 while(timeout) { 00398 if ( QDBusConnection::sessionBus().interface()->isServiceRegistered( name ) ) 00399 break; 00400 Sleep(200); 00401 timeout--; 00402 } 00403 if (!timeout) { 00404 if (verbose) 00405 fprintf(stderr,"not registered %s in dbus after %d secs\n",qPrintable(name),_timeout); 00406 return false; 00407 } 00408 if (verbose) 00409 fprintf(stderr,"%s is registered in dbus\n",qPrintable(name)); 00410 return true; 00411 } 00412 00413 void listAllRunningKDEProcesses(ProcessList &processList) 00414 { 00415 ProcessListEntry *ple; 00416 QString installPrefix = KStandardDirs::installPath("kdedir"); 00417 QList<ProcessListEntry*> l = processList.listProcesses(); 00418 00419 foreach(ple,l) 00420 { 00421 if (!ple->path.isEmpty() && ple->path.toLower().startsWith(installPrefix.toLower())) 00422 fprintf(stderr,"path: %s name: %s pid: %u\n", ple->path.toLatin1().data(), ple->name.toLatin1().data(), ple->pid); 00423 } 00424 } 00425 00426 void terminateAllRunningKDEProcesses(ProcessList &processList) 00427 { 00428 ProcessListEntry *ple; 00429 QString installPrefix = KStandardDirs::installPath("kdedir"); 00430 QList<ProcessListEntry*> l = processList.listProcesses(); 00431 00432 foreach(ple,l) 00433 { 00434 if (!ple->path.isEmpty() && ple->path.toLower().startsWith(installPrefix.toLower())) 00435 { 00436 if (verbose) 00437 fprintf(stderr,"terminating path: %s name: %s pid: %u\n", ple->path.toLatin1().data(), ple->name.toLatin1().data(), ple->pid); 00438 processList.terminateProcess(ple->name); 00439 } 00440 } 00441 } 00442 00443 void listAllNamedAppsInDBus() 00444 { 00445 QDBusConnection connection = QDBusConnection::sessionBus(); 00446 QDBusConnectionInterface *bus = connection.interface(); 00447 const QStringList services = bus->registeredServiceNames(); 00448 foreach(const QString &service, services) { 00449 if (service.startsWith(QLatin1String("org.freedesktop.DBus")) || service.startsWith(QLatin1Char(':'))) 00450 continue; 00451 fprintf(stderr, "%s \n", service.toLatin1().data()); 00452 } 00453 } 00454 00455 void quitApplicationsOverDBus() 00456 { 00457 QDBusConnection connection = QDBusConnection::sessionBus(); 00458 QDBusConnectionInterface *bus = connection.interface(); 00459 const QStringList services = bus->registeredServiceNames(); 00460 foreach(const QString &service, services) { 00461 if (service.startsWith(QLatin1String("org.freedesktop.DBus")) || service.startsWith(QLatin1Char(':'))) 00462 continue; 00463 QDBusInterface *iface = new QDBusInterface(service, 00464 QLatin1String("/MainApplication"), 00465 QLatin1String("org.kde.KApplication"), 00466 connection); 00467 if (!iface->isValid()) { 00468 if (verbose) 00469 fprintf(stderr, "invalid interface of service %s\n", service.toLatin1().data()); 00470 continue; 00471 } 00472 iface->call("quit"); 00473 if (iface->lastError().isValid()) { 00474 if (verbose) 00475 fprintf(stderr,"killing %s with result\n", iface->lastError().message().toLatin1().data()); 00476 } 00477 delete iface; 00478 } 00479 } 00480 00481 int main(int argc, char **argv, char **envp) 00482 { 00483 pid_t pid = 0; 00484 bool launch_dbus = true; 00485 bool launch_klauncher = true; 00486 bool launch_kded = true; 00487 bool suicide = false; 00488 bool listProcesses = false; 00489 bool killProcesses = false; 00490 bool listAppsInDBus = false; 00491 bool quitAppsOverDBus = false; 00492 bool shutdown = false; 00493 00495 char **safe_argv = (char **) malloc( sizeof(char *) * argc); 00496 for(int i = 0; i < argc; i++) 00497 { 00498 safe_argv[i] = strcpy((char*)malloc(strlen(argv[i])+1), argv[i]); 00499 if (strcmp(safe_argv[i], "--no-dbus") == 0) 00500 launch_dbus = false; 00501 if (strcmp(safe_argv[i], "--no-klauncher") == 0) 00502 launch_klauncher = false; 00503 if (strcmp(safe_argv[i], "--no-kded") == 0) 00504 launch_kded = false; 00505 if (strcmp(safe_argv[i], "--suicide") == 0) 00506 suicide = true; 00507 #ifdef ENABLE_EXIT 00508 if (strcmp(safe_argv[i], "--exit") == 0) 00509 keep_running = 0; 00510 #endif 00511 if (strcmp(safe_argv[i], "--verbose") == 0) 00512 verbose = 1; 00513 if (strcmp(safe_argv[i], "--version") == 0) 00514 { 00515 printf("Qt: %s\n",qVersion()); 00516 printf("KDE: %s\n", KDE_VERSION_STRING); 00517 exit(0); 00518 } 00519 if (strcmp(safe_argv[i], "--help") == 0) 00520 { 00521 printf("Usage: kdeinit4 [options]\n"); 00522 #ifdef ENABLE_EXIT 00523 printf(" --exit Terminate when kded has run\n"); 00524 #endif 00525 printf(" --help this help page\n"); 00526 printf(" --list list kde processes\n"); 00527 printf(" --list-dbus-apps list all applications registered in dbus\n"); 00528 printf(" --quit-over-dbus quit all application registered in dbus\n"); 00529 printf(" --no-dbus do not start dbus-daemon\n"); 00530 printf(" --no-klauncher do not start klauncher\n"); 00531 printf(" --no-kded do not start kded\n"); 00532 printf(" --shutdown safe shutdown of all running kde processes\n"); 00533 printf(" first over dbus, then using hard kill\n"); 00534 #ifdef ENABLE_SUICIDE 00535 printf(" --suicide terminate when no KDE applications are left running\n"); 00536 #endif 00537 printf(" --terminate hard kill of *all* running kde processes\n"); 00538 printf(" --verbose print verbose messages\n"); 00539 printf(" --version Show version information\n"); 00540 exit(0); 00541 } 00542 if (strcmp(safe_argv[i], "--list") == 0) 00543 listProcesses = true; 00544 if (strcmp(safe_argv[i], "--shutdown") == 0) 00545 shutdown = true; 00546 if (strcmp(safe_argv[i], "--terminate") == 0 || strcmp(safe_argv[i], "--kill") == 0) 00547 killProcesses = true; 00548 if (strcmp(safe_argv[i], "--list-dbus-apps") == 0) 00549 listAppsInDBus = true; 00550 if (strcmp(safe_argv[i], "--quit-over-dbus") == 0) 00551 quitAppsOverDBus = true; 00552 } 00553 00554 ProcessList processList; 00555 00556 if (listProcesses) { 00557 listAllRunningKDEProcesses(processList); 00558 return 0; 00559 } 00560 else if (killProcesses) { 00561 terminateAllRunningKDEProcesses(processList); 00562 return 0; 00563 } 00564 else if (listAppsInDBus) { 00565 listAllNamedAppsInDBus(); 00566 return 0; 00567 } 00568 else if (quitAppsOverDBus) { 00569 quitApplicationsOverDBus(); 00570 return 0; 00571 } 00572 else if (shutdown) { 00573 quitApplicationsOverDBus(); 00574 Sleep(2000); 00575 terminateAllRunningKDEProcesses(processList); 00576 } 00577 00579 s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration); 00580 00581 #ifdef _DEBUG 00582 // first try to launch dbus-daemond in debug mode 00583 if (launch_dbus && processList.hasProcessInList("dbus-daemond")) 00584 launch_dbus = false; 00585 if (launch_dbus) 00586 { 00587 pid = launch("dbus-launchd.exe"); 00588 if (!pid) 00589 pid = launch("dbus-launchd.bat"); 00590 launch_dbus = (pid == 0); 00591 } 00592 #endif 00593 if (launch_dbus && !processList.hasProcessInList("dbus-daemon")) 00594 { 00595 if (!pid) 00596 pid = launch("dbus-launch.exe"); 00597 if (!pid) 00598 pid = launch("dbus-launch.bat"); 00599 if (!pid) 00600 exit(1); 00601 } 00602 00603 if (launch_klauncher && !processList.hasProcessInList("klauncher")) 00604 { 00605 pid = launch("klauncher"); 00606 if (!pid || !checkIfRegisteredInDBus("org.kde.klauncher",10)) 00607 exit(1); 00608 } 00609 00610 00611 if (launch_kded && !processList.hasProcessInList(KDED_EXENAME)) 00612 { 00613 pid = launch(KDED_EXENAME); 00614 if (!pid || !checkIfRegisteredInDBus("org.kde.kded",10)) 00615 exit(1); 00616 } 00617 00618 for(int i = 1; i < argc; i++) 00619 { 00620 if (safe_argv[i][0] == '+') 00621 { 00622 pid = launch(safe_argv[i]+1); 00623 } 00624 else if (safe_argv[i][0] == '-') 00625 { 00626 // Ignore 00627 } 00628 else 00629 { 00630 pid = launch( safe_argv[i]); 00631 } 00632 } 00633 00635 for(int i = 0; i < argc; i++) 00636 { 00637 free(safe_argv[i]); 00638 } 00639 free (safe_argv); 00640 00642 #ifdef ENABLE_SUICIDE 00643 if (suicide) { 00644 QProcess *proc; 00645 int can_exit=1; 00646 do { 00647 foreach(proc,startedProcesses) { 00648 if (proc->state() != QProcess::NotRunning) 00649 can_exit = 0; 00650 } 00651 if (!can_exit) 00652 Sleep(2000); 00653 } while(!can_exit); 00654 return 0; 00655 } 00656 #endif 00657 return 0; 00658 }
KDE 4.6 API Reference