/* * Copyright (c) 1995 MINOURA Makoto. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Minoura Makoto. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* poffd: looks at the power switch / alarm and does shutdown. */ #include #include #include #include #include #include #include #include #include #include #include #include "pathnames.h" char *prog; char *shutdownprog = _PATH_DEFAULT_SHUTDOWN; int fd; time_t boottime; int oldsw; static void dofork __P((void)); static void sethandler __P((void)); static void usage __P((void)); static void logerror __P((const char *)); static void alarmhandler __P((int)); static void usr1handler __P((int)); int main(argc, argv) int argc; char *argv[]; { prog = strrchr(argv[0], '/'); if (prog) prog++; else prog = argv[0]; if (argc == 2) shutdownprog = argv[1]; else if (argc > 2) usage(); #ifndef DEBUG dofork(); #endif openlog(prog, LOG_PID, LOG_DAEMON); fd = open(_PATH_DEVPOW, O_RDWR); if (fd < 0) { logerror("Could not open /dev/pow: %s"); unlink (_PATH_POFFDPID); exit(1); } sethandler(); while (1) pause(); return 0; } static void dofork(void) { int pid; pid = fork(); if (pid < 0) { /* Cannot fork! */ perror(prog); exit(1); } if (pid > 0) { /* Parent: Create /var/run/poffd.pid */ FILE *fp; fp = fopen(_PATH_POFFDPID, "w"); if (fp == NULL) { perror(_PATH_POFFDPID); exit(1); } fprintf(fp, "%d\n", pid); fclose(fp); exit(0); } { /* Child: Detatch tty */ int tty; tty = open("/dev/tty", O_RDWR); if (tty >= 0) { ioctl(tty, TIOCNOTTY, NULL); close(tty); } } } static void sethandler(void) { struct x68k_powerinfo powerinfo; int sw, sig; if (ioctl(fd, POWIOCGPOWERINFO, &powerinfo) < 0) { logerror("Failed POWIOCGPOWERINFO: %s"); close(fd); unlink (_PATH_POFFDPID); exit(1); } sw = powerinfo.pow_switch_boottime; oldsw = powerinfo.pow_switch_current & 6; if (sw & POW_ALARMSW) { struct x68k_alarminfo alarminfo; int secs; time_t boottime, offtime, now; if (ioctl(fd, POWIOCGALARMINFO, &alarminfo) < 0) { logerror(" Failed POWIOCGALARMINFO: %s"); close(fd); unlink (_PATH_POFFDPID); exit(1); } boottime = powerinfo.pow_boottime; now = time(NULL); offtime = alarminfo.al_offtime; if (alarminfo.al_enable && (int) offtime != 0) { signal(SIGALRM, alarmhandler); secs = difftime(boottime + offtime, now); if (secs > 5) alarm(secs); else alarm(5); } } signal(SIGUSR1, usr1handler); sig = SIGUSR1; if (ioctl(fd, POWIOCSSIGNAL, &sig) < 0) { logerror("Failed POWIOCSSIGNAL: %s"); close(fd); unlink (_PATH_POFFDPID); exit(1); } } /* ARGSUSED */ static void usr1handler(sig) int sig; { struct x68k_powerinfo powerinfo; char *shut, *p; char how; if (ioctl(fd, POWIOCGPOWERINFO, &powerinfo) < 0) { logerror("Failed POWIOCGPOWERINFO: %s"); close(fd); unlink (_PATH_POFFDPID); exit(1); } if (powerinfo.pow_switch_current & 6) { oldsw = powerinfo.pow_switch_current & 6; return; } close(fd); syslog(LOG_DEBUG, "Executing shutdown program."); switch (oldsw) { case 0: how = '2'; break; case 2: how = '1'; break; case 4: how = '0'; break; default: /* ??? */ how = '0'; break; } shut = alloca(strlen(shutdownprog) + 1); strcpy(shut, shutdownprog); p = shut; while (p = index(p, '%')) *p = how; sigsetmask (sigsetmask (0) & (~sigmask (SIGUSR1))); unlink (_PATH_POFFDPID); execl(_PATH_BSHELL, "sh", "-c", shut, NULL); logerror("Failed in exec: %s"); exit(1); } /* ARGSUSED */ static void alarmhandler(sig) int sig; { int oldmask = sigsetmask(sigmask(SIGUSR1)); signal(SIGALRM, SIG_IGN); usr1handler(0); sigsetmask(oldmask); } static void usage(void) { printf("Usage: %s [shutdown-program]\n", prog); exit(1); } static void logerror(const char *str) { char buf[1024]; sprintf(buf, str, strerror(errno)); syslog(LOG_ERR, buf); }