Skip to content

fix: use flock to check dpkg lock instead of ps scan - #771

Open
add-uos wants to merge 1 commit into
linuxdeepin:masterfrom
add-uos:agent/bug/22211f7e56cf
Open

add-uos wants to merge 1 commit into
linuxdeepin:masterfrom
add-uos:agent/bug/22211f7e56cf

Conversation

@add-uos

@add-uos add-uos commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

fix: use flock to check dpkg lock instead of ps scan

  1. Root cause: isDpkgLocked() scanned ps output for "dpkg" processes
    and only excluded dpkg-query, causing false positives from other
    dpkg-related processes like dpkg-stat
  2. Fix: replace ps scanning with non-blocking exclusive flock on dpkg
    lock files (/var/lib/dpkg/lock-frontend and /var/lib/dpkg/lock)
    to accurately detect active dpkg operations
  3. Impact: isDpkgLocked() now returns accurate results, eliminating
    false positives and improving performance by avoiding QProcess

Influence:

  1. Test isDpkgLocked() returns false when no dpkg operation is running
  2. Test isDpkgLocked() returns true when dpkg is actively running
  3. Verify no regression in driver install/uninstall workflows

fix: 使用flock检查dpkg锁替代ps进程扫描

  1. 根因:isDpkgLocked()通过扫描ps输出中包含"dpkg"的进程来判断锁状态,
    仅排除dpkg-query,其他dpkg相关进程如dpkg-stat会导致误报
  2. 方案:使用非阻塞排他flock检查dpkg锁文件(/var/lib/dpkg/lock-frontend
    和/var/lib/dpkg/lock)替代ps扫描,准确检测dpkg操作状态
  3. 影响:isDpkgLocked()返回结果更准确,消除误报,避免QProcess开销提升性能

Influence:

  1. 测试无dpkg操作运行时isDpkgLocked()返回false
  2. 测试dpkg正在运行时isDpkgLocked()返回true
  3. 验证驱动安装/卸载流程无回归

PMS: DEFECT-002

Summary by Sourcery

Replace process scanning with non-blocking dpkg lock checks to accurately determine whether package operations are active.

Bug Fixes:

  • Correct dpkg operation detection by checking dpkg lock-file availability instead of scanning process names, eliminating false positives from unrelated dpkg processes.

Enhancements:

  • Avoid spawning QProcess for dpkg lock checks, improving the efficiency of driver installation and uninstallation workflows.

1. Root cause: isDpkgLocked() scanned ps output for "dpkg" processes
   and only excluded dpkg-query, causing false positives from other
   dpkg-related processes like dpkg-stat
2. Fix: replace ps scanning with non-blocking exclusive flock on dpkg
   lock files (/var/lib/dpkg/lock-frontend and /var/lib/dpkg/lock)
   to accurately detect active dpkg operations
3. Impact: isDpkgLocked() now returns accurate results, eliminating
   false positives and improving performance by avoiding QProcess

Influence:
1. Test isDpkgLocked() returns false when no dpkg operation is running
2. Test isDpkgLocked() returns true when dpkg is actively running
3. Verify no regression in driver install/uninstall workflows

fix: 使用flock检查dpkg锁替代ps进程扫描

1. 根因:isDpkgLocked()通过扫描ps输出中包含"dpkg"的进程来判断锁状态,
   仅排除dpkg-query,其他dpkg相关进程如dpkg-stat会导致误报
2. 方案:使用非阻塞排他flock检查dpkg锁文件(/var/lib/dpkg/lock-frontend
   和/var/lib/dpkg/lock)替代ps扫描,准确检测dpkg操作状态
3. 影响:isDpkgLocked()返回结果更准确,消除误报,避免QProcess开销提升性能

Influence:
1. 测试无dpkg操作运行时isDpkgLocked()返回false
2. 测试dpkg正在运行时isDpkgLocked()返回true
3. 验证驱动安装/卸载流程无回归

PMS: DEFECT-002
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: add-uos

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai

sourcery-ai Bot commented Sep 17, 2026

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Updates isDpkgLocked() to determine whether dpkg is active by attempting non-blocking exclusive locks on the frontend and general dpkg lock files, eliminating false positives from unrelated dpkg-named processes and avoiding QProcess overhead.

Sequence diagram for dpkg lock detection

sequenceDiagram
    participant Caller
    participant Utils
    participant DpkgLockFiles

    Caller->>Utils: isDpkgLocked()
    loop each lock file
        Utils->>DpkgLockFiles: open(lockFile, O_RDONLY | O_CLOEXEC)
        alt open fails
            Utils-->>Caller: true
        else file opened
            Utils->>DpkgLockFiles: flock(fd, LOCK_EX | LOCK_NB)
            alt lock unavailable
                Utils-->>Caller: true
            else lock acquired
                Utils->>DpkgLockFiles: close(fd)
            end
        end
    end
    Utils-->>Caller: false
Loading

File-Level Changes

Change Details Files
Replace process-list scanning with direct, non-blocking checks of dpkg lock files.
  • Open both dpkg lock files with close-on-exec flags.
  • Attempt exclusive non-blocking flock acquisition and report the lock as active when opening or locking fails.
  • Remove the QProcess-based ps invocation and dpkg-query filtering logic.
deepin-devicemanager-server/deepin-devicecontrol/src/drivercontrol/utils.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="deepin-devicemanager-server/deepin-devicecontrol/src/drivercontrol/utils.cpp" line_range="243" />
<code_context>
+        "/var/lib/dpkg/lock"
+    };
+    for (const QString &lockFile : lockFiles) {
+        int fd = open(lockFile.toLocal8Bit().constData(), O_RDONLY | O_CLOEXEC);
+        if (fd < 0) {
+            return true;
+        }
+        if (flock(fd, LOCK_EX | LOCK_NB) == -1) {
+            close(fd);
+            return true;
+        }
</code_context>
<issue_to_address>
**issue (bug_risk):** `flock(fd, LOCK_EX | LOCK_NB)` fails with `EBADF` because each lock file is opened with `O_RDONLY`, while an exclusive flock requires a file descriptor opened for writing. Since every existing dpkg lock file follows this path, `isDpkgLocked()` returns true even when no dpkg operation is running, causing installation workflows to retry until timeout.

**Triggers:** When either dpkg lock file exists, including the normal idle system state.

**Suggested fix:** Open the lock files with a writable mode such as `O_RDWR` before attempting `LOCK_EX`, or use a lock-checking operation compatible with the descriptor mode.

```suggestion
        int fd = open(lockFile.toLocal8Bit().constData(), O_RDWR | O_CLOEXEC);
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

"/var/lib/dpkg/lock"
};
for (const QString &lockFile : lockFiles) {
int fd = open(lockFile.toLocal8Bit().constData(), O_RDONLY | O_CLOEXEC);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): flock(fd, LOCK_EX | LOCK_NB) fails with EBADF because each lock file is opened with O_RDONLY, while an exclusive flock requires a file descriptor opened for writing. Since every existing dpkg lock file follows this path, isDpkgLocked() returns true even when no dpkg operation is running, causing installation workflows to retry until timeout.

Triggers: When either dpkg lock file exists, including the normal idle system state.

Suggested fix: Open the lock files with a writable mode such as O_RDWR before attempting LOCK_EX, or use a lock-checking operation compatible with the descriptor mode.

Suggested change
int fd = open(lockFile.toLocal8Bit().constData(), O_RDONLY | O_CLOEXEC);
int fd = open(lockFile.toLocal8Bit().constData(), O_RDWR | O_CLOEXEC);

@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

🤖 AI 代码审查报告

总体评分: 95 分 (通过阈值: 70分)

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 总体评分 95 分,大于 70 分通过阈值,代码质量符合要求。本次修改将 isDpkgLocked() 函数从 ps 进程扫描改为 flock 锁文件检查,消除了误报问题,提升了检测准确性和性能,未发现安全漏洞。

🔍 详细分析

1. 语法逻辑 ✅

评价: 优秀 ✅ 通过

潜在问题:

  1. deepin-devicemanager-server/deepin-devicecontrol/src/drivercontrol/utils.cpp:244 - open() 失败时返回 true(已锁定)偏保守,锁文件不存在的极端情况下可能误报

建议: 语法正确,逻辑清晰。建议在 open() 失败时检查 errno,仅在文件确实被锁定时返回 true,其他错误(如 ENOENT)可记录日志并返回 false


2. 代码质量 ✅

评价: 优秀 ✅ 通过

潜在问题:

  1. deepin-devicemanager-server/deepin-devicecontrol/src/drivercontrol/utils.cpp:235 - 函数缺少 @brief 文档注释,建议参考 isDriverPackage() 添加
  2. deepin-devicemanager-server/deepin-devicecontrol/src/drivercontrol/utils.cpp:244 - open() 失败时缺少错误日志,建议参考 isFileLocked() 添加 qCInfo 日志

建议: 代码结构清晰,注释完整。建议添加函数文档注释和错误日志,保持与同文件其他函数的风格一致性


3. 代码性能 ✅

评价: 优秀 ✅ 通过

潜在问题:

  1. deepin-devicemanager-server/deepin-devicecontrol/src/drivercontrol/utils.cpp:242 - 两次独立 open/flock/close 操作,性能影响可忽略

建议: 性能良好,资源使用合理。本次修改将 QProcess 进程创建替换为直接系统调用,显著提升了性能。两次 open/flock/close 操作性能影响可忽略


4. 代码安全 🔒

评价: 优秀 ✅ 通过

🔐 发现 0 个安全漏洞

安全漏洞详情:
✅ 未发现安全漏洞

建议: 安全合规。本次修改移除了 QProcess 进程调用,降低了命令注入风险。使用 O_CLOEXEC 标志防止文件描述符泄漏到子进程,文件路径为硬编码常量,无路径遍历风险


💡 改进建议代码示例

// 改进建议:增加 errno 检查和错误日志
bool Utils::isDpkgLocked()
{
    // Check dpkg lock files using non-blocking exclusive flock.
    const QStringList lockFiles = {
        "/var/lib/dpkg/lock-frontend",
        "/var/lib/dpkg/lock"
    };
    for (const QString &lockFile : lockFiles) {
        int fd = open(lockFile.toLocal8Bit().constData(), O_RDONLY | O_CLOEXEC);
        if (fd < 0) {
            qCWarning(appLog) << "Failed to open lock file:" << lockFile
                              << "errno:" << errno;
            return true; // Conservative: assume locked
        }
        if (flock(fd, LOCK_EX | LOCK_NB) == -1) {
            qCInfo(appLog) << "dpkg lock file is held:" << lockFile;
            close(fd);
            return true;
        }
        close(fd);
    }
    return false;
}

本报告由 AI 代码审查工具自动生成

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants