halt.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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_ODDNAME:name main location suid_type help
  48. //applet:IF_POWEROFF(APPLET_ODDNAME(poweroff, halt, BB_DIR_SBIN, BB_SUID_DROP, poweroff))
  49. //applet:IF_REBOOT( APPLET_ODDNAME(reboot, halt, BB_DIR_SBIN, BB_SUID_DROP, reboot))
  50. //kbuild:lib-$(CONFIG_HALT) += halt.o
  51. //kbuild:lib-$(CONFIG_POWEROFF) += halt.o
  52. //kbuild:lib-$(CONFIG_REBOOT) += halt.o
  53. //usage:#define halt_trivial_usage
  54. //usage: "[-d DELAY] [-n] [-f]" IF_FEATURE_WTMP(" [-w]")
  55. //usage:#define halt_full_usage "\n\n"
  56. //usage: "Halt the system\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: IF_FEATURE_WTMP(
  61. //usage: "\n -w Only write a wtmp record"
  62. //usage: )
  63. //usage:
  64. //usage:#define poweroff_trivial_usage
  65. //usage: "[-d DELAY] [-n] [-f]"
  66. //usage:#define poweroff_full_usage "\n\n"
  67. //usage: "Halt and shut off power\n"
  68. //usage: "\n -d SEC Delay interval"
  69. //usage: "\n -n Do not sync"
  70. //usage: "\n -f Force (don't go through init)"
  71. //usage:
  72. //usage:#define reboot_trivial_usage
  73. //usage: "[-d DELAY] [-n] [-f]"
  74. //usage:#define reboot_full_usage "\n\n"
  75. //usage: "Reboot the system\n"
  76. //usage: "\n -d SEC Delay interval"
  77. //usage: "\n -n Do not sync"
  78. //usage: "\n -f Force (don't go through init)"
  79. #include "libbb.h"
  80. #include "reboot.h"
  81. #if ENABLE_FEATURE_WTMP
  82. #include <sys/utsname.h>
  83. static void write_wtmp(void)
  84. {
  85. struct utmpx utmp;
  86. struct utsname uts;
  87. /* "man utmp" says wtmp file should *not* be created automagically */
  88. /*if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) {
  89. close(creat(bb_path_wtmp_file, 0664));
  90. }*/
  91. memset(&utmp, 0, sizeof(utmp));
  92. utmp.ut_tv.tv_sec = time(NULL);
  93. strcpy(utmp.ut_user, "shutdown"); /* it is wide enough */
  94. utmp.ut_type = RUN_LVL;
  95. utmp.ut_id[0] = '~'; utmp.ut_id[1] = '~'; /* = strcpy(utmp.ut_id, "~~"); */
  96. utmp.ut_line[0] = '~'; utmp.ut_line[1] = '~'; /* = strcpy(utmp.ut_line, "~~"); */
  97. uname(&uts);
  98. safe_strncpy(utmp.ut_host, uts.release, sizeof(utmp.ut_host));
  99. updwtmpx(bb_path_wtmp_file, &utmp);
  100. }
  101. #else
  102. #define write_wtmp() ((void)0)
  103. #endif
  104. int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  105. int halt_main(int argc UNUSED_PARAM, char **argv)
  106. {
  107. static const int magic[] = {
  108. RB_HALT_SYSTEM,
  109. RB_POWER_OFF,
  110. RB_AUTOBOOT
  111. };
  112. static const smallint signals[] = { SIGUSR1, SIGUSR2, SIGTERM };
  113. int delay = 0;
  114. int which, flags, rc;
  115. /* Figure out which applet we're running */
  116. if (ENABLE_HALT && !ENABLE_POWEROFF && !ENABLE_REBOOT)
  117. which = 0;
  118. else
  119. if (!ENABLE_HALT && ENABLE_POWEROFF && !ENABLE_REBOOT)
  120. which = 1;
  121. else
  122. if (!ENABLE_HALT && !ENABLE_POWEROFF && ENABLE_REBOOT)
  123. which = 2;
  124. else
  125. for (which = 0; "hpr"[which] != applet_name[0]; which++)
  126. continue;
  127. /* Parse and handle arguments */
  128. /* We support -w even if !ENABLE_FEATURE_WTMP,
  129. * in order to not break scripts.
  130. * -i (shut down network interfaces) is ignored.
  131. */
  132. flags = getopt32(argv, "d:+nfwi", &delay);
  133. sleep(delay);
  134. write_wtmp();
  135. if (flags & 8) /* -w */
  136. return EXIT_SUCCESS;
  137. if (!(flags & 2)) /* no -n */
  138. sync();
  139. /* Perform action. */
  140. rc = 1;
  141. if (!(flags & 4)) { /* no -f */
  142. //TODO: I tend to think that signalling linuxrc is wrong
  143. // pity original author didn't comment on it...
  144. if (ENABLE_LINUXRC) {
  145. /* talk to linuxrc */
  146. /* bbox init/linuxrc assumed */
  147. pid_t *pidlist = find_pid_by_name("linuxrc");
  148. if (pidlist[0] > 0)
  149. rc = kill(pidlist[0], signals[which]);
  150. if (ENABLE_FEATURE_CLEAN_UP)
  151. free(pidlist);
  152. }
  153. if (rc) {
  154. /* talk to init */
  155. if (!ENABLE_FEATURE_CALL_TELINIT) {
  156. /* bbox init assumed */
  157. rc = kill(1, signals[which]);
  158. } else {
  159. /* SysV style init assumed */
  160. /* runlevels:
  161. * 0 == shutdown
  162. * 6 == reboot */
  163. execlp(CONFIG_TELINIT_PATH,
  164. CONFIG_TELINIT_PATH,
  165. which == 2 ? "6" : "0",
  166. (char *)NULL
  167. );
  168. bb_perror_msg_and_die("can't execute '%s'",
  169. CONFIG_TELINIT_PATH);
  170. }
  171. }
  172. } else {
  173. rc = reboot(magic[which]);
  174. }
  175. if (rc)
  176. bb_perror_nomsg_and_die();
  177. return rc;
  178. }