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).

Momergil
  • 2,213
  • 5
  • 29
  • 59

5 Answers5

19

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>

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

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

Steak Overflow
  • 7,041
  • 1
  • 37
  • 59
tux3
  • 7,171
  • 6
  • 39
  • 51
  • That's what dbus is for, although since it's an embeded system I don't know if dbus is used, it could be. – Iharob Al Asimi Mar 02 '15 at 14:55
  • @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. – tux3 Mar 02 '15 at 14:58
  • 1
    Does this stop running systemd services correctly as `system(reboot)` does ? – VP. Feb 01 '17 at 09:01
  • 1
    I would recommend calling [sync(2)](http://man7.org/linux/man-pages/man2/sync.2.html) and probably `usleep`-ing some deciseconds before that `reboot` – Basile Starynkevitch Sep 05 '17 at 08:42
  • 5
    The code in this answer won't work: if you include the correct prototype from ``, 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)`. – Ruslan Jan 12 '18 at 10:52
15

Under glibc you'll need:

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

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

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

reboot's man page

Steak Overflow
  • 7,041
  • 1
  • 37
  • 59
Nathan Phillips
  • 11,899
  • 1
  • 31
  • 24
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
Tomilov Anatoliy
  • 15,657
  • 10
  • 64
  • 169
  • Does anybody really use systemd on an embedded system? *Shudder.* – Toby Speight Jan 12 '18 at 10:44
  • @TobySpeight me. But my embedded system is fat enough to run Ubuntu Server and graphical application with peak RAM=~1.5GB and VRAM=~2GB. – Tomilov Anatoliy Jan 12 '18 at 11:58
  • 1
    I guess we have different expectations of what's "embedded", then! – Toby Speight Jan 12 '18 at 12:06
  • @TobySpeight sure. For me it is just standalone unmaintained machine. Non-desktop and non-server. Say kiosk. – Tomilov Anatoliy Jan 12 '18 at 12:09
  • @TobySpeight a lot of arm socs are sufficient for running a systemd-based linux, i.e. Yocto Poky distro runs with it by default. – Nayfe Mar 18 '19 at 17:02
  • 1
    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`. – ulatekh Apr 28 '22 at 18:32
3

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

QProcess process;
process.startDetached("shutdown -P now");
Nejat
  • 31,784
  • 12
  • 106
  • 138
  • 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/) – Momergil Mar 02 '15 at 17:31
  • 1
    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. – Toby Speight Jan 12 '18 at 10:47
-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.

tux3
  • 7,171
  • 6
  • 39
  • 51