]>
Commit | Line | Data |
---|---|---|
a74aeac6 PR |
1 | /* |
2 | * Halt Stop the system running. | |
3 | * It re-enables CTRL-ALT-DEL, so that a hard reboot can | |
4 | * be done. If called as reboot, it will reboot the system. | |
5 | * | |
6 | * If the system is not in runlevel 0 or 6, halt will just | |
7 | * execute a "shutdown -h" to halt the system, and reboot will | |
8 | * execute an "shutdown -r". This is for compatibility with | |
9 | * sysvinit 2.4. | |
10 | * | |
11 | * Usage: halt [-n] [-w] [-d] [-f] [-h] [-i] [-p] | |
12 | * -n: don't sync before halting the system | |
13 | * -w: only write a wtmp reboot record and exit. | |
14 | * -d: don't write a wtmp record. | |
15 | * -f: force halt/reboot, don't call shutdown. | |
16 | * -h: put harddisks in standby mode | |
17 | * -i: shut down all network interfaces. | |
18 | * -p: power down the system (if possible, otherwise halt). | |
19 | * | |
20 | * Reboot and halt are both this program. Reboot | |
21 | * is just a link to halt. Invoking the program | |
22 | * as poweroff implies the -p option. | |
23 | * | |
24 | * Author: Miquel van Smoorenburg, miquels@cistron.nl | |
25 | * | |
26 | * Version: 2.86, 30-Jul-2004 | |
27 | * | |
28 | * This file is part of the sysvinit suite, | |
29 | * Copyright (C) 1991-2004 Miquel van Smoorenburg. | |
30 | * | |
31 | * This program is free software; you can redistribute it and/or modify | |
32 | * it under the terms of the GNU General Public License as published by | |
33 | * the Free Software Foundation; either version 2 of the License, or | |
34 | * (at your option) any later version. | |
35 | * | |
36 | * This program is distributed in the hope that it will be useful, | |
37 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
38 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
39 | * GNU General Public License for more details. | |
40 | * | |
41 | * You should have received a copy of the GNU General Public License | |
42 | * along with this program; if not, write to the Free Software | |
43 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
44 | */ | |
45 | ||
46 | #include <sys/types.h> | |
47 | #include <sys/stat.h> | |
48 | #include <sys/param.h> | |
49 | #include <stdlib.h> | |
50 | #include <utmp.h> | |
51 | #include <fcntl.h> | |
52 | #include <string.h> | |
53 | #include <unistd.h> | |
54 | #include <sys/times.h> | |
55 | #include <time.h> | |
56 | #include <signal.h> | |
57 | #include <stdio.h> | |
58 | #include <getopt.h> | |
59 | #include "reboot.h" | |
60 | ||
61 | char *Version = "@(#)halt 2.86 31-Jul-2004 miquels@cistron.nl"; | |
62 | char *progname; | |
63 | ||
64 | #define KERNEL_MONITOR 1 /* If halt() puts you into the kernel monitor. */ | |
65 | #define RUNLVL_PICKY 0 /* Be picky about the runlevel */ | |
66 | ||
67 | extern int ifdown(void); | |
68 | extern int hddown(void); | |
5f959b29 | 69 | extern int hdflush(void); |
a74aeac6 PR |
70 | extern void write_wtmp(char *user, char *id, int pid, int type, char *line); |
71 | ||
72 | /* | |
73 | * Send usage message. | |
74 | */ | |
75 | void usage(void) | |
76 | { | |
77 | fprintf(stderr, "usage: %s [-n] [-w] [-d] [-f] [-h] [-i]%s\n", | |
78 | progname, strcmp(progname, "halt") ? "" : " [-p]"); | |
79 | fprintf(stderr, "\t-n: don't sync before halting the system\n"); | |
80 | fprintf(stderr, "\t-w: only write a wtmp reboot record and exit.\n"); | |
81 | fprintf(stderr, "\t-d: don't write a wtmp record.\n"); | |
82 | fprintf(stderr, "\t-f: force halt/reboot, don't call shutdown.\n"); | |
83 | fprintf(stderr, "\t-h: put harddisks in standby mode.\n"); | |
84 | fprintf(stderr, "\t-i: shut down all network interfaces.\n"); | |
85 | if (!strcmp(progname, "halt")) | |
86 | fprintf(stderr, "\t-p: power down the system (if possible, otherwise halt).\n"); | |
87 | exit(1); | |
88 | } | |
89 | ||
90 | /* | |
91 | * See if we were started directly from init. | |
92 | * Get the runlevel from /var/run/utmp or the environment. | |
93 | */ | |
94 | int get_runlevel(void) | |
95 | { | |
96 | struct utmp *ut; | |
97 | char *r; | |
98 | #if RUNLVL_PICKY | |
99 | time_t boottime; | |
100 | #endif | |
101 | ||
102 | /* | |
103 | * First see if we were started directly from init. | |
104 | */ | |
105 | if (getenv("INIT_VERSION") && (r = getenv("RUNLEVEL")) != NULL) | |
106 | return *r; | |
107 | ||
108 | /* | |
109 | * Hmm, failed - read runlevel from /var/run/utmp.. | |
110 | */ | |
111 | #if RUNLVL_PICKY | |
112 | /* | |
113 | * Get boottime from the kernel. | |
114 | */ | |
115 | time(&boottime); | |
116 | boottime -= (times(NULL) / HZ); | |
117 | #endif | |
118 | ||
119 | /* | |
120 | * Find runlevel in utmp. | |
121 | */ | |
122 | setutent(); | |
123 | while ((ut = getutent()) != NULL) { | |
124 | #if RUNLVL_PICKY | |
125 | /* | |
126 | * Only accept value if it's from after boottime. | |
127 | */ | |
128 | if (ut->ut_type == RUN_LVL && ut->ut_time > boottime) | |
129 | return (ut->ut_pid & 255); | |
130 | #else | |
131 | if (ut->ut_type == RUN_LVL) | |
132 | return (ut->ut_pid & 255); | |
133 | #endif | |
134 | } | |
135 | endutent(); | |
136 | ||
137 | /* This should not happen but warn the user! */ | |
138 | fprintf(stderr, "WARNING: could not determine runlevel" | |
139 | " - doing soft %s\n", progname); | |
140 | fprintf(stderr, " (it's better to use shutdown instead of %s" | |
141 | " from the command line)\n", progname); | |
142 | ||
143 | return -1; | |
144 | } | |
145 | ||
146 | /* | |
147 | * Switch to another runlevel. | |
148 | */ | |
149 | void do_shutdown(char *fl, char *tm) | |
150 | { | |
151 | char *args[8]; | |
152 | int i = 0; | |
153 | ||
154 | args[i++] = "shutdown"; | |
155 | args[i++] = fl; | |
156 | if (tm) { | |
157 | args[i++] = "-t"; | |
158 | args[i++] = tm; | |
159 | } | |
160 | args[i++] = "now"; | |
161 | args[i++] = NULL; | |
162 | ||
163 | execv("/sbin/shutdown", args); | |
164 | execv("/etc/shutdown", args); | |
165 | execv("/bin/shutdown", args); | |
166 | ||
167 | perror("shutdown"); | |
168 | exit(1); | |
169 | } | |
170 | ||
171 | /* | |
172 | * Main program. | |
173 | * Write a wtmp entry and reboot cq. halt. | |
174 | */ | |
175 | int main(int argc, char **argv) | |
176 | { | |
177 | int do_reboot = 0; | |
178 | int do_sync = 1; | |
179 | int do_wtmp = 1; | |
180 | int do_nothing = 0; | |
181 | int do_hard = 0; | |
182 | int do_ifdown = 0; | |
183 | int do_hddown = 0; | |
184 | int do_poweroff = 0; | |
185 | int c; | |
186 | char *tm = NULL; | |
187 | ||
188 | /* | |
189 | * Find out who we are | |
190 | */ | |
191 | /* Remove dash passed on in argv[0] when used as login shell. */ | |
192 | if (argv[0][0] == '-') argv[0]++; | |
193 | if ((progname = strrchr(argv[0], '/')) != NULL) | |
194 | progname++; | |
195 | else | |
196 | progname = argv[0]; | |
197 | ||
198 | if (!strcmp(progname, "reboot")) do_reboot = 1; | |
199 | if (!strcmp(progname, "poweroff")) do_poweroff = 1; | |
200 | ||
201 | /* | |
202 | * Get flags | |
203 | */ | |
204 | while((c = getopt(argc, argv, ":ihdfnpwt:")) != EOF) { | |
205 | switch(c) { | |
206 | case 'n': | |
207 | do_sync = 0; | |
208 | do_wtmp = 0; | |
209 | break; | |
210 | case 'w': | |
211 | do_nothing = 1; | |
212 | break; | |
213 | case 'd': | |
214 | do_wtmp = 0; | |
215 | break; | |
216 | case 'f': | |
217 | do_hard = 1; | |
218 | break; | |
219 | case 'i': | |
220 | do_ifdown = 1; | |
221 | break; | |
222 | case 'h': | |
223 | do_hddown = 1; | |
224 | break; | |
225 | case 'p': | |
226 | do_poweroff = 1; | |
227 | break; | |
228 | case 't': | |
229 | tm = optarg; | |
230 | break; | |
231 | default: | |
232 | usage(); | |
233 | } | |
234 | } | |
235 | if (argc != optind) usage(); | |
236 | ||
237 | if (geteuid() != 0) { | |
238 | fprintf(stderr, "%s: must be superuser.\n", progname); | |
239 | exit(1); | |
240 | } | |
241 | ||
242 | (void)chdir("/"); | |
243 | ||
244 | if (!do_hard && !do_nothing) { | |
245 | /* | |
246 | * See if we are in runlevel 0 or 6. | |
247 | */ | |
248 | c = get_runlevel(); | |
249 | if (c != '0' && c != '6') | |
250 | do_shutdown(do_reboot ? "-r" : "-h", tm); | |
251 | } | |
252 | ||
253 | /* | |
254 | * Record the fact that we're going down | |
255 | */ | |
256 | if (do_wtmp) | |
257 | write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~"); | |
258 | ||
259 | /* | |
260 | * Exit if all we wanted to do was write a wtmp record. | |
261 | */ | |
262 | if (do_nothing && !do_hddown && !do_ifdown) exit(0); | |
263 | ||
264 | if (do_sync) { | |
265 | sync(); | |
266 | sleep(2); | |
267 | } | |
268 | ||
269 | if (do_ifdown) | |
270 | (void)ifdown(); | |
271 | ||
272 | if (do_hddown) | |
273 | (void)hddown(); | |
46fd2e25 DWF |
274 | else |
275 | (void)hdflush(); | |
a74aeac6 PR |
276 | |
277 | if (do_nothing) exit(0); | |
278 | ||
279 | if (do_reboot) { | |
280 | init_reboot(BMAGIC_REBOOT); | |
281 | } else { | |
282 | /* | |
283 | * Turn on hard reboot, CTRL-ALT-DEL will reboot now | |
284 | */ | |
285 | #ifdef BMAGIC_HARD | |
286 | init_reboot(BMAGIC_HARD); | |
287 | #endif | |
288 | ||
289 | /* | |
290 | * Stop init; it is insensitive to the signals sent | |
291 | * by the kernel. | |
292 | */ | |
293 | kill(1, SIGTSTP); | |
294 | ||
295 | /* | |
296 | * Halt or poweroff. | |
297 | */ | |
298 | if (do_poweroff) | |
299 | init_reboot(BMAGIC_POWEROFF); | |
300 | /* | |
301 | * Fallthrough if failed. | |
302 | */ | |
303 | init_reboot(BMAGIC_HALT); | |
304 | } | |
305 | ||
306 | /* | |
307 | * If we return, we (c)ontinued from the kernel monitor. | |
308 | */ | |
309 | #ifdef BMAGIC_SOFT | |
310 | init_reboot(BMAGIC_SOFT); | |
311 | #endif | |
312 | kill(1, SIGCONT); | |
313 | ||
314 | exit(0); | |
315 | } |