diff --git a/Telegram/SourceFiles/_other/updater_linux.cpp b/Telegram/SourceFiles/_other/updater_linux.cpp index ca191e601..58bc10efa 100644 --- a/Telegram/SourceFiles/_other/updater_linux.cpp +++ b/Telegram/SourceFiles/_other/updater_linux.cpp @@ -47,6 +47,7 @@ string updaterName; string workDir; string exeName; string exePath; +string argv0; FILE *_logFile = 0; void openLog() { @@ -356,17 +357,44 @@ string CurrentExecutablePath(int argc, char *argv[]) { } int main(int argc, char *argv[]) { + bool needupdate = true; + bool autostart = false; + bool debug = false; + bool tosettings = false; + bool startintray = false; + bool customWorkingDir = false; + bool justUpdate = false; + + char *key = 0; + char *workdir = 0; for (int i = 1; i < argc; ++i) { - if (equal(argv[i], "-debug")) { - _debug = true; + if (equal(argv[i], "-noupdate")) { + needupdate = false; + } else if (equal(argv[i], "-autostart")) { + autostart = true; + } else if (equal(argv[i], "-debug")) { + debug = _debug = true; + } else if (equal(argv[i], "-startintray")) { + startintray = true; + } else if (equal(argv[i], "-tosettings")) { + tosettings = true; + } else if (equal(argv[i], "-workdir_custom")) { + customWorkingDir = true; } else if (equal(argv[i], "-writeprotected")) { writeprotected = true; + justUpdate = true; + } else if (equal(argv[i], "-justupdate")) { + justUpdate = true; + } else if (equal(argv[i], "-key") && ++i < argc) { + key = argv[i]; } else if (equal(argv[i], "-workpath") && ++i < argc) { - workDir = argv[i]; + workDir = workdir = argv[i]; } else if (equal(argv[i], "-exename") && ++i < argc) { exeName = argv[i]; } else if (equal(argv[i], "-exepath") && ++i < argc) { exePath = argv[i]; + } else if (equal(argv[i], "-argv0") && ++i < argc) { + argv0 = argv[i]; } } if (exeName.empty() || exeName.find('/') != string::npos) { @@ -378,6 +406,8 @@ int main(int argc, char *argv[]) { for (int i = 0; i < argc; ++i) { writeLog("Argument: '%s'", argv[i]); } + if (needupdate) writeLog("Need to update!"); + if (autostart) writeLog("From autostart!"); if (writeprotected) writeLog("Write Protected folder!"); updaterName = CurrentExecutablePath(argc, argv); @@ -395,38 +425,42 @@ int main(int argc, char *argv[]) { exePath = updaterDir; writeLog("Using updater binary dir.", exePath.c_str()); } - if (workDir.empty()) { // old app launched, update prepared in tupdates/ready (not in tupdates/temp) - writeLog("No workdir, trying to figure it out"); - struct passwd *pw = getpwuid(getuid()); - if (pw && pw->pw_dir && strlen(pw->pw_dir)) { - string tryDir = pw->pw_dir + string("/.TelegramDesktop/"); - struct stat statbuf; - writeLog("Trying to use '%s' as workDir, getting stat() for tupdates/ready", tryDir.c_str()); - if (!stat((tryDir + "tupdates/ready").c_str(), &statbuf)) { - writeLog("Stat got"); - if (S_ISDIR(statbuf.st_mode)) { - writeLog("It is directory, using home work dir"); - workDir = tryDir; - } - } - } - if (workDir.empty()) { - workDir = exePath; + if (needupdate) { + if (workDir.empty()) { // old app launched, update prepared in tupdates/ready (not in tupdates/temp) + customWorkingDir = false; - struct stat statbuf; - writeLog("Trying to use current as workDir, getting stat() for tupdates/ready"); - if (!stat("tupdates/ready", &statbuf)) { - writeLog("Stat got"); - if (S_ISDIR(statbuf.st_mode)) { - writeLog("It is directory, using current dir"); - workDir = string(); + writeLog("No workdir, trying to figure it out"); + struct passwd *pw = getpwuid(getuid()); + if (pw && pw->pw_dir && strlen(pw->pw_dir)) { + string tryDir = pw->pw_dir + string("/.TelegramDesktop/"); + struct stat statbuf; + writeLog("Trying to use '%s' as workDir, getting stat() for tupdates/ready", tryDir.c_str()); + if (!stat((tryDir + "tupdates/ready").c_str(), &statbuf)) { + writeLog("Stat got"); + if (S_ISDIR(statbuf.st_mode)) { + writeLog("It is directory, using home work dir"); + workDir = tryDir; + } } } + if (workDir.empty()) { + workDir = exePath; + + struct stat statbuf; + writeLog("Trying to use current as workDir, getting stat() for tupdates/ready"); + if (!stat("tupdates/ready", &statbuf)) { + writeLog("Stat got"); + if (S_ISDIR(statbuf.st_mode)) { + writeLog("It is directory, using current dir"); + workDir = string(); + } + } + } + } else { + writeLog("Passed workpath is '%s'", workDir.c_str()); } - } else { - writeLog("Passed workpath is '%s'", workDir.c_str()); + update(); } - update(); } else { writeLog("Error: bad exe name!"); } @@ -434,7 +468,51 @@ int main(int argc, char *argv[]) { writeLog("Error: short exe name!"); } - writeLog("Closing log and quitting.."); + // let the parent launch instead + if (justUpdate) { + writeLog("Closing log and quitting.."); + } else { + const auto fullBinaryPath = exePath + exeName; + + auto values = vector(); + const auto push = [&](string arg) { + // Force null-terminated .data() call result. + values.push_back(arg + char(0)); + }; + push(!argv0.empty() ? argv0 : fullBinaryPath); + push("-noupdate"); + if (autostart) push("-autostart"); + if (debug) push("-debug"); + if (startintray) push("-startintray"); + if (tosettings) push("-tosettings"); + if (key) { + push("-key"); + push(key); + } + if (customWorkingDir && workdir) { + push("-workdir"); + push(workdir); + } + + auto args = vector(); + for (auto &arg : values) { + args.push_back(arg.data()); + } + args.push_back(nullptr); + + pid_t pid = fork(); + switch (pid) { + case -1: + writeLog("fork() failed!"); + return 1; + case 0: + execv(fullBinaryPath.c_str(), args.data()); + return 1; + } + + writeLog("Executed Telegram, closing log and quitting.."); + } + closeLog(); return 0; diff --git a/Telegram/SourceFiles/platform/linux/launcher_linux.cpp b/Telegram/SourceFiles/platform/linux/launcher_linux.cpp index bef25c7f8..0a5b8168d 100644 --- a/Telegram/SourceFiles/platform/linux/launcher_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/launcher_linux.cpp @@ -44,21 +44,27 @@ bool Launcher::launchUpdater(UpdaterLaunch action) { const auto justRelaunch = action == UpdaterLaunch::JustRelaunch; - const auto binaryPath = justRelaunch - ? (cExeDir() + cExeName()).toStdString() - : (cWriteProtected() - ? (cWorkingDir() + u"tupdates/temp/Updater"_q) - : (cExeDir() + u"Updater"_q)).toStdString(); - std::vector argumentsList; - if (justRelaunch) { - argumentsList.push_back(binaryPath); - } else if (cWriteProtected()) { - argumentsList.push_back("pkexec"); + + // What we are launching. + const auto launching = justRelaunch + ? (cExeDir() + cExeName()) + : cWriteProtected() + ? u"pkexec"_q + : (cExeDir() + u"Updater"_q); + argumentsList.push_back(launching.toStdString()); + + // argv[0] that is passed to what we are launching. + const auto argv0 = (justRelaunch && !arguments().isEmpty()) + ? arguments().first() + : launching; + argumentsList.push_back(argv0.toStdString()); + + if (!justRelaunch && cWriteProtected()) { + // Elevated process that pkexec should launch. + const auto elevated = cWorkingDir() + u"tupdates/temp/Updater"_q; + argumentsList.push_back(elevated.toStdString()); } - argumentsList.push_back((justRelaunch && !arguments().isEmpty()) - ? arguments().first().toStdString() - : binaryPath); if (Logs::DebugEnabled()) { argumentsList.push_back("-debug"); @@ -82,6 +88,9 @@ bool Launcher::launchUpdater(UpdaterLaunch action) { argumentsList.push_back(cWorkingDir().toStdString()); } } else { + // Don't relaunch Telegram. + argumentsList.push_back("-justupdate"); + argumentsList.push_back("-workpath"); argumentsList.push_back(cWorkingDir().toStdString()); argumentsList.push_back("-exename"); @@ -105,24 +114,22 @@ bool Launcher::launchUpdater(UpdaterLaunch action) { nullptr, nullptr, nullptr); - } else { - if (!GLib::spawn_sync( - argumentsList, - std::nullopt, - // if the spawn is sync, working directory is not set - // and GLib::SpawnFlags::LEAVE_DESCRIPTORS_OPEN_ is set, - // it goes through an optimized code path - GLib::SpawnFlags::SEARCH_PATH_ - | GLib::SpawnFlags::LEAVE_DESCRIPTORS_OPEN_, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr)) { - return false; - } - return launchUpdater(UpdaterLaunch::JustRelaunch); + } else if (!GLib::spawn_sync( + argumentsList, + std::nullopt, + // if the spawn is sync, working directory is not set + // and GLib::SpawnFlags::LEAVE_DESCRIPTORS_OPEN_ is set, + // it goes through an optimized code path + GLib::SpawnFlags::SEARCH_PATH_ + | GLib::SpawnFlags::LEAVE_DESCRIPTORS_OPEN_, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr)) { + return false; } + return launchUpdater(UpdaterLaunch::JustRelaunch); } } // namespace