Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.11.4)

project(
linglong
VERSION 1.13.2
VERSION 1.13.3
DESCRIPTION "a container based application package manager for Linux desktop"
HOMEPAGE_URL "https://github.com/OpenAtom-Linyaps/linyaps"
LANGUAGES CXX C)
Expand Down
50 changes: 40 additions & 10 deletions apps/ll-cli/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@
#include "linglong/utils/log/log.h"
#include "ocppi/cli/crun/Crun.hpp"

#include <CLI/CLI.hpp>

Check warning on line 23 in apps/ll-cli/src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <CLI/CLI.hpp> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <sys/file.h>

Check warning on line 24 in apps/ll-cli/src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <sys/file.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <QDBusConnection>

Check warning on line 26 in apps/ll-cli/src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDBusConnection> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QDBusMetaType>

Check warning on line 27 in apps/ll-cli/src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDBusMetaType> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QDBusObjectPath>

Check warning on line 28 in apps/ll-cli/src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDBusObjectPath> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QJsonDocument>

Check warning on line 29 in apps/ll-cli/src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QJsonDocument> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QJsonObject>
#include <QProcess>
#include <QtGlobal>
Expand All @@ -35,10 +36,11 @@
#include <map>
#include <memory>
#include <string_view>
#include <thread>

Check warning on line 39 in apps/ll-cli/src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <thread> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <fcntl.h>

Check warning on line 41 in apps/ll-cli/src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <fcntl.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <signal.h>

Check warning on line 42 in apps/ll-cli/src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <signal.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <unistd.h>

Check warning on line 43 in apps/ll-cli/src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <unistd.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <wordexp.h>

using namespace linglong::utils::error;
Expand All @@ -47,6 +49,26 @@

namespace {

void startProcess(const QString &program, const QStringList &args = {})
{
QProcess process;
auto envs = process.environment();
envs.push_back("QT_FORCE_STDERR_LOGGING=1");
process.setEnvironment(envs);
process.setProgram(program);
process.setArguments(args);

qint64 pid = 0;
process.startDetached(&pid);

LogD("start {} {} as {}", program.toStdString(), args.join(" ").toStdString(), pid);

QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, [pid]() {
LogD("kill {}", pid);
kill(pid, SIGTERM);
});
}
Comment on lines +52 to +70

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

There are two critical issues in the startProcess helper function:

  1. Environment Wiping: Calling process.environment() on a newly constructed QProcess returns an empty list. Appending "QT_FORCE_STDERR_LOGGING=1" and calling process.setEnvironment(envs) replaces the entire environment of the child process with just this single variable. This discards all system environment variables (such as PATH, LD_LIBRARY_PATH, USER, etc.), which will cause sudo or ll-package-manager to fail to start or run incorrectly. Use QProcess::systemEnvironment() to preserve the parent process's environment.

  2. Dangerous Signal Handling: If process.startDetached(&pid) fails, pid remains 0. Calling kill(0, SIGTERM) inside the aboutToQuit lambda will send SIGTERM to the entire process group of ll-cli, abruptly terminating the CLI itself and potentially other sibling/parent processes. You must check that startDetached succeeded and that pid > 0 before registering the cleanup connection.

void startProcess(const QString &program, const QStringList &args = {})
{
    QProcess process;
    auto envs = QProcess::systemEnvironment();
    envs.push_back("QT_FORCE_STDERR_LOGGING=1");
    process.setEnvironment(envs);
    process.setProgram(program);
    process.setArguments(args);

    qint64 pid = 0;
    if (process.startDetached(&pid) && pid > 0) {
        LogD("start {} {} as {}", program.toStdString(), args.join(" ").toStdString(), pid);

        QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, [pid]() {
            LogD("kill {}", pid);
            kill(pid, SIGTERM);
        });
    } else {
        LogE("failed to start process: {}", program.toStdString());
    }
}


std::vector<std::string> transformOldExec(int argc, char **argv) noexcept
{
std::vector<std::string> res;
Expand Down Expand Up @@ -692,16 +714,24 @@
return -1;
}

// Start ll-package-manager --no-dbus first to initialize the repository
QProcess::startDetached("sudo",
{ "--user",
LINGLONG_USERNAME,
"--preserve-env=QT_FORCE_STDERR_LOGGING",
"--preserve-env=QDBUS_DEBUG",
LINGLONG_LIBEXEC_DIR "/ll-package-manager",
"--no-dbus" });
using namespace std::chrono_literals;
std::this_thread::sleep_for(1s);
const auto pkgManAddress = QString("unix:path=/tmp/linglong-package-manager.socket");

// Check if ll-package-manager is already running
auto pkgManConn = QDBusConnection::connectToPeer(pkgManAddress, "ll-package-manager");
if (!pkgManConn.isConnected()) {
// Only start a new process if no existing one is listening
startProcess("sudo",
{ "--user",
LINGLONG_USERNAME,
"--preserve-env=QT_FORCE_STDERR_LOGGING",
"--preserve-env=QDBUS_DEBUG",
LINGLONG_LIBEXEC_DIR "/ll-package-manager",
"--no-dbus" });
using namespace std::chrono_literals;
std::this_thread::sleep_for(1s);
} else {
LogD("ll-package-manager is already running, reuse existing process");
}
Comment on lines +717 to +734

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using the connection name "ll-package-manager" for the temporary startup check can conflict with the actual connection established later in cli.cpp (line 471).

If the connection is not fully unregistered or closed immediately upon the destruction of pkgManConn (due to Qt's internal DBus thread handling or event loop delays), the subsequent connectToPeer call in cli.cpp will fail with a "connection already exists" error, preventing ll-cli from working in --no-dbus mode.

To prevent this, use a distinct connection name (e.g., "ll-package-manager-check") and explicitly disconnect from it once the check is complete.

        const auto pkgManAddress = QString("unix:path=/tmp/linglong-package-manager.socket");

        // Check if ll-package-manager is already running
        bool alreadyRunning = false;
        {
            auto checkConn = QDBusConnection::connectToPeer(pkgManAddress, "ll-package-manager-check");
            if (checkConn.isConnected()) {
                alreadyRunning = true;
                QDBusConnection::disconnectFromPeer("ll-package-manager-check");
            }
        }

        if (!alreadyRunning) {
            // Only start a new process if no existing one is listening
            startProcess("sudo",
                         { "--user",
                           LINGLONG_USERNAME,
                           "--preserve-env=QT_FORCE_STDERR_LOGGING",
                           "--preserve-env=QDBUS_DEBUG",
                           LINGLONG_LIBEXEC_DIR "/ll-package-manager",
                           "--no-dbus" });
            using namespace std::chrono_literals;
            std::this_thread::sleep_for(1s);
        } else {
            LogD("ll-package-manager is already running, reuse existing process");
        }

}
auto repo = linglong::repo::OSTreeRepo::loadFromPath(LINGLONG_ROOT);
if (!repo.has_value()) {
Expand Down
Loading