File:  [ELWIX - Embedded LightWeight unIX -] / embedtools / src / wdog.c
Revision 1.2: download - view: text, annotated - select for diffs - revision graph
Wed Jun 8 12:45:41 2011 UTC (13 years ago) by misho
Branches: MAIN
CVS tags: tools1_1, TOOLS1_0, HEAD
new ver

/*************************************************************************
 * (C) 2010 AITNET - Sofia/Bulgaria - <office@aitbg.com>
 *  by Michael Pounov <misho@aitbg.com>
 *
 * $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 <dir>\tBefore execute chroot to dir [default=/]\n"
		"\t-u <user>\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;
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>