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?
22 -d: default CTRL-ALT-DEL shutdown for current bootloader
25 #define _POSIX_SOURCE 1
26 #include <sys/types.h>
41 static char SHUT_PID
[] = "/usr/run/shutdown.pid";
42 static char NOLOGIN
[] = "/etc/nologin";
45 #define inform_user_time inf_time
46 #define inform_user inf_user
50 void write_pid( void );
51 int inform_user_time( void );
52 void inform_user( void );
53 void terminate( void );
54 void wall( char *when
, char *extra
);
55 int crash_check( void );
56 void parse_time( char *arg
);
57 void get_message( void );
58 int main( int argc
, char *argv
[] );
64 int reboot_flag
='h'; /* default is halt */
65 int info_min
, info_hour
;
78 if (p
[0] == '+') { delta
= 1; p
++; }
80 hours
= strtoul(p
, &p
, 10);
81 if (*p
== 0 && delta
) {
85 if (*p
!= ':' && *p
!= '.')
89 minutes
= strtoul(p
, &p
, 10);
93 fprintf(stderr
,"Invalid time specification `%s'\n",arg
);
101 hours
-= tm
->tm_hour
;
102 minutes
-= tm
->tm_min
;
109 if (hours
< 0) hours
+= 24; /* Time after midnight. */
111 tm
->tm_hour
+= hours
;
112 tm
->tm_min
+= minutes
;
114 info_hour
= tm
->tm_hour
;
115 info_min
= tm
->tm_min
;
118 "The system will shutdown in %d hour%s and %d minute%s at %02d:%02d\n\n",
119 hours
,hours
==1?"":"s",minutes
,minutes
==1?"":"s",info_hour
,info_min
);
121 wait_time
+= hours
* 3600 + minutes
* 60;
129 int i
, now
= 0, nologin
= 0, want_terminate
= 0, want_message
= 0, check
= 0;
132 static char HALT1
[] = "-?";
133 static char *HALT
[] = { "shutdown", HALT1
, NULL
};
136 for (i
= 1; i
< argc
&& argv
[i
][0] == '-'; i
++) {
137 if (argv
[i
][1] == '-' && argv
[i
][2] == 0) {
142 for (opt
= argv
[i
] + 1; *opt
!= 0; opt
++) {
161 fprintf (stderr
,"shutdown: invalid option '-%c'\n",*opt
);
167 if ((argc
- i
) > 2) usage();
169 if (check
) exit(crash_check() ? 0 : 2);
172 /* No timespec, assume "now". */
175 if (!strcmp(argv
[i
], "now"))
181 if ((argc
- i
) == 2) {
182 /* One line message */
183 strcat(message
, argv
[i
+1]);
184 strcat(message
, "\n");
187 if (want_terminate
) terminate();
188 if (want_message
) get_message();
192 prog
= strrchr(*argv
,'/');
193 if (prog
== (char *)0)
204 fprintf(stderr
, "%s: can't fork\n", prog
);
209 /* Detach from the terminal (if any). */
210 if ((tty
= open("/dev/tty", O_RDONLY
)) != -1) {
218 if (wait_time
<= 5 * 60 && !nologin
&& !now
) {
219 close(creat(NOLOGIN
,00644));
222 if (wait_time
<= 60) break;
223 if(inform_user_time())
231 sleep (30); /* Last minute before shutdown */
234 sleep (30); /* Last 30 seconds before shutdown */
239 unlink(SHUT_PID
); /* No way of stopping anymore */
242 HALT
[1][1] = reboot_flag
;
244 execv("/usr/sbin/halt", HALT
);
246 execv("/usr/bin/halt", HALT
);
249 fprintf(stderr
, "Can't execute 'halt': %s\n", strerror(errno
));
253 fprintf(stderr
, "Reboot call failed: %s\n", strerror(errno
));
260 fputs("Usage: shutdown [-hrRpmkd] [time [message]]\n", stderr
);
261 fputs(" -h -> halt system after shutdown\n", stderr
);
262 fputs(" -r -> reboot system after shutdown\n", stderr
);
263 fputs(" -R -> reset system after shutdown\n", stderr
);
264 fputs(" -p -> power system off after shutdown\n", stderr
);
265 fputs(" -d -> default CTRL-ALT-DEL shutdown for current bootloader\n", stderr
);
266 fputs(" -m -> read a shutdown message from standard input\n", stderr
);
267 fputs(" -k -> stop an already running shutdown\n", stderr
);
268 fputs(" time -> keyword ``now'', minutes before shutdown ``+5'',\n", stderr
);
269 fputs(" or absolute time specification ``11:20''\n", stderr
);
270 fputs(" message -> short shutdown message\n", stderr
);
280 in
= fopen(SHUT_PID
,"r");
281 if (in
== (FILE *)0) {
282 fputs ("Can't get pid of shutdown process, probably not running shutdown\n", stderr
);
288 if (kill(pid
,9) == -1)
289 fputs("Can't kill the shutdown process, probably not running anymore\n",stderr
);
291 puts("Shutdown process terminated");
301 puts ("Type your message. End with ^D at an empty line");
302 fputs ("shutdown> ",stdout
);fflush(stdout
);
303 while (fgets(line
,80,stdin
) != (char *)0) {
304 strcat (message
,line
);
305 bzero(line
,strlen(line
));
306 fputs ("shutdown> ",stdout
);fflush(stdout
);
308 putc('\n',stdout
);fflush(stdout
);
311 int inform_user_time()
317 if (min
== 60 || min
== 30 || min
== 15 || min
== 10 || min
<= 5)
329 minute
= wait_time
/ 60;
330 while (minute
>= 60) {
337 "\nThe system will shutdown in %d hour%s and %d minute%s at %.02d:%.02d\n\n",
338 hour
,hour
==1?"":"s",minute
,minute
==1?"":"s",info_hour
,info_min
);
342 "\nThe system will shutdown in %d minutes at %.02d:%.02d\n\n",
343 minute
,info_hour
,info_min
);
347 "\nThe system will shutdown in %ld seconds\n\n",
351 "\nThe system will shutdown NOW\n\n");
361 fd
= creat(SHUT_PID
,00600);
364 strncpy (pid
,itoa(getpid()), sizeof(pid
));
365 write (fd
,pid
,sizeof(pid
));
373 int fd
= -1, crashed
;
376 if (stat(STR_ROOT_WTMP
, &st
) < 0 || st
.st_size
== 0) {
377 if (stat(STR_WTMP
, &st
) < 0 || st
.st_size
== 0) {
380 if ((fd
= open(STR_WTMP
, O_RDONLY
)) < 0) return 0;
381 } else if ((fd
= open(STR_ROOT_WTMP
, O_RDONLY
)) < 0) return 0;
383 crashed
= (lseek(fd
, - (off_t
) sizeof(last
), SEEK_END
) == -1
384 || read(fd
, (void *) &last
, sizeof(last
)) != sizeof(last
)
385 || last
.ut_line
[0] != '~'
387 || (strncmp(last
.ut_name
, "shutdown", sizeof(last
.ut_name
))
388 && strncmp(last
.ut_name
, "halt", sizeof(last
.ut_name
)))
390 || (strncmp(last
.ut_user
, "shutdown", sizeof(last
.ut_user
))
391 && strncmp(last
.ut_user
, "halt", sizeof(last
.ut_user
)))