How to shutdown Linux using C++ or Qt without call to "system()"?
Asked Answered
B

5

17

I want to shutdown an Embedded Linux when a close button is pushed on the UI. I know I can do it with a call to system:

system("shutdown -P now");

Ref: Link

But knowing that using system is not advised, I'ld like to know if there is another way in C++ to do this (if there is also a specific way to do this using Qt, I'ld also like to know it although a general C++ method is more important).

Bray answered 2/3, 2015 at 14:44 Comment(5)
Why is system() not advised?Pittsburgh
Read about DBus. BTW, there is a QDBus api I think.Sucrase
@Pittsburgh for a very simple reason if the OP is using Qt it means that it would require root privileges within a GUI application, really bad idea. Invoking programs with system() almost always represents a security problem.Sucrase
@iharob it is an embedded system.Wulfe
@Wulfe embedded has nothing to do with GUI, you can run graphics on any kinds of HW. The embedded system definition is vague and covers huge classes of devices from tiny MCU to the powerful mobile phone or raspberry pi that can have multiple monitor outputsZurn
G
20

On Linux you can call the reboot system call to poweroff, halt, or reboot. The following snippet shows how to poweroff a machine, but note that it will of course only work on Linux :

#include <unistd.h>
#include <linux/reboot.h>  /* Definition of LINUX_REBOOT_* constants */
#include <sys/syscall.h>   /* Definition of SYS_* constants */

int main() {
    syscall(SYS_reboot,
            LINUX_REBOOT_MAGIC1, 
            LINUX_REBOOT_MAGIC2, 
            LINUX_REBOOT_CMD_POWER_OFF, NULL);
}

Of course, you will need sufficient privileges to use this syscall.

Glibc also provides a reboot(int cmd) wrapper for it, see the man page.

Gig answered 2/3, 2015 at 14:48 Comment(5)
That's what dbus is for, although since it's an embeded system I don't know if dbus is used, it could be.Sucrase
@iharob Indeed, you could also use DBus to talk to ConsoleKit or UPower if they are installed. I wouldn't expect all embedded systems to have them running, though.Gig
Does this stop running systemd services correctly as system(reboot) does ?Stertor
I would recommend calling sync(2) and probably usleep-ing some deciseconds before that rebootFogg
The code in this answer won't work: if you include the correct prototype from <sys/reboot.h>, you'll see int reboot(int __howto) wrapper instead of the direct system call signature — that's what glibc provides. To really do the call with magic numbers, you have to use syscall(2).Aldos
I
15

Under glibc you'll need:

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

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

Again, as always, you'll need to be running with sufficient privileges.

reboot's man page

Illbehaved answered 27/7, 2015 at 12:13 Comment(0)
B
4

If your system have systemd, then you can use logind functionality via D-Bus. Qt solution is the following (just tested):

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;
}

Also possible there is a need to add a file /etc/polkit-1/localauthority/50-local.d/10-enable-shutdown.pkla to suppress interactive authentication requirement:

[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
Bertiebertila answered 5/9, 2017 at 8:38 Comment(6)
Does anybody really use systemd on an embedded system? Shudder.Tlemcen
@TobySpeight me. But my embedded system is fat enough to run Ubuntu Server and graphical application with peak RAM=~1.5GB and VRAM=~2GB.Bertiebertila
I guess we have different expectations of what's "embedded", then!Tlemcen
@TobySpeight sure. For me it is just standalone unmaintained machine. Non-desktop and non-server. Say kiosk.Bertiebertila
@TobySpeight a lot of arm socs are sufficient for running a systemd-based linux, i.e. Yocto Poky distro runs with it by default.Igniter
For anyone else who's not a DBus expert, that wants to enable rebooting as well as powering-off, substitute CanReboot for CanPowerOff and Reboot for PowerOff, then you'll need 3 extra rules in the polkit file, substituting reboot for power-off.Aubrette
A
3

The Qt way is to use QProcess to run the shutdown command:

QProcess process;
process.startDetached("shutdown -P now");
Angelesangelfish answered 2/3, 2015 at 17:19 Comment(2)
Thanks! I may end up using this since I can't find which header file includes reboot :x (no help page including man tells that \o/)Bray
Er, that's pretty much the same as system() - in particular, the command is parsed by a shell. However, the other QProcess::startDetached(), that accepts a QStringList of arguments, avoids some of the problems.Tlemcen
W
-3

If your problem is that you think system() isn't secure, you can use

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

then you can be sure you're using the right shutdown function.

Wilow answered 2/3, 2015 at 15:23 Comment(3)
As far as I remember on my readings on system(), the reasons why it's not recommended go far beyond "using the right shutdown function" :) But thanks!Bray
This command does not work on my Ubuntu. Says "/bin/sh: 0: Can't open shutdown".Weber
@AlexanderDyagilev because it should be /bin/sh -c <command>Baiel

© 2022 - 2024 — McMap. All rights reserved.