• 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 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 }

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