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