• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

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-2011 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 #endif
00036 #include <tlhelp32.h>
00037 #include <psapi.h>
00038 
00039 
00040 #include <QtCore/QProcess>
00041 #include <QtCore/QFileInfo>
00042 // Under wince interface is defined, so undef it otherwise it breaks it
00043 #undef interface
00044 #include <QtDBus/QtDBus>
00045 
00046 #include <kcomponentdata.h>
00047 #include <kstandarddirs.h>
00048 #include <kapplication.h>
00049 #include <kdeversion.h>
00050 
00051 //#define ENABLE_SUICIDE 
00052 //#define ENABLE_EXIT
00053 
00054 #define KDED_EXENAME "kded4"
00055 
00056 static KComponentData *s_instance = 0;
00057 
00058 // print verbose messages
00059 int verbose=0;
00060 
00062 QList<QProcess*> startedProcesses;
00063 
00064 /* --------------------------------------------------------------------
00065   sid helper - will be migrated later to a class named Sid, which could 
00066   be used as base class for platform independent K_UID and K_GID types 
00067   - would this be possible before KDE 5 ? 
00068   --------------------------------------------------------------------- */
00069 
00076 PSID copySid(PSID from)
00077 {
00078     if (!from)
00079         return 0;
00080     int sidLength = GetLengthSid(from);
00081     PSID to = (PSID) malloc(sidLength);
00082     CopySid(sidLength, to, from);
00083     return to;
00084 }
00085 
00092 void freeSid(PSID sid)
00093 {
00094     if (sid)
00095         free(sid);
00096 }
00097 
00104 QString toString(PSID sid)
00105 {
00106     LPWSTR s;
00107     if (!ConvertSidToStringSid(sid, &s))
00108         return QString();
00109 
00110     QString result = QString::fromUtf16(reinterpret_cast<ushort*>(s));
00111     LocalFree(s);
00112     return result;
00113 }
00114 
00115 /* --------------------------------------------------------------------
00116   process helper 
00117   --------------------------------------------------------------------- */
00118 
00124 static HANDLE getProcessHandle(int processID)
00125 {
00126     return OpenProcess( SYNCHRONIZE|PROCESS_QUERY_INFORMATION |
00127                         PROCESS_VM_READ | PROCESS_TERMINATE,
00128                         false, processID );
00129 }
00130 
00136 static QString getProcessName(DWORD pid)
00137 {
00138     HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
00139     MODULEENTRY32 me32;
00140 
00141     hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pid );
00142     if( hModuleSnap == INVALID_HANDLE_VALUE )
00143         return QString();
00144 
00145     me32.dwSize = sizeof( MODULEENTRY32 );
00146 
00147     if( !Module32First( hModuleSnap, &me32 ) ) {
00148         CloseHandle( hModuleSnap );           // clean the snapshot object
00149         return QString();
00150     }
00151     QString name = QString::fromWCharArray(me32.szExePath);
00152     CloseHandle( hModuleSnap );
00153     return name;
00154 }
00155 
00161 static PSID getProcessOwner(HANDLE hProcess)
00162 {
00163 #ifndef _WIN32_WCE
00164     HANDLE hToken = NULL;    
00165     PSID sid;
00166             
00167     OpenProcessToken(hProcess, TOKEN_READ, &hToken);
00168     if(hToken)
00169     {
00170         DWORD size;
00171         PTOKEN_USER userStruct;
00172                 
00173         // check how much space is needed
00174         GetTokenInformation(hToken, TokenUser, NULL, 0, &size);
00175         if( ERROR_INSUFFICIENT_BUFFER == GetLastError() )
00176         {
00177             userStruct = reinterpret_cast<PTOKEN_USER>( new BYTE[size] );
00178             GetTokenInformation(hToken, TokenUser, userStruct, size, &size);
00179 
00180             sid = copySid(userStruct->User.Sid);
00181             CloseHandle(hToken);
00182             delete [] userStruct;
00183             return sid;
00184         }
00185     }
00186 #endif
00187     return 0;
00188 }
00189 
00193 static PSID getCurrentProcessOwner()
00194 {
00195     return getProcessOwner(GetCurrentProcess());
00196 }
00197 
00201 class ProcessListEntry {
00202     public:
00203        ProcessListEntry( HANDLE _handle, QString _path, int _pid, PSID _owner=0 ) 
00204        {    
00205            QFileInfo p(_path);
00206            path = p.absolutePath();
00207            name = p.baseName();
00208            handle = _handle; 
00209            pid = _pid;
00210            owner = copySid(_owner);
00211        }
00212 
00213        ~ProcessListEntry()
00214        {
00215            freeSid(owner);
00216            CloseHandle(handle);
00217        }
00218        
00219        QString name;
00220        QString path;
00221        int pid;
00222        HANDLE handle;
00223        PSID owner;
00224        friend QDebug operator <<(QDebug out, const ProcessListEntry &c);
00225 };
00226 
00227 QDebug operator <<(QDebug out, const ProcessListEntry &c)
00228 {
00229     out << "(ProcessListEntry" 
00230         << "name" << c.name
00231         << "path" << c.path
00232         << "pid" << c.pid
00233         << "handle" << c.handle
00234         << "sid" << toString(c.owner)
00235         << ")";
00236     return out;
00237 }    
00238 
00246 class ProcessList {
00247 public:
00252     ProcessList(PSID userSid=0);
00253 
00254     ~ProcessList();
00255 
00261     ProcessListEntry *find(const QString &name);
00262 
00268     bool terminateProcess(const QString &name);
00269 
00274     QList<ProcessListEntry *> &list() { return m_processes; }
00275 
00276 private:
00277     void init();
00278     QList<ProcessListEntry *> m_processes;
00279     PSID m_userId;
00280 };
00281 
00282 ProcessList::ProcessList(PSID userSid) 
00283 {
00284     m_userId = userSid;
00285     init(); 
00286 }
00287 
00288 ProcessList::~ProcessList()
00289 {
00290     foreach(const ProcessListEntry *ple,m_processes)
00291         delete ple;
00292 }
00293 
00294 void ProcessList::init()
00295 {
00296     HANDLE h;
00297     PROCESSENTRY32 pe32;
00298 
00299     h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
00300     if (h == INVALID_HANDLE_VALUE) {
00301         return;
00302     }
00303     pe32.dwSize = sizeof(PROCESSENTRY32);
00304     if (!Process32First( h, &pe32 ))
00305         return;
00306       
00307     do
00308     {
00309         HANDLE hProcess = getProcessHandle(pe32.th32ProcessID);
00310         if (!hProcess)
00311             continue;
00312         QString name = getProcessName(pe32.th32ProcessID);
00313 #ifndef _WIN32_WCE
00314         PSID sid = getProcessOwner(hProcess);
00315         if (!sid || m_userId && !EqualSid(m_userId,sid))
00316         {
00317             freeSid(sid);
00318             continue;
00319         }
00320 #else
00321         PSID sid = 0;
00322 #endif
00323         m_processes << new ProcessListEntry( hProcess, name, pe32.th32ProcessID, sid);
00324     } while(Process32Next( h, &pe32 ));
00325 #ifndef _WIN32_WCE
00326     CloseHandle(h);
00327 #else
00328     CloseToolhelp32Snapshot(h);
00329 #endif
00330 }
00331 
00332 ProcessListEntry *ProcessList::find(const QString &name)
00333 {
00334     ProcessListEntry *ple;
00335     foreach(ple,m_processes) {
00336         if (ple->pid < 0) { 
00337             qDebug() << "negative pid!";
00338             continue;
00339         }
00340         
00341         if (ple->name != name && ple->name != name + ".exe") {
00342             continue;
00343         }
00344         
00345         if (!ple->path.isEmpty() && !ple->path.toLower().startsWith(KStandardDirs::installPath("kdedir").toLower())) {
00346             // process is outside of installation directory
00347             qDebug() << "path of the process" << name << "seems to be outside of the installPath:" << ple->path << KStandardDirs::installPath("kdedir");
00348             continue;
00349         }
00350         return ple;
00351     }
00352     return NULL;
00353 }
00354 
00355 bool ProcessList::terminateProcess(const QString &name)
00356 {
00357     qDebug() << "going to terminate process" << name;
00358     ProcessListEntry *p = find(name);
00359     if (!p) {
00360         qDebug() << "could not find ProcessListEntry for process name" << name;
00361         return false;
00362     }
00363 
00364     bool ret = TerminateProcess(p->handle,0);
00365     if (ret) {
00366         int i = m_processes.indexOf(p);
00367         if(i != -1) m_processes.removeAt(i);
00368         delete p;
00369         return true;
00370     } else {
00371         return false;
00372     }
00373 }
00374 
00375 // internal launch function
00376 int launch(const QString &cmd)
00377 {
00378     QProcess *proc = new QProcess();
00379     proc->start(cmd);
00380     proc->waitForStarted();
00381     startedProcesses << proc;
00382     _PROCESS_INFORMATION* _pid = proc->pid();
00383     int pid = _pid ? _pid->dwProcessId : 0;
00384     if (verbose) {
00385         fprintf(stderr,"%s",proc->readAllStandardError().constData());
00386         fprintf(stderr,"%s",proc->readAllStandardOutput().constData());
00387     }
00388     if (pid) {
00389        if (verbose)
00390            fprintf(stderr, "kdeinit4: Launched %s, pid = %ld\n", qPrintable(cmd),(long) pid);
00391     }
00392     else {
00393        if (verbose)
00394            fprintf(stderr, "kdeinit4: could not launch %s, exiting\n",qPrintable(cmd));
00395     }
00396     return pid;
00397 }
00398 
00400 bool checkIfRegisteredInDBus(const QString &name, int _timeout=10)
00401 {
00402     int timeout = _timeout * 5;
00403     while(timeout) {
00404         if ( QDBusConnection::sessionBus().interface()->isServiceRegistered( name ) )
00405             break;
00406         Sleep(200);
00407         timeout--;
00408     }
00409         if (!timeout) {
00410             if (verbose)
00411                 fprintf(stderr,"not registered %s in dbus after %d secs\n",qPrintable(name),_timeout);
00412             return false;
00413         }
00414         if (verbose)
00415             fprintf(stderr,"%s is registered in dbus\n",qPrintable(name));
00416     return true;
00417 }
00418 
00419 void listAllRunningKDEProcesses(ProcessList &processList)
00420 {
00421     QString installPrefix = KStandardDirs::installPath("kdedir");
00422 
00423     foreach(const ProcessListEntry *ple, processList.list()) 
00424     {
00425         if (!ple->path.isEmpty() && ple->path.toLower().startsWith(installPrefix.toLower()))
00426             fprintf(stderr,"path: %s name: %s pid: %u\n", ple->path.toLatin1().data(), ple->name.toLatin1().data(), ple->pid);
00427     }
00428 }
00429 
00430 void terminateAllRunningKDEProcesses(ProcessList &processList)
00431 {
00432     QString installPrefix = KStandardDirs::installPath("kdedir");
00433 
00434     foreach(const ProcessListEntry *ple, processList.list()) 
00435     {
00436         if (!ple->path.isEmpty() && ple->path.toLower().startsWith(installPrefix.toLower())) 
00437         {
00438             if (verbose)
00439                 fprintf(stderr,"terminating path: %s name: %s pid: %u\n", ple->path.toLatin1().data(), ple->name.toLatin1().data(), ple->pid);
00440             processList.terminateProcess(ple->name);
00441         }
00442     }
00443 }
00444 
00445 void listAllNamedAppsInDBus()
00446 {
00447     QDBusConnection connection = QDBusConnection::sessionBus();
00448     QDBusConnectionInterface *bus = connection.interface();
00449     const QStringList services = bus->registeredServiceNames();
00450     foreach(const QString &service, services) {
00451         if (service.startsWith(QLatin1String("org.freedesktop.DBus")) || service.startsWith(QLatin1Char(':')))
00452             continue;
00453         fprintf(stderr, "%s \n", service.toLatin1().data());
00454     }
00455 }
00456 
00457 void quitApplicationsOverDBus()
00458 {
00459     QDBusConnection connection = QDBusConnection::sessionBus();
00460     QDBusConnectionInterface *bus = connection.interface();
00461     const QStringList services = bus->registeredServiceNames();
00462     foreach(const QString &service, services) {
00463         if (service.startsWith(QLatin1String("org.freedesktop.DBus")) || service.startsWith(QLatin1Char(':')))
00464             continue;
00465         QDBusInterface *iface = new QDBusInterface(service,
00466                                QLatin1String("/MainApplication"),
00467                                QLatin1String("org.kde.KApplication"),
00468                                connection);
00469         if (!iface->isValid()) {
00470             if (verbose)
00471                 fprintf(stderr, "invalid interface of service %s\n", service.toLatin1().data());
00472             continue;
00473         }
00474         iface->call("quit");
00475         if (iface->lastError().isValid()) {
00476             if (verbose)
00477                 fprintf(stderr,"killing %s with result\n", iface->lastError().message().toLatin1().data());
00478         }
00479         delete iface;
00480     }
00481 }
00482 
00483 int main(int argc, char **argv, char **envp)
00484 {
00485     pid_t pid = 0;
00486     bool launch_dbus = true;
00487     bool launch_klauncher = true;
00488     bool launch_kded = true;
00489     bool suicide = false;
00490     bool listProcesses = false;
00491     bool killProcesses = false;
00492     bool listAppsInDBus = false;
00493     bool quitAppsOverDBus = false;
00494     bool shutdown = false;
00495 
00497     char **safe_argv = (char **) malloc( sizeof(char *) * argc);
00498     for(int i = 0; i < argc; i++)
00499     {
00500         safe_argv[i] = strcpy((char*)malloc(strlen(argv[i])+1), argv[i]);
00501         if (strcmp(safe_argv[i], "--no-dbus") == 0)
00502             launch_dbus = false;
00503         if (strcmp(safe_argv[i], "--no-klauncher") == 0)
00504             launch_klauncher = false;
00505         if (strcmp(safe_argv[i], "--no-kded") == 0)
00506             launch_kded = false;
00507         if (strcmp(safe_argv[i], "--suicide") == 0)
00508             suicide = true;
00509 #ifdef ENABLE_EXIT
00510         if (strcmp(safe_argv[i], "--exit") == 0)
00511             keep_running = 0;
00512 #endif            
00513         if (strcmp(safe_argv[i], "--verbose") == 0)
00514             verbose = 1;
00515         if (strcmp(safe_argv[i], "--version") == 0) 
00516         { 
00517             printf("Qt: %s\n",qVersion()); 
00518             printf("KDE: %s\n", KDE_VERSION_STRING); 
00519             exit(0);
00520         } 
00521         if (strcmp(safe_argv[i], "--help") == 0)
00522         {
00523            printf("Usage: kdeinit4 [options]\n");
00524 #ifdef ENABLE_EXIT
00525            printf("   --exit                     Terminate when kded has run\n");
00526 #endif
00527            printf("   --help                     this help page\n");
00528            printf("   --list                     list kde processes\n");
00529            printf("   --list-dbus-apps           list all applications registered in dbus\n");
00530            printf("   --quit-over-dbus           quit all application registered in dbus\n");
00531            printf("   --no-dbus                  do not start dbus-daemon\n");
00532            printf("   --no-klauncher             do not start klauncher\n");
00533            printf("   --no-kded                  do not start kded\n");
00534            printf("   --shutdown                 safe shutdown of all running kde processes\n");
00535            printf("                              first over dbus, then using hard kill\n");
00536 #ifdef ENABLE_SUICIDE
00537            printf("    --suicide                 terminate when no KDE applications are left running\n");
00538 #endif
00539            printf("   --terminate                hard kill of *all* running kde processes\n");
00540            printf("   --verbose                  print verbose messages\n");
00541        printf("   --version                  Show version information\n");
00542            exit(0);
00543         }
00544         if (strcmp(safe_argv[i], "--list") == 0)
00545             listProcesses = true;
00546         if (strcmp(safe_argv[i], "--shutdown") == 0)
00547             shutdown = true;
00548         if (strcmp(safe_argv[i], "--terminate") == 0 || strcmp(safe_argv[i], "--kill") == 0)
00549             killProcesses = true;
00550         if (strcmp(safe_argv[i], "--list-dbus-apps") == 0)
00551             listAppsInDBus = true;
00552         if (strcmp(safe_argv[i], "--quit-over-dbus") == 0)
00553             quitAppsOverDBus = true;
00554     }
00555 
00556     PSID currentSid = getCurrentProcessOwner();
00557     if (verbose)
00558         fprintf(stderr,"current user sid: %s\n",qPrintable(toString(currentSid)));
00559     ProcessList processList(currentSid);
00560     freeSid(currentSid);
00561 
00562     if (listProcesses) {
00563         listAllRunningKDEProcesses(processList);
00564         return 0;
00565     }
00566     else if (killProcesses) {
00567         terminateAllRunningKDEProcesses(processList);
00568         return 0;
00569     }
00570     else if (listAppsInDBus) {
00571         listAllNamedAppsInDBus();
00572         return 0;
00573     }
00574     else if (quitAppsOverDBus) {
00575         quitApplicationsOverDBus();
00576         return 0;
00577     }
00578     else if (shutdown) {
00579         quitApplicationsOverDBus();
00580         Sleep(2000);
00581         terminateAllRunningKDEProcesses(processList);
00582     }
00583     
00585     s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration);
00586 
00587 #ifdef _DEBUG
00588     // first try to launch dbus-daemond in debug mode
00589     if (launch_dbus && processList.find("dbus-daemond"))
00590           launch_dbus = false;
00591     if (launch_dbus)
00592     {
00593           pid = launch("dbus-launchd.exe");
00594           if (!pid)
00595               pid = launch("dbus-launchd.bat");
00596           launch_dbus = (pid == 0);
00597     }
00598 #endif
00599     if (launch_dbus && !processList.find("dbus-daemon"))
00600     {
00601           if (!pid)
00602               pid = launch("dbus-launch.exe");
00603           if (!pid)
00604               pid = launch("dbus-launch.bat");
00605           if (!pid)
00606               exit(1);
00607     }
00608 
00609     if (launch_klauncher && !processList.find("klauncher"))
00610     {
00611           pid = launch("klauncher");
00612           if (!pid || !checkIfRegisteredInDBus("org.kde.klauncher",10))
00613               exit(1);
00614     }
00615 
00616 
00617     if (launch_kded && !processList.find(KDED_EXENAME))
00618     {
00619         pid = launch(KDED_EXENAME);
00620         if (!pid || !checkIfRegisteredInDBus("org.kde.kded",10))
00621             exit(1);
00622     }
00623 
00624     for(int i = 1; i < argc; i++)
00625     {
00626         if (safe_argv[i][0] == '+')
00627         {
00628             pid = launch(safe_argv[i]+1);
00629         }
00630         else if (safe_argv[i][0] == '-')
00631         {
00632             // Ignore
00633         }
00634         else
00635         {
00636             pid = launch( safe_argv[i]);
00637         }
00638     }
00639 
00641     for(int i = 0; i < argc; i++)
00642     {
00643           free(safe_argv[i]);
00644     }
00645     free (safe_argv);
00646 
00648 #ifdef ENABLE_SUICIDE
00649     if (suicide) {
00650         QProcess *proc;
00651         int can_exit=1;
00652         do {
00653            foreach(proc,startedProcesses) {
00654              if (proc->state() != QProcess::NotRunning)
00655                 can_exit = 0;
00656            }
00657            if (!can_exit)
00658              Sleep(2000);
00659         } while(!can_exit);
00660         return 0;
00661     }
00662 #endif    
00663     return 0;
00664 }

KInit

Skip menu "KInit"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal