File indexing completed on 2024-04-21 05:45:46
0001 /******************************************************************************* 0002 * Copyright (C) 2008-2013 Konstantinos Smanis <konstantinos.smanis@gmail.com> * 0003 * * 0004 * This program is free software: you can redistribute it and/or modify it * 0005 * under the terms of the GNU General Public License as published by the Free * 0006 * Software Foundation, either version 3 of the License, or (at your option) * 0007 * any later version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT * 0010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 0011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * 0012 * more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License along * 0015 * with this program. If not, see <http://www.gnu.org/licenses/>. * 0016 *******************************************************************************/ 0017 0018 //Krazy 0019 //krazy:excludeall=cpp 0020 0021 //Own 0022 #include "helper.h" 0023 0024 //Qt 0025 #include <QDebug> 0026 #include <QDir> 0027 0028 //KDE 0029 #include <KLocalizedString> 0030 #include <KProcess> 0031 #include <KAuth/HelperSupport> 0032 0033 //Project 0034 #include "../common.h" 0035 #include "../config.h" 0036 #if HAVE_HD 0037 #undef slots 0038 #include <hd.h> 0039 #endif 0040 0041 //The $PATH environment variable is emptied by D-Bus activation, 0042 //so let's provide a sane default. Needed for os-prober to work. 0043 static const QLatin1String path("/usr/sbin:/usr/bin:/sbin:/bin"); 0044 0045 Helper::Helper() 0046 { 0047 qputenv("PATH", path.latin1()); 0048 } 0049 0050 ActionReply Helper::executeCommand(const QStringList &command) 0051 { 0052 KProcess process; 0053 process.setProgram(command); 0054 process.setOutputChannelMode(KProcess::MergedChannels); 0055 0056 qDebug() << "Executing" << command.join(QLatin1String(" ")); 0057 int exitCode = process.execute(); 0058 const QByteArray output = process.readAll(); 0059 0060 ActionReply reply; 0061 if (exitCode != 0) { 0062 reply = ActionReply::HelperErrorReply(exitCode); 0063 QString errorMessage; 0064 switch (exitCode) { 0065 case -2: 0066 errorMessage = i18nc("@info", "The process could not be started."); 0067 break; 0068 case -1: 0069 errorMessage = i18nc("@info", "The process crashed."); 0070 break; 0071 default: 0072 errorMessage = QString::fromUtf8(output); 0073 break; 0074 } 0075 reply.setErrorDescription(i18nc("@info", "Command: <command>%1</command><nl/>", command.join(QLatin1String(" "))) + 0076 errorDescription(exitCode, errorMessage)); 0077 } else { 0078 reply.addData(QStringLiteral("command"), command); 0079 reply.addData(QStringLiteral("output"), output); 0080 } 0081 return reply; 0082 } 0083 bool Helper::setLang(const QString &lang) 0084 { 0085 QFile file(grubMenuPath()); 0086 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { 0087 qCritical() << "Failed to open file for reading:" << grubMenuPath(); 0088 qCritical() << "Error code:" << file.error(); 0089 qCritical() << "Error description:" << file.errorString(); 0090 return false; 0091 } 0092 QString fileContents = QString::fromUtf8(file.readAll().constData()); 0093 file.close(); 0094 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { 0095 qCritical() << "Failed to open file for writing:" << grubMenuPath(); 0096 qCritical() << "Error code:" << file.error(); 0097 qCritical() << "Error description:" << file.errorString(); 0098 return false; 0099 } 0100 fileContents.replace(QRegExp(QStringLiteral("(\\n\\s*set\\s+lang=)\\S*\\n")), QStringLiteral("\\1%1\n").arg(lang)); 0101 if (file.write(fileContents.toUtf8()) == -1) { 0102 qCritical() << "Failed to write data to file:" << grubMenuPath(); 0103 qCritical() << "Error code:" << file.error(); 0104 qCritical() << "Error description:" << file.errorString(); 0105 return false; 0106 } 0107 file.close(); 0108 return true; 0109 } 0110 0111 ActionReply Helper::defaults(QVariantMap args) 0112 { 0113 Q_UNUSED(args) 0114 ActionReply reply; 0115 QString configFileName = grubConfigPath(); 0116 QString originalConfigFileName = configFileName + QLatin1String(".original"); 0117 0118 if (!QFile::exists(originalConfigFileName)) { 0119 reply = ActionReply::HelperErrorReply(); 0120 reply.setError(1); 0121 reply.setErrorDescription(errorDescription(reply.errorCode(), i18n("Original configuration file <filename>%1</filename> does not exist.", originalConfigFileName))); 0122 return reply; 0123 } 0124 if (!QFile::remove(configFileName)) { 0125 reply = ActionReply::HelperErrorReply(); 0126 reply.setError(2); 0127 reply.setErrorDescription(errorDescription(reply.errorCode(), i18n("Cannot remove current configuration file <filename>%1</filename>.", configFileName))); 0128 return reply; 0129 } 0130 if (!QFile::copy(originalConfigFileName, configFileName)) { 0131 reply = ActionReply::HelperErrorReply(); 0132 reply.setError(3); 0133 reply.setErrorDescription(errorDescription(reply.errorCode(), i18n("Cannot copy original configuration file <filename>%1</filename> to <filename>%2</filename>.", originalConfigFileName, configFileName))); 0134 return reply; 0135 } 0136 return reply; 0137 } 0138 ActionReply Helper::install(QVariantMap args) 0139 { 0140 ActionReply reply; 0141 QString partition = args.value(QStringLiteral("partition")).toString(); 0142 QString mountPoint = args.value(QStringLiteral("mountPoint")).toString(); 0143 bool mbrInstall = args.value(QStringLiteral("mbrInstall")).toBool(); 0144 0145 if (mountPoint.isEmpty()) { 0146 for (int i = 0; QDir(mountPoint = QStringLiteral("%1/kcm-grub2-%2").arg(QDir::tempPath(), QString::number(i))).exists(); i++); 0147 if (!QDir().mkpath(mountPoint)) { 0148 reply = ActionReply::HelperErrorReply(); 0149 reply.setError(4); 0150 reply.setErrorDescription(errorDescription(reply.errorCode(), i18n("Failed to create temporary mount point."))); 0151 return reply; 0152 } 0153 ActionReply mountReply = executeCommand(QStringList() << QStringLiteral("mount") << partition << mountPoint); 0154 if (mountReply.failed()) { 0155 return mountReply; 0156 } 0157 } 0158 0159 QStringList grub_installCommand; 0160 grub_installCommand << grubInstallExePath() << QStringLiteral("--root-directory") << mountPoint; 0161 if (mbrInstall) { 0162 grub_installCommand << partition.remove(QRegExp(QLatin1String("\\d+"))); 0163 } else { 0164 grub_installCommand << QStringLiteral("--force") << partition; 0165 } 0166 return executeCommand(grub_installCommand); 0167 } 0168 ActionReply Helper::load(QVariantMap args) 0169 { 0170 ActionReply reply; 0171 LoadOperations operations = (LoadOperations)(args.value(QStringLiteral("operations")).toInt()); 0172 0173 if (operations.testFlag(MenuFile)) { 0174 QFile file(grubMenuPath()); 0175 bool ok = file.open(QIODevice::ReadOnly | QIODevice::Text); 0176 reply.addData(QStringLiteral("menuSuccess"), ok); 0177 if (ok) { 0178 reply.addData(QStringLiteral("menuContents"), file.readAll()); 0179 } else { 0180 reply.addData(QStringLiteral("menuError"), file.error()); 0181 reply.addData(QStringLiteral("menuErrorString"), file.errorString()); 0182 } 0183 } 0184 if (operations.testFlag(ConfigurationFile)) { 0185 QFile file(grubConfigPath()); 0186 bool ok = file.open(QIODevice::ReadOnly | QIODevice::Text); 0187 reply.addData(QStringLiteral("configSuccess"), ok); 0188 if (ok) { 0189 reply.addData(QStringLiteral("configContents"), file.readAll()); 0190 } else { 0191 reply.addData(QStringLiteral("configError"), file.error()); 0192 reply.addData(QStringLiteral("configErrorString"), file.errorString()); 0193 } 0194 } 0195 if (operations.testFlag(EnvironmentFile)) { 0196 QFile file(grubEnvPath()); 0197 bool ok = file.open(QIODevice::ReadOnly | QIODevice::Text); 0198 reply.addData(QStringLiteral("envSuccess"), ok); 0199 if (ok) { 0200 reply.addData(QStringLiteral("envContents"), file.readAll()); 0201 } else { 0202 reply.addData(QStringLiteral("envError"), file.error()); 0203 reply.addData(QStringLiteral("envErrorString"), file.errorString()); 0204 } 0205 } 0206 if (operations.testFlag(MemtestFile)) { 0207 bool memtest = QFile::exists(grubMemtestPath()); 0208 reply.addData(QStringLiteral("memtest"), memtest); 0209 if (memtest) { 0210 reply.addData(QStringLiteral("memtestOn"), (bool)(QFile::permissions(grubMemtestPath()) & (QFile::ExeOwner | QFile::ExeGroup | QFile::ExeOther))); 0211 } 0212 } 0213 #if HAVE_HD 0214 if (operations.testFlag(Vbe)) { 0215 QStringList gfxmodes; 0216 hd_data_t hd_data; 0217 memset(&hd_data, 0, sizeof(hd_data)); 0218 hd_t *hd = hd_list(&hd_data, hw_framebuffer, 1, NULL); 0219 for (hd_res_t *res = hd->res; res; res = res->next) { 0220 if (res->any.type == res_framebuffer) { 0221 gfxmodes += QString(QLatin1String("%1x%2x%3")).arg(QString::number(res->framebuffer.width), QString::number(res->framebuffer.height), QString::number(res->framebuffer.colorbits)); 0222 } 0223 } 0224 hd_free_hd_list(hd); 0225 hd_free_hd_data(&hd_data); 0226 reply.addData(QLatin1String("gfxmodes"), gfxmodes); 0227 } 0228 #endif 0229 if (operations.testFlag(Locales)) { 0230 reply.addData(QStringLiteral("locales"), QDir(grubLocalePath()).entryList(QStringList() << QStringLiteral("*.mo"), QDir::Files).replaceInStrings(QRegExp(QLatin1String("\\.mo$")), QString())); 0231 } 0232 return reply; 0233 } 0234 ActionReply Helper::save(QVariantMap args) 0235 { 0236 ActionReply reply; 0237 QString configFileName = grubConfigPath(); 0238 QByteArray rawConfigFileContents = args.value(QStringLiteral("rawConfigFileContents")).toByteArray(); 0239 QByteArray rawDefaultEntry = args.value(QStringLiteral("rawDefaultEntry")).toByteArray(); 0240 bool memtest = args.value(QStringLiteral("memtest")).toBool(); 0241 0242 QFile::copy(configFileName, configFileName + QLatin1String(".original")); 0243 0244 QFile file(configFileName); 0245 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { 0246 reply = ActionReply::HelperErrorReply(); 0247 reply.setError(5); 0248 reply.setErrorDescription(errorDescription(reply.errorCode(), file.errorString())); 0249 return reply; 0250 } 0251 file.write(rawConfigFileContents); 0252 file.close(); 0253 0254 if (args.contains(QStringLiteral("memtest"))) { 0255 QFile::Permissions permissions = QFile::permissions(grubMemtestPath()); 0256 if (memtest) { 0257 permissions |= (QFile::ExeOwner | QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther); 0258 } else { 0259 permissions &= ~(QFile::ExeOwner | QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther); 0260 } 0261 QFile::setPermissions(grubMemtestPath(), permissions); 0262 } 0263 0264 if (args.contains(QStringLiteral("LANG"))) { 0265 qputenv("LANG", args.value(QStringLiteral("LANG")).toByteArray()); 0266 } 0267 ActionReply grub_mkconfigReply = executeCommand(QStringList() << grubMkconfigExePath() << QStringLiteral("-o") << grubMenuPath()); 0268 if (grub_mkconfigReply.failed()) { 0269 return grub_mkconfigReply; 0270 } 0271 if (args.contains(QStringLiteral("LANGUAGE"))) { 0272 if (!setLang(args.value(QStringLiteral("LANGUAGE")).toString())) { 0273 qCritical() << "An error occurred while setting the language for the GRUB menu."; 0274 qCritical() << "The GRUB menu will not be properly translated!"; 0275 } 0276 } 0277 0278 ActionReply grub_set_defaultReply = executeCommand(QStringList() << grubSetDefaultExePath() << QString::fromUtf8(rawDefaultEntry.constData())); 0279 if (grub_set_defaultReply.failed()) { 0280 return grub_set_defaultReply; 0281 } 0282 0283 return grub_mkconfigReply; 0284 } 0285 0286 QString Helper::errorDescription(int errorCode, const QString &errorMessage) const 0287 { 0288 return i18nc("@info", "Error code: <numid>%1</numid><nl/>Error message: <message>%2</message>", errorCode, errorMessage); 0289 } 0290 0291 KAUTH_HELPER_MAIN("org.kde.kcontrol.kcmgrub2", Helper)