Initial revision

This commit is contained in:
Ben Gras
2005-04-21 14:53:53 +00:00
commit 9865aeaa79
2264 changed files with 411685 additions and 0 deletions

42
commands/reboot/Makefile Executable file
View File

@@ -0,0 +1,42 @@
# Makefile for shutdown / halt / reboot.
CFLAGS=$(OPT) -D_MINIX -D_POSIX_SOURCE
LDFLAGS=-i
PROGRAMS= shutdown halt tinyhalt
MANUALS= shutdown.8 halt.8 reboot.2 reboot.8
all: $(PROGRAMS)
shutdown: shutdown.o sh_wall.o log.o
$(CC) $(LDFLAGS) -o shutdown shutdown.o sh_wall.o log.o
install -S 4kw $@
halt: halt.o log.o
$(CC) $(LDFLAGS) -o halt halt.o log.o
install -S 4kw $@
tinyhalt: tinyhalt.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $?
install -S 4kw $@
install: /usr/bin/halt /usr/bin/reboot /usr/bin/shutdown \
/bin/halt /bin/reboot
/usr/bin/halt: halt
install -cs -o root -g operator -m 744 $? $@
/usr/bin/reboot: /usr/bin/halt
install -l $? $@
/usr/bin/shutdown: shutdown
install -cs -o root -g operator -m 4754 $? $@
/bin/halt: tinyhalt
install -cs -o root -g operator -m 744 $? $@
/bin/reboot: /bin/halt
install -l $? $@
clean:
rm -f *.o a.out core $(PROGRAMS)

52
commands/reboot/README Executable file
View File

@@ -0,0 +1,52 @@
This a new implementation of a shutdown procedure. It allows
the system to go down graciously with informing the
users. This package contains 3 programs:
- halt = Immediately stop the system, no info to users
- shutdown = Inform users, close down the system properly
- wall = Vincent Archer's implementation of wall (Write all)
Installing
Shutdown and halt use a new systemcall, which I've added to
MM. Therefor there are several diff's which should be applied:
callnr.hd - New callnr for reboot(2)
Diff against /usr/include/minix/callnr.h.
Those of you using a symlink package should
change the number and mm/table.c into a free
number. I used 54, LSTAT.
param.hd - Defines reboot_flag as a part of the messages
proto.hd - Add's prototype for do_reboot()
table.cd - Interpretation of the systemcall to MM
mm.cd - I have added the do_reboot code to mm/getset.c but
I couldn't find a getset.c to create a useable diff :-(
So you can add where you want it. It is pure code, no diff.
Now edit log.c and search for ``host''. Change this into your
systemname or make it empty.
Shutdown and halt log their actions in /usr/adm/log, edit the
makefile and undefine -DLOG if you don't want this (this at the end of
the makefile). You can change SHUT_LOG in shutdown.c and log.c if you
want it in another file.
Then type a `make'. This will take a minute or so (13 sec. with bcc :-).
Remember to build a new image and update the ps_database.
Type `make install' to place the program's where I've got them.
Use them, try them and let me now if you've got problems running
something.
I have tested to sources both on 16-bits and 32-bits MINIX. I have compiled
it with gcc, bcc and ACK, so that shouldn't really give a problem. Maybe
the standard MINIX-make chokes on the makefile, atleast mine did.
NOTE:
Make install does not place the man-pages somewhere. You should
do this yourself.
--
Edvard Tuinder ed@pulstar.NL.mugnet.org v892231@si.hhs.NL
Student Computer Science
Haagse Hogeschool, The Hague, The Netherlands

135
commands/reboot/halt.c Executable file
View File

@@ -0,0 +1,135 @@
/* halt / reboot - halt or reboot system (depends on name)
halt - calling reboot() with RBT_HALT
reboot - calling reboot() with RBT_REBOOT
author: Edvard Tuinder v892231@si.hhs.NL
This program calls the library function reboot(2) which performs
the system-call do_reboot.
*/
#define _POSIX_SOURCE 1
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
void write_log _ARGS(( void ));
void usage _ARGS(( void ));
int main _ARGS(( int argc, char *argv[] ));
char *prog;
void
usage()
{
fprintf(stderr, "Usage: %s [-hrRf] [-x reboot-code]\n", prog);
exit(1);
}
int
main(argc,argv)
int argc;
char **argv;
{
int flag = -1; /* default action unknown */
int fast = 0; /* fast halt/reboot, don't bother being nice. */
int i;
struct stat dummy;
char *monitor_code = "";
pid_t pid;
if ((prog = strrchr(argv[0],'/')) == NULL) prog = argv[0]; else prog++;
if (strcmp(prog, "halt") == 0) flag = RBT_HALT;
if (strcmp(prog, "reboot") == 0) flag = RBT_REBOOT;
i = 1;
while (i < argc && argv[i][0] == '-') {
char *opt = argv[i++] + 1;
if (*opt == '-' && opt[1] == 0) break; /* -- */
while (*opt != 0) switch (*opt++) {
case 'h':
flag = RBT_HALT;
break;
case 'r':
flag = RBT_REBOOT;
break;
case 'R':
flag = RBT_RESET;
break;
case 'f':
fast = 1;
break;
case 'x':
flag = RBT_MONITOR;
if (*opt == 0) {
if (i == argc) usage();
opt = argv[i++];
}
monitor_code = opt;
opt = "";
break;
default:
usage();
}
}
if (i != argc) usage();
if (flag == -1) {
fprintf(stderr, "Don't know what to do when named '%s'\n", prog);
exit(1);
}
if (stat("/usr/bin", &dummy) < 0) {
/* It seems that /usr isn't present, let's assume "-f." */
fast = 1;
}
write_log();
if (fast) {
/* But not too fast... */
sleep(1);
} else {
/* Run the shutdown scripts. */
signal(SIGHUP, SIG_IGN);
signal(SIGTERM, SIG_IGN);
switch ((pid = fork())) {
case -1:
fprintf(stderr, "%s: can't fork(): %s\n", prog, strerror(errno));
exit(1);
case 0:
execl("/bin/sh", "sh", "/etc/rc", "down", (char *) NULL);
fprintf(stderr, "%s: can't execute: /bin/sh: %s\n",
prog, strerror(errno));
exit(1);
default:
while (waitpid(pid, NULL, 0) != pid) {}
}
/* Tell init to stop spawning getty's. */
kill(1, SIGTERM);
/* Give everybody a chance to die peacefully. */
kill(-1, SIGTERM);
sleep(3);
}
reboot(flag, monitor_code, strlen(monitor_code));
fprintf(stderr, "%s: reboot(): %s\n", strerror(errno));
return 1;
}

81
commands/reboot/log.c Executable file
View File

@@ -0,0 +1,81 @@
/*
log - log the shutdown's and the halt's
Author: Edvard Tuinder <v892231@si.hhs.NL>
shutdown is logged in /usr/adm/wtmp and in /usr/adm/log (if desired)
halt is logged only in /usr/adm/wtmp as `halt' to prevent last from
reporting halt's as crashes.
*/
#define _POSIX_SOURCE 1
#include <sys/types.h>
#include <stdio.h>
#include <utmp.h>
#include <pwd.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <sys/utsname.h>
#undef WTMP
static char WTMP[] = "/usr/adm/wtmp"; /* Record of logins and logouts. */
static char SHUT_LOG[] = "/usr/adm/log";
char who[8];
extern char *prog;
static char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
void write_log _ARGS(( void ));
void write_log()
{
int fd;
static struct utmp wtmp;
static struct passwd *pwd;
char mes[90];
struct tm *tm;
time_t now;
struct utsname utsname;
char *host = "localhost";
time(&now);
tm = localtime(&now);
if (uname(&utsname) >= 0) host = utsname.nodename;
pwd = getpwuid(getuid());
if (pwd == (struct passwd *)0)
strcpy (who,"root");
else
strcpy (who,pwd->pw_name);
fd = open(WTMP,O_APPEND|O_WRONLY,1);
if (fd) {
if (strcmp(prog,"reboot"))
strcpy (wtmp.ut_user, prog);
else
strcpy (wtmp.ut_user, "shutdown"); /* last ... */
strcpy (wtmp.ut_id, "~~");
strcpy (wtmp.ut_line, "~");
wtmp.ut_pid = 0;
wtmp.ut_type = BOOT_TIME;
wtmp.ut_time = now;
wtmp.ut_host[0]= '\0';
write (fd, (char *) &wtmp,sizeof(struct utmp));
close(fd);
}
fd = open(SHUT_LOG,O_APPEND|O_WRONLY,1);
if (!fd)
perror ("open");
else {
sprintf (mes,"%s %02d %02d:%02d:%02d %s: system %s by %s@%s\n",
month[tm->tm_mon],tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,
prog,prog,who,host);
write (fd,mes,strlen(mes));
close(fd);
}
return;
}

109
commands/reboot/sh_wall.c Executable file
View File

@@ -0,0 +1,109 @@
/* wall - write to all logged in users Author: V. Archer */
/*
Edvard Tuinder v892231@si.hhs.NL
Modified some things to include this with my shutdown/halt
package
*/
#define _POSIX_SOURCE 1
#include <sys/types.h>
#include <fcntl.h>
#include <pwd.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <utmp.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#undef UTMP
static char UTMP[] = "/etc/utmp"; /* Currently logged in users. */
void wall _ARGS(( char *when, char *extra ));
void crnlcat _ARGS(( char *message, char *more ));
void
wall(when, extra)
char *when; /* When is shutdown */
char *extra; /* If non-nil, why is the shutdown */
{
struct utmp utmp;
char utmptty[5 + sizeof(utmp.ut_line) + 1];
char message[1024];
struct passwd *pw;
int utmpfd, ttyfd;
char *ourtty, *ourname;
time_t now;
struct utsname utsname;
struct stat con_st, tty_st;
if (ourtty = ttyname(1)) {
if (ourname = strrchr(ourtty, '/')) ourtty = ourname+1;
} else ourtty = "system task";
if (pw = getpwuid(getuid())) ourname = pw->pw_name;
else ourname = "unknown";
time(&now);
if (uname(&utsname) != 0) strcpy(utsname.nodename, "?");
sprintf(message, "\r\nBroadcast message from %s@%s (%s)\r\n%.24s...\007\007\007\r\n",
ourname, utsname.nodename, ourtty, ctime(&now));
crnlcat(message, when);
crnlcat(message, extra);
/* Search the UTMP database for all logged-in users. */
if ((utmpfd = open(UTMP, O_RDONLY)) < 0) {
fprintf(stderr, "Cannot open utmp file\r\n");
return;
}
/* first the console */
strcpy(utmptty, "/dev/console");
if ((ttyfd = open(utmptty, O_WRONLY | O_NONBLOCK)) < 0) {
perror(utmptty);
} else {
fstat(ttyfd, &con_st);
write(ttyfd, message, strlen(message));
close(ttyfd);
}
while (read(utmpfd, (char *) &utmp, sizeof(utmp)) == sizeof(utmp)) {
/* is this the user we are looking for? */
if (utmp.ut_type != USER_PROCESS) continue;
strncpy(utmptty+5, utmp.ut_line, sizeof(utmp.ut_line));
utmptty[5 + sizeof(utmp.ut_line) + 1] = 0;
if ((ttyfd = open(utmptty, O_WRONLY | O_NONBLOCK)) < 0) {
perror(utmptty);
continue;
}
fstat(ttyfd, &tty_st);
if (tty_st.st_rdev != con_st.st_rdev)
write(ttyfd, message, strlen(message));
close(ttyfd);
}
close(utmpfd);
return;
}
void
crnlcat(message, more)
char *message, *more;
{
char *p = message;
char *m = more;
char *end = message + 1024 - 1;
while (p < end && *p != 0) *p++;
while (p < end && *m != 0) {
if (*m == '\n' && (p == message || p[-1] != '\n')) {
*p++ = '\r';
if (p == end) p--;
}
*p++ = *m++;
}
*p = 0;
}

408
commands/reboot/shutdown.c Executable file
View File

@@ -0,0 +1,408 @@
/*
shutdown - close down the system graciously
Author: Edvard Tuinder <v892231@si.hhs.NL>
This program informs the users that the system is going
down, when and why. After that a shutdown notice is written in
both /usr/adm/wtmp and by syslog(3). Then reboot(2) is called
to really close the system.
This actually is a ``nice'' halt(8).
Options are supposed to be as with BSD
-h: shutdown and halt the system
-r: shutdown and reboot
-k: stop an already running shutdown
-o: obsolete: not implemented
New Minix options:
-C: crash check, i.e. is the last wtmp entry a shutdown entry?
-x: let the monitor execute the given code
-R: reset the system
*/
#define _POSIX_SOURCE 1
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#include <time.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <utmp.h>
#include <errno.h>
#undef WTMP
static char WTMP[] = "/usr/adm/wtmp";
static char SHUT_PID[] = "/usr/run/shutdown.pid";
static char NOLOGIN[] = "/etc/nologin";
#ifndef __STDC__
#define inform_user_time inf_time
#define inform_user inf_user
#endif
void usage _ARGS(( void ));
void write_pid _ARGS(( void ));
int inform_user_time _ARGS(( void ));
void inform_user _ARGS(( void ));
void terminate _ARGS(( void ));
void wall _ARGS(( char *when, char *extra ));
int crash_check _ARGS(( void ));
void parse_time _ARGS(( char *arg ));
void get_message _ARGS(( void ));
void main _ARGS(( int argc, char *argv[] ));
char *itoa _ARGS(( int n ));
long wait_time=0L;
char message[1024];
char info[80];
int reboot_flag='h'; /* default is halt */
char *reboot_code=""; /* optional monitor code */
int info_min, info_hour;
char *prog;
void parse_time (arg)
char *arg;
{
char *p = arg;
int hours, minutes;
time_t now;
struct tm *tm;
int delta = 0;
int bad = 0;
if (p[0] == '+') { delta = 1; p++; }
hours = strtoul(p, &p, 10);
if (*p == 0 && delta) {
minutes = hours;
hours = 0;
} else {
if (*p != ':' && *p != '.')
bad = 1;
else
p++;
minutes = strtoul(p, &p, 10);
if (*p != 0) bad = 1;
}
if (bad) {
fprintf(stderr,"Invalid time specification `%s'\n",arg);
usage();
}
time(&now);
tm = localtime(&now);
if (!delta) {
hours -= tm->tm_hour;
minutes -= tm->tm_min;
}
if (minutes < 0) {
minutes += 60;
hours--;
}
if (hours < 0) hours += 24; /* Time after midnight. */
tm->tm_hour += hours;
tm->tm_min += minutes;
(void) mktime(tm);
info_hour = tm->tm_hour;
info_min = tm->tm_min;
sprintf(info,
"The system will shutdown in %d hour%s and %d minute%s at %02d:%02d\n\n",
hours,hours==1?"":"s",minutes,minutes==1?"":"s",info_hour,info_min);
wait_time += hours * 3600 + minutes * 60;
return;
}
void main(argc,argv)
int argc;
char *argv[];
{
int i, now = 0, nologin = 0, want_terminate = 0, want_message = 0, check = 0;
char *opt;
int tty;
static char HALT1[] = "-?";
static char *HALT[] = { "shutdown", HALT1, NULL, NULL };
/* Parse options. */
for (i = 1; i < argc && argv[i][0] == '-'; i++) {
if (argv[i][1] == '-' && argv[i][2] == 0) {
/* -- */
i++;
break;
}
for (opt = argv[i] + 1; *opt != 0; opt++) {
switch (*opt) {
case 'k':
want_terminate = 1;
break;
case 'h':
case 'r':
case 'x':
reboot_flag = *opt;
if (reboot_flag == 'x') {
if (*++opt == 0) {
if (++i == argc) {
fprintf (stderr,"shutdown: option '-x' requires an argument\n");
usage();
}
opt=argv[i];
}
reboot_code=opt;
opt="";
}
break;
case 'R':
reboot_flag = 'R';
break;
case 'm':
want_message = 1;
break;
case 'C':
check = 1;
break;
default:
fprintf (stderr,"shutdown: invalid option '-%c'\n",*opt);
usage();
break;
}
}
}
if ((argc - i) > 2) usage();
if (check) exit(crash_check() ? 0 : 2);
if (i == argc) {
/* No timespec, assume "now". */
now = 1;
} else {
if (!strcmp(argv[i], "now"))
now++;
else
parse_time(argv[i]);
}
if ((argc - i) == 2) {
/* One line message */
strcat(message, argv[i+1]);
strcat(message, "\n");
}
if (want_terminate) terminate();
if (want_message) get_message();
puts(info);
prog = strrchr(*argv,'/');
if (prog == (char *)0)
prog = *argv;
else
prog++;
if (!now) {
/* Daemonize. */
switch (fork()) {
case 0:
break;
case -1:
fprintf(stderr, "%s: can't fork\n", prog);
exit(1);
default:
exit(0);
}
/* Detach from the terminal (if any). */
if ((tty = open("/dev/tty", O_RDONLY)) != -1) {
close(tty);
setsid();
}
write_pid();
}
for (;;) {
if (wait_time <= 5 * 60 && !nologin && !now) {
close(creat(NOLOGIN,00644));
nologin = 1;
}
if (wait_time <= 60) break;
if(inform_user_time())
inform_user();
sleep (60);
wait_time -= 60;
}
if (!now) {
inform_user();
sleep (30); /* Last minute before shutdown */
wait_time -= 30;
inform_user();
sleep (30); /* Last 30 seconds before shutdown */
}
wait_time = 0;
inform_user();
unlink(SHUT_PID); /* No way of stopping anymore */
unlink(NOLOGIN);
HALT[1][1] = reboot_flag;
if (reboot_flag == 'x') HALT[2] = reboot_code;
#if __minix_vmd
execv("/usr/sbin/halt", HALT);
#else
execv("/usr/bin/halt", HALT);
#endif
if (errno != ENOENT)
fprintf(stderr, "Can't execute 'halt': %s\n", strerror(errno));
sleep(2);
reboot(RBT_HALT);
fprintf(stderr, "Reboot call failed: %s\n", strerror(errno));
exit(1);
}
void usage()
{
fputs("Usage: shutdown [-hrRmk] [-x code] [time [message]]\n", stderr);
fputs(" -h -> halt system after shutdown\n", stderr);
fputs(" -r -> reboot system after shutdown\n", stderr);
fputs(" -R -> reset system after shutdown\n", stderr);
fputs(" -x -> return to the monitor doing...\n", stderr);
fputs(" -m -> read a shutdown message from standard input\n", stderr);
fputs(" -k -> stop an already running shutdown\n", stderr);
fputs(" code -> boot monitor code to be executed\n", stderr);
fputs(" time -> keyword ``now'', minutes before shutdown ``+5'',\n", stderr);
fputs(" or absolute time specification ``11:20''\n", stderr);
fputs(" message -> short shutdown message\n", stderr);
exit(1);
}
void terminate()
{
FILE *in;
pid_t pid;
char c_pid[5];
char buf[80];
in = fopen(SHUT_PID,"r");
if (in == (FILE *)0) {
fputs ("Can't get pid of shutdown process, probably not running shutdown\n", stderr);
exit(1);
}
fgets(c_pid,5,in);
fclose(in);
pid = atoi(c_pid);
if (kill(pid,9) == -1)
fputs("Can't kill the shutdown process, probably not running anymore\n",stderr);
else
puts("Shutdown process terminated");
unlink(SHUT_PID);
unlink(NOLOGIN);
#ifdef not_very_useful
in = fopen (SHUT_LOG,"a");
if (in == (FILE *)0)
exit(0);
sprintf (buf, "Shutdown with pid %d terminated\n",pid);
fputs(buf,in);
fclose(in);
#endif
exit(0);
}
void get_message()
{
char line[80];
int max_lines=12;
puts ("Type your message. End with ^D at an empty line");
fputs ("shutdown> ",stdout);fflush(stdout);
while (fgets(line,80,stdin) != (char *)0) {
strcat (message,line);
bzero(line,strlen(line));
fputs ("shutdown> ",stdout);fflush(stdout);
}
putc('\n',stdout);fflush(stdout);
}
int inform_user_time()
{
int min;
min = wait_time /60;
if (min == 60 || min == 30 || min == 15 || min == 10 || min <= 5)
return 1;
else
return 0;
}
void inform_user()
{
int hour, minute;
char mes[80];
hour = 0;
minute = wait_time / 60;
while (minute >= 60) {
minute -= 60;
hour++;
}
if (hour)
sprintf(mes,
"\nThe system will shutdown in %d hour%s and %d minute%s at %.02d:%.02d\n\n",
hour,hour==1?"":"s",minute,minute==1?"":"s",info_hour,info_min);
else
if (minute > 1)
sprintf(mes,
"\nThe system will shutdown in %d minutes at %.02d:%.02d\n\n",
minute,info_hour,info_min);
else
if (wait_time > 1)
sprintf(mes,
"\nThe system will shutdown in %d seconds\n\n",
wait_time);
else
sprintf(mes,
"\nThe system will shutdown NOW\n\n");
wall(mes,message);
}
void write_pid()
{
char pid[5];
int fd;
fd = creat(SHUT_PID,00600);
if (!fd)
return;
strncpy (pid,itoa(getpid()), sizeof(pid));
write (fd,pid,sizeof(pid));
close(fd);
return;
}
int crash_check()
{
struct utmp last;
int fd, crashed;
struct stat st;
if (stat(WTMP, &st) < 0 || st.st_size == 0) return 0;
if ((fd = open(WTMP, O_RDONLY)) < 0) return 0;
crashed = (lseek(fd, - (off_t) sizeof(last), SEEK_END) == -1
|| read(fd, (void *) &last, sizeof(last)) != sizeof(last)
|| last.ut_line[0] != '~'
|| strncmp(last.ut_user, "shutdown", sizeof(last.ut_user)));
close(fd);
return crashed;
}

35
commands/reboot/tinyhalt.c Executable file
View File

@@ -0,0 +1,35 @@
/* tinyhalt 1.0 - small forerunner Author: Kees J. Bot
*
* Disk space on the root file system is a scarce resource. This little
* program sits in /sbin. It normally calls the real halt/reboot, but if
* that isn't available then it simply calls reboot(). Can't do any logging
* of the event anyhow.
*/
#define nil 0
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int flag;
char *prog;
/* Try to run the real McCoy. */
#if __minix_vmd
execv("/usr/sbin/halt", argv);
#else
execv("/usr/bin/halt", argv);
#endif
if ((prog = strrchr(*argv,'/')) == nil) prog= argv[0]; else argv++;
sleep(2); /* Not too fast. */
reboot(strcmp(prog, "reboot") == 0 ? RBT_REBOOT : RBT_HALT);
write(2, "reboot call failed\n", 19);
return 1;
}