halt.c 4.8 KB

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