You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

退出sd-bus容器时出现'Device or Resource busy'错误的排查求助

问题分析与解决

你的问题核心在于sd-bus消息容器处理不完整,加上错误处理缺失,导致系统总线资源未正确释放,进而引发容器退出时的"Device or Resource busy"错误。具体原因包括:

  • 仅调用sd_bus_message_enter_container和sd_bus_message_exit_container但未遍历容器内所有元素,sd-bus消息指针未正确重置,内部资源无法正常释放。
  • 错误处理不完整:sd_bus_open_system、sd_bus_call_method失败时未清理已分配资源,也未处理sd_bus_error。
  • 未确保所有sd-bus对象(bus、reply)在任何执行路径下都被正确释放。

解决方案

  1. 完整遍历容器元素:必须遍历数组容器内的每一个结构体元素,直到sd_bus_message_next_container返回非0,确保消息指针状态正确。
  2. 完善错误处理:所有sd-bus调用失败时,清理已分配资源并打印明确错误信息。
  3. 统一资源释放:使用跳转或RAII机制,保证无论执行路径如何,bus和reply都能被正确unref。

修改后的代码

#include <iostream>
#include <unistd.h>
#include <systemd/sd-bus.h>
#include <cstring>

int main() {
    sd_bus_error error = SD_BUS_ERROR_NULL;
    sd_bus *bus = nullptr;
    sd_bus_message *reply = nullptr;
    int ret = 0;

    // 打开系统总线
    ret = sd_bus_open_system(&bus);
    if (ret < 0) {
        std::cerr << "打开系统总线失败: " << strerror(-ret) << std::endl;
        goto cleanup;
    }

    const char *service_name = "org.freedesktop.systemd1";
    const char *object_path = "/org/freedesktop/systemd1";
    const char *interface = "org.freedesktop.systemd1.Manager";
    const char *method = "ListUnits";

    // 调用ListUnits方法
    ret = sd_bus_call_method(bus,
                            service_name,
                            object_path,
                            interface,
                            method,
                            &error,
                            &reply,
                            "");
    if (ret < 0) {
        std::cerr << "调用ListUnits失败: " << error.message << std::endl;
        sd_bus_error_free(&error);
        goto cleanup;
    }

    // 进入数组容器
    ret = sd_bus_message_enter_container(reply, 'a', "(ssssssouso)");
    if (ret < 0) {
        std::cerr << "进入容器失败: " << strerror(-ret) << std::endl;
        goto cleanup;
    }

    // 遍历数组内所有结构体元素
    while ((ret = sd_bus_message_enter_container(reply, 'r', nullptr)) > 0) {
        const char *unit_name, *unit_description, *unit_load_state, *unit_active_state;
        const char *sub_state, *followed_state, *object1_path, *queued_job, *job_type, *job_object_path;
        unsigned int uint;

        // 读取结构体字段(匹配ListUnits返回类型)
        ret = sd_bus_message_read(reply, "ssssssouso",
                                &unit_name, &unit_description, &unit_load_state, &unit_active_state,
                                &sub_state, &followed_state, &uint, &object1_path,
                                &queued_job, &job_type, &job_object_path);
        if (ret < 0) {
            std::cerr << "读取消息字段失败: " << strerror(-ret) << std::endl;
            break;
        }

        // 此处可添加数据处理逻辑,比如打印单元信息
        // std::cout << "单元名称: " << unit_name << " 状态: " << unit_active_state << std::endl;

        // 退出当前结构体容器
        sd_bus_message_exit_container(reply);
    }

    // 退出数组容器
    sd_bus_message_exit_container(reply);

cleanup:
    // 统一释放所有资源
    if (reply) sd_bus_message_unref(reply);
    if (bus) sd_bus_unref(bus);
    return ret < 0 ? 1 : 0;
}

关键修改说明

  • 用goto cleanup统一处理资源释放,避免因执行路径分支导致资源泄漏。
  • 遍历数组内每个结构体元素,确保消息指针正确推进,完成容器的完整处理流程。
  • 新增sd_bus_error_free调用,释放错误信息资源。
  • 所有sd-bus调用失败时打印明确错误信息,便于调试定位问题。

修改后sd-bus资源会被正确释放,容器退出时不会再出现"Device or Resource busy"错误,同时能正常读取所有单元数据。

内容的提问来源于stack exchange,提问作者안성현

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 00:00:30