2 shutdown - close down the system graciously
4 Author: Edvard Tuinder <v892231@si.hhs.NL>
6 This program informs the users that the system is going
7 down, when and why. After that a shutdown notice is written in
8 both /usr/adm/wtmp and by syslog(3). Then reboot(2) is called
9 to really close the system.
11 This actually is a ``nice'' halt(8).
13 Options are supposed to be as with BSD
14 -h: shutdown and halt the system
15 -r: shutdown and reboot
16 -k: stop an already running shutdown
17 -o: obsolete: not implemented
20 -C: crash check, i.e. is the last wtmp entry a shutdown entry?
21 -x: let the monitor execute the given code
23 -d: default CTRL-ALT-DEL shutdown for current bootloader
26 #define _POSIX_SOURCE 1
27 #include <sys/types.h>
42 static char SHUT_PID
[] = "/usr/run/shutdown.pid";
43 static char NOLOGIN
[] = "/etc/nologin";
46 #define inform_user_time inf_time
47 #define inform_user inf_user
51 void write_pid( void );
52 int inform_user_time( void );
53 void inform_user( void );
54 void terminate( void );
55 void wall( char *when
, char *extra
);
56 int crash_check( void );
57 void parse_time( char *arg
);
58 void get_message( void );
59 int main( int argc
, char *argv
[] );
65 int reboot_flag
='h'; /* default is halt */
66 char *reboot_code
=""; /* optional monitor code */
67 int info_min
, info_hour
;
80 if (p
[0] == '+') { delta
= 1; p
++; }
82 hours
= strtoul(p
, &p
, 10);
83 if (*p
== 0 && delta
) {
87 if (*p
!= ':' && *p
!= '.')
91 minutes
= strtoul(p
, &p
, 10);
95 fprintf(stderr
,"Invalid time specification `%s'\n",arg
);
100 tm
= localtime(&now
);
103 hours
-= tm
->tm_hour
;
104 minutes
-= tm
->tm_min
;
111 if (hours
< 0) hours
+= 24; /* Time after midnight. */
113 tm
->tm_hour
+= hours
;
114 tm
->tm_min
+= minutes
;
116 info_hour
= tm
->tm_hour
;
117 info_min
= tm
->tm_min
;
120 "The system will shutdown in %d hour%s and %d minute%s at %02d:%02d\n\n",
121 hours
,hours
==1?"":"s",minutes
,minutes
==1?"":"s",info_hour
,info_min
);
123 wait_time
+= hours
* 3600 + minutes
* 60;
131 int i
, now
= 0, nologin
= 0, want_terminate
= 0, want_message
= 0, check
= 0;
134 static char HALT1
[] = "-?";
135 static char *HALT
[] = { "shutdown", HALT1
, NULL
, NULL
};
138 for (i
= 1; i
< argc
&& argv
[i
][0] == '-'; i
++) {
139 if (argv
[i
][1] == '-' && argv
[i
][2] == 0) {
144 for (opt
= argv
[i
] + 1; *opt
!= 0; opt
++) {
154 if (reboot_flag
== 'x') {
157 fprintf (stderr
,"shutdown: option '-x' requires an argument\n");
176 fprintf (stderr
,"shutdown: invalid option '-%c'\n",*opt
);
182 if ((argc
- i
) > 2) usage();
184 if (check
) exit(crash_check() ? 0 : 2);
187 /* No timespec, assume "now". */
190 if (!strcmp(argv
[i
], "now"))
196 if ((argc
- i
) == 2) {
197 /* One line message */
198 strcat(message
, argv
[i
+1]);
199 strcat(message
, "\n");
202 if (want_terminate
) terminate();
203 if (want_message
) get_message();
207 prog
= strrchr(*argv
,'/');
208 if (prog
== (char *)0)
219 fprintf(stderr
, "%s: can't fork\n", prog
);
224 /* Detach from the terminal (if any). */
225 if ((tty
= open("/dev/tty", O_RDONLY
)) != -1) {
233 if (wait_time
<= 5 * 60 && !nologin
&& !now
) {
234 close(creat(NOLOGIN
,00644));
237 if (wait_time
<= 60) break;
238 if(inform_user_time())
246 sleep (30); /* Last minute before shutdown */
249 sleep (30); /* Last 30 seconds before shutdown */
254 unlink(SHUT_PID
); /* No way of stopping anymore */
257 HALT
[1][1] = reboot_flag
;
258 if (reboot_flag
== 'x') HALT
[2] = reboot_code
;
260 execv("/usr/sbin/halt", HALT
);
262 execv("/usr/bin/halt", HALT
);
265 fprintf(stderr
, "Can't execute 'halt': %s\n", strerror(errno
));
269 fprintf(stderr
, "Reboot call failed: %s\n", strerror(errno
));
276 fputs("Usage: shutdown [-hrRmkd] [-x code] [time [message]]\n", stderr
);
277 fputs(" -h -> halt system after shutdown\n", stderr
);
278 fputs(" -r -> reboot system after shutdown\n", stderr
);
279 fputs(" -R -> reset system after shutdown\n", stderr
);
280 fputs(" -x -> return to the monitor doing...\n", stderr
);
281 fputs(" -d -> default CTRL-ALT-DEL shutdown for current bootloader\n", stderr
);
282 fputs(" -m -> read a shutdown message from standard input\n", stderr
);
283 fputs(" -k -> stop an already running shutdown\n", stderr
);
284 fputs(" code -> boot monitor code to be executed\n", stderr
);
285 fputs(" time -> keyword ``now'', minutes before shutdown ``+5'',\n", stderr
);
286 fputs(" or absolute time specification ``11:20''\n", stderr
);
287 fputs(" message -> short shutdown message\n", stderr
);
297 in
= fopen(SHUT_PID
,"r");
298 if (in
== (FILE *)0) {
299 fputs ("Can't get pid of shutdown process, probably not running shutdown\n", stderr
);
305 if (kill(pid
,9) == -1)
306 fputs("Can't kill the shutdown process, probably not running anymore\n",stderr
);
308 puts("Shutdown process terminated");
318 puts ("Type your message. End with ^D at an empty line");
319 fputs ("shutdown> ",stdout
);fflush(stdout
);
320 while (fgets(line
,80,stdin
) != (char *)0) {
321 strcat (message
,line
);
322 bzero(line
,strlen(line
));
323 fputs ("shutdown> ",stdout
);fflush(stdout
);
325 putc('\n',stdout
);fflush(stdout
);
328 int inform_user_time()
334 if (min
== 60 || min
== 30 || min
== 15 || min
== 10 || min
<= 5)
346 minute
= wait_time
/ 60;
347 while (minute
>= 60) {
354 "\nThe system will shutdown in %d hour%s and %d minute%s at %.02d:%.02d\n\n",
355 hour
,hour
==1?"":"s",minute
,minute
==1?"":"s",info_hour
,info_min
);
359 "\nThe system will shutdown in %d minutes at %.02d:%.02d\n\n",
360 minute
,info_hour
,info_min
);
364 "\nThe system will shutdown in %ld seconds\n\n",
368 "\nThe system will shutdown NOW\n\n");
378 fd
= creat(SHUT_PID
,00600);
381 strncpy (pid
,itoa(getpid()), sizeof(pid
));
382 write (fd
,pid
,sizeof(pid
));
390 int fd
= -1, crashed
;
393 if (stat(STR_ROOT_WTMP
, &st
) < 0 || st
.st_size
== 0) {
394 if (stat(STR_WTMP
, &st
) < 0 || st
.st_size
== 0) {
397 if ((fd
= open(STR_WTMP
, O_RDONLY
)) < 0) return 0;
398 } else if ((fd
= open(STR_ROOT_WTMP
, O_RDONLY
)) < 0) return 0;
400 crashed
= (lseek(fd
, - (off_t
) sizeof(last
), SEEK_END
) == -1
401 || read(fd
, (void *) &last
, sizeof(last
)) != sizeof(last
)
402 || last
.ut_line
[0] != '~'
404 || (strncmp(last
.ut_name
, "shutdown", sizeof(last
.ut_name
))
405 && strncmp(last
.ut_name
, "halt", sizeof(last
.ut_name
)))
407 || (strncmp(last
.ut_user
, "shutdown", sizeof(last
.ut_user
))
408 && strncmp(last
.ut_user
, "halt", sizeof(last
.ut_user
)))