File indexing completed on 2024-04-28 05:35:30
0001 /* 0002 ksmserver - the KDE session management server 0003 0004 SPDX-FileCopyrightText: 2000 Matthias Ettrich <ettrich@kde.org> 0005 0006 SPDX-License-Identifier: MIT 0007 */ 0008 0009 #include <cerrno> 0010 #include <config-ksmserver.h> 0011 #include <config-workspace.h> 0012 #include <cstdlib> 0013 #include <cstring> 0014 #include <fcntl.h> 0015 #include <fixx11h.h> 0016 #include <unistd.h> 0017 0018 #include "server.h" 0019 #include <KLocalizedString> 0020 #include <KMessageBox> 0021 #include <KRuntimePlatform> 0022 #include <KSelectionOwner> 0023 #include <KSharedConfig> 0024 #include <kconfig.h> 0025 #include <kconfiggroup.h> 0026 #include <kdbusservice.h> 0027 #include <ksmserver_debug.h> 0028 #include <kwindowsystem.h> 0029 #include <private/qtx11extras_p.h> 0030 0031 #include <QApplication> 0032 #include <QCommandLineParser> 0033 #include <QFile> 0034 0035 static const char version[] = "0.4"; 0036 0037 void IoErrorHandler(IceConn iceConn) 0038 { 0039 KSMServer::self()->ioError(iceConn); 0040 } 0041 0042 bool writeTest(QByteArray path) 0043 { 0044 path += "/XXXXXX"; 0045 int fd = mkstemp(path.data()); 0046 if (fd == -1) { 0047 return false; 0048 } 0049 if (write(fd, "Hello World\n", 12) == -1) { 0050 int save_errno = errno; 0051 close(fd); 0052 unlink(path.data()); 0053 errno = save_errno; 0054 return false; 0055 } 0056 close(fd); 0057 unlink(path.data()); 0058 return true; 0059 } 0060 0061 void sanity_check(int argc, char *argv[]) 0062 { 0063 QString msg; 0064 QByteArray path = qgetenv("HOME"); 0065 const QByteArray readOnly = qgetenv("KDE_HOME_READONLY"); 0066 if (path.isEmpty()) { 0067 msg = i18n("$HOME not set!"); 0068 } 0069 if (msg.isEmpty() && access(path.data(), W_OK)) { 0070 if (errno == ENOENT) { 0071 msg = i18n("$HOME directory (%1) does not exist.", QFile::decodeName(path)); 0072 } else if (readOnly.isEmpty()) { 0073 msg = xi18nc("@info", 0074 "No write access to $HOME directory (%1). If this is intentional, set <envar>KDE_HOME_READONLY=1</envar> in your environment.", 0075 QFile::decodeName(path)); 0076 } 0077 } 0078 if (msg.isEmpty() && access(path.data(), R_OK)) { 0079 if (errno == ENOENT) { 0080 msg = i18n("$HOME directory (%1) does not exist.", QFile::decodeName(path)); 0081 } else { 0082 msg = i18n("No read access to $HOME directory (%1).", QFile::decodeName(path)); 0083 } 0084 } 0085 if (msg.isEmpty() && readOnly.isEmpty() && !writeTest(path)) { 0086 if (errno == ENOSPC) { 0087 msg = i18n("$HOME directory (%1) is out of disk space.", QFile::decodeName(path)); 0088 } else { 0089 msg = i18n( 0090 "Writing to the $HOME directory (%2) failed with " 0091 "the error '%1'", 0092 QString::fromLocal8Bit(strerror(errno)), 0093 QFile::decodeName(path)); 0094 } 0095 } 0096 if (msg.isEmpty()) { 0097 path = getenv("ICEAUTHORITY"); 0098 if (path.isEmpty()) { 0099 path = qgetenv("HOME"); 0100 path += "/.ICEauthority"; 0101 } 0102 0103 if (access(path.data(), W_OK) && (errno != ENOENT)) { 0104 msg = i18n("No write access to '%1'.", QFile::decodeName(path)); 0105 } else if (access(path.data(), R_OK) && (errno != ENOENT)) { 0106 msg = i18n("No read access to '%1'.", QFile::decodeName(path)); 0107 } 0108 } 0109 if (msg.isEmpty()) { 0110 path = getenv("KDETMP"); 0111 if (path.isEmpty()) { 0112 path = "/tmp"; 0113 } 0114 if (!writeTest(path)) { 0115 if (errno == ENOSPC) { 0116 msg = i18n("Temp directory (%1) is out of disk space.", QFile::decodeName(path)); 0117 } else { 0118 msg = i18n( 0119 "Writing to the temp directory (%2) failed with\n " 0120 "the error '%1'", 0121 QString::fromLocal8Bit(strerror(errno)), 0122 QFile::decodeName(path)); 0123 } 0124 } 0125 } 0126 if (msg.isEmpty() && (path != "/tmp")) { 0127 path = "/tmp"; 0128 if (!writeTest(path)) { 0129 if (errno == ENOSPC) { 0130 msg = i18n("Temp directory (%1) is out of disk space.", QFile::decodeName(path)); 0131 } else { 0132 msg = i18n( 0133 "Writing to the temp directory (%2) failed with\n " 0134 "the error '%1'", 0135 QString::fromLocal8Bit(strerror(errno)), 0136 QFile::decodeName(path)); 0137 } 0138 } 0139 } 0140 if (msg.isEmpty()) { 0141 path += "/.ICE-unix"; 0142 if (access(path.data(), W_OK) && (errno != ENOENT)) { 0143 msg = i18n("No write access to '%1'.", QFile::decodeName(path)); 0144 } else if (access(path.data(), R_OK) && (errno != ENOENT)) { 0145 msg = i18n("No read access to '%1'.", QFile::decodeName(path)); 0146 } 0147 } 0148 if (!msg.isEmpty()) { 0149 const QString msg_pre = i18n( 0150 "The following installation problem was detected\n" 0151 "while trying to start Plasma:") 0152 + QStringLiteral("\n\n "); 0153 const QString msg_post = i18n("\n\nPlasma is unable to start.\n"); 0154 fputs(msg_pre.toUtf8().constData(), stderr); 0155 fprintf(stderr, "%s", msg.toUtf8().constData()); 0156 fputs(msg_post.toUtf8().constData(), stderr); 0157 0158 QApplication a(argc, argv); 0159 const QString qmsg = msg_pre + msg + msg_post; 0160 KMessageBox::error(nullptr, qmsg, i18n("Plasma Workspace installation problem!")); 0161 exit(255); 0162 } 0163 } 0164 0165 int main(int argc, char *argv[]) 0166 { 0167 sanity_check(argc, argv); 0168 0169 qunsetenv("SESSION_MANAGER"); 0170 0171 // force xcb QPA plugin as ksmserver is very X11 specific 0172 const QByteArray origQpaPlatform = qgetenv("QT_QPA_PLATFORM"); 0173 qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("xcb")); 0174 0175 QCoreApplication::setQuitLockEnabled(false); 0176 auto a = new QGuiApplication(argc, argv); 0177 0178 // now the QPA platform is set, unset variable again to not launch apps with incorrect environment 0179 if (origQpaPlatform.isEmpty()) { 0180 qunsetenv("QT_QPA_PLATFORM"); 0181 } else { 0182 qputenv("QT_QPA_PLATFORM", origQpaPlatform); 0183 } 0184 0185 QCoreApplication::setApplicationName(QStringLiteral("ksmserver")); 0186 QCoreApplication::setApplicationVersion(QString::fromLatin1(version)); 0187 QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org")); 0188 0189 fcntl(ConnectionNumber(QX11Info::display()), F_SETFD, 1); 0190 0191 a->setQuitOnLastWindowClosed(false); // #169486 0192 0193 QCommandLineParser parser; 0194 parser.setApplicationDescription(i18n("The reliable Plasma session manager that talks the standard X11R6 \nsession management protocol (XSMP).")); 0195 parser.addHelpOption(); 0196 parser.addVersionOption(); 0197 0198 QCommandLineOption restoreOption(QStringList() << QStringLiteral("r") << QStringLiteral("restore"), i18n("Restores the saved user session if available")); 0199 parser.addOption(restoreOption); 0200 0201 QCommandLineOption nolocalOption(QStringLiteral("nolocal"), i18n("Also allow remote connections")); 0202 parser.addOption(nolocalOption); 0203 0204 QCommandLineOption lockscreenOption(QStringLiteral("lockscreen"), i18n("Starts the session in locked mode")); 0205 parser.addOption(lockscreenOption); 0206 0207 QCommandLineOption noLockscreenOption(QStringLiteral("no-lockscreen"), 0208 i18n("Starts without lock screen support. Only needed if other component provides the lock screen.")); 0209 parser.addOption(noLockscreenOption); 0210 0211 parser.process(*a); 0212 0213 bool only_local = !parser.isSet(nolocalOption); 0214 #ifndef HAVE__ICETRANSNOLISTEN 0215 /* this seems strange, but the default is only_local, so if !only_local 0216 * the option --nolocal was given, and we warn (the option --nolocal 0217 * does nothing on this platform, as here the default is reversed) 0218 */ 0219 if (!only_local) { 0220 qCWarning(KSMSERVER, "--nolocal is not supported on your platform. Sorry."); 0221 } 0222 only_local = false; 0223 #endif 0224 0225 KSMServer::InitFlags flags = KSMServer::InitFlag::None; 0226 if (only_local) { 0227 flags |= KSMServer::InitFlag::OnlyLocal; 0228 } 0229 if (parser.isSet(lockscreenOption)) { 0230 flags |= KSMServer::InitFlag::ImmediateLockScreen; 0231 } 0232 if (parser.isSet(noLockscreenOption)) { 0233 flags |= KSMServer::InitFlag::NoLockScreen; 0234 } 0235 0236 // we use the session_type here as ksmserver is already forced as X above 0237 // in wayland, kwin manages the lock screen 0238 if (qgetenv("XDG_SESSION_TYPE") == QByteArrayLiteral("wayland")) { 0239 flags |= KSMServer::InitFlag::NoLockScreen; 0240 } 0241 0242 auto server = new KSMServer(flags); 0243 0244 // for the KDE-already-running check in startkde 0245 KSelectionOwner kde_running("_KDE_RUNNING", 0); 0246 kde_running.claim(false); 0247 0248 IceSetIOErrorHandler(IoErrorHandler); 0249 0250 KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("General")); 0251 0252 QString loginMode = config.readEntry("loginMode", "restorePreviousLogout"); 0253 0254 // we don't need session restoring in Plasma Mobile 0255 if (KRuntimePlatform::runtimePlatform().contains(QStringLiteral("phone"))) { 0256 loginMode = QStringLiteral("emptySession"); 0257 } 0258 0259 if (parser.isSet(restoreOption)) { 0260 server->setRestoreSession(SESSION_BY_USER); 0261 } else if (loginMode == QLatin1String("restorePreviousLogout")) { 0262 server->setRestoreSession(SESSION_PREVIOUS_LOGOUT); 0263 } else if (loginMode == QLatin1String("restoreSavedSession")) { 0264 server->setRestoreSession(SESSION_BY_USER); 0265 } else { 0266 server->startDefaultSession(); 0267 } 0268 0269 KDBusService service(KDBusService::Unique); 0270 0271 int ret = a->exec(); 0272 kde_running.release(); // needs to be done before QGuiApplication destruction 0273 delete a; 0274 return ret; 0275 }