--- embedtools/src/wdog.c 2010/10/16 03:30:51 1.1 +++ embedtools/src/wdog.c 2011/06/08 12:45:41 1.2 @@ -0,0 +1,188 @@ +/************************************************************************* + * (C) 2010 AITNET - Sofia/Bulgaria - + * by Michael Pounov + * + * $Author: misho $ + * $Id: wdog.c,v 1.2 2011/06/08 12:45:41 misho Exp $ + * + *************************************************************************/ +#include "global.h" + + +int Verbose, Kill, Log; +extern char compiled[], compiledby[], compilehost[]; + + +static void +Usage() +{ + + printf( "WatchDog tool for risk process managment\n" + "=== %s === %s@%s ===\n\n" + " Syntax: wdog [options] [exec_file]\n\n" + "\t-v\t\tVerbose ...\n" + "\t-c \tBefore execute chroot to dir [default=/]\n" + "\t-u \tBefore execute change user\n" + "\t-P\t\tInfinit loop, bypass penalty timeout\n" + "\t-S\t\tDisable send log events to syslog\n" + "\n", compiled, compiledby, compilehost); +} + +static void +sigHand(int sig) +{ + int stat; + + switch (sig) { + case SIGTERM: + Kill++; + break; + case SIGCHLD: + while (waitpid(-1, &stat, WNOHANG) > 0); + break; + } +} + +static void +logmsg(int prio, const char *fmt, ...) +{ + va_list lst; + + va_start(lst, fmt); + if (!Log) + vsyslog(prio, fmt, lst); + else + vprintf(fmt, lst); + va_end(lst); +} + + +int +main(int argc, char **argv) +{ + char ch, bypass = 0, szChroot[MAXPATHLEN] = DEFAULT_CHROOT; + int status = 0, ret = 1; + struct sigaction sa; + struct passwd *pass = NULL; + u_int penalty = 1; + uid_t uid = getuid(); + + while ((ch = getopt(argc, argv, "vhSPc:u:")) != -1) + switch (ch) { + case 'v': + Verbose++; + break; + case 'P': + bypass = 1; + break; + case 'S': + Log = 1; + break; + case 'c': + if (uid) { + printf("Error:: can`t chroot, please run as root!\n"); + goto end; + } + if (access(optarg, R_OK)) { + printf("Error:: can`t chroot to %s #%d - %s\n", optarg, + errno, strerror(errno)); + goto end; + } else + strlcpy(szChroot, optarg, MAXPATHLEN); + status |= 1; + break; + case 'u': + if (uid) { + printf("Error:: can`t setuid, please run as root!\n"); + goto end; + } + pass = getpwnam(optarg); + if (!pass) { + printf("Error:: can`t find user %s\n", optarg); + goto end; + } else + uid = pass->pw_uid; + endpwent(); + status |= 2; + break; + case 'h': + default: + Usage(); + goto end; + } + argc -= optind; + argv += optind; + if (!argc || !argv || !*argv) { + Usage(); + goto end; + } + + if (!Log) + openlog("wdog", LOG_PID, LOG_USER); + + VERB(2) logmsg(LOG_NOTICE, "Info:: Chroot=%s Run=%s\n", szChroot, *argv); + + memset(&sa, 0, sizeof sa); + sa.sa_handler = sigHand; + sigemptyset(&sa.sa_mask); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGCHLD, &sa, NULL); + sa.sa_handler = SIG_IGN; + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGPIPE, &sa, NULL); + sigaction(SIGTSTP, &sa, NULL); + sigaction(SIGSTOP, &sa, NULL); + VERB(5) logmsg(LOG_NOTICE, "Info:: Catched signals ...\n"); + + if (status & 1 && (ret = chroot(szChroot)) == -1) { + printf("Error:: error in chroot to %s #%d - %s\n", szChroot, errno, strerror(errno)); + ret = 3; + goto end; + } else + VERB(1) logmsg(LOG_NOTICE, "Info:: chrooted to %s\n", szChroot); + + if (status & 2 && setuid(uid) == -1) { + printf("Error:: error in setuid to %u #%d - %s\n", uid, errno, strerror(errno)); + ret = 4; + goto end; + } else + VERB(1) logmsg(LOG_NOTICE, "Info:: setuid to %u\n", uid); + + status ^= status; + while (!Kill && penalty) { + switch ((ret = fork())) { + case -1: + logmsg(LOG_ERR, "Error:: error in fork #%d - %s\n", errno, strerror(errno)); + ret = 5; + goto end; + case 0: + VERB(3) logmsg(LOG_NOTICE, "Info:: I`m child of shadows ...\n"); + if (execvp(*argv, argv) == -1) { + logmsg(LOG_ERR, "Error:: error in exec %s #%d - %s\n", + *argv, errno, strerror(errno)); + ret = 6; + goto end; + } + /* never reached !!! */ + break; + default: + wait(&status); + kill(ret, SIGTERM); + ret = status; + } + /* penalty timeout retry */ + usleep(penalty); + if (!bypass) { + penalty <<= 1; + VERB(2) logmsg(LOG_NOTICE, "Info:: penalty timeout %u microseconds\n", penalty); + } + } + if (!penalty) + ret = 9; +end: + if (!Log) + closelog(); + return ret; +}