diff -Nur minit-0.9.1/Makefile minit-0.9.1-shutdown/Makefile --- minit-0.9.1/Makefile 2003-04-25 15:07:37.000000000 +0200 +++ minit-0.9.1-shutdown/Makefile 2003-05-09 17:27:30.000000000 +0200 @@ -1,4 +1,4 @@ -all: minit msvc pidfilehack hard-reboot write_proc +all: minit msvc pidfilehack hard-reboot write_proc shutdown #CFLAGS=-pipe -march=i386 -fomit-frame-pointer -Os -I../dietlibc/include DIET=diet @@ -17,11 +17,14 @@ str_start.o $(DIET) $(CROSS)$(CC) $(LDFLAGS) -o msvc $^ +shutdown: shutdown.o split.o openreadclose.o + $(DIET) $(CROSS)$(CC) $(LDFLAGS) -o shutdown $^ + %.o: %.c $(DIET) $(CROSS)$(CC) $(CFLAGS) -c $^ clean: - rm -f *.o minit msvc pidfilehack hard-reboot write_proc + rm -f *.o minit msvc pidfilehack hard-reboot write_proc shutdown test: test.c gcc -nostdlib -o $@ $^ -I../dietlibc/include ../dietlibc/start.o ../dietlibc/dietlibc.a @@ -39,6 +42,7 @@ install minit pidfilehack $(DESTDIR)/sbin install write_proc hard-reboot $(DESTDIR)/sbin install msvc $(DESTDIR)/bin + install -m 4750 shutdown $(DESTDIR)/sbin test -d $(DESTDIR)/etc/minit || mkdir $(DESTDIR)/etc/minit install-fifos: diff -Nur minit-0.9.1/shutdown.c minit-0.9.1-shutdown/shutdown.c --- minit-0.9.1/shutdown.c 1970-01-01 01:00:00.000000000 +0100 +++ minit-0.9.1-shutdown/shutdown.c 2003-05-09 18:53:45.000000000 +0200 @@ -0,0 +1,255 @@ +/* + * Notes: + * - uncomment `#define ALLOW_SUID' below if you want users other than + * root to be able to shut down the system. + * - after compiling, install under /sbin/shutdown with chgrp adm and + * chmod 4750 for SUID root, or 0700 for root only + * - uncomment `#define USE_MINIT' below if you want to use shutdown + * with minit. If defined, shutdown will try to bring down the services + * halt (for -h or -o) or reboot (-r) before killing all other processes. + * Please make sure that you have a depends in reboot and halt that + * will bring down all respawning services. A respawning service during + * shutdown might cause you to wait for a fsck during the next boot + * - If you do not use minit shutdown will bring your system down similar + * to SysV-Inits shutdown with -n + * + * TODO: + * - add a function for wall-messages + * - cleanup + */ + +#include +#include +#include +#include +#include +#include + +#define ALLOW_SUID +#define USE_MINIT + +#ifdef USE_MINIT +#define MINITROOT "/etc/minit" +#endif + +extern char **environ; +extern int openreadclose(char *fn, char **buf, unsigned long *len); +extern char **split(char *buf,int c,int *len,int plus,int ofs); +extern char *optarg; + +void msg(char *buf) { + write(2,buf,strlen(buf)); +} + +void wall(char *buf) { + msg(buf); +} + +int exec_cmd(char *cmd, ...) { + char *argv[10]; + va_list arguments; + pid_t pid; + int i; + + va_start(arguments, cmd); + for (i=0;i<9 && (argv[i] = va_arg(arguments, char *)) != NULL; i++); + argv[i] = NULL; + va_end(arguments); + pid = fork(); + if (pid < 0) return -1; + if (pid > 0) { + while (wait(NULL) != pid); + } else { + execve(cmd, argv, environ); + //perror("execvp failed"); + exit(0); + } + return 0; +} + +#ifdef USE_MINIT + +static int infd, outfd; +static char buf[1500]; + +int minit_serviceDown(char *service) { + char *s=0; + unsigned long len; + pid_t pid=0; + + if (service < 0) return 0; + if (chdir(MINITROOT) || chdir(service)) return -1; + + if (!openreadclose("depends", &s, &len)) { + char **deps; + int depc, i; + deps=split(s, '\n', &depc, 0, 0); + for (i=0; i "); msg(service); + buf[0]='r'; // we want to disable respawning first + strncpy(buf+1, service, 1400); + buf[1400]=0; + write(infd, buf, strlen(buf)); + read(outfd, buf, 1500); + int i=kill(pid, SIGTERM); + if (i == 0) msg("\t\tdone\n"); + else msg("\t\tfailed\n"); + } +} + +int minit_shutdown(int level) { + char* service; + msg("Shutting down minit services: \n"); + infd=open("/etc/minit/in", O_WRONLY); + outfd=open("/etc/minit/out", O_RDONLY); + if (infd>=0) { + while (lockf(infd, F_LOCK, 1)) { + msg("no lock"); + sleep(1); + } + } + + if (!level) + minit_serviceDown("reboot"); + else + minit_serviceDown("halt"); +} +#endif + +void printUsage() { + msg("usage: shutdown -[rhosmn] -[t secs]\n" + "\t -r: reboot after shutdown\n" + "\t -h: halt after shutdown\n" + "\t -o: power-off after shutdown\n" + "\t -s: single-user console after shutdown\n" + "\t -m: only shutdown the minit-part\n" + "\t -n: do not shutdown services using minit\n" + "\t -t secs: delay between SIGTERM and SIGKILL\n"); +} + +main(int argc, char **argv[]) { + int c; + int cfg_downlevel=2; + /* 0: reboot + * 1: halt + * 2: power off + */ + char *cfg_delay = "3"; + int cfg_minitonly = 0; + int cfg_sulogin = 0; + + #ifdef ALLOW_SUID + setuid(geteuid()); + #endif + if (getuid() != 0) { + msg("you are not root, go away!\n"); + return 1; + } + + if (argc<2) { + printUsage(); + return 0; + } + + /* parse commandline options */ + while((c = getopt(argc, argv, "rhosmnt:")) != EOF) { + switch(c) { + case 'r': /* do we have to reboot... */ + cfg_downlevel = 0; + break; + case 'h': /* ...halt.. */ + cfg_downlevel = 1; + break; + case 's': /* rescue system */ + cfg_sulogin = 1; + break; + case 'm': /* exit after minit down */ + cfg_minitonly = 1; + break; + case 'o': /* ..or power off? */ + cfg_downlevel = 2; + break; + case 't': /* delay between SIGTERM and SIGKILL */ + cfg_delay = optarg; + break; + default: + printUsage(); + return 1; + } + } + + switch (cfg_downlevel) { + case 0: + wall("system is going down for reboot NOW\n"); + break; + case 1: + wall("system is going down for system halt NOW\n"); + break; + case 2: + wall("system is going down for power-off NOW\n"); + break; + } + + /* + * catch some signals; + * getting killed after killing the controlling terminal wouldn't be + * such a great thing... + */ + signal(SIGQUIT, SIG_IGN); + signal(SIGCHLD, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + + // real shutdown? then lets rock.. + #ifdef USE_MINIT + minit_shutdown(cfg_downlevel); + if (cfg_minitonly) return 0; + #endif + + /* kill all processes still left */ + msg("sending all processes the TERM signal...\n"); + kill(-1, SIGTERM); + sleep(atoi(cfg_delay)); + + msg("sending all processes the KILL signal...\n"); + kill(-1, SIGKILL); + + if (cfg_sulogin) { + exec_cmd("/sbin/sulogin", "sulogin", (char *) 0); + return 0; + } + + /* sync buffers */ + sync(); + + exec_cmd("/bin/swapoff", "swapoff", "-a", (char *) 0); + exec_cmd("/bin/umount", "umount", "-a", (char *) 0); + exec_cmd("/bin/umount", "umount", "/", (char *) 0); + + /* and finally reboot, halt or power-off the system */ + if (cfg_downlevel == 0) { + reboot(RB_AUTOBOOT); + } else if (cfg_downlevel == 1) { + reboot(RB_HALT_SYSTEM); + } else { + reboot(RB_POWER_OFF); + } +}