| 85 | } |
| 86 | |
| 87 | bool dkmsRemove(const QString &driver, QWidget *parent) { |
| 88 | if (!isValidModuleName(driver)) { |
| 89 | QMessageBox::warning(parent, "Uninstall failed", "Invalid driver name."); |
| 90 | return false; |
| 91 | } |
| 92 | |
| 93 | QProcess proc; |
| 94 | proc.start("dkms", {"status"}); |
| 95 | bool statusOk = proc.waitForFinished(5000); |
| 96 | if (!statusOk) { |
| 97 | QMessageBox::warning(parent, "Uninstall failed", |
| 98 | "Could not query DKMS status (timed out)."); |
| 99 | return false; |
| 100 | } |
| 101 | QString dkmsStatus = QString::fromUtf8(proc.readAllStandardOutput()); |
| 102 | |
| 103 | // Match on the module name at the start of each line only. |
| 104 | // dkms status formats: "name/version, ..." (new) or "name, version, ..." (old). |
| 105 | // Using contains() would match "foo" inside "foobar", removing the wrong module. |
| 106 | QString moduleLine; |
| 107 | for (const QString &line : dkmsStatus.split('\n')) { |
| 108 | if (line.startsWith(driver + "/") || line.startsWith(driver + ",")) { |
| 109 | moduleLine = line; |
| 110 | break; |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | QString nameVer; |
| 115 | if (!moduleLine.isEmpty()) |
| 116 | nameVer = moduleLine.section(',', 0, 0).trimmed(); |
| 117 | |
| 118 | if (nameVer.isEmpty()) { |
| 119 | QMessageBox::warning(parent, "Uninstall failed", |
| 120 | "Could not find DKMS module information."); |
| 121 | return false; |
| 122 | } |
| 123 | |
| 124 | // Validate the parsed token before passing it to a privileged process. |
| 125 | // DKMS identifiers look like "name/version" or just "name"; permit only |
| 126 | // alphanumerics, underscores, hyphens, dots, and one optional slash. |
| 127 | static const QRegularExpression kDkmsRe("^[a-zA-Z0-9_./-]+$"); |
| 128 | if (!kDkmsRe.match(nameVer).hasMatch()) { |
| 129 | QMessageBox::warning(parent, "Uninstall failed", |
| 130 | "Unexpected DKMS module name format."); |
| 131 | return false; |
| 132 | } |
| 133 | |
| 134 | QProcess uninstall; |
| 135 | uninstall.start("pkexec", {"dkms", "remove", nameVer, "--all"}); |
| 136 | bool removeOk = uninstall.waitForFinished(30000); |
| 137 | if (!removeOk || uninstall.exitCode() != 0) { |
| 138 | showOpError(parent, "Uninstall failed", |
| 139 | !removeOk, uninstall.readAllStandardError()); |
| 140 | return false; |
| 141 | } |
| 142 | |
| 143 | QMessageBox::information(parent, "Uninstalled", "The driver has been removed."); |
| 144 | return true; |
no test coverage detected