halt.c 4.8 KB

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