Add casts to get rid of compiler warning about signed/unsigned issues.
[sysvinit.git] / src / halt.c
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 }