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

KInit

  • kinit
kinit_win.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the KDE libraries
3 * Copyright (c) 1999-2000 Waldo Bastian <bastian@kde.org>
4 * (c) 1999 Mario Weilguni <mweilguni@sime.com>
5 * (c) 2001 Lubos Lunak <l.lunak@kde.org>
6 * (c) 2006-2011 Ralf Habacker <ralf.habacker@freenet.de>
7 * (c) 2009 Patrick Spendrin <ps_ml@gmx.de>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License version 2 as published by the Free Software Foundation.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#include <config.h>
25
26
27#include <errno.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include <windows.h>
33#ifndef _WIN32_WCE
34#include <Sddl.h>
35#endif
36#include <tlhelp32.h>
37#include <psapi.h>
38
39
40#include <QtCore/QProcess>
41#include <QtCore/QFileInfo>
42// Under wince interface is defined, so undef it otherwise it breaks it
43#undef interface
44#include <QtDBus/QtDBus>
45
46#include <kcomponentdata.h>
47#include <kstandarddirs.h>
48#include <kapplication.h>
49#include <kdeversion.h>
50
51//#define ENABLE_SUICIDE
52//#define ENABLE_EXIT
53
54#define KDED_EXENAME "kded4"
55
56static KComponentData *s_instance = 0;
57
58// print verbose messages
59int verbose=0;
60
62QList<QProcess*> startedProcesses;
63
64/* --------------------------------------------------------------------
65 sid helper - will be migrated later to a class named Sid, which could
66 be used as base class for platform independent K_UID and K_GID types
67 - would this be possible before KDE 5 ?
68 --------------------------------------------------------------------- */
69
76PSID copySid(PSID from)
77{
78 if (!from)
79 return 0;
80 int sidLength = GetLengthSid(from);
81 PSID to = (PSID) malloc(sidLength);
82 CopySid(sidLength, to, from);
83 return to;
84}
85
92void freeSid(PSID sid)
93{
94 if (sid)
95 free(sid);
96}
97
104QString toString(PSID sid)
105{
106 LPWSTR s;
107 if (!ConvertSidToStringSid(sid, &s))
108 return QString();
109
110 QString result = QString::fromUtf16(reinterpret_cast<ushort*>(s));
111 LocalFree(s);
112 return result;
113}
114
115/* --------------------------------------------------------------------
116 process helper
117 --------------------------------------------------------------------- */
118
124static HANDLE getProcessHandle(int processID)
125{
126 return OpenProcess( SYNCHRONIZE|PROCESS_QUERY_INFORMATION |
127 PROCESS_VM_READ | PROCESS_TERMINATE,
128 false, processID );
129}
130
136static QString getProcessName(DWORD pid)
137{
138 HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
139 MODULEENTRY32 me32;
140
141 hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pid );
142 if( hModuleSnap == INVALID_HANDLE_VALUE )
143 return QString();
144
145 me32.dwSize = sizeof( MODULEENTRY32 );
146
147 if( !Module32First( hModuleSnap, &me32 ) ) {
148 CloseHandle( hModuleSnap ); // clean the snapshot object
149 return QString();
150 }
151 QString name = QString::fromWCharArray(me32.szExePath);
152 CloseHandle( hModuleSnap );
153 return name;
154}
155
161static PSID getProcessOwner(HANDLE hProcess)
162{
163#ifndef _WIN32_WCE
164 HANDLE hToken = NULL;
165 PSID sid;
166
167 OpenProcessToken(hProcess, TOKEN_READ, &hToken);
168 if(hToken)
169 {
170 DWORD size;
171 PTOKEN_USER userStruct;
172
173 // check how much space is needed
174 GetTokenInformation(hToken, TokenUser, NULL, 0, &size);
175 if( ERROR_INSUFFICIENT_BUFFER == GetLastError() )
176 {
177 userStruct = reinterpret_cast<PTOKEN_USER>( new BYTE[size] );
178 GetTokenInformation(hToken, TokenUser, userStruct, size, &size);
179
180 sid = copySid(userStruct->User.Sid);
181 CloseHandle(hToken);
182 delete [] userStruct;
183 return sid;
184 }
185 }
186#endif
187 return 0;
188}
189
193static PSID getCurrentProcessOwner()
194{
195 return getProcessOwner(GetCurrentProcess());
196}
197
201class ProcessListEntry {
202 public:
203 ProcessListEntry( HANDLE _handle, QString _path, int _pid, PSID _owner=0 )
204 {
205 QFileInfo p(_path);
206 path = p.absolutePath();
207 name = p.baseName();
208 handle = _handle;
209 pid = _pid;
210 owner = copySid(_owner);
211 }
212
213 ~ProcessListEntry()
214 {
215 freeSid(owner);
216 CloseHandle(handle);
217 }
218
219 QString name;
220 QString path;
221 int pid;
222 HANDLE handle;
223 PSID owner;
224 friend QDebug operator <<(QDebug out, const ProcessListEntry &c);
225};
226
227QDebug operator <<(QDebug out, const ProcessListEntry &c)
228{
229 out << "(ProcessListEntry"
230 << "name" << c.name
231 << "path" << c.path
232 << "pid" << c.pid
233 << "handle" << c.handle
234 << "sid" << toString(c.owner)
235 << ")";
236 return out;
237}
238
246class ProcessList {
247public:
252 ProcessList(PSID userSid=0);
253
254 ~ProcessList();
255
261 ProcessListEntry *find(const QString &name);
262
268 bool terminateProcess(const QString &name);
269
274 QList<ProcessListEntry *> &list() { return m_processes; }
275
276private:
277 void init();
278 QList<ProcessListEntry *> m_processes;
279 PSID m_userId;
280};
281
282ProcessList::ProcessList(PSID userSid)
283{
284 m_userId = userSid;
285 init();
286}
287
288ProcessList::~ProcessList()
289{
290 foreach(const ProcessListEntry *ple,m_processes)
291 delete ple;
292}
293
294void ProcessList::init()
295{
296 HANDLE h;
297 PROCESSENTRY32 pe32;
298
299 h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
300 if (h == INVALID_HANDLE_VALUE) {
301 return;
302 }
303 pe32.dwSize = sizeof(PROCESSENTRY32);
304 if (!Process32First( h, &pe32 ))
305 return;
306
307 do
308 {
309 HANDLE hProcess = getProcessHandle(pe32.th32ProcessID);
310 if (!hProcess)
311 continue;
312 QString name = getProcessName(pe32.th32ProcessID);
313#ifndef _WIN32_WCE
314 PSID sid = getProcessOwner(hProcess);
315 if (!sid || m_userId && !EqualSid(m_userId,sid))
316 {
317 freeSid(sid);
318 continue;
319 }
320#else
321 PSID sid = 0;
322#endif
323 m_processes << new ProcessListEntry( hProcess, name, pe32.th32ProcessID, sid);
324 } while(Process32Next( h, &pe32 ));
325#ifndef _WIN32_WCE
326 CloseHandle(h);
327#else
328 CloseToolhelp32Snapshot(h);
329#endif
330}
331
332ProcessListEntry *ProcessList::find(const QString &name)
333{
334 ProcessListEntry *ple;
335 foreach(ple,m_processes) {
336 if (ple->pid < 0) {
337 qDebug() << "negative pid!";
338 continue;
339 }
340
341 if (ple->name != name && ple->name != name + ".exe") {
342 continue;
343 }
344
345 if (!ple->path.isEmpty() && !ple->path.toLower().startsWith(KStandardDirs::installPath("kdedir").toLower())) {
346 // process is outside of installation directory
347 qDebug() << "path of the process" << name << "seems to be outside of the installPath:" << ple->path << KStandardDirs::installPath("kdedir");
348 continue;
349 }
350 return ple;
351 }
352 return NULL;
353}
354
355bool ProcessList::terminateProcess(const QString &name)
356{
357 qDebug() << "going to terminate process" << name;
358 ProcessListEntry *p = find(name);
359 if (!p) {
360 qDebug() << "could not find ProcessListEntry for process name" << name;
361 return false;
362 }
363
364 bool ret = TerminateProcess(p->handle,0);
365 if (ret) {
366 int i = m_processes.indexOf(p);
367 if(i != -1) m_processes.removeAt(i);
368 delete p;
369 return true;
370 } else {
371 return false;
372 }
373}
374
375// internal launch function
376int launch(const QString &cmd)
377{
378 QProcess *proc = new QProcess();
379 proc->start(cmd);
380 proc->waitForStarted();
381 startedProcesses << proc;
382 _PROCESS_INFORMATION* _pid = proc->pid();
383 int pid = _pid ? _pid->dwProcessId : 0;
384 if (verbose) {
385 fprintf(stderr,"%s",proc->readAllStandardError().constData());
386 fprintf(stderr,"%s",proc->readAllStandardOutput().constData());
387 }
388 if (pid) {
389 if (verbose)
390 fprintf(stderr, "kdeinit4: Launched %s, pid = %ld\n", qPrintable(cmd),(long) pid);
391 }
392 else {
393 if (verbose)
394 fprintf(stderr, "kdeinit4: could not launch %s, exiting\n",qPrintable(cmd));
395 }
396 return pid;
397}
398
400bool checkIfRegisteredInDBus(const QString &name, int _timeout=10)
401{
402 int timeout = _timeout * 5;
403 while(timeout) {
404 if ( QDBusConnection::sessionBus().interface()->isServiceRegistered( name ) )
405 break;
406 Sleep(200);
407 timeout--;
408 }
409 if (!timeout) {
410 if (verbose)
411 fprintf(stderr,"not registered %s in dbus after %d secs\n",qPrintable(name),_timeout);
412 return false;
413 }
414 if (verbose)
415 fprintf(stderr,"%s is registered in dbus\n",qPrintable(name));
416 return true;
417}
418
419void listAllRunningKDEProcesses(ProcessList &processList)
420{
421 QString installPrefix = KStandardDirs::installPath("kdedir");
422
423 foreach(const ProcessListEntry *ple, processList.list())
424 {
425 if (!ple->path.isEmpty() && ple->path.toLower().startsWith(installPrefix.toLower()))
426 fprintf(stderr,"path: %s name: %s pid: %u\n", ple->path.toLatin1().data(), ple->name.toLatin1().data(), ple->pid);
427 }
428}
429
430void terminateAllRunningKDEProcesses(ProcessList &processList)
431{
432 QString installPrefix = KStandardDirs::installPath("kdedir");
433
434 foreach(const ProcessListEntry *ple, processList.list())
435 {
436 if (!ple->path.isEmpty() && ple->path.toLower().startsWith(installPrefix.toLower()))
437 {
438 if (verbose)
439 fprintf(stderr,"terminating path: %s name: %s pid: %u\n", ple->path.toLatin1().data(), ple->name.toLatin1().data(), ple->pid);
440 processList.terminateProcess(ple->name);
441 }
442 }
443}
444
445void listAllNamedAppsInDBus()
446{
447 QDBusConnection connection = QDBusConnection::sessionBus();
448 QDBusConnectionInterface *bus = connection.interface();
449 const QStringList services = bus->registeredServiceNames();
450 foreach(const QString &service, services) {
451 if (service.startsWith(QLatin1String("org.freedesktop.DBus")) || service.startsWith(QLatin1Char(':')))
452 continue;
453 fprintf(stderr, "%s \n", service.toLatin1().data());
454 }
455}
456
457void quitApplicationsOverDBus()
458{
459 QDBusConnection connection = QDBusConnection::sessionBus();
460 QDBusConnectionInterface *bus = connection.interface();
461 const QStringList services = bus->registeredServiceNames();
462 foreach(const QString &service, services) {
463 if (service.startsWith(QLatin1String("org.freedesktop.DBus")) || service.startsWith(QLatin1Char(':')))
464 continue;
465 QDBusInterface *iface = new QDBusInterface(service,
466 QLatin1String("/MainApplication"),
467 QLatin1String("org.kde.KApplication"),
468 connection);
469 if (!iface->isValid()) {
470 if (verbose)
471 fprintf(stderr, "invalid interface of service %s\n", service.toLatin1().data());
472 continue;
473 }
474 iface->call("quit");
475 if (iface->lastError().isValid()) {
476 if (verbose)
477 fprintf(stderr,"killing %s with result\n", iface->lastError().message().toLatin1().data());
478 }
479 delete iface;
480 }
481}
482
483int main(int argc, char **argv, char **envp)
484{
485 pid_t pid = 0;
486 bool launch_dbus = true;
487 bool launch_klauncher = true;
488 bool launch_kded = true;
489 bool suicide = false;
490 bool listProcesses = false;
491 bool killProcesses = false;
492 bool listAppsInDBus = false;
493 bool quitAppsOverDBus = false;
494 bool shutdown = false;
495
497 char **safe_argv = (char **) malloc( sizeof(char *) * argc);
498 for(int i = 0; i < argc; i++)
499 {
500 safe_argv[i] = strcpy((char*)malloc(strlen(argv[i])+1), argv[i]);
501 if (strcmp(safe_argv[i], "--no-dbus") == 0)
502 launch_dbus = false;
503 if (strcmp(safe_argv[i], "--no-klauncher") == 0)
504 launch_klauncher = false;
505 if (strcmp(safe_argv[i], "--no-kded") == 0)
506 launch_kded = false;
507 if (strcmp(safe_argv[i], "--suicide") == 0)
508 suicide = true;
509#ifdef ENABLE_EXIT
510 if (strcmp(safe_argv[i], "--exit") == 0)
511 keep_running = 0;
512#endif
513 if (strcmp(safe_argv[i], "--verbose") == 0)
514 verbose = 1;
515 if (strcmp(safe_argv[i], "--version") == 0)
516 {
517 printf("Qt: %s\n",qVersion());
518 printf("KDE: %s\n", KDE_VERSION_STRING);
519 exit(0);
520 }
521 if (strcmp(safe_argv[i], "--help") == 0)
522 {
523 printf("Usage: kdeinit4 [options]\n");
524#ifdef ENABLE_EXIT
525 printf(" --exit Terminate when kded has run\n");
526#endif
527 printf(" --help this help page\n");
528 printf(" --list list kde processes\n");
529 printf(" --list-dbus-apps list all applications registered in dbus\n");
530 printf(" --quit-over-dbus quit all application registered in dbus\n");
531 printf(" --no-dbus do not start dbus-daemon\n");
532 printf(" --no-klauncher do not start klauncher\n");
533 printf(" --no-kded do not start kded\n");
534 printf(" --shutdown safe shutdown of all running kde processes\n");
535 printf(" first over dbus, then using hard kill\n");
536#ifdef ENABLE_SUICIDE
537 printf(" --suicide terminate when no KDE applications are left running\n");
538#endif
539 printf(" --terminate hard kill of *all* running kde processes\n");
540 printf(" --verbose print verbose messages\n");
541 printf(" --version Show version information\n");
542 exit(0);
543 }
544 if (strcmp(safe_argv[i], "--list") == 0)
545 listProcesses = true;
546 if (strcmp(safe_argv[i], "--shutdown") == 0)
547 shutdown = true;
548 if (strcmp(safe_argv[i], "--terminate") == 0 || strcmp(safe_argv[i], "--kill") == 0)
549 killProcesses = true;
550 if (strcmp(safe_argv[i], "--list-dbus-apps") == 0)
551 listAppsInDBus = true;
552 if (strcmp(safe_argv[i], "--quit-over-dbus") == 0)
553 quitAppsOverDBus = true;
554 }
555
556 PSID currentSid = getCurrentProcessOwner();
557 if (verbose)
558 fprintf(stderr,"current user sid: %s\n",qPrintable(toString(currentSid)));
559 ProcessList processList(currentSid);
560 freeSid(currentSid);
561
562 if (listProcesses) {
563 listAllRunningKDEProcesses(processList);
564 return 0;
565 }
566 else if (killProcesses) {
567 terminateAllRunningKDEProcesses(processList);
568 return 0;
569 }
570 else if (listAppsInDBus) {
571 listAllNamedAppsInDBus();
572 return 0;
573 }
574 else if (quitAppsOverDBus) {
575 quitApplicationsOverDBus();
576 return 0;
577 }
578 else if (shutdown) {
579 quitApplicationsOverDBus();
580 Sleep(2000);
581 terminateAllRunningKDEProcesses(processList);
582 }
583
585 s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration);
586
587#ifdef _DEBUG
588 // first try to launch dbus-daemond in debug mode
589 if (launch_dbus && processList.find("dbus-daemond"))
590 launch_dbus = false;
591 if (launch_dbus)
592 {
593 pid = launch("dbus-launchd.exe");
594 if (!pid)
595 pid = launch("dbus-launchd.bat");
596 launch_dbus = (pid == 0);
597 }
598#endif
599 if (launch_dbus && !processList.find("dbus-daemon"))
600 {
601 if (!pid)
602 pid = launch("dbus-launch.exe");
603 if (!pid)
604 pid = launch("dbus-launch.bat");
605 if (!pid)
606 exit(1);
607 }
608
609 if (launch_klauncher && !processList.find("klauncher"))
610 {
611 pid = launch("klauncher");
612 if (!pid || !checkIfRegisteredInDBus("org.kde.klauncher",10))
613 exit(1);
614 }
615
616
617 if (launch_kded && !processList.find(KDED_EXENAME))
618 {
619 pid = launch(KDED_EXENAME);
620 if (!pid || !checkIfRegisteredInDBus("org.kde.kded",10))
621 exit(1);
622 }
623
624 for(int i = 1; i < argc; i++)
625 {
626 if (safe_argv[i][0] == '+')
627 {
628 pid = launch(safe_argv[i]+1);
629 }
630 else if (safe_argv[i][0] == '-')
631 {
632 // Ignore
633 }
634 else
635 {
636 pid = launch( safe_argv[i]);
637 }
638 }
639
641 for(int i = 0; i < argc; i++)
642 {
643 free(safe_argv[i]);
644 }
645 free (safe_argv);
646
648#ifdef ENABLE_SUICIDE
649 if (suicide) {
650 QProcess *proc;
651 int can_exit=1;
652 do {
653 foreach(proc,startedProcesses) {
654 if (proc->state() != QProcess::NotRunning)
655 can_exit = 0;
656 }
657 if (!can_exit)
658 Sleep(2000);
659 } while(!can_exit);
660 return 0;
661 }
662#endif
663 return 0;
664}
KComponentData
KComponentData::SkipMainComponentRegistration
SkipMainComponentRegistration
KStandardDirs::installPath
static QString installPath(const char *type)
QList
QProcess
kcomponentdata.h
result
char result
Definition: kinit.cpp:135
suicide
bool suicide
Definition: kinit.cpp:147
argv
char ** argv
Definition: kinit.cpp:141
getProcessOwner
static PSID getProcessOwner(HANDLE hProcess)
return sid of specific process
Definition: kinit_win.cpp:161
startedProcesses
QList< QProcess * > startedProcesses
holds process list for suicide mode
Definition: kinit_win.cpp:62
verbose
int verbose
Definition: kinit_win.cpp:59
KDED_EXENAME
#define KDED_EXENAME
Definition: kinit_win.cpp:54
terminateAllRunningKDEProcesses
void terminateAllRunningKDEProcesses(ProcessList &processList)
Definition: kinit_win.cpp:430
listAllRunningKDEProcesses
void listAllRunningKDEProcesses(ProcessList &processList)
Definition: kinit_win.cpp:419
main
int main(int argc, char **argv, char **envp)
Definition: kinit_win.cpp:483
launch
int launch(const QString &cmd)
Definition: kinit_win.cpp:376
copySid
PSID copySid(PSID from)
copy sid
Definition: kinit_win.cpp:76
getProcessHandle
static HANDLE getProcessHandle(int processID)
return process handle
Definition: kinit_win.cpp:124
listAllNamedAppsInDBus
void listAllNamedAppsInDBus()
Definition: kinit_win.cpp:445
getCurrentProcessOwner
static PSID getCurrentProcessOwner()
return sid of current process owner
Definition: kinit_win.cpp:193
quitApplicationsOverDBus
void quitApplicationsOverDBus()
Definition: kinit_win.cpp:457
checkIfRegisteredInDBus
bool checkIfRegisteredInDBus(const QString &name, int _timeout=10)
check dbus registration
Definition: kinit_win.cpp:400
toString
QString toString(PSID sid)
copy sid
Definition: kinit_win.cpp:104
operator<<
QDebug operator<<(QDebug out, const ProcessListEntry &c)
Definition: kinit_win.cpp:227
s_instance
static KComponentData * s_instance
Definition: kinit_win.cpp:56
getProcessName
static QString getProcessName(DWORD pid)
return absolute path of process
Definition: kinit_win.cpp:136
freeSid
void freeSid(PSID sid)
copy sid
Definition: kinit_win.cpp:92
timeout
int timeout
kstandarddirs.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KInit

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

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • 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
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal