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 GPL version 2, see file LICENSE in this tarball for details. 8 */ 9 10#include "libbb.h" 11#include <sys/reboot.h> 12 13#if ENABLE_FEATURE_WTMP 14#include <sys/utsname.h> 15#include <utmp.h> 16 17static void write_wtmp(void) 18{ 19 struct utmp utmp; 20 struct utsname uts; 21 /* "man utmp" says wtmp file should *not* be created automagically */ 22 /*if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) { 23 close(creat(bb_path_wtmp_file, 0664)); 24 }*/ 25 memset(&utmp, 0, sizeof(utmp)); 26 utmp.ut_tv.tv_sec = time(NULL); 27 strcpy(utmp.ut_user, "shutdown"); /* it is wide enough */ 28 utmp.ut_type = RUN_LVL; 29 utmp.ut_id[0] = '~'; utmp.ut_id[1] = '~'; /* = strcpy(utmp.ut_id, "~~"); */ 30 utmp.ut_line[0] = '~'; utmp.ut_line[1] = '~'; /* = strcpy(utmp.ut_line, "~~"); */ 31 uname(&uts); 32 safe_strncpy(utmp.ut_host, uts.release, sizeof(utmp.ut_host)); 33 updwtmp(bb_path_wtmp_file, &utmp); 34} 35#else 36#define write_wtmp() ((void)0) 37#endif 38 39#ifndef RB_HALT_SYSTEM 40#define RB_HALT_SYSTEM RB_HALT 41#endif 42 43#ifndef RB_POWERDOWN 44/* Stop system and switch power off if possible. */ 45# define RB_POWERDOWN 0x4321fedc 46#endif 47#ifndef RB_POWER_OFF 48# define RB_POWER_OFF RB_POWERDOWN 49#endif 50 51 52int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 53int halt_main(int argc UNUSED_PARAM, char **argv) 54{ 55 static const int magic[] = { 56 RB_HALT_SYSTEM, 57 RB_POWER_OFF, 58 RB_AUTOBOOT 59 }; 60 static const smallint signals[] = { SIGUSR1, SIGUSR2, SIGTERM }; 61 62 int delay = 0; 63 int which, flags, rc; 64 65 /* Figure out which applet we're running */ 66 for (which = 0; "hpr"[which] != applet_name[0]; which++) 67 continue; 68 69 /* Parse and handle arguments */ 70 opt_complementary = "d+"; /* -d N */ 71 /* We support -w even if !ENABLE_FEATURE_WTMP, 72 * in order to not break scripts. 73 * -i (shut down network interfaces) is ignored. 74 */ 75 flags = getopt32(argv, "d:nfwi", &delay); 76 77 sleep(delay); 78 79 write_wtmp(); 80 81 if (flags & 8) /* -w */ 82 return EXIT_SUCCESS; 83 84 if (!(flags & 2)) /* no -n */ 85 sync(); 86 87 /* Perform action. */ 88 rc = 1; 89 if (!(flags & 4)) { /* no -f */ 90//TODO: I tend to think that signalling linuxrc is wrong 91// pity original author didn't comment on it... 92 if (ENABLE_FEATURE_INITRD) { 93 /* talk to linuxrc */ 94 /* bbox init/linuxrc assumed */ 95 pid_t *pidlist = find_pid_by_name("linuxrc"); 96 if (pidlist[0] > 0) 97 rc = kill(pidlist[0], signals[which]); 98 if (ENABLE_FEATURE_CLEAN_UP) 99 free(pidlist); 100 } 101 if (rc) { 102 /* talk to init */ 103 if (!ENABLE_FEATURE_CALL_TELINIT) { 104 /* bbox init assumed */ 105 rc = kill(1, signals[which]); 106 } else { 107 /* SysV style init assumed */ 108 /* runlevels: 109 * 0 == shutdown 110 * 6 == reboot */ 111 rc = execlp(CONFIG_TELINIT_PATH, 112 CONFIG_TELINIT_PATH, 113 which == 2 ? "6" : "0", 114 (char *)NULL 115 ); 116 } 117 } 118 } else { 119 rc = reboot(magic[which]); 120 } 121 122 if (rc) 123 bb_perror_nomsg_and_die(); 124 return rc; 125} 126