busybox/init/halt.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Poweroff reboot and halt, oh my.
   4 *
   5 * Copyright 2006 by Rob Landley <rob@landley.net>
   6 *
   7 * Licensed under GPLv2, see file LICENSE in this source tree.
   8 */
   9
  10//applet:IF_HALT(APPLET(halt, BB_DIR_SBIN, BB_SUID_DROP))
  11//applet:IF_HALT(APPLET_ODDNAME(poweroff, halt, BB_DIR_SBIN, BB_SUID_DROP, poweroff))
  12//applet:IF_HALT(APPLET_ODDNAME(reboot, halt, BB_DIR_SBIN, BB_SUID_DROP, reboot))
  13
  14//kbuild:lib-$(CONFIG_HALT) += halt.o
  15
  16//config:config HALT
  17//config:       bool "poweroff, halt, and reboot"
  18//config:       default y
  19//config:       help
  20//config:         Stop all processes and either halt, reboot, or power off the system.
  21//config:
  22//config:config FEATURE_CALL_TELINIT
  23//config:       bool "Call telinit on shutdown and reboot"
  24//config:       default y
  25//config:       depends on HALT && !INIT
  26//config:       help
  27//config:         Call an external program (normally telinit) to facilitate
  28//config:         a switch to a proper runlevel.
  29//config:
  30//config:         This option is only available if you selected halt and friends,
  31//config:         but did not select init.
  32//config:
  33//config:config TELINIT_PATH
  34//config:       string "Path to telinit executable"
  35//config:       default "/sbin/telinit"
  36//config:       depends on FEATURE_CALL_TELINIT
  37//config:       help
  38//config:         When busybox halt and friends have to call external telinit
  39//config:         to facilitate proper shutdown, this path is to be used when
  40//config:         locating telinit executable.
  41
  42//usage:#define halt_trivial_usage
  43//usage:       "[-d DELAY] [-n] [-f]" IF_FEATURE_WTMP(" [-w]")
  44//usage:#define halt_full_usage "\n\n"
  45//usage:       "Halt the system\n"
  46//usage:     "\n        -d SEC  Delay interval"
  47//usage:     "\n        -n      Do not sync"
  48//usage:     "\n        -f      Force (don't go through init)"
  49//usage:        IF_FEATURE_WTMP(
  50//usage:     "\n        -w      Only write a wtmp record"
  51//usage:        )
  52//usage:
  53//usage:#define poweroff_trivial_usage
  54//usage:       "[-d DELAY] [-n] [-f]"
  55//usage:#define poweroff_full_usage "\n\n"
  56//usage:       "Halt and shut off power\n"
  57//usage:     "\n        -d SEC  Delay interval"
  58//usage:     "\n        -n      Do not sync"
  59//usage:     "\n        -f      Force (don't go through init)"
  60//usage:
  61//usage:#define reboot_trivial_usage
  62//usage:       "[-d DELAY] [-n] [-f]"
  63//usage:#define reboot_full_usage "\n\n"
  64//usage:       "Reboot the system\n"
  65//usage:     "\n        -d SEC  Delay interval"
  66//usage:     "\n        -n      Do not sync"
  67//usage:     "\n        -f      Force (don't go through init)"
  68
  69#include "libbb.h"
  70#include "reboot.h"
  71
  72#if ENABLE_FEATURE_WTMP
  73#include <sys/utsname.h>
  74
  75static void write_wtmp(void)
  76{
  77        struct utmp utmp;
  78        struct utsname uts;
  79        /* "man utmp" says wtmp file should *not* be created automagically */
  80        /*if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) {
  81                close(creat(bb_path_wtmp_file, 0664));
  82        }*/
  83        memset(&utmp, 0, sizeof(utmp));
  84        utmp.ut_tv.tv_sec = time(NULL);
  85        strcpy(utmp.ut_user, "shutdown"); /* it is wide enough */
  86        utmp.ut_type = RUN_LVL;
  87        utmp.ut_id[0] = '~'; utmp.ut_id[1] = '~'; /* = strcpy(utmp.ut_id, "~~"); */
  88        utmp.ut_line[0] = '~'; utmp.ut_line[1] = '~'; /* = strcpy(utmp.ut_line, "~~"); */
  89        uname(&uts);
  90        safe_strncpy(utmp.ut_host, uts.release, sizeof(utmp.ut_host));
  91        updwtmp(bb_path_wtmp_file, &utmp);
  92}
  93#else
  94#define write_wtmp() ((void)0)
  95#endif
  96
  97
  98int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  99int halt_main(int argc UNUSED_PARAM, char **argv)
 100{
 101        static const int magic[] = {
 102                RB_HALT_SYSTEM,
 103                RB_POWER_OFF,
 104                RB_AUTOBOOT
 105        };
 106        static const smallint signals[] = { SIGUSR1, SIGUSR2, SIGTERM };
 107
 108        int delay = 0;
 109        int which, flags, rc;
 110
 111        /* Figure out which applet we're running */
 112        for (which = 0; "hpr"[which] != applet_name[0]; which++)
 113                continue;
 114
 115        /* Parse and handle arguments */
 116        opt_complementary = "d+"; /* -d N */
 117        /* We support -w even if !ENABLE_FEATURE_WTMP,
 118         * in order to not break scripts.
 119         * -i (shut down network interfaces) is ignored.
 120         */
 121        flags = getopt32(argv, "d:nfwi", &delay);
 122
 123        sleep(delay);
 124
 125        write_wtmp();
 126
 127        if (flags & 8) /* -w */
 128                return EXIT_SUCCESS;
 129
 130        if (!(flags & 2)) /* no -n */
 131                sync();
 132
 133        /* Perform action. */
 134        rc = 1;
 135        if (!(flags & 4)) { /* no -f */
 136//TODO: I tend to think that signalling linuxrc is wrong
 137// pity original author didn't comment on it...
 138                if (ENABLE_FEATURE_INITRD) {
 139                        /* talk to linuxrc */
 140                        /* bbox init/linuxrc assumed */
 141                        pid_t *pidlist = find_pid_by_name("linuxrc");
 142                        if (pidlist[0] > 0)
 143                                rc = kill(pidlist[0], signals[which]);
 144                        if (ENABLE_FEATURE_CLEAN_UP)
 145                                free(pidlist);
 146                }
 147                if (rc) {
 148                        /* talk to init */
 149                        if (!ENABLE_FEATURE_CALL_TELINIT) {
 150                                /* bbox init assumed */
 151                                rc = kill(1, signals[which]);
 152                        } else {
 153                                /* SysV style init assumed */
 154                                /* runlevels:
 155                                 * 0 == shutdown
 156                                 * 6 == reboot */
 157                                execlp(CONFIG_TELINIT_PATH,
 158                                                CONFIG_TELINIT_PATH,
 159                                                which == 2 ? "6" : "0",
 160                                                (char *)NULL
 161                                );
 162                                bb_perror_msg_and_die("can't execute '%s'",
 163                                                CONFIG_TELINIT_PATH);
 164                        }
 165                }
 166        } else {
 167                rc = reboot(magic[which]);
 168        }
 169
 170        if (rc)
 171                bb_perror_nomsg_and_die();
 172        return rc;
 173}
 174