blob: b7d439bdd5f0307e95262d352642dadfaebf943c [file] [log] [blame]
xf.libfc6e712025-02-07 01:54:34 -08001/* 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
10//applet:IF_HALT(APPLET(halt, BB_DIR_SBIN, BB_SUID_DROP))
11//applet:IF_HALT(APPLET_ODDNAME(poweroff, halt, BB_DIR_SBIN, BB_SUID_DROP, poweroff))
12//applet:IF_HALT(APPLET_ODDNAME(reboot, halt, BB_DIR_SBIN, BB_SUID_DROP, reboot))
13
14//kbuild:lib-$(CONFIG_HALT) += halt.o
15
16//config:config HALT
17//config: bool "poweroff, halt, and reboot"
18//config: default y
19//config: help
20//config: Stop all processes and either halt, reboot, or power off the system.
21//config:
22//config:config FEATURE_CALL_TELINIT
23//config: bool "Call telinit on shutdown and reboot"
24//config: default y
25//config: depends on HALT && !INIT
26//config: help
27//config: Call an external program (normally telinit) to facilitate
28//config: a switch to a proper runlevel.
29//config:
30//config: This option is only available if you selected halt and friends,
31//config: but did not select init.
32//config:
33//config:config TELINIT_PATH
34//config: string "Path to telinit executable"
35//config: default "/sbin/telinit"
36//config: depends on FEATURE_CALL_TELINIT
37//config: help
38//config: When busybox halt and friends have to call external telinit
39//config: to facilitate proper shutdown, this path is to be used when
40//config: locating telinit executable.
41
42//usage:#define halt_trivial_usage
43//usage: "[-d DELAY] [-n] [-f]" IF_FEATURE_WTMP(" [-w]")
44//usage:#define halt_full_usage "\n\n"
45//usage: "Halt the system\n"
46//usage: "\n -d SEC Delay interval"
47//usage: "\n -n Do not sync"
48//usage: "\n -f Force (don't go through init)"
49//usage: IF_FEATURE_WTMP(
50//usage: "\n -w Only write a wtmp record"
51//usage: )
52//usage:
53//usage:#define poweroff_trivial_usage
54//usage: "[-d DELAY] [-n] [-f]"
55//usage:#define poweroff_full_usage "\n\n"
56//usage: "Halt and shut off power\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:
61//usage:#define reboot_trivial_usage
62//usage: "[-d DELAY] [-n] [-f]"
63//usage:#define reboot_full_usage "\n\n"
64//usage: "Reboot the system\n"
65//usage: "\n -d SEC Delay interval"
66//usage: "\n -n Do not sync"
67//usage: "\n -f Force (don't go through init)"
68
69#include "libbb.h"
70#include "reboot.h"
71
72#if ENABLE_FEATURE_WTMP
73#include <sys/utsname.h>
74
75static void write_wtmp(void)
76{
77 struct utmp utmp;
78 struct utsname uts;
79 /* "man utmp" says wtmp file should *not* be created automagically */
80 /*if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) {
81 close(creat(bb_path_wtmp_file, 0664));
82 }*/
83 memset(&utmp, 0, sizeof(utmp));
84 utmp.ut_tv.tv_sec = time(NULL);
85 strcpy(utmp.ut_user, "shutdown"); /* it is wide enough */
86 utmp.ut_type = RUN_LVL;
87 utmp.ut_id[0] = '~'; utmp.ut_id[1] = '~'; /* = strcpy(utmp.ut_id, "~~"); */
88 utmp.ut_line[0] = '~'; utmp.ut_line[1] = '~'; /* = strcpy(utmp.ut_line, "~~"); */
89 uname(&uts);
90 safe_strncpy(utmp.ut_host, uts.release, sizeof(utmp.ut_host));
91 updwtmp(bb_path_wtmp_file, &utmp);
92}
93#else
94#define write_wtmp() ((void)0)
95#endif
96
xf.li771eb062025-02-09 23:05:11 -080097/* Started by AICoder, pid:eecb340c7fw298714a9d0b3210b0288be1203207 */
98static void get_app_name_by_pid(int pid, char *app_name, int app_name_len)
99{
100 char file_comm[256];
101 FILE *pfile;
102 size_t len;
103
104 memset(file_comm, 0, sizeof(file_comm));
105 snprintf(file_comm, sizeof(file_comm), "/proc/%d/comm", pid);
106
107 pfile = fopen(file_comm, "r");
108 if (pfile)
109 {
110 memset(app_name, 0, app_name_len);
111 fgets(app_name, app_name_len, pfile);
112 app_name[app_name_len-1] = '\0';
113 app_name[strlen(app_name) - 1] = '\0'; //last byte is \n
114 fclose(pfile);
115 }
116}
117
118static int get_ppid(int pid) {
119 char path[256];
120 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
121
122 FILE *fp = fopen(path, "r");
123 if (fp == NULL) {
124 perror("fopen");
125 return -1;
126 }
127
128 int ppid = -1;
129 // 通过解析第4列(ppid)来获取父进程ID
130 fscanf(fp, "%*d %*s %*c %d", &ppid);
131 fclose(fp);
132 return ppid;
133}
134
135static int get_reboot_caller(char *applet_name)
136{
137 int pid = get_ppid(getpid());
138 char app_name[32];
139 int app_name_len = sizeof(app_name);
140 char cmd_str[256];
141 int try_cnt = 0;
142
143 while(1)
144 {
145 if (try_cnt > 5) {
146 strcpy(app_name, "unkown");
147 break;
148 }
149 try_cnt++;
150 if (pid == 1) {
151 get_app_name_by_pid(pid, app_name, app_name_len);
152 break; //init
153 }
154 get_app_name_by_pid(pid, app_name, app_name_len);
155 if ((strcmp(app_name, "sh") == 0) || (strcmp(app_name, "bash") == 0)) {
156 //printf("shell %s continue %d\n", app_name, strlen(app_name));
157 pid = get_ppid(pid); //sh continue
158 } else {
159 //printf("not sh break %s %d\n", app_name, strlen(app_name));
160 break; //not sh
161 }
162 }
163
164 memset(cmd_str, 0, sizeof(cmd_str));
165 snprintf(cmd_str, sizeof(cmd_str), "nv set ap_reset_app=%s_%d; nv save", app_name, pid);
166 system(cmd_str);
167 printf("call %s by %s(%d)\n", applet_name, app_name, pid);
168
169 return 0;
170}
171/* Ended by AICoder, pid:eecb340c7fw298714a9d0b3210b0288be1203207 */
xf.libfc6e712025-02-07 01:54:34 -0800172
173int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
174int halt_main(int argc UNUSED_PARAM, char **argv)
175{
176 static const int magic[] = {
177 RB_HALT_SYSTEM,
178 RB_POWER_OFF,
179 RB_AUTOBOOT
180 };
181 static const smallint signals[] = { SIGUSR1, SIGUSR2, SIGTERM };
182
183 int delay = 0;
184 int which, flags, rc;
185
186 /* Figure out which applet we're running */
187 for (which = 0; "hpr"[which] != applet_name[0]; which++)
188 continue;
xf.li771eb062025-02-09 23:05:11 -0800189#if ENABLE_INSTALL_TO_RECOVERY
190#else
191 get_reboot_caller(applet_name); //add by zxic, print parent proccess name and pid
192#endif
xf.libfc6e712025-02-07 01:54:34 -0800193
194 /* Parse and handle arguments */
195 opt_complementary = "d+"; /* -d N */
196 /* We support -w even if !ENABLE_FEATURE_WTMP,
197 * in order to not break scripts.
198 * -i (shut down network interfaces) is ignored.
199 */
200 flags = getopt32(argv, "d:nfwi", &delay);
201
202 sleep(delay);
203
204 write_wtmp();
205
206 if (flags & 8) /* -w */
207 return EXIT_SUCCESS;
208
209 if (!(flags & 2)) /* no -n */
210 sync();
211
212 /* Perform action. */
213 rc = 1;
214 if (!(flags & 4)) { /* no -f */
215//TODO: I tend to think that signalling linuxrc is wrong
216// pity original author didn't comment on it...
217 if (ENABLE_FEATURE_INITRD) {
218 /* talk to linuxrc */
219 /* bbox init/linuxrc assumed */
220 pid_t *pidlist = find_pid_by_name("linuxrc");
221 if (pidlist[0] > 0)
222 rc = kill(pidlist[0], signals[which]);
223 if (ENABLE_FEATURE_CLEAN_UP)
224 free(pidlist);
225 }
226 if (rc) {
227 /* talk to init */
228 if (!ENABLE_FEATURE_CALL_TELINIT) {
229 /* bbox init assumed */
230 rc = kill(1, signals[which]);
231 } else {
232 /* SysV style init assumed */
233 /* runlevels:
234 * 0 == shutdown
235 * 6 == reboot */
236 execlp(CONFIG_TELINIT_PATH,
237 CONFIG_TELINIT_PATH,
238 which == 2 ? "6" : "0",
239 (char *)NULL
240 );
241 bb_perror_msg_and_die("can't execute '%s'",
242 CONFIG_TELINIT_PATH);
243 }
244 }
245 } else {
246 rc = reboot(magic[which]);
247 }
248
249 if (rc)
250 bb_perror_nomsg_and_die();
251 return rc;
252}