halt.c 5.3 KB

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