* Add fix for Debian bug #536574 -- Can be enabled by -DACCTON_OFF
[sysvinit.git] / src / shutdown.c
1 /*
2 * shutdown.c Shut the system down.
3 *
4 * Usage: shutdown [-krhfnc] time [warning message]
5 * -k: don't really shutdown, only warn.
6 * -r: reboot after shutdown.
7 * -h: halt after shutdown.
8 * -f: do a 'fast' reboot (skip fsck).
9 * -F: Force fsck on reboot.
10 * -n: do not go through init but do it ourselves.
11 * -c: cancel an already running shutdown.
12 * -t secs: delay between SIGTERM and SIGKILL for init.
13 *
14 * Author: Miquel van Smoorenburg, miquels@cistron.nl
15 *
16 * Version: @(#)shutdown 2.86-1 31-Jul-2004 miquels@cistron.nl
17 *
18 * This file is part of the sysvinit suite,
19 * Copyright (C) 1991-2004 Miquel van Smoorenburg.
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
34 */
35 #ifndef _GNU_SOURCE
36 # define _GNU_SOURCE /* otherwise `extern char **environ' is missed */
37 #endif
38 #ifndef ACCTON_OFF
39 # define ACCTON_OFF 0
40 #endif
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/wait.h>
44 #include <time.h>
45 #include <string.h>
46 #include <errno.h>
47 #include <unistd.h>
48 #include <errno.h>
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <signal.h>
52 #include <fcntl.h>
53 #include <stdarg.h>
54 #include <utmp.h>
55 #include <syslog.h>
56 #include "paths.h"
57 #include "reboot.h"
58 #include "initreq.h"
59 #include "init.h"
60
61
62 char *Version = "@(#) shutdown 2.86-1 31-Jul-2004 miquels@cistron.nl";
63
64 #define MESSAGELEN 256
65
66 int dontshut = 0; /* Don't shutdown, only warn */
67 char down_level[2]; /* What runlevel to go to. */
68 int dosync = 1; /* Sync before reboot or halt */
69 int fastboot = 0; /* Do a 'fast' reboot */
70 int forcefsck = 0; /* Force fsck on reboot */
71 char message[MESSAGELEN]; /* Warning message */
72 char *sltime = 0; /* Sleep time */
73 char newstate[64]; /* What are we gonna do */
74 int doself = 0; /* Don't use init */
75 int got_alrm = 0;
76
77 char *clean_env[] = {
78 "HOME=/",
79 "PATH=/bin:/usr/bin:/sbin:/usr/sbin",
80 "TERM=dumb",
81 "SHELL=/bin/sh",
82 NULL,
83 };
84
85 /* From "utmp.c" */
86 extern void write_wtmp(char *user, char *id, int pid, int type, char *line);
87
88 /*
89 * Sleep without being interrupted.
90 */
91 void hardsleep(int secs)
92 {
93 struct timespec ts, rem;
94
95 ts.tv_sec = secs;
96 ts.tv_nsec = 0;
97
98 while(nanosleep(&ts, &rem) < 0 && errno == EINTR)
99 ts = rem;
100 }
101
102 /*
103 * Break off an already running shutdown.
104 */
105 # ifdef __GNUC__
106 void stopit(int sig __attribute__((unused)))
107 # else
108 void stopit(int sig)
109 # endif
110
111 {
112 unlink(NOLOGIN);
113 unlink(FASTBOOT);
114 unlink(FORCEFSCK);
115 unlink(SDPID);
116 printf("\r\nShutdown cancelled.\r\n");
117 exit(0);
118 }
119
120 /*
121 * Show usage message.
122 */
123 void usage(void)
124 {
125 fprintf(stderr,
126 "Usage:\t shutdown [-akrhPHfFnc] [-t sec] time [warning message]\n"
127 "\t\t -a: use /etc/shutdown.allow\n"
128 "\t\t -k: don't really shutdown, only warn.\n"
129 "\t\t -r: reboot after shutdown.\n"
130 "\t\t -h: halt after shutdown.\n"
131 "\t\t -P: halt action is to turn off power.\n"
132 "\t\t -H: halt action is to just halt.\n"
133 "\t\t -f: do a 'fast' reboot (skip fsck).\n"
134 "\t\t -F: Force fsck on reboot.\n"
135 "\t\t -n: do not go through \"init\" but go down real fast.\n"
136 "\t\t -c: cancel a running shutdown.\n"
137 "\t\t -t secs: delay between warning and kill signal.\n"
138 "\t\t ** the \"time\" argument is mandatory! (try \"now\") **\n");
139 exit(1);
140 }
141
142
143 void alrm_handler(int sig)
144 {
145 got_alrm = sig;
146 }
147
148
149 /*
150 * Set environment variables in the init process.
151 */
152 int init_setenv(char *name, char *value)
153 {
154 struct init_request request;
155 struct sigaction sa;
156 int fd;
157 int nl, vl;
158
159 memset(&request, 0, sizeof(request));
160 request.magic = INIT_MAGIC;
161 request.cmd = INIT_CMD_SETENV;
162 nl = strlen(name);
163 vl = value ? strlen(value) : 0;
164
165 if (nl + vl + 3 >= (int)sizeof(request.i.data))
166 return -1;
167
168 memcpy(request.i.data, name, nl);
169 if (value) {
170 request.i.data[nl] = '=';
171 memcpy(request.i.data + nl + 1, value, vl);
172 }
173
174 /*
175 * Open the fifo and write the command.
176 * Make sure we don't hang on opening /dev/initctl
177 */
178 memset(&sa, 0, sizeof(sa));
179 sa.sa_handler = alrm_handler;
180 sigaction(SIGALRM, &sa, NULL);
181 got_alrm = 0;
182 alarm(3);
183 if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0) {
184 ssize_t p = 0;
185 size_t s = sizeof(request);
186 void *ptr = &request;
187 while (s > 0) {
188 p = write(fd, ptr, s);
189 if (p < 0) {
190 if (errno == EINTR || errno == EAGAIN)
191 continue;
192 break;
193 }
194 ptr += p;
195 s -= p;
196 }
197 close(fd);
198 alarm(0);
199 return 0;
200 }
201
202 fprintf(stderr, "shutdown: ");
203 if (got_alrm) {
204 fprintf(stderr, "timeout opening/writing control channel %s\n",
205 INIT_FIFO);
206 } else {
207 perror(INIT_FIFO);
208 }
209 return -1;
210 }
211
212
213 /*
214 * Tell everyone the system is going down in 'mins' minutes.
215 */
216 void warn(int mins)
217 {
218 char buf[MESSAGELEN + sizeof(newstate)];
219 int len;
220
221 buf[0] = 0;
222 strncat(buf, message, sizeof(buf) - 1);
223 len = strlen(buf);
224
225 if (mins == 0)
226 snprintf(buf + len, sizeof(buf) - len,
227 "\rThe system is going down %s NOW!\r\n",
228 newstate);
229 else
230 snprintf(buf + len, sizeof(buf) - len,
231 "\rThe system is going DOWN %s in %d minute%s!\r\n",
232 newstate, mins, mins == 1 ? "" : "s");
233 wall(buf, 0);
234 }
235
236 /*
237 * Create the /etc/nologin file.
238 */
239 void donologin(int min)
240 {
241 FILE *fp;
242 time_t t;
243
244 time(&t);
245 t += 60 * min;
246
247 if ((fp = fopen(NOLOGIN, "w")) != NULL) {
248 fprintf(fp, "\rThe system is going down on %s\r\n", ctime(&t));
249 if (message[0]) fputs(message, fp);
250 fclose(fp);
251 }
252 }
253
254 /*
255 * Spawn an external program.
256 */
257 int spawn(int noerr, char *prog, ...)
258 {
259 va_list ap;
260 pid_t pid, rc;
261 int i;
262 char *argv[8];
263
264 i = 0;
265 while ((pid = fork()) < 0 && i < 10) {
266 perror("fork");
267 sleep(5);
268 i++;
269 }
270
271 if (pid < 0) return -1;
272
273 if (pid > 0) {
274 while((rc = wait(&i)) != pid)
275 if (rc < 0 && errno == ECHILD)
276 break;
277 return (rc == pid) ? WEXITSTATUS(i) : -1;
278 }
279
280 if (noerr) fclose(stderr);
281
282 argv[0] = prog;
283 va_start(ap, prog);
284 for (i = 1; i < 7 && (argv[i] = va_arg(ap, char *)) != NULL; i++)
285 ;
286 argv[i] = NULL;
287 va_end(ap);
288
289 chdir("/");
290 environ = clean_env;
291
292 execvp(argv[0], argv);
293 perror(argv[0]);
294 exit(1);
295
296 /*NOTREACHED*/
297 return 0;
298 }
299
300 /*
301 * Kill all processes, call /etc/init.d/halt (if present)
302 */
303 void fastdown()
304 {
305 int do_halt = (down_level[0] == '0');
306 int i;
307 #if 0
308 char cmd[128];
309 char *script;
310
311 /*
312 * Currently, the halt script is either init.d/halt OR rc.d/rc.0,
313 * likewise for the reboot script. Test for the presence
314 * of either.
315 */
316 if (do_halt) {
317 if (access(HALTSCRIPT1, X_OK) == 0)
318 script = HALTSCRIPT1;
319 else
320 script = HALTSCRIPT2;
321 } else {
322 if (access(REBOOTSCRIPT1, X_OK) == 0)
323 script = REBOOTSCRIPT1;
324 else
325 script = REBOOTSCRIPT2;
326 }
327 #endif
328
329 /* First close all files. */
330 for(i = 0; i < 3; i++)
331 if (!isatty(i)) {
332 close(i);
333 open("/dev/null", O_RDWR);
334 }
335 for(i = 3; i < 20; i++) close(i);
336 close(255);
337
338 /* First idle init. */
339 if (kill(1, SIGTSTP) < 0) {
340 fprintf(stderr, "shutdown: can't idle init: %s.\r\n", strerror(errno));
341 exit(1);
342 }
343
344 /* Kill all processes. */
345 fprintf(stderr, "shutdown: sending all processes the TERM signal...\r\n");
346 kill(-1, SIGTERM);
347 sleep(sltime ? atoi(sltime) : 3);
348 fprintf(stderr, "shutdown: sending all processes the KILL signal.\r\n");
349 (void) kill(-1, SIGKILL);
350
351 #if 0
352 /* See if we can run /etc/init.d/halt */
353 if (access(script, X_OK) == 0) {
354 spawn(1, cmd, "fast", NULL);
355 fprintf(stderr, "shutdown: %s returned - falling back "
356 "on default routines\r\n", script);
357 }
358 #endif
359
360 /* script failed or not present: do it ourself. */
361 sleep(1); /* Give init the chance to collect zombies. */
362
363 /* Record the fact that we're going down */
364 write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
365
366 /* This is for those who have quota installed. */
367 #if defined(ACCTON_OFF)
368 # if (ACCTON_OFF > 1) && (_BSD_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500))
369 /* This is an alternative way to disable accounting, saving a fork() */
370 if (acct(NULL))
371 fprintf(stderr, "shutdown: can not stop process accounting: %s.\r\n", strerror(errno));
372 # elif (ACCTON_OFF > 0)
373 spawn(1, "accton", "off", NULL);
374 # else
375 spawn(1, "accton", NULL);
376 # endif
377 #endif
378 spawn(1, "quotaoff", "-a", NULL);
379
380 sync();
381 fprintf(stderr, "shutdown: turning off swap\r\n");
382 spawn(0, "swapoff", "-a", NULL);
383 fprintf(stderr, "shutdown: unmounting all file systems\r\n");
384 spawn(0, "umount", "-a", NULL);
385
386 /* We're done, halt or reboot now. */
387 if (do_halt) {
388 fprintf(stderr, "The system is halted. Press CTRL-ALT-DEL "
389 "or turn off power\r\n");
390 init_reboot(BMAGIC_HALT);
391 exit(0);
392 }
393
394 fprintf(stderr, "Please stand by while rebooting the system.\r\n");
395 init_reboot(BMAGIC_REBOOT);
396 exit(0);
397 }
398
399 /*
400 * Go to runlevel 0, 1 or 6.
401 */
402 void shutdown(char *halttype)
403 {
404 char *args[8];
405 int argp = 0;
406 int do_halt = (down_level[0] == '0');
407
408 /* Warn for the last time */
409 warn(0);
410 if (dontshut) {
411 hardsleep(1);
412 stopit(0);
413 }
414 openlog("shutdown", LOG_PID, LOG_USER);
415 if (do_halt)
416 syslog(LOG_NOTICE, "shutting down for system halt");
417 else
418 syslog(LOG_NOTICE, "shutting down for system reboot");
419 closelog();
420
421 /* See if we have to do it ourself. */
422 if (doself) fastdown();
423
424 /* Create the arguments for init. */
425 args[argp++] = INIT;
426 if (sltime) {
427 args[argp++] = "-t";
428 args[argp++] = sltime;
429 }
430 args[argp++] = down_level;
431 args[argp] = (char *)NULL;
432
433 unlink(SDPID);
434 unlink(NOLOGIN);
435
436 /* Now execute init to change runlevel. */
437 sync();
438 init_setenv("INIT_HALT", halttype);
439 execv(INIT, args);
440
441 /* Oops - failed. */
442 fprintf(stderr, "\rshutdown: cannot execute %s\r\n", INIT);
443 unlink(FASTBOOT);
444 unlink(FORCEFSCK);
445 init_setenv("INIT_HALT", NULL);
446 openlog("shutdown", LOG_PID, LOG_USER);
447 syslog(LOG_NOTICE, "shutdown failed");
448 closelog();
449 exit(1);
450 }
451
452 /*
453 * returns if a warning is to be sent for wt
454 */
455 static int needwarning(int wt)
456 {
457 int ret;
458
459 if (wt < 10)
460 ret = 1;
461 else if (wt < 60)
462 ret = (wt % 15 == 0);
463 else if (wt < 180)
464 ret = (wt % 30 == 0);
465 else
466 ret = (wt % 60 == 0);
467
468 return ret;
469 }
470
471 /*
472 * Main program.
473 * Process the options and do the final countdown.
474 */
475 int main(int argc, char **argv)
476 {
477 FILE *fp;
478 extern int getopt();
479 extern int optind;
480 struct sigaction sa;
481 struct tm *lt;
482 struct stat st;
483 struct utmp *ut;
484 time_t t;
485 uid_t realuid;
486 char *halttype;
487 char *downusers[32];
488 char buf[128];
489 char term[UT_LINESIZE + 6];
490 char *sp;
491 char *when = NULL;
492 int c, i, wt;
493 int hours, mins;
494 int didnolog = 0;
495 int cancel = 0;
496 int useacl = 0;
497 int pid = 0;
498 int user_ok = 0;
499
500 /* We can be installed setuid root (executable for a special group) */
501 realuid = getuid();
502 setuid(geteuid());
503
504 if (getuid() != 0) {
505 fprintf(stderr, "shutdown: you must be root to do that!\n");
506 usage();
507 exit(1);
508 }
509 strcpy(down_level, "1");
510 halttype = NULL;
511
512 /* Process the options. */
513 while((c = getopt(argc, argv, "HPacqkrhnfFyt:g:i:")) != EOF) {
514 switch(c) {
515 case 'H':
516 halttype = "HALT";
517 break;
518 case 'P':
519 halttype = "POWERDOWN";
520 break;
521 case 'a': /* Access control. */
522 useacl = 1;
523 break;
524 case 'c': /* Cancel an already running shutdown. */
525 cancel = 1;
526 break;
527 case 'k': /* Don't really shutdown, only warn.*/
528 dontshut = 1;
529 break;
530 case 'r': /* Automatic reboot */
531 down_level[0] = '6';
532 break;
533 case 'h': /* Halt after shutdown */
534 down_level[0] = '0';
535 break;
536 case 'f': /* Don't perform fsck after next boot */
537 fastboot = 1;
538 break;
539 case 'F': /* Force fsck after next boot */
540 forcefsck = 1;
541 break;
542 case 'n': /* Don't switch runlevels. */
543 doself = 1;
544 break;
545 case 't': /* Delay between TERM and KILL */
546 sltime = optarg;
547 break;
548 case 'y': /* Ignored for sysV compatibility */
549 break;
550 case 'g': /* sysv style to specify time. */
551 when = optarg;
552 break;
553 case 'i': /* Level to go to. */
554 if (!strchr("0156aAbBcCsS", optarg[0])) {
555 fprintf(stderr,
556 "shutdown: `%s': bad runlevel\n",
557 optarg);
558 exit(1);
559 }
560 down_level[0] = optarg[0];
561 break;
562 default:
563 usage();
564 break;
565 }
566 }
567
568 if (NULL != halttype && down_level[0] != '0') {
569 fprintf(stderr, "shutdown: -H and -P flags can only be used along with -h flag.\n");
570 usage();
571 exit(1);
572 }
573
574 /* Do we need to use the shutdown.allow file ? */
575 if (useacl && (fp = fopen(SDALLOW, "r")) != NULL) {
576
577 /* Read /etc/shutdown.allow. */
578 i = 0;
579 while(fgets(buf, 128, fp)) {
580 if (buf[0] == '#' || buf[0] == '\n') continue;
581 if (i > 31) continue;
582 for(sp = buf; *sp; sp++) if (*sp == '\n') *sp = 0;
583 downusers[i++] = strdup(buf);
584 }
585 if (i < 32) downusers[i] = 0;
586 fclose(fp);
587
588 /* Now walk through /var/run/utmp to find logged in users. */
589 while(!user_ok && (ut = getutent()) != NULL) {
590
591 /* See if this is a user process on a VC. */
592 if (ut->ut_type != USER_PROCESS) continue;
593 sprintf(term, "/dev/%.*s", UT_LINESIZE, ut->ut_line);
594 if (stat(term, &st) < 0) continue;
595 #ifdef major /* glibc */
596 if (major(st.st_rdev) != 4 ||
597 minor(st.st_rdev) > 63) continue;
598 #else
599 if ((st.st_rdev & 0xFFC0) != 0x0400) continue;
600 #endif
601 /* Root is always OK. */
602 if (strcmp(ut->ut_user, "root") == 0) {
603 user_ok++;
604 break;
605 }
606
607 /* See if this is an allowed user. */
608 for(i = 0; i < 32 && downusers[i]; i++)
609 if (!strncmp(downusers[i], ut->ut_user,
610 UT_NAMESIZE)) {
611 user_ok++;
612 break;
613 }
614 }
615 endutent();
616
617 /* See if user was allowed. */
618 if (!user_ok) {
619 if ((fp = fopen(CONSOLE, "w")) != NULL) {
620 fprintf(fp, "\rshutdown: no authorized users "
621 "logged in.\r\n");
622 fclose(fp);
623 }
624 exit(1);
625 }
626 }
627
628 /* Read pid of running shutdown from a file */
629 if ((fp = fopen(SDPID, "r")) != NULL) {
630 fscanf(fp, "%d", &pid);
631 fclose(fp);
632 }
633
634 /* Read remaining words, skip time if needed. */
635 message[0] = 0;
636 for(c = optind + (!cancel && !when); c < argc; c++) {
637 if (strlen(message) + strlen(argv[c]) + 4 > MESSAGELEN)
638 break;
639 strcat(message, argv[c]);
640 strcat(message, " ");
641 }
642 if (message[0]) strcat(message, "\r\n");
643
644 /* See if we want to run or cancel. */
645 if (cancel) {
646 if (pid <= 0) {
647 fprintf(stderr, "shutdown: cannot find pid "
648 "of running shutdown.\n");
649 exit(1);
650 }
651 init_setenv("INIT_HALT", NULL);
652 if (kill(pid, SIGINT) < 0) {
653 fprintf(stderr, "shutdown: not running.\n");
654 exit(1);
655 }
656 if (message[0]) wall(message, 0);
657 exit(0);
658 }
659
660 /* Check syntax. */
661 if (when == NULL) {
662 if (optind == argc) usage();
663 when = argv[optind++];
664 }
665
666 /* See if we are already running. */
667 if (pid > 0 && kill(pid, 0) == 0) {
668 fprintf(stderr, "\rshutdown: already running.\r\n");
669 exit(1);
670 }
671
672 /* Extra check. */
673 if (doself && down_level[0] != '0' && down_level[0] != '6') {
674 fprintf(stderr,
675 "shutdown: can use \"-n\" for halt or reboot only.\r\n");
676 exit(1);
677 }
678
679 /* Tell users what we're gonna do. */
680 switch(down_level[0]) {
681 case '0':
682 strcpy(newstate, "for system halt");
683 break;
684 case '6':
685 strcpy(newstate, "for reboot");
686 break;
687 case '1':
688 strcpy(newstate, "to maintenance mode");
689 break;
690 default:
691 sprintf(newstate, "to runlevel %s", down_level);
692 break;
693 }
694
695 /* Create a new PID file. */
696 unlink(SDPID);
697 umask(022);
698 if ((fp = fopen(SDPID, "w")) != NULL) {
699 fprintf(fp, "%d\n", getpid());
700 fclose(fp);
701 } else if (errno != EROFS)
702 fprintf(stderr, "shutdown: warning: cannot open %s\n", SDPID);
703
704 /*
705 * Catch some common signals.
706 */
707 signal(SIGQUIT, SIG_IGN);
708 signal(SIGCHLD, SIG_IGN);
709 signal(SIGHUP, SIG_IGN);
710 signal(SIGTSTP, SIG_IGN);
711 signal(SIGTTIN, SIG_IGN);
712 signal(SIGTTOU, SIG_IGN);
713
714 memset(&sa, 0, sizeof(sa));
715 sa.sa_handler = stopit;
716 sigaction(SIGINT, &sa, NULL);
717
718 /* Go to the root directory */
719 chdir("/");
720 if (fastboot) close(open(FASTBOOT, O_CREAT | O_RDWR, 0644));
721 if (forcefsck) close(open(FORCEFSCK, O_CREAT | O_RDWR, 0644));
722
723 /* Alias now and take care of old '+mins' notation. */
724 if (!strcmp(when, "now")) strcpy(when, "0");
725 if (when[0] == '+') when++;
726
727 /* Decode shutdown time. */
728 for (sp = when; *sp; sp++) {
729 if (*sp != ':' && (*sp < '0' || *sp > '9'))
730 usage();
731 }
732 if (strchr(when, ':') == NULL) {
733 /* Time in minutes. */
734 wt = atoi(when);
735 if (wt == 0 && when[0] != '0') usage();
736 } else {
737 /* Time in hh:mm format. */
738 if (sscanf(when, "%d:%2d", &hours, &mins) != 2) usage();
739 if (hours > 23 || mins > 59) usage();
740 time(&t);
741 lt = localtime(&t);
742 wt = (60*hours + mins) - (60*lt->tm_hour + lt->tm_min);
743 if (wt < 0) wt += 1440;
744 }
745 /* Shutdown NOW if time == 0 */
746 if (wt == 0) shutdown(halttype);
747
748 /* Give warnings on regular intervals and finally shutdown. */
749 if (wt < 15 && !needwarning(wt)) warn(wt);
750 while(wt) {
751 if (wt <= 5 && !didnolog) {
752 donologin(wt);
753 didnolog++;
754 }
755 if (needwarning(wt)) warn(wt);
756 hardsleep(60);
757 wt--;
758 }
759 shutdown(halttype);
760
761 return 0; /* Never happens */
762 }