File indexing completed on 2024-05-05 09:51:29
0001 /* 0002 KSysGuard, the KDE System Guard 0003 0004 SPDX-FileCopyrightText: 2006-2007 John Tapsell <john.tapsell@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 0008 */ 0009 #include "processui_debug.h" 0010 0011 /* For getuid() */ 0012 #include <sys/types.h> 0013 #include <unistd.h> 0014 0015 #include <QDebug> 0016 #include <QVariant> 0017 0018 #include "ProcessFilter.h" 0019 #include "ProcessModel.h" 0020 #include "ProcessModel_p.h" 0021 0022 bool ProcessFilter::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const 0023 { 0024 if ((mFilter == AllProcesses || mFilter == AllProcessesInTreeForm) && filterRegularExpression().pattern().isEmpty()) { 0025 return true; // Shortcut for common case 0026 } 0027 0028 ProcessModel *model = static_cast<ProcessModel *>(sourceModel()); 0029 const KSysGuard::Process *process; 0030 if (model->isSimpleMode()) { 0031 if (source_parent.isValid()) { 0032 qCDebug(LIBKSYSGUARD_PROCESSUI) << "Serious error with data. In simple mode, there should be no children"; 0033 return true; 0034 } 0035 process = model->getProcessAtIndex(source_row); 0036 } else { 0037 KSysGuard::Process *parent_process = nullptr; 0038 if (source_parent.isValid()) { 0039 parent_process = reinterpret_cast<KSysGuard::Process *>(source_parent.internalPointer()); 0040 Q_ASSERT(parent_process); 0041 } else { 0042 // if(!model->isSimpleMode()) { 0043 parent_process = model->getProcess(-1); // Get our 'special' process which should have the root init child 0044 Q_ASSERT(parent_process); 0045 //} 0046 } 0047 if (!model->isSimpleMode() && source_row >= parent_process->children().size()) { 0048 qCDebug(LIBKSYSGUARD_PROCESSUI) << "Serious error with data. Source row requested for a non existent row. Requested " << source_row << " of " 0049 << parent_process->children().size() << " for " << parent_process->pid(); 0050 return true; 0051 } 0052 0053 process = parent_process->children().at(source_row); 0054 } 0055 Q_ASSERT(process); 0056 long uid = process->uid(); 0057 long euid = process->euid(); 0058 0059 bool accepted = true; 0060 switch (mFilter) { 0061 case AllProcesses: 0062 case AllProcessesInTreeForm: 0063 break; 0064 case SystemProcesses: 0065 if (uid >= 100 && model->canUserLogin(uid)) { 0066 accepted = false; 0067 } 0068 break; 0069 case UserProcesses: 0070 if ((uid < 100 || !model->canUserLogin(uid)) && (euid < 100 || !model->canUserLogin(euid))) { 0071 accepted = false; 0072 } 0073 break; 0074 case OwnProcesses: { 0075 long ownuid = getuid(); 0076 if (uid != ownuid && process->suid() != ownuid && process->fsuid() != ownuid && euid != ownuid) { 0077 accepted = false; 0078 } 0079 break; 0080 } 0081 case ProgramsOnly: 0082 if (process->tty().isEmpty()) { 0083 if (!model->hasGUIWindow(process->pid())) { 0084 accepted = false; 0085 } 0086 } else { 0087 // login and getty kinda _are_ the tty, so I do not really count them as 'programs'. So make a special case and hide them 0088 // Their ppid are 1 (init) so by checking we try to avoid false matches, and speed up checking overall 0089 QString name = process->name().section(QLatin1Char(' '), 0, 0); 0090 if (process->parentPid() == 1 && (name == QLatin1String("login") || name.endsWith(QLatin1String("getty")))) { 0091 accepted = false; 0092 } 0093 } 0094 break; 0095 default: 0096 break; 0097 } 0098 0099 if (accepted) { 0100 if (filterRegularExpression().pattern().isEmpty()) { 0101 return true; 0102 } 0103 0104 // Allow the user to search by PID 0105 if (QString::number(process->pid()).contains(filterRegularExpression())) { 0106 return true; 0107 } 0108 // None of our tests have rejected it. Pass it on to qsortfilterproxymodel's filter 0109 if (QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent)) { 0110 return true; 0111 } 0112 0113 auto strings = filterRegularExpression().pattern().split(QLatin1Char(','), Qt::SkipEmptyParts); 0114 for (auto string : strings) { 0115 string = string.trimmed(); 0116 if (process->name().indexOf(string) != -1 || QString::number(process->pid()).indexOf(string) != -1) { 0117 return true; 0118 } 0119 } 0120 } 0121 0122 // We did not accept this row at all. 0123 0124 // If we are in flat mode, then give up now 0125 if (mFilter != AllProcessesInTreeForm) { 0126 return false; 0127 } 0128 0129 // one of our children might be accepted, so accept this row if our children are accepted. 0130 QModelIndex source_index = sourceModel()->index(source_row, 0, source_parent); 0131 for (int i = 0; i < sourceModel()->rowCount(source_index); i++) { 0132 if (filterAcceptsRow(i, source_index)) { 0133 return true; 0134 } 0135 } 0136 return false; 0137 } 0138 0139 bool ProcessFilter::lessThan(const QModelIndex &left, const QModelIndex &right) const 0140 { 0141 if (right.isValid() && left.isValid()) { 0142 Q_ASSERT(left.model()); 0143 Q_ASSERT(right.model()); 0144 const ProcessModel *model = static_cast<const ProcessModel *>(left.model()); 0145 return model->lessThan(left, right); 0146 } 0147 return QSortFilterProxyModel::lessThan(left, right); 0148 } 0149 0150 void ProcessFilter::setFilter(State filter) 0151 { 0152 mFilter = filter; 0153 invalidateFilter(); // Tell the proxy view to refresh all its information 0154 }