symbolic links
[unix-history] / usr / src / sbin / shutdown / shutdown.c
CommitLineData
a3180dc7 1static char *sccsid = "@(#)shutdown.c 4.11 (Berkeley) 82/02/01";
954bb1fe
BJ
2
3#include <stdio.h>
4#include <ctype.h>
5#include <signal.h>
6#include <utmp.h>
7#include <time.h>
8#include <sys/types.h>
a3180dc7 9#include <whoami.h>
954bb1fe
BJ
10/*
11 * /etc/shutdown when [messages]
12 *
13 * allow super users to tell users and remind users
14 * of iminent shutdown of unix
15 * and shut it down automatically
16 * and even reboot or halt the machine if they desire
17 *
18 * Ian Johnstone, Sydney, 1977
19 * Robert Elz, Melbourne, 1978
20 * Peter Lamb, Melbourne, 1980
21 * William Joy, Berkeley, 1981
8fa8eeab 22 * Michael Toy, Berkeley, 1981
d3818e48 23 * Dave Presotto, Berkeley, 1981
954bb1fe 24 */
8fa8eeab
BJ
25#ifdef DEBUG
26#define LOGFILE "shutdown.log"
27#else
28#define LOGFILE "/usr/adm/shutdownlog"
29#endif
954bb1fe
BJ
30#define REBOOT "/etc/reboot"
31#define HALT "/etc/halt"
32#define MAXINTS 20
33#define HOURS *3600
34#define MINUTES *60
35#define SECONDS
ab07e5ac 36#define NLOG 20 /* no of args possible for message */
954bb1fe 37#define NOLOGTIME 5 MINUTES
d3818e48 38#define IGNOREUSER "sleeper"
954bb1fe
BJ
39
40int do_nothing();
41time_t getsdt();
42
43extern char *ctime();
44extern struct tm *localtime();
45
46struct utmp utmp;
47int sint;
48int stogo;
49char tpath[] = "/dev/";
50int nlflag = 1; /* nolog yet to be done */
51int killflg = 1;
52int reboot = 0;
53int halt = 0;
54char term[sizeof tpath + sizeof utmp.ut_line];
55char tbuf[BUFSIZ];
56char nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n";
57char *nolog2[NLOG+1];
58#ifdef DEBUG
59char nologin[] = "nologin";
60#else
61char nologin[] = "/etc/nologin";
62#endif
63int slots;
64struct interval {
65 int stogo;
66 int sint;
67} interval[] = {
68 4 HOURS, 1 HOURS,
69 2 HOURS, 30 MINUTES,
70 1 HOURS, 15 MINUTES,
71 30 MINUTES, 10 MINUTES,
72 15 MINUTES, 5 MINUTES,
8fa8eeab
BJ
73 10 MINUTES, 5 MINUTES,
74 5 MINUTES, 3 MINUTES,
954bb1fe 75 2 MINUTES, 30 SECONDS,
ab07e5ac 76 40 SECONDS, 10 SECONDS,
954bb1fe
BJ
77 0 SECONDS, 0 SECONDS
78};
8fa8eeab 79char *shutter, *getlogin();
954bb1fe
BJ
80main(argc,argv)
81 int argc;
82 char **argv;
83{
84 register i, ufd;
85 register char **mess, *f;
86 char *ts;
87 long sdt;
88 int h, m;
89 long nowtime;
90 FILE *termf;
91
8fa8eeab 92 shutter = getlogin();
954bb1fe
BJ
93 argc--, argv++;
94 while (argc > 0 && (f = argv[0], *f++ == '-')) {
95 while (i = *f++) switch (i) {
96 case 'k':
97 killflg = 0;
98 continue;
99 case 'r':
100 reboot = 1;
101 continue;
102 case 'h':
103 halt = 1;
104 continue;
105 default:
106 fprintf(stderr, "shutdown: '%c' - unknown flag\n", i);
107 exit(1);
108 }
109 argc--, argv++;
110 }
111 if (argc < 1) {
ab07e5ac 112 printf("Usage: %s [ -krh ] shutdowntime [ message ]\n",
954bb1fe
BJ
113 argv[0]);
114 finish();
115 }
4004e859
BJ
116 if (geteuid()) {
117 fprintf(stderr, "NOT super-user\n");
7b602762
MT
118 finish();
119 }
954bb1fe
BJ
120 sdt = getsdt(argv[0]);
121 argc--, argv++;
122 i = 0;
123 while (argc-- > 0)
124 if (i < NLOG)
125 nolog2[i++] = *argv++;
126 nolog2[i] = NULL;
127 nowtime = time((long *)0);
128 m = ((stogo = sdt - nowtime) + 30)/60;
129 h = m/60;
130 m %= 60;
131 ts = ctime(&sdt);
8fa8eeab 132 printf("Shutdown at %5.5s (in ", ts+11);
954bb1fe
BJ
133 if (h > 0)
134 printf("%d hour%s ", h, h != 1 ? "s" : "");
8fa8eeab 135 printf("%d minute%s) ", m, m != 1 ? "s" : "");
954bb1fe
BJ
136#ifndef DEBUG
137 signal(SIGHUP, SIG_IGN);
138 signal(SIGQUIT, SIG_IGN);
139 signal(SIGINT, SIG_IGN);
140#endif
141 signal(SIGTERM, finish);
142 signal(SIGALRM, do_nothing);
143 nice(-20);
ab07e5ac 144 fflush(stdout);
8fa8eeab 145#ifndef DEBUG
954bb1fe 146 if (i = fork()) {
8fa8eeab 147 printf("[pid %d]\n", i);
954bb1fe
BJ
148 exit(0);
149 }
8fa8eeab 150#endif
954bb1fe
BJ
151 sint = 1 HOURS;
152 f = "";
153 for (;;) {
154 for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++)
155 sint = interval[i].sint;
156 if (stogo <= NOLOGTIME && nlflag) {
157 nlflag = 0;
158 nolog(sdt);
159 }
160 if (sint >= stogo || sint == 0)
161 f = "FINAL ";
162 ufd = open("/etc/utmp",0);
163 nowtime = time((long *) 0);
164 while (read(ufd,&utmp,sizeof utmp)==sizeof utmp)
d3818e48
BJ
165 if (utmp.ut_name[0] &&
166 strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) {
954bb1fe
BJ
167 strcpy(term, tpath);
168 strncat(term, utmp.ut_line, sizeof utmp.ut_line);
169 alarm(3);
170#ifdef DEBUG
8fa8eeab 171 if ((termf = stdout) != NULL)
954bb1fe
BJ
172#else
173 if ((termf = fopen(term, "w")) != NULL)
174#endif
175 {
176 alarm(0);
177 setbuf(termf, tbuf);
178 fprintf(termf, "\n\n");
179 warn(termf, sdt, nowtime);
180 if (sdt - nowtime > 1 MINUTES)
181 for (mess = nolog2; *mess; mess++)
182 fprintf(termf, "%s ", *mess);
183 fputc('\n', termf);
8fa8eeab
BJ
184 alarm(5);
185#ifdef DEBUG
186 fflush(termf);
187#else
954bb1fe 188 fclose(termf);
8fa8eeab 189#endif
954bb1fe
BJ
190 alarm(0);
191 }
192 }
193 if (stogo < 0) {
194 printf("\n\007\007System shutdown time has arrived\007\007\n");
8fa8eeab 195 log_entry(sdt);
954bb1fe
BJ
196 unlink(nologin);
197 if (!killflg) {
198 printf("but you'll have to do it yourself\n");
199 finish();
200 }
201#ifndef DEBUG
202 if (reboot)
203 execle(REBOOT, "reboot", 0, 0);
204 if (halt)
205 execle(HALT, "halt", 0, 0);
206 kill(1, SIGTERM); /* sync */
207 kill(1, SIGTERM); /* sync */
208 sleep(20);
209#else
210 printf("EXTERMINATE EXTERMINATE\n");
211#endif
212 finish();
213 }
214 stogo = sdt - time((long *) 0);
215 if (stogo > 0)
216 sleep(sint<stogo ? sint : stogo);
217 stogo -= sint;
218 }
219}
220
221time_t
222getsdt(s)
223register char *s;
224{
225 time_t t, t1, tim;
226 register char c;
227 struct tm *lt;
228
229 if (*s == '+') {
230 ++s;
231 t = 0;
232 for (;;) {
233 c = *s++;
234 if (!isdigit(c))
235 break;
236 t = t * 10 + c - '0';
237 }
238 if (t <= 0)
239 t = 5;
240 t *= 60;
241 tim = time((long *) 0) + t;
242 return(tim);
243 }
244 t = 0;
245 while (strlen(s) > 2 && isdigit(*s))
246 t = t * 10 + *s++ - '0';
247 if (*s == ':')
248 s++;
249 if (t > 23)
250 goto badform;
251 tim = t*60;
252 t = 0;
253 while (isdigit(*s))
254 t = t * 10 + *s++ - '0';
255 if (t > 59)
256 goto badform;
257 tim += t;
258 tim *= 60;
259 t1 = time((long *) 0);
260 lt = localtime(&t1);
261 t = lt->tm_sec + lt->tm_min*60 + lt->tm_hour*3600;
262 if (tim < t || tim >= (24*3600)) {
263 /* before now or after midnight */
264 printf("That must be tomorrow\nCan't you wait till then?\n");
265 finish();
266 }
267 return (t1 + tim -t);
268badform:
269 printf("Bad time format\n");
270 finish();
271}
272
273warn(term, sdt, nowtime)
274 FILE *term;
275 long sdt, nowtime;
276{
277 char *ts;
2bfc5a4f 278 register delay = sdt - nowtime;
954bb1fe 279
ab07e5ac
BJ
280 if (delay > 8)
281 while (delay % 5)
282 delay++;
283
284 if (shutter)
285 fprintf(term,
a3180dc7
BJ
286 "\007\007*** System shutdown message from %s!%s ***\n",
287 sysname,shutter);
ab07e5ac
BJ
288 else
289 fprintf(term,
290 "\007\007*** System shutdown message ***\n");
954bb1fe 291 ts = ctime(&sdt);
ab07e5ac 292 if (delay> 10 MINUTES)
954bb1fe 293 fprintf(term, "System going down at %5.5s\n", ts+11);
ab07e5ac 294 else if ( delay > 60 SECONDS ) {
954bb1fe 295 fprintf(term, "System going down in %d minute%s\n",
ab07e5ac
BJ
296 (delay+30)/60, (delay+30)/60 != 1 ? "s" : "");
297 } else if ( delay > 0 ) {
8fa8eeab 298 fprintf(term, "System going down in %d second%s\n",
ab07e5ac 299 delay, delay != 1 ? "s" : "");
954bb1fe
BJ
300 } else
301 fprintf(term, "System going down IMMEDIATELY\n");
302}
303
304nolog(sdt)
305 long sdt;
306{
307 FILE *nologf;
308 register char **mess;
309
310 if ((nologf = fopen(nologin, "w")) != NULL) {
311 fprintf(nologf, nolog1, (ctime(&sdt)) + 11);
ab07e5ac 312 putc('\t', nologf);
954bb1fe 313 for (mess = nolog2; *mess; mess++)
ab07e5ac
BJ
314 fprintf(nologf, " %s", *mess);
315 putc('\n', nologf);
954bb1fe
BJ
316 fclose(nologf);
317 }
318}
319
320finish()
321{
322 signal(SIGTERM, SIG_IGN);
323 unlink(nologin);
324 exit(0);
325}
326
327do_nothing()
328{
329
330 signal(SIGALRM, do_nothing);
331}
8fa8eeab
BJ
332
333/*
334 * make an entry in the shutdown log
335 */
336
f8969a9a
BJ
337char *days[] = {
338 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
339};
340
341char *months[] = {
342 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
343 "Oct", "Nov", "Dec"
344};
345
346log_entry(now)
347time_t now;
8fa8eeab 348{
f8969a9a
BJ
349 register FILE *fp;
350 register char **mess;
351 struct tm *tm, *localtime();
8fa8eeab 352
f8969a9a
BJ
353 tm = localtime(&now);
354 fp = fopen(LOGFILE, "a");
3f51f330
BJ
355 if (fp==0)
356 return;
f8969a9a
BJ
357 fseek(fp, 0L, 2);
358 fprintf(fp, "%02d:%02d %s %s %2d, %4d. Shutdown:", tm->tm_hour,
359 tm->tm_min, days[tm->tm_wday], months[tm->tm_mon],
360 tm->tm_mday, tm->tm_year + 1900);
8fa8eeab 361 for (mess = nolog2; *mess; mess++)
f8969a9a 362 fprintf(fp, " %s", *mess);
ab07e5ac 363 if (shutter)
a3180dc7 364 fprintf(fp, " (by %s!%s)", sysname,shutter);
f8969a9a
BJ
365 fputc('\n', fp);
366 fclose(fp);
8fa8eeab 367}