]>
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); | |
69 | extern void write_wtmp(char *user, char *id, int pid, int type, char *line); | |
70 | ||
71 | /* | |
72 | * Send usage message. | |
73 | */ | |
74 | void usage(void) | |
75 | { | |
76 | fprintf(stderr, "usage: %s [-n] [-w] [-d] [-f] [-h] [-i]%s\n", | |
77 | progname, strcmp(progname, "halt") ? "" : " [-p]"); | |
78 | fprintf(stderr, "\t-n: don't sync before halting the system\n"); | |
79 | fprintf(stderr, "\t-w: only write a wtmp reboot record and exit.\n"); | |
80 | fprintf(stderr, "\t-d: don't write a wtmp record.\n"); | |
81 | fprintf(stderr, "\t-f: force halt/reboot, don't call shutdown.\n"); | |
82 | fprintf(stderr, "\t-h: put harddisks in standby mode.\n"); | |
83 | fprintf(stderr, "\t-i: shut down all network interfaces.\n"); | |
84 | if (!strcmp(progname, "halt")) | |
85 | fprintf(stderr, "\t-p: power down the system (if possible, otherwise halt).\n"); | |
86 | exit(1); | |
87 | } | |
88 | ||
89 | /* | |
90 | * See if we were started directly from init. | |
91 | * Get the runlevel from /var/run/utmp or the environment. | |
92 | */ | |
93 | int get_runlevel(void) | |
94 | { | |
95 | struct utmp *ut; | |
96 | char *r; | |
97 | #if RUNLVL_PICKY | |
98 | time_t boottime; | |
99 | #endif | |
100 | ||
101 | /* | |
102 | * First see if we were started directly from init. | |
103 | */ | |
104 | if (getenv("INIT_VERSION") && (r = getenv("RUNLEVEL")) != NULL) | |
105 | return *r; | |
106 | ||
107 | /* | |
108 | * Hmm, failed - read runlevel from /var/run/utmp.. | |
109 | */ | |
110 | #if RUNLVL_PICKY | |
111 | /* | |
112 | * Get boottime from the kernel. | |
113 | */ | |
114 | time(&boottime); | |
115 | boottime -= (times(NULL) / HZ); | |
116 | #endif | |
117 | ||
118 | /* | |
119 | * Find runlevel in utmp. | |
120 | */ | |
121 | setutent(); | |
122 | while ((ut = getutent()) != NULL) { | |
123 | #if RUNLVL_PICKY | |
124 | /* | |
125 | * Only accept value if it's from after boottime. | |
126 | */ | |
127 | if (ut->ut_type == RUN_LVL && ut->ut_time > boottime) | |
128 | return (ut->ut_pid & 255); | |
129 | #else | |
130 | if (ut->ut_type == RUN_LVL) | |
131 | return (ut->ut_pid & 255); | |
132 | #endif | |
133 | } | |
134 | endutent(); | |
135 | ||
136 | /* This should not happen but warn the user! */ | |
137 | fprintf(stderr, "WARNING: could not determine runlevel" | |
138 | " - doing soft %s\n", progname); | |
139 | fprintf(stderr, " (it's better to use shutdown instead of %s" | |
140 | " from the command line)\n", progname); | |
141 | ||
142 | return -1; | |
143 | } | |
144 | ||
145 | /* | |
146 | * Switch to another runlevel. | |
147 | */ | |
148 | void do_shutdown(char *fl, char *tm) | |
149 | { | |
150 | char *args[8]; | |
151 | int i = 0; | |
152 | ||
153 | args[i++] = "shutdown"; | |
154 | args[i++] = fl; | |
155 | if (tm) { | |
156 | args[i++] = "-t"; | |
157 | args[i++] = tm; | |
158 | } | |
159 | args[i++] = "now"; | |
160 | args[i++] = NULL; | |
161 | ||
162 | execv("/sbin/shutdown", args); | |
163 | execv("/etc/shutdown", args); | |
164 | execv("/bin/shutdown", args); | |
165 | ||
166 | perror("shutdown"); | |
167 | exit(1); | |
168 | } | |
169 | ||
170 | /* | |
171 | * Main program. | |
172 | * Write a wtmp entry and reboot cq. halt. | |
173 | */ | |
174 | int main(int argc, char **argv) | |
175 | { | |
176 | int do_reboot = 0; | |
177 | int do_sync = 1; | |
178 | int do_wtmp = 1; | |
179 | int do_nothing = 0; | |
180 | int do_hard = 0; | |
181 | int do_ifdown = 0; | |
182 | int do_hddown = 0; | |
183 | int do_poweroff = 0; | |
184 | int c; | |
185 | char *tm = NULL; | |
186 | ||
187 | /* | |
188 | * Find out who we are | |
189 | */ | |
190 | /* Remove dash passed on in argv[0] when used as login shell. */ | |
191 | if (argv[0][0] == '-') argv[0]++; | |
192 | if ((progname = strrchr(argv[0], '/')) != NULL) | |
193 | progname++; | |
194 | else | |
195 | progname = argv[0]; | |
196 | ||
197 | if (!strcmp(progname, "reboot")) do_reboot = 1; | |
198 | if (!strcmp(progname, "poweroff")) do_poweroff = 1; | |
199 | ||
200 | /* | |
201 | * Get flags | |
202 | */ | |
203 | while((c = getopt(argc, argv, ":ihdfnpwt:")) != EOF) { | |
204 | switch(c) { | |
205 | case 'n': | |
206 | do_sync = 0; | |
207 | do_wtmp = 0; | |
208 | break; | |
209 | case 'w': | |
210 | do_nothing = 1; | |
211 | break; | |
212 | case 'd': | |
213 | do_wtmp = 0; | |
214 | break; | |
215 | case 'f': | |
216 | do_hard = 1; | |
217 | break; | |
218 | case 'i': | |
219 | do_ifdown = 1; | |
220 | break; | |
221 | case 'h': | |
222 | do_hddown = 1; | |
223 | break; | |
224 | case 'p': | |
225 | do_poweroff = 1; | |
226 | break; | |
227 | case 't': | |
228 | tm = optarg; | |
229 | break; | |
230 | default: | |
231 | usage(); | |
232 | } | |
233 | } | |
234 | if (argc != optind) usage(); | |
235 | ||
236 | if (geteuid() != 0) { | |
237 | fprintf(stderr, "%s: must be superuser.\n", progname); | |
238 | exit(1); | |
239 | } | |
240 | ||
241 | (void)chdir("/"); | |
242 | ||
243 | if (!do_hard && !do_nothing) { | |
244 | /* | |
245 | * See if we are in runlevel 0 or 6. | |
246 | */ | |
247 | c = get_runlevel(); | |
248 | if (c != '0' && c != '6') | |
249 | do_shutdown(do_reboot ? "-r" : "-h", tm); | |
250 | } | |
251 | ||
252 | /* | |
253 | * Record the fact that we're going down | |
254 | */ | |
255 | if (do_wtmp) | |
256 | write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~"); | |
257 | ||
258 | /* | |
259 | * Exit if all we wanted to do was write a wtmp record. | |
260 | */ | |
261 | if (do_nothing && !do_hddown && !do_ifdown) exit(0); | |
262 | ||
263 | if (do_sync) { | |
264 | sync(); | |
265 | sleep(2); | |
266 | } | |
267 | ||
268 | if (do_ifdown) | |
269 | (void)ifdown(); | |
270 | ||
271 | if (do_hddown) | |
272 | (void)hddown(); | |
273 | ||
274 | if (do_nothing) exit(0); | |
275 | ||
276 | if (do_reboot) { | |
277 | init_reboot(BMAGIC_REBOOT); | |
278 | } else { | |
279 | /* | |
280 | * Turn on hard reboot, CTRL-ALT-DEL will reboot now | |
281 | */ | |
282 | #ifdef BMAGIC_HARD | |
283 | init_reboot(BMAGIC_HARD); | |
284 | #endif | |
285 | ||
286 | /* | |
287 | * Stop init; it is insensitive to the signals sent | |
288 | * by the kernel. | |
289 | */ | |
290 | kill(1, SIGTSTP); | |
291 | ||
292 | /* | |
293 | * Halt or poweroff. | |
294 | */ | |
295 | if (do_poweroff) | |
296 | init_reboot(BMAGIC_POWEROFF); | |
297 | /* | |
298 | * Fallthrough if failed. | |
299 | */ | |
300 | init_reboot(BMAGIC_HALT); | |
301 | } | |
302 | ||
303 | /* | |
304 | * If we return, we (c)ontinued from the kernel monitor. | |
305 | */ | |
306 | #ifdef BMAGIC_SOFT | |
307 | init_reboot(BMAGIC_SOFT); | |
308 | #endif | |
309 | kill(1, SIGCONT); | |
310 | ||
311 | exit(0); | |
312 | } |