typo in nntp name
[unix-history] / usr / src / sbin / shutdown / shutdown.c
CommitLineData
8c5eec2f 1/*
b0af3d20 2 * Copyright (c) 1983,1986 Regents of the University of California.
8c5eec2f
DF
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
37c640e2 7#ifndef lint
8c5eec2f 8char copyright[] =
b0af3d20 9"@(#) Copyright (c) 1983,1986 Regents of the University of California.\n\
8c5eec2f
DF
10 All rights reserved.\n";
11#endif not lint
12
13#ifndef lint
b0af3d20 14static char sccsid[] = "@(#)shutdown.c 5.6 (Berkeley) %G%";
8c5eec2f 15#endif not lint
954bb1fe
BJ
16
17#include <stdio.h>
18#include <ctype.h>
19#include <signal.h>
297efed7 20#include <setjmp.h>
954bb1fe 21#include <utmp.h>
b0af3d20 22#include <pwd.h>
2c5483d8
SL
23#include <sys/time.h>
24#include <sys/resource.h>
b0af3d20 25#include <sys/param.h>
a96b688d
EA
26#include <sys/syslog.h>
27
954bb1fe
BJ
28/*
29 * /etc/shutdown when [messages]
30 *
31 * allow super users to tell users and remind users
32 * of iminent shutdown of unix
33 * and shut it down automatically
34 * and even reboot or halt the machine if they desire
954bb1fe 35 */
a96b688d 36
954bb1fe
BJ
37#define REBOOT "/etc/reboot"
38#define HALT "/etc/halt"
39#define MAXINTS 20
40#define HOURS *3600
41#define MINUTES *60
42#define SECONDS
a96b688d 43#define NLOG 600 /* no of bytes possible for message */
954bb1fe 44#define NOLOGTIME 5 MINUTES
d3818e48 45#define IGNOREUSER "sleeper"
954bb1fe 46
b0af3d20 47char hostname[MAXHOSTNAMELEN];
cf288731 48
297efed7 49int timeout();
954bb1fe
BJ
50time_t getsdt();
51
52extern char *ctime();
53extern struct tm *localtime();
db1d8af0
JB
54extern long time();
55
56extern char *strcpy();
57extern char *strncat();
58extern off_t lseek();
954bb1fe
BJ
59
60struct utmp utmp;
61int sint;
62int stogo;
63char tpath[] = "/dev/";
64int nlflag = 1; /* nolog yet to be done */
65int killflg = 1;
db1d8af0 66int doreboot = 0;
954bb1fe 67int halt = 0;
8b3f4639
JB
68int fast = 0;
69char *nosync = NULL;
70char nosyncflag[] = "-n";
954bb1fe
BJ
71char term[sizeof tpath + sizeof utmp.ut_line];
72char tbuf[BUFSIZ];
73char nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n";
a96b688d 74char nolog2[NLOG+1];
954bb1fe
BJ
75#ifdef DEBUG
76char nologin[] = "nologin";
8b3f4639 77char fastboot[] = "fastboot";
954bb1fe
BJ
78#else
79char nologin[] = "/etc/nologin";
8b3f4639 80char fastboot[] = "/fastboot";
954bb1fe 81#endif
3ce26e8e 82time_t nowtime;
297efed7 83jmp_buf alarmbuf;
3ce26e8e 84
954bb1fe
BJ
85struct interval {
86 int stogo;
87 int sint;
88} interval[] = {
89 4 HOURS, 1 HOURS,
90 2 HOURS, 30 MINUTES,
91 1 HOURS, 15 MINUTES,
92 30 MINUTES, 10 MINUTES,
93 15 MINUTES, 5 MINUTES,
8fa8eeab
BJ
94 10 MINUTES, 5 MINUTES,
95 5 MINUTES, 3 MINUTES,
3ce26e8e
KM
96 2 MINUTES, 1 MINUTES,
97 1 MINUTES, 30 SECONDS,
954bb1fe
BJ
98 0 SECONDS, 0 SECONDS
99};
3ce26e8e 100
8fa8eeab 101char *shutter, *getlogin();
3ce26e8e 102
954bb1fe
BJ
103main(argc,argv)
104 int argc;
105 char **argv;
106{
107 register i, ufd;
a96b688d 108 register char *f;
954bb1fe 109 char *ts;
3ce26e8e 110 time_t sdt;
954bb1fe 111 int h, m;
3ce26e8e 112 int first;
954bb1fe 113 FILE *termf;
b0af3d20 114 struct passwd *pw, *getpwuid();
f4a2e501
EA
115 extern char *strcat();
116 extern uid_t geteuid();
954bb1fe 117
8fa8eeab 118 shutter = getlogin();
b0af3d20
MK
119 if (shutter == 0 && (pw = getpwuid(getuid())))
120 shutter = pw->pw_name;
a96b688d
EA
121 if (shutter == 0)
122 shutter = "???";
db1d8af0 123 (void) gethostname(hostname, sizeof (hostname));
a96b688d 124 openlog("shutdown", 0, LOG_AUTH);
954bb1fe
BJ
125 argc--, argv++;
126 while (argc > 0 && (f = argv[0], *f++ == '-')) {
127 while (i = *f++) switch (i) {
128 case 'k':
129 killflg = 0;
130 continue;
8b3f4639
JB
131 case 'n':
132 nosync = nosyncflag;
133 continue;
134 case 'f':
135 fast = 1;
136 continue;
954bb1fe 137 case 'r':
db1d8af0 138 doreboot = 1;
954bb1fe
BJ
139 continue;
140 case 'h':
141 halt = 1;
142 continue;
143 default:
144 fprintf(stderr, "shutdown: '%c' - unknown flag\n", i);
145 exit(1);
146 }
147 argc--, argv++;
148 }
149 if (argc < 1) {
8b3f4639
JB
150 /* argv[0] is not available after the argument handling. */
151 printf("Usage: shutdown [ -krhfn ] shutdowntime [ message ]\n");
152 finish();
153 }
154 if (fast && (nosync == nosyncflag)) {
155 printf ("shutdown: Incompatible switches 'fast' & 'nosync'\n");
954bb1fe
BJ
156 finish();
157 }
4004e859
BJ
158 if (geteuid()) {
159 fprintf(stderr, "NOT super-user\n");
7b602762
MT
160 finish();
161 }
db1d8af0 162 nowtime = time((long *)0);
954bb1fe
BJ
163 sdt = getsdt(argv[0]);
164 argc--, argv++;
a96b688d
EA
165 nolog2[0] = '\0';
166 while (argc-- > 0) {
f4a2e501
EA
167 (void) strcat(nolog2, " ");
168 (void) strcat(nolog2, *argv++);
a96b688d 169 }
954bb1fe
BJ
170 m = ((stogo = sdt - nowtime) + 30)/60;
171 h = m/60;
172 m %= 60;
173 ts = ctime(&sdt);
8fa8eeab 174 printf("Shutdown at %5.5s (in ", ts+11);
954bb1fe
BJ
175 if (h > 0)
176 printf("%d hour%s ", h, h != 1 ? "s" : "");
8fa8eeab 177 printf("%d minute%s) ", m, m != 1 ? "s" : "");
954bb1fe 178#ifndef DEBUG
db1d8af0
JB
179 (void) signal(SIGHUP, SIG_IGN);
180 (void) signal(SIGQUIT, SIG_IGN);
181 (void) signal(SIGINT, SIG_IGN);
954bb1fe 182#endif
db1d8af0
JB
183 (void) signal(SIGTTOU, SIG_IGN);
184 (void) signal(SIGTERM, finish);
185 (void) signal(SIGALRM, timeout);
186 (void) setpriority(PRIO_PROCESS, 0, PRIO_MIN);
187 (void) fflush(stdout);
8fa8eeab 188#ifndef DEBUG
954bb1fe 189 if (i = fork()) {
8fa8eeab 190 printf("[pid %d]\n", i);
954bb1fe
BJ
191 exit(0);
192 }
3ce26e8e 193#else
db1d8af0 194 (void) putc('\n', stdout);
8fa8eeab 195#endif
954bb1fe
BJ
196 sint = 1 HOURS;
197 f = "";
3ce26e8e
KM
198 ufd = open("/etc/utmp",0);
199 if (ufd < 0) {
200 perror("shutdown: /etc/utmp");
201 exit(1);
202 }
203 first = 1;
954bb1fe
BJ
204 for (;;) {
205 for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++)
206 sint = interval[i].sint;
3ce26e8e
KM
207 if (stogo > 0 && (stogo-sint) < interval[i].stogo)
208 sint = stogo - interval[i].stogo;
954bb1fe
BJ
209 if (stogo <= NOLOGTIME && nlflag) {
210 nlflag = 0;
211 nolog(sdt);
212 }
213 if (sint >= stogo || sint == 0)
214 f = "FINAL ";
db1d8af0
JB
215 nowtime = time((long *)0);
216 (void) lseek(ufd, 0L, 0);
217 while (read(ufd,(char *)&utmp,sizeof utmp)==sizeof utmp)
d3818e48
BJ
218 if (utmp.ut_name[0] &&
219 strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) {
297efed7
MK
220 if (setjmp(alarmbuf))
221 continue;
db1d8af0
JB
222 (void) strcpy(term, tpath);
223 (void) strncat(term, utmp.ut_line, sizeof utmp.ut_line);
224 (void) alarm(3);
954bb1fe 225#ifdef DEBUG
8fa8eeab 226 if ((termf = stdout) != NULL)
954bb1fe
BJ
227#else
228 if ((termf = fopen(term, "w")) != NULL)
229#endif
230 {
db1d8af0 231 (void) alarm(0);
954bb1fe 232 setbuf(termf, tbuf);
3ce26e8e
KM
233 fprintf(termf, "\n\r\n");
234 warn(termf, sdt, nowtime, f);
235 if (first || sdt - nowtime > 1 MINUTES) {
236 if (*nolog2)
a96b688d 237 fprintf(termf, "\t...%s", nolog2);
3ce26e8e 238 }
db1d8af0
JB
239 (void) fputc('\r', termf);
240 (void) fputc('\n', termf);
241 (void) alarm(5);
8fa8eeab 242#ifdef DEBUG
db1d8af0 243 (void) fflush(termf);
8fa8eeab 244#else
db1d8af0 245 (void) fclose(termf);
8fa8eeab 246#endif
db1d8af0 247 (void) alarm(0);
954bb1fe
BJ
248 }
249 }
3ce26e8e 250 if (stogo <= 0) {
a96b688d 251 printf("\n\007\007System shutdown time has arrived\007\007\n");
b0af3d20
MK
252 syslog(LOG_CRIT, "%s by %s: %s",
253 doreboot ? "reboot" : halt ? "halt" : "shutdown",
254 shutter, nolog2);
255 sleep(2);
db1d8af0 256 (void) unlink(nologin);
954bb1fe
BJ
257 if (!killflg) {
258 printf("but you'll have to do it yourself\n");
259 finish();
260 }
8b3f4639
JB
261 if (fast)
262 doitfast();
954bb1fe 263#ifndef DEBUG
db1d8af0 264 if (doreboot)
b0af3d20 265 execle(REBOOT, "reboot", "-l", nosync, 0, 0);
954bb1fe 266 if (halt)
b0af3d20
MK
267 execle(HALT, "halt", "-l", nosync, 0, 0);
268 (void) kill(1, SIGTERM); /* to single user */
954bb1fe 269#else
db1d8af0 270 if (doreboot)
8b3f4639
JB
271 printf("REBOOT");
272 if (halt)
273 printf(" HALT");
274 if (fast)
b0af3d20 275 printf(" -l %s (without fsck's)\n", nosync);
8b3f4639 276 else
b0af3d20
MK
277 printf(" -l %s\n", nosync);
278 else
279 printf("kill -HUP 1\n");
8b3f4639 280
954bb1fe
BJ
281#endif
282 finish();
283 }
db1d8af0 284 stogo = sdt - time((long *) 0);
3ce26e8e 285 if (stogo > 0 && sint > 0)
db1d8af0 286 sleep((unsigned)(sint<stogo ? sint : stogo));
954bb1fe 287 stogo -= sint;
3ce26e8e 288 first = 0;
954bb1fe
BJ
289 }
290}
291
292time_t
293getsdt(s)
3ce26e8e 294 register char *s;
954bb1fe
BJ
295{
296 time_t t, t1, tim;
297 register char c;
298 struct tm *lt;
299
3ce26e8e
KM
300 if (strcmp(s, "now") == 0)
301 return(nowtime);
954bb1fe
BJ
302 if (*s == '+') {
303 ++s;
304 t = 0;
305 for (;;) {
306 c = *s++;
307 if (!isdigit(c))
308 break;
309 t = t * 10 + c - '0';
310 }
311 if (t <= 0)
312 t = 5;
313 t *= 60;
db1d8af0 314 tim = time((long *) 0) + t;
954bb1fe
BJ
315 return(tim);
316 }
317 t = 0;
318 while (strlen(s) > 2 && isdigit(*s))
319 t = t * 10 + *s++ - '0';
320 if (*s == ':')
321 s++;
322 if (t > 23)
323 goto badform;
324 tim = t*60;
325 t = 0;
326 while (isdigit(*s))
327 t = t * 10 + *s++ - '0';
328 if (t > 59)
329 goto badform;
330 tim += t;
331 tim *= 60;
db1d8af0 332 t1 = time((long *) 0);
954bb1fe
BJ
333 lt = localtime(&t1);
334 t = lt->tm_sec + lt->tm_min*60 + lt->tm_hour*3600;
335 if (tim < t || tim >= (24*3600)) {
336 /* before now or after midnight */
337 printf("That must be tomorrow\nCan't you wait till then?\n");
338 finish();
339 }
3ce26e8e 340 return (t1 + tim - t);
954bb1fe
BJ
341badform:
342 printf("Bad time format\n");
343 finish();
db1d8af0 344 /*NOTREACHED*/
954bb1fe
BJ
345}
346
3ce26e8e 347warn(term, sdt, now, type)
954bb1fe 348 FILE *term;
3ce26e8e
KM
349 time_t sdt, now;
350 char *type;
954bb1fe
BJ
351{
352 char *ts;
3ce26e8e 353 register delay = sdt - now;
954bb1fe 354
ab07e5ac
BJ
355 if (delay > 8)
356 while (delay % 5)
357 delay++;
358
a96b688d 359 fprintf(term,
b17445e6
BJ
360 "\007\007\t*** %sSystem shutdown message from %s@%s ***\r\n\n",
361 type, shutter, hostname);
3ce26e8e 362
954bb1fe 363 ts = ctime(&sdt);
3ce26e8e
KM
364 if (delay > 10 MINUTES)
365 fprintf(term, "System going down at %5.5s\r\n", ts+11);
366 else if (delay > 95 SECONDS) {
367 fprintf(term, "System going down in %d minute%s\r\n",
368 (delay+30)/60, (delay+30)/60 != 1 ? "s" : "");
369 } else if (delay > 0) {
370 fprintf(term, "System going down in %d second%s\r\n",
371 delay, delay != 1 ? "s" : "");
954bb1fe 372 } else
3ce26e8e 373 fprintf(term, "System going down IMMEDIATELY\r\n");
954bb1fe
BJ
374}
375
8b3f4639
JB
376doitfast()
377{
378 FILE *fastd;
379
380 if ((fastd = fopen(fastboot, "w")) != NULL) {
381 putc('\n', fastd);
db1d8af0 382 (void) fclose(fastd);
8b3f4639
JB
383 }
384}
385
954bb1fe 386nolog(sdt)
3ce26e8e 387 time_t sdt;
954bb1fe
BJ
388{
389 FILE *nologf;
954bb1fe 390
db1d8af0 391 (void) unlink(nologin); /* in case linked to std file */
954bb1fe
BJ
392 if ((nologf = fopen(nologin, "w")) != NULL) {
393 fprintf(nologf, nolog1, (ctime(&sdt)) + 11);
a96b688d
EA
394 if (*nolog2)
395 fprintf(nologf, "\t%s\n", nolog2 + 1);
db1d8af0 396 (void) fclose(nologf);
954bb1fe
BJ
397 }
398}
399
400finish()
401{
db1d8af0
JB
402 (void) signal(SIGTERM, SIG_IGN);
403 (void) unlink(nologin);
954bb1fe
BJ
404 exit(0);
405}
406
297efed7 407timeout()
954bb1fe 408{
297efed7 409 longjmp(alarmbuf, 1);
954bb1fe 410}