【问题标题】:How to shutdown Linux using C++ or Qt without call to "system()"?如何在不调用“system()”的情况下使用 C++ 或 Qt 关闭 Linux?
【发布时间】:2015-05-02 23:10:29
【问题描述】:

当按下 UI 上的关闭按钮时,我想关闭嵌入式 Linux。我知道我可以打电话给system

system("shutdown -P now");

参考:Link

但是知道不建议使用system,我想知道C++中是否有另一种方法可以做到这一点(如果还有使用Qt的特定方法,我也想虽然通用的 C++ 方法更重要,但要知道)。

【问题讨论】:

  • 为什么不建议system()
  • 阅读DBus。顺便说一句,我认为有一个QDBus api。
  • @cmannett85 出于一个非常简单的原因,如果 OP 使用 Qt,这意味着它需要在 GUI 应用程序中具有 root 权限,这真是个坏主意。使用system() 调用程序几乎总是代表安全问题。
  • @iharob 它是一个嵌入式系统。

标签: c++ c linux qt shutdown


【解决方案1】:

在 Linux 上,您可以调用 reboot system call 来关闭、暂停或重新启动。 下面的 sn-p 显示了如何关闭机器,但请注意它当然只能在 Linux 上工作:

#include <unistd.h>
#include <linux/reboot.h>

int main() {
    reboot(LINUX_REBOOT_MAGIC1, 
           LINUX_REBOOT_MAGIC2, 
           LINUX_REBOOT_CMD_POWER_OFF, 0);
}

当然,您需要足够的权限才能使用此系统调用。

【讨论】:

  • 这就是 dbus 的用途,虽然因为它是一个嵌入式系统我不知道是否使用了 dbus,它可能是。
  • @iharob 实际上,如果安装了 DBus,您还可以使用它们与 ConsoleKit 或 UPower 通信。不过,我不希望所有嵌入式系统都能运行它们。
  • 这会像system(reboot) 那样停止正确运行 systemd 服务吗?
  • 我会建议调用sync(2) 并且可能在reboot 之前调用usleep-ing
  • 此答案中的代码不起作用:如果您包含来自&lt;sys/reboot.h&gt; 的正确原型,您将看到int reboot(int __howto) 包装器而不是直接系统调用签名——这就是glibc 提供的。要真正使用幻数进行通话,您必须使用syscall(2)
【解决方案2】:

在 glibc 下你需要:

#include <unistd.h>
#include <linux/reboot.h>
#include <sys/reboot.h>

int main() {
    sync();
    reboot(LINUX_REBOOT_CMD_POWER_OFF);
}

同样,您需要以足够的权限运行。

reboot's man page

【讨论】:

    【解决方案3】:

    如果您的系统有 systemd,那么您可以通过 D-Bus 使用logind 功能。 Qt 解决方案如下(刚刚测试):

    QDBusInterface logind{"org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", QDBusConnection::systemBus()};
    const auto message = logind.callWithArgumentList(QDBus::Block, "CanPowerOff", {});
    QDBusPendingReply< QString > canPowerOff = message;
    Q_ASSERT(canPowerOff.isFinished());
    if (canPowerOff.isError()) {
        const auto error = canPowerOff.error();
        qWarning().noquote()
                << QDBusInterface::tr("Asynchronous call finished with error: %1 (%2)")
                   .arg(error.name(), error.message());
        return EXIT_FAILURE;
    }
    if (canPowerOff.value() == "yes") {
        QDBusPendingReply<> powerOff = logind.callWithArgumentList(QDBus::Block, "PowerOff", {true, });
        Q_ASSERT(powerOff.isFinished());
        if (powerOff.isError()) {
            const auto error = powerOff.error();
            qWarning().noquote()
                    << QDBusInterface::tr("Asynchronous call finished with error: %1 (%2)")
                       .arg(error.name(), error.message());
            return EXIT_FAILURE;
        }
    } else {
        qCritical().noquote()
                << QCoreApplication::translate("poweroff", "Can't power off: CanPowerOff() result is %1")
                   .arg(canPowerOff.value());
        return EXIT_FAILURE;
    }
    

    还可能需要添加一个文件/etc/polkit-1/localauthority/50-local.d/10-enable-shutdown.pkla 来抑制交互式身份验证要求:

    [Enable shoutdown for users]
    Identity=unix-group:users
    Action=org.freedesktop.login1;org.freedesktop.login1.power-off;org.freedesktop.login1.power-off-ignore-inhibit;org.freedesktop.login1.power-off-multiple-sessions
    ResultAny=yes
    ResultInactive=yes
    ResultActive=yes
    

    【讨论】:

    • 真的有人在嵌入式系统上使用 systemd 吗? 颤抖。
    • @TobySpeight 我。但是我的嵌入式系统足够胖,可以运行 Ubuntu Server 和图形应用程序,峰值 RAM=~1.5GB 和 VRAM=~2GB。
    • 我猜我们对什么是“嵌入式”有不同的期望,那么!
    • @TobySpeight 当然。对我来说,它只是独立的无人维护的机器。非桌面和非服务器。说信息亭。
    • @TobySpeight 很多 arm soc 足以运行基于 systemd 的 linux,即 Yocto Poky 发行版默认运行。
    【解决方案4】:

    Qt方式是使用QProcess运行关机命令:

    QProcess process;
    process.startDetached("shutdown -P now");
    

    【讨论】:

    • 谢谢!我可能最终会使用它,因为我找不到包含 reboot :x 的头文件(没有包含 man 的帮助页面告诉 \o/)
    • 呃,这和system() 差不多——特别是命令是由shell 解析的。但是,另一个接受 QStringList 参数的 QProcess::startDetached() 避免了一些问题。
    【解决方案5】:

    如果你的问题是你认为 system() 不安全,你可以使用

    system("/bin/sh shutdown -P now");
    

    那么您就可以确定您使用的是正确的关机功能。

    【讨论】:

    • 据我在system() 上的阅读记忆,不推荐它的原因远不止“使用正确的关机功能” :) 但是谢谢!
    • 这个命令在我的 Ubuntu 上不起作用。说“/bin/sh: 0: Can't open shutdown”。
    • @AlexanderDyagilev 因为它应该是 /bin/sh -c
    猜你喜欢
    • 2012-05-21
    • 2013-12-03
    • 1970-01-01
    • 1970-01-01
    • 2013-09-24
    • 2011-06-30
    • 2016-02-20
    • 1970-01-01
    相关资源
    最近更新 更多