1 |
|
|
/* $OpenBSD: shutdown.c,v 1.46 2017/04/03 20:59:19 fcambus Exp $ */ |
2 |
|
|
/* $NetBSD: shutdown.c,v 1.9 1995/03/18 15:01:09 cgd Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 1988, 1990, 1993 |
6 |
|
|
* The Regents of the University of California. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* Redistribution and use in source and binary forms, with or without |
9 |
|
|
* modification, are permitted provided that the following conditions |
10 |
|
|
* are met: |
11 |
|
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer in the |
15 |
|
|
* documentation and/or other materials provided with the distribution. |
16 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
17 |
|
|
* may be used to endorse or promote products derived from this software |
18 |
|
|
* without specific prior written permission. |
19 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
21 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
24 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
28 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
29 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 |
|
|
* SUCH DAMAGE. |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
#include <sys/types.h> |
34 |
|
|
#include <sys/resource.h> |
35 |
|
|
#include <sys/syslog.h> |
36 |
|
|
#include <sys/types.h> |
37 |
|
|
#include <sys/wait.h> |
38 |
|
|
|
39 |
|
|
#include <ctype.h> |
40 |
|
|
#include <fcntl.h> |
41 |
|
|
#include <sys/termios.h> |
42 |
|
|
#include <pwd.h> |
43 |
|
|
#include <setjmp.h> |
44 |
|
|
#include <signal.h> |
45 |
|
|
#include <stdio.h> |
46 |
|
|
#include <stdlib.h> |
47 |
|
|
#include <string.h> |
48 |
|
|
#include <time.h> |
49 |
|
|
#include <unistd.h> |
50 |
|
|
#include <limits.h> |
51 |
|
|
#include <errno.h> |
52 |
|
|
#include <err.h> |
53 |
|
|
|
54 |
|
|
#include "pathnames.h" |
55 |
|
|
|
56 |
|
|
#ifdef DEBUG |
57 |
|
|
#undef _PATH_NOLOGIN |
58 |
|
|
#define _PATH_NOLOGIN "./nologin" |
59 |
|
|
#undef _PATH_FASTBOOT |
60 |
|
|
#define _PATH_FASTBOOT "./fastboot" |
61 |
|
|
#endif |
62 |
|
|
|
63 |
|
|
#define H *60*60 |
64 |
|
|
#define M *60 |
65 |
|
|
#define S *1 |
66 |
|
|
#define NOLOG_TIME 5*60 |
67 |
|
|
struct interval { |
68 |
|
|
int timeleft, timetowait; |
69 |
|
|
} tlist[] = { |
70 |
|
|
{ 10 H, 5 H }, |
71 |
|
|
{ 5 H, 3 H }, |
72 |
|
|
{ 2 H, 1 H }, |
73 |
|
|
{ 1 H, 30 M }, |
74 |
|
|
{ 30 M, 10 M }, |
75 |
|
|
{ 20 M, 10 M }, |
76 |
|
|
{ 10 M, 5 M }, |
77 |
|
|
{ 5 M, 3 M }, |
78 |
|
|
{ 2 M, 1 M }, |
79 |
|
|
{ 1 M, 30 S }, |
80 |
|
|
{ 30 S, 30 S }, |
81 |
|
|
{ 0, 0 } |
82 |
|
|
}; |
83 |
|
|
#undef H |
84 |
|
|
#undef M |
85 |
|
|
#undef S |
86 |
|
|
|
87 |
|
|
static time_t offset, shuttime; |
88 |
|
|
static int dofast, dohalt, doreboot, dopower, dodump, mbuflen, nosync; |
89 |
|
|
static sig_atomic_t killflg; |
90 |
|
|
static char *whom, mbuf[BUFSIZ]; |
91 |
|
|
|
92 |
|
|
void badtime(void); |
93 |
|
|
void __dead die_you_gravy_sucking_pig_dog(void); |
94 |
|
|
void doitfast(void); |
95 |
|
|
void __dead finish(int); |
96 |
|
|
void getoffset(char *); |
97 |
|
|
void __dead loop(void); |
98 |
|
|
void nolog(void); |
99 |
|
|
void timeout(int); |
100 |
|
|
void timewarn(int); |
101 |
|
|
void usage(void); |
102 |
|
|
|
103 |
|
|
int |
104 |
|
|
main(int argc, char *argv[]) |
105 |
|
|
{ |
106 |
|
|
int arglen, ch, len, readstdin = 0; |
107 |
|
|
struct passwd *pw; |
108 |
|
|
char *p, *endp; |
109 |
|
|
pid_t forkpid; |
110 |
|
|
|
111 |
|
|
if (pledge("stdio rpath wpath cpath getpw tty id proc exec flock", NULL) == -1) |
112 |
|
|
err(1, "pledge"); |
113 |
|
|
|
114 |
|
|
#ifndef DEBUG |
115 |
|
|
if (geteuid()) |
116 |
|
|
errx(1, "NOT super-user"); |
117 |
|
|
#endif |
118 |
|
|
while ((ch = getopt(argc, argv, "dfhknpr-")) != -1) |
119 |
|
|
switch (ch) { |
120 |
|
|
case '-': |
121 |
|
|
readstdin = 1; |
122 |
|
|
break; |
123 |
|
|
case 'd': |
124 |
|
|
dodump = 1; |
125 |
|
|
break; |
126 |
|
|
case 'f': |
127 |
|
|
dofast = 1; |
128 |
|
|
break; |
129 |
|
|
case 'h': |
130 |
|
|
dohalt = 1; |
131 |
|
|
break; |
132 |
|
|
case 'k': |
133 |
|
|
killflg = 1; |
134 |
|
|
break; |
135 |
|
|
case 'n': |
136 |
|
|
nosync = 1; |
137 |
|
|
break; |
138 |
|
|
case 'p': |
139 |
|
|
dopower = 1; |
140 |
|
|
break; |
141 |
|
|
case 'r': |
142 |
|
|
doreboot = 1; |
143 |
|
|
break; |
144 |
|
|
default: |
145 |
|
|
usage(); |
146 |
|
|
} |
147 |
|
|
argc -= optind; |
148 |
|
|
argv += optind; |
149 |
|
|
|
150 |
|
|
if (argc < 1) |
151 |
|
|
usage(); |
152 |
|
|
|
153 |
|
|
if (dofast && nosync) { |
154 |
|
|
(void)fprintf(stderr, |
155 |
|
|
"shutdown: incompatible switches -f and -n.\n"); |
156 |
|
|
usage(); |
157 |
|
|
} |
158 |
|
|
if (doreboot && dohalt) { |
159 |
|
|
(void)fprintf(stderr, |
160 |
|
|
"shutdown: incompatible switches -h and -r.\n"); |
161 |
|
|
usage(); |
162 |
|
|
} |
163 |
|
|
if (doreboot && dopower) { |
164 |
|
|
(void)fprintf(stderr, |
165 |
|
|
"shutdown: incompatible switches -p and -r.\n"); |
166 |
|
|
usage(); |
167 |
|
|
} |
168 |
|
|
getoffset(*argv++); |
169 |
|
|
|
170 |
|
|
if (*argv) { |
171 |
|
|
for (p = mbuf, len = sizeof(mbuf); *argv; ++argv) { |
172 |
|
|
arglen = strlen(*argv); |
173 |
|
|
if ((len -= arglen) <= 2) |
174 |
|
|
break; |
175 |
|
|
if (p != mbuf) |
176 |
|
|
*p++ = ' '; |
177 |
|
|
memcpy(p, *argv, arglen); |
178 |
|
|
p += arglen; |
179 |
|
|
} |
180 |
|
|
*p = '\n'; |
181 |
|
|
*++p = '\0'; |
182 |
|
|
} |
183 |
|
|
|
184 |
|
|
if (readstdin) { |
185 |
|
|
p = mbuf; |
186 |
|
|
endp = mbuf + sizeof(mbuf) - 2; |
187 |
|
|
for (;;) { |
188 |
|
|
if (!fgets(p, endp - p + 1, stdin)) |
189 |
|
|
break; |
190 |
|
|
for (; *p && p < endp; ++p) |
191 |
|
|
; |
192 |
|
|
if (p == endp) { |
193 |
|
|
*p = '\n'; |
194 |
|
|
*++p = '\0'; |
195 |
|
|
break; |
196 |
|
|
} |
197 |
|
|
} |
198 |
|
|
} |
199 |
|
|
mbuflen = strlen(mbuf); |
200 |
|
|
|
201 |
|
|
if (offset) { |
202 |
|
|
char *ct = ctime(&shuttime); |
203 |
|
|
|
204 |
|
|
if (ct) |
205 |
|
|
printf("Shutdown at %.24s.\n", ct); |
206 |
|
|
else |
207 |
|
|
printf("Shutdown soon.\n"); |
208 |
|
|
} else |
209 |
|
|
(void)printf("Shutdown NOW!\n"); |
210 |
|
|
|
211 |
|
|
if (!(whom = getlogin())) |
212 |
|
|
whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; |
213 |
|
|
|
214 |
|
|
#ifdef DEBUG |
215 |
|
|
(void)putc('\n', stdout); |
216 |
|
|
#else |
217 |
|
|
(void)setpriority(PRIO_PROCESS, 0, PRIO_MIN); |
218 |
|
|
|
219 |
|
|
forkpid = fork(); |
220 |
|
|
if (forkpid == -1) |
221 |
|
|
err(1, "fork"); |
222 |
|
|
if (forkpid) { |
223 |
|
|
(void)printf("shutdown: [pid %ld]\n", (long)forkpid); |
224 |
|
|
exit(0); |
225 |
|
|
} |
226 |
|
|
setsid(); |
227 |
|
|
#endif |
228 |
|
|
openlog("shutdown", LOG_CONS, LOG_AUTH); |
229 |
|
|
loop(); |
230 |
|
|
/* NOTREACHED */ |
231 |
|
|
} |
232 |
|
|
|
233 |
|
|
void |
234 |
|
|
loop(void) |
235 |
|
|
{ |
236 |
|
|
struct interval *tp; |
237 |
|
|
u_int sltime; |
238 |
|
|
int logged; |
239 |
|
|
|
240 |
|
|
if (offset <= NOLOG_TIME) { |
241 |
|
|
logged = 1; |
242 |
|
|
nolog(); |
243 |
|
|
} else |
244 |
|
|
logged = 0; |
245 |
|
|
tp = tlist; |
246 |
|
|
if (tp->timeleft < offset) |
247 |
|
|
(void)sleep((u_int)(offset - tp->timeleft)); |
248 |
|
|
else { |
249 |
|
|
while (offset < tp->timeleft) |
250 |
|
|
++tp; |
251 |
|
|
/* |
252 |
|
|
* Warn now, if going to sleep more than a fifth of |
253 |
|
|
* the next wait time. |
254 |
|
|
*/ |
255 |
|
|
if ((sltime = offset - tp->timeleft)) { |
256 |
|
|
if (sltime > tp->timetowait / 5) |
257 |
|
|
timewarn(offset); |
258 |
|
|
(void)sleep(sltime); |
259 |
|
|
} |
260 |
|
|
} |
261 |
|
|
for (;; ++tp) { |
262 |
|
|
timewarn(tp->timeleft); |
263 |
|
|
if (!logged && tp->timeleft <= NOLOG_TIME) { |
264 |
|
|
logged = 1; |
265 |
|
|
nolog(); |
266 |
|
|
} |
267 |
|
|
(void)sleep((u_int)tp->timetowait); |
268 |
|
|
if (!tp->timeleft) |
269 |
|
|
break; |
270 |
|
|
} |
271 |
|
|
die_you_gravy_sucking_pig_dog(); |
272 |
|
|
} |
273 |
|
|
|
274 |
|
|
static jmp_buf alarmbuf; |
275 |
|
|
|
276 |
|
|
static char *restricted_environ[] = { |
277 |
|
|
"PATH=" _PATH_STDPATH, |
278 |
|
|
NULL |
279 |
|
|
}; |
280 |
|
|
|
281 |
|
|
void |
282 |
|
|
timewarn(int timeleft) |
283 |
|
|
{ |
284 |
|
|
static char hostname[HOST_NAME_MAX+1]; |
285 |
|
|
char wcmd[PATH_MAX + 4]; |
286 |
|
|
extern char **environ; |
287 |
|
|
static int first; |
288 |
|
|
FILE *pf; |
289 |
|
|
|
290 |
|
|
if (!first++) |
291 |
|
|
(void)gethostname(hostname, sizeof(hostname)); |
292 |
|
|
|
293 |
|
|
/* undoc -n option to wall suppresses normal wall banner */ |
294 |
|
|
(void)snprintf(wcmd, sizeof(wcmd), "%s -n", _PATH_WALL); |
295 |
|
|
environ = restricted_environ; |
296 |
|
|
if (!(pf = popen(wcmd, "w"))) { |
297 |
|
|
syslog(LOG_ERR, "shutdown: can't find %s: %m", _PATH_WALL); |
298 |
|
|
return; |
299 |
|
|
} |
300 |
|
|
|
301 |
|
|
(void)fprintf(pf, |
302 |
|
|
"\007*** %sSystem shutdown message from %s@%s ***\007\n", |
303 |
|
|
timeleft ? "": "FINAL ", whom, hostname); |
304 |
|
|
|
305 |
|
|
if (timeleft > 10*60) { |
306 |
|
|
struct tm *tm = localtime(&shuttime); |
307 |
|
|
|
308 |
|
|
fprintf(pf, "System going down at %d:%02d\n\n", |
309 |
|
|
tm->tm_hour, tm->tm_min); |
310 |
|
|
} else if (timeleft > 59) |
311 |
|
|
(void)fprintf(pf, "System going down in %d minute%s\n\n", |
312 |
|
|
timeleft / 60, (timeleft > 60) ? "s" : ""); |
313 |
|
|
else if (timeleft) |
314 |
|
|
(void)fprintf(pf, "System going down in 30 seconds\n\n"); |
315 |
|
|
else |
316 |
|
|
(void)fprintf(pf, "System going down IMMEDIATELY\n\n"); |
317 |
|
|
|
318 |
|
|
if (mbuflen) |
319 |
|
|
(void)fwrite(mbuf, sizeof(*mbuf), mbuflen, pf); |
320 |
|
|
|
321 |
|
|
/* |
322 |
|
|
* play some games, just in case wall doesn't come back |
323 |
|
|
* probably unnecessary, given that wall is careful. |
324 |
|
|
*/ |
325 |
|
|
if (!setjmp(alarmbuf)) { |
326 |
|
|
(void)signal(SIGALRM, timeout); |
327 |
|
|
(void)alarm((u_int)30); |
328 |
|
|
(void)pclose(pf); |
329 |
|
|
(void)alarm((u_int)0); |
330 |
|
|
(void)signal(SIGALRM, SIG_DFL); |
331 |
|
|
} |
332 |
|
|
} |
333 |
|
|
|
334 |
|
|
void |
335 |
|
|
timeout(int signo) |
336 |
|
|
{ |
337 |
|
|
longjmp(alarmbuf, 1); /* XXX signal/longjmp resource leaks */ |
338 |
|
|
} |
339 |
|
|
|
340 |
|
|
void |
341 |
|
|
die_you_gravy_sucking_pig_dog(void) |
342 |
|
|
{ |
343 |
|
|
|
344 |
|
|
syslog(LOG_NOTICE, "%s by %s: %s", |
345 |
|
|
doreboot ? "reboot" : dopower ? "power-down" : dohalt ? "halt" : |
346 |
|
|
"shutdown", whom, mbuf); |
347 |
|
|
(void)sleep(2); |
348 |
|
|
|
349 |
|
|
(void)printf("\r\nSystem shutdown time has arrived\007\007\r\n"); |
350 |
|
|
if (killflg) { |
351 |
|
|
(void)printf("\rbut you'll have to do it yourself\r\n"); |
352 |
|
|
finish(0); |
353 |
|
|
} |
354 |
|
|
if (dofast) |
355 |
|
|
doitfast(); |
356 |
|
|
|
357 |
|
|
if (pledge("stdio rpath wpath cpath tty id proc exec flock", NULL) == -1) |
358 |
|
|
err(1, "pledge"); |
359 |
|
|
|
360 |
|
|
#ifdef DEBUG |
361 |
|
|
if (doreboot) |
362 |
|
|
(void)printf("reboot"); |
363 |
|
|
else if (dopower) |
364 |
|
|
(void)printf("power-down"); |
365 |
|
|
else if (dohalt) |
366 |
|
|
(void)printf("halt"); |
367 |
|
|
if (nosync) |
368 |
|
|
(void)printf(" no sync"); |
369 |
|
|
if (dofast) |
370 |
|
|
(void)printf(" no fsck"); |
371 |
|
|
if (dodump) |
372 |
|
|
(void)printf(" with dump"); |
373 |
|
|
(void)printf("\nkill -HUP 1\n"); |
374 |
|
|
#else |
375 |
|
|
if (dohalt || dopower || doreboot) { |
376 |
|
|
char *args[10]; |
377 |
|
|
char **arg, *path; |
378 |
|
|
|
379 |
|
|
if (pledge("stdio exec flock rpath cpath wpath", NULL) == -1) |
380 |
|
|
err(1, "pledge"); |
381 |
|
|
|
382 |
|
|
arg = &args[0]; |
383 |
|
|
if (doreboot) { |
384 |
|
|
path = _PATH_REBOOT; |
385 |
|
|
*arg++ = "reboot"; |
386 |
|
|
} else { |
387 |
|
|
path = _PATH_HALT; |
388 |
|
|
*arg++ = "halt"; |
389 |
|
|
} |
390 |
|
|
*arg++ = "-l"; |
391 |
|
|
if (dopower) |
392 |
|
|
*arg++ = "-p"; |
393 |
|
|
if (nosync) |
394 |
|
|
*arg++ = "-n"; |
395 |
|
|
if (dodump) |
396 |
|
|
*arg++ = "-d"; |
397 |
|
|
*arg++ = NULL; |
398 |
|
|
execve(path, args, NULL); |
399 |
|
|
syslog(LOG_ERR, "shutdown: can't exec %s: %m.", path); |
400 |
|
|
warn("%s", path); |
401 |
|
|
} |
402 |
|
|
if (access(_PATH_RC, R_OK) != -1) { |
403 |
|
|
pid_t pid; |
404 |
|
|
struct termios t; |
405 |
|
|
int fd; |
406 |
|
|
|
407 |
|
|
switch ((pid = fork())) { |
408 |
|
|
case -1: |
409 |
|
|
break; |
410 |
|
|
case 0: |
411 |
|
|
if (revoke(_PATH_CONSOLE) == -1) |
412 |
|
|
perror("revoke"); |
413 |
|
|
if (setsid() == -1) |
414 |
|
|
perror("setsid"); |
415 |
|
|
fd = open(_PATH_CONSOLE, O_RDWR); |
416 |
|
|
if (fd == -1) |
417 |
|
|
perror("open"); |
418 |
|
|
dup2(fd, 0); |
419 |
|
|
dup2(fd, 1); |
420 |
|
|
dup2(fd, 2); |
421 |
|
|
if (fd > 2) |
422 |
|
|
close(fd); |
423 |
|
|
|
424 |
|
|
/* At a minimum... */ |
425 |
|
|
tcgetattr(0, &t); |
426 |
|
|
t.c_oflag |= (ONLCR | OPOST); |
427 |
|
|
tcsetattr(0, TCSANOW, &t); |
428 |
|
|
|
429 |
|
|
execl(_PATH_BSHELL, "sh", _PATH_RC, "shutdown", (char *)NULL); |
430 |
|
|
_exit(1); |
431 |
|
|
default: |
432 |
|
|
waitpid(pid, NULL, 0); |
433 |
|
|
} |
434 |
|
|
} |
435 |
|
|
(void)kill(1, SIGTERM); /* to single user */ |
436 |
|
|
#endif |
437 |
|
|
finish(0); |
438 |
|
|
} |
439 |
|
|
|
440 |
|
|
#define ATOI2(p) (p[0] - '0') * 10 + (p[1] - '0'); p += 2; |
441 |
|
|
|
442 |
|
|
void |
443 |
|
|
getoffset(char *timearg) |
444 |
|
|
{ |
445 |
|
|
struct tm *lt; |
446 |
|
|
int this_year; |
447 |
|
|
time_t now; |
448 |
|
|
char *p; |
449 |
|
|
|
450 |
|
|
if (!strcasecmp(timearg, "now")) { /* now */ |
451 |
|
|
offset = 0; |
452 |
|
|
return; |
453 |
|
|
} |
454 |
|
|
|
455 |
|
|
(void)time(&now); |
456 |
|
|
if (*timearg == '+') { /* +minutes */ |
457 |
|
|
const char *errstr; |
458 |
|
|
|
459 |
|
|
offset = strtonum(++timearg, 0, INT_MAX, &errstr); |
460 |
|
|
if (errstr) |
461 |
|
|
badtime(); |
462 |
|
|
offset *= 60; |
463 |
|
|
shuttime = now + offset; |
464 |
|
|
return; |
465 |
|
|
} |
466 |
|
|
|
467 |
|
|
/* handle hh:mm by getting rid of the colon */ |
468 |
|
|
for (p = timearg; *p; ++p) { |
469 |
|
|
if (!isascii((unsigned char)*p) || !isdigit((unsigned char)*p)) { |
470 |
|
|
if (*p == ':' && strlen(p) == 3) { |
471 |
|
|
p[0] = p[1]; |
472 |
|
|
p[1] = p[2]; |
473 |
|
|
p[2] = '\0'; |
474 |
|
|
} else |
475 |
|
|
badtime(); |
476 |
|
|
} |
477 |
|
|
} |
478 |
|
|
|
479 |
|
|
unsetenv("TZ"); /* OUR timezone */ |
480 |
|
|
lt = localtime(&now); /* current time val */ |
481 |
|
|
|
482 |
|
|
switch (strlen(timearg)) { |
483 |
|
|
case 10: |
484 |
|
|
this_year = lt->tm_year; |
485 |
|
|
lt->tm_year = ATOI2(timearg); |
486 |
|
|
/* |
487 |
|
|
* check if the specified year is in the next century. |
488 |
|
|
* allow for one year of user error as many people will |
489 |
|
|
* enter n - 1 at the start of year n. |
490 |
|
|
*/ |
491 |
|
|
if (lt->tm_year < (this_year % 100) - 1) |
492 |
|
|
lt->tm_year += 100; |
493 |
|
|
/* adjust for the year 2000 and beyond */ |
494 |
|
|
lt->tm_year += (this_year - (this_year % 100)); |
495 |
|
|
/* FALLTHROUGH */ |
496 |
|
|
case 8: |
497 |
|
|
lt->tm_mon = ATOI2(timearg); |
498 |
|
|
if (--lt->tm_mon < 0 || lt->tm_mon > 11) |
499 |
|
|
badtime(); |
500 |
|
|
/* FALLTHROUGH */ |
501 |
|
|
case 6: |
502 |
|
|
lt->tm_mday = ATOI2(timearg); |
503 |
|
|
if (lt->tm_mday < 1 || lt->tm_mday > 31) |
504 |
|
|
badtime(); |
505 |
|
|
/* FALLTHROUGH */ |
506 |
|
|
case 4: |
507 |
|
|
lt->tm_hour = ATOI2(timearg); |
508 |
|
|
if (lt->tm_hour < 0 || lt->tm_hour > 23) |
509 |
|
|
badtime(); |
510 |
|
|
lt->tm_min = ATOI2(timearg); |
511 |
|
|
if (lt->tm_min < 0 || lt->tm_min > 59) |
512 |
|
|
badtime(); |
513 |
|
|
lt->tm_sec = 0; |
514 |
|
|
if ((shuttime = mktime(lt)) == -1) |
515 |
|
|
badtime(); |
516 |
|
|
if ((offset = shuttime - now) < 0) |
517 |
|
|
errx(1, "that time is already past."); |
518 |
|
|
break; |
519 |
|
|
default: |
520 |
|
|
badtime(); |
521 |
|
|
} |
522 |
|
|
} |
523 |
|
|
|
524 |
|
|
void |
525 |
|
|
doitfast(void) |
526 |
|
|
{ |
527 |
|
|
int fastfd; |
528 |
|
|
|
529 |
|
|
if ((fastfd = open(_PATH_FASTBOOT, O_WRONLY|O_CREAT|O_TRUNC, |
530 |
|
|
0664)) >= 0) { |
531 |
|
|
dprintf(fastfd, "fastboot file for fsck\n"); |
532 |
|
|
close(fastfd); |
533 |
|
|
} |
534 |
|
|
} |
535 |
|
|
|
536 |
|
|
void |
537 |
|
|
nolog(void) |
538 |
|
|
{ |
539 |
|
|
int logfd; |
540 |
|
|
struct tm *tm; |
541 |
|
|
|
542 |
|
|
(void)unlink(_PATH_NOLOGIN); /* in case linked to another file */ |
543 |
|
|
(void)signal(SIGINT, finish); |
544 |
|
|
(void)signal(SIGHUP, finish); |
545 |
|
|
(void)signal(SIGQUIT, finish); |
546 |
|
|
(void)signal(SIGTERM, finish); |
547 |
|
|
tm = localtime(&shuttime); |
548 |
|
|
if (tm && (logfd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT|O_TRUNC, |
549 |
|
|
0664)) >= 0) { |
550 |
|
|
dprintf(logfd, |
551 |
|
|
"\n\nNO LOGINS: System going down at %d:%02d\n\n", |
552 |
|
|
tm->tm_hour, tm->tm_min); |
553 |
|
|
close(logfd); |
554 |
|
|
} |
555 |
|
|
} |
556 |
|
|
|
557 |
|
|
void |
558 |
|
|
finish(int signo) |
559 |
|
|
{ |
560 |
|
|
if (!killflg) |
561 |
|
|
(void)unlink(_PATH_NOLOGIN); |
562 |
|
|
if (signo == 0) |
563 |
|
|
exit(0); |
564 |
|
|
else |
565 |
|
|
_exit(0); |
566 |
|
|
} |
567 |
|
|
|
568 |
|
|
void |
569 |
|
|
badtime(void) |
570 |
|
|
{ |
571 |
|
|
errx(1, "bad time format."); |
572 |
|
|
} |
573 |
|
|
|
574 |
|
|
void |
575 |
|
|
usage(void) |
576 |
|
|
{ |
577 |
|
|
fprintf(stderr, |
578 |
|
|
"usage: shutdown [-] [-dfhknpr] time [warning-message ...]\n"); |
579 |
|
|
exit(1); |
580 |
|
|
} |