[vhffs-dev] [1340] added getopt(), fixed some bugs, added robustness

[ Thread Index | Date Index | More vhffs.org/vhffs-dev Archives ]


Revision: 1340
Author:   gradator
Date:     2009-02-18 02:18:52 +0100 (Wed, 18 Feb 2009)

Log Message:
-----------
added getopt(), fixed some bugs, added robustness

Modified Paths:
--------------
    trunk/vhffs-autokill/autokill.c


Modified: trunk/vhffs-autokill/autokill.c
===================================================================
--- trunk/vhffs-autokill/autokill.c	2009-02-17 02:13:40 UTC (rev 1339)
+++ trunk/vhffs-autokill/autokill.c	2009-02-18 01:18:52 UTC (rev 1340)
@@ -19,6 +19,10 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifndef __linux__
+#error This software is only running on Linux-based OS, bye!
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -29,51 +33,136 @@
 #include <time.h>
 #include <sys/time.h>
 #include <pwd.h>
+#include <getopt.h>
 
 #define FALSE 0
 #define TRUE !FALSE
 
-// Assume you are using a system with jiffies at 100 HZ (all linux >= 2.4 kernels)
-#define HERTZ 100.0
 
-// All process between MINUID included and MAXUID included will be killed
-#define MINUID 10000
-#define MAXUID 65000
+void addlogline(char *line, char *logfile);
+static void usage_exit(int ret_code, char *progname);
 
-// Interval between checks, in centiseconds (100 = 1 sec)
-#define WAITTIME 100
+int main(int argc, char *argv[])  {
+	long tickspersec;
+	int foreground = FALSE;
+	int demomode = FALSE;
+	char *logfile = NULL;
+	long minuid = 10000, maxuid = -1; // default is 10000 for minuid, unlimited for maxuid
+	long waittime = 100; // default is to wait 1s between probes
+	long runtimeterm, runtimekill;
+	long cputimeterm, cputimekill;
 
-// The maximum time the process are allowed to run, in jiffies
-#define MAXRUNTIMESIGTERM 30000
-#define MAXRUNTIMESIGKILL 30120
+	struct option long_options[] = {
+		{ "foreground", no_argument, NULL, 'f' },
+		{ "logfile", required_argument, NULL, 'l' },
+		{ "demo", no_argument, NULL, 'd' },
+		{ "minuid", required_argument, NULL, 1000 },
+		{ "maxuid", required_argument, NULL, 1001 },
+		{ "runtimeterm", required_argument, NULL, 1002 },
+		{ "runtimekill", required_argument, NULL, 1003 },
+		{ "cputimeterm", required_argument, NULL, 1004 },
+		{ "cputimekill", required_argument, NULL, 1005 },
+		{ "interval", required_argument, NULL, 'i' },
+		{ "help", no_argument, NULL, 'h' },
+		{ "version", no_argument, NULL, 'v' },
+		{ 0, 0, 0, 0 }
+	};
 
-// The maximum cpu time the process are allowed to use, in jiffies
-#define MAXCPUTIMESIGTERM 3100
-#define MAXCPUTIMESIGKILL 3210
 
-// Demo mode ?
-#define DEMOMODE FALSE
+	tickspersec = sysconf(_SC_CLK_TCK);
+	if(tickspersec <= 0) tickspersec = 100;  // assume 100
 
-// Daemonize ?
-#define DAEMONIZE TRUE
+	runtimeterm = 300 * tickspersec; // default is ~300s for running time
+	runtimekill = 302 * tickspersec;
+	cputimeterm = 32 * tickspersec;  // default is ~32s for cputime
+	cputimekill = 34 * tickspersec;
 
-// Logs ?
-#define LOGENABLE TRUE
-#define LOGFILE "/var/log/autokill.log"
+	while(1) {
+		int option_index = 0, c;
+		c = getopt_long(argc, argv, "fl:di:hv", long_options, &option_index);
+		if(c == -1)
+			break;
 
+		switch(c) {
+			case 'f':
+				foreground = TRUE;
+				break;
 
+			case 'd':
+				demomode = TRUE;
+				break;
 
-void addlogline(char *line);
+			case 'l':
+				logfile = strdup(optarg);
+				break;
 
-int main(int argc, char *argv[])  {
+			case 1000:
+				minuid = atoll(optarg);
+				break;
 
-	if(LOGENABLE)  {
-		if(DEMOMODE) addlogline("Starting autokill in DEMOMODE");
-		else addlogline("Starting autokill");
+			case 1001:
+				maxuid = atoll(optarg);
+				break;
+
+			case 1002:
+				runtimeterm = (long)(atof(optarg)*(double)tickspersec);
+				break;
+
+			case 1003:
+				runtimekill = (long)(atof(optarg)*(double)tickspersec);
+				break;
+
+			case 1004:
+				cputimeterm = (long)(atof(optarg)*(double)tickspersec);
+				break;
+
+			case 1005:
+				cputimekill = (long)(atof(optarg)*(double)tickspersec);
+				break;
+
+			case 'i':
+				waittime = (long)(atof(optarg)*100.0);
+				break;
+
+			case 'h':
+				usage_exit(0, argv[0]);
+
+			case 'v':
+#ifdef VERSION
+				fputs("autokill " VERSION "\n", stdout);
+#else
+				fputs("autokill\n", stdout);
+#endif
+				exit(0);
+
+			case '?':
+				/* `getopt_long' already printed an error message. */
+				fprintf(stderr,"Try `%s --help' for more information.\n", argv[0]);
+				exit(1);
+
+			default:
+				abort();
+		}
 	}
 
-	if(DAEMONIZE && fork()) exit(0);
+	if(optind != argc)
+		usage_exit(1, argv[0]);
 
+	if(runtimeterm > runtimekill) runtimeterm = runtimekill;
+	if(cputimeterm > cputimekill) cputimeterm = cputimekill;
+
+	if(logfile || foreground) {
+		if(demomode) addlogline("Starting autokill in DEMOMODE", logfile);
+		else addlogline("Starting autokill", logfile);
+	}
+
+	if(!foreground) {
+		close(STDIN_FILENO);
+		close(STDOUT_FILENO);
+		close(STDERR_FILENO);
+		if(fork()) exit(0);
+	}
+
 	while(1)  {
 		char path[256], data[8192];
 		FILE *f;
@@ -82,14 +171,6 @@
 		DIR *d;
 		struct dirent *dir;
 
-		// just wait, nothing more, really, I am not kidding, you can trust me
-		// be serious, if I tell you that it is only a stupid wait inside an
-		// infinite loop it is probably true, it is not an uncommon thing
-		// as far as I know !
-		// ok... give up... and let me do my job right now, want you ?
-		if(WAITTIME/100) sleep(WAITTIME/100);
-		if(WAITTIME%100) usleep((WAITTIME%100)*10000);
-
 		// read uptime
 		f = fopen("/proc/uptime", "r");
 		if(!f) continue;
@@ -97,7 +178,7 @@
 		fclose(f);
 		if(!br) continue;
 
-		uptime = (unsigned long long)(atof(data)*HERTZ);
+		uptime = (unsigned long long)(atof(data)*100.0);
 		if(!uptime) continue;
 
 		// search running process
@@ -105,8 +186,10 @@
 		if(!d) continue;
 
 		while( (dir = readdir(d) ) )  {
-			int i, c, s, pid, zombie;
-			unsigned long long uid, starttime, rtime, cputime;
+			int i, c, s, zombie;
+			uid_t uid;
+			pid_t pid;
+			long long starttime, rtime, cputime;
 			int signal;
 			char *signame;
 
@@ -124,12 +207,12 @@
 			fclose(f);
 			if(!br) continue;
 
-			uid = -1;
+			uid = 0;
 			for(i = 0 ; i < br-4 ; i++)  {
 				if( (i == 0 || data[i-1] == '\n') && data[i] == 'U' && data[i+1] == 'i' && data[i+2] == 'd')  {
 					for(; i < br ; i++)  {
 						if(data[i] >= '0' && data[i] <= '9')  {
-							uid = atoll(data+i);
+							uid = atol(data+i);
 							break;
 						}
 					}
@@ -137,7 +220,9 @@
 				}
 			}
 
-			if(uid < MINUID || uid > MAXUID) continue;
+			if(uid <= 0) continue;
+			if(minuid >= 0 && uid < minuid) continue;
+			if(maxuid >= 0 && uid > maxuid) continue;
 
 			// read /proc/pid/stats
 			snprintf(path, 256, "/proc/%d/stat", pid);
@@ -167,7 +252,9 @@
 						}
 
 						if(c >= 14 && c <= 17)  {
-							cputime += atoll(data+i);
+							long long cpu;
+							cpu = atoll(data+i);
+							if(cpu > 0) cputime += cpu;
 						}
 
 						if(c == 22)  {
@@ -180,12 +267,13 @@
 
 			if(zombie) continue;
 			if(starttime < 0) continue;
+			if(cputime <= 0) continue;
 
 			signal = -1;
 			// check cputime
-			if(cputime > MAXCPUTIMESIGTERM)  {
+			if(cputimeterm > 0 && cputimekill > 0 && cputime > cputimeterm)  {
 
-				if(cputime > MAXCPUTIMESIGKILL)  {
+				if(cputime > cputimekill)  {
 					signal = SIGKILL;
 					signame = "SIGKILL";
 				}
@@ -197,9 +285,9 @@
 
 			// check running time
 			rtime = uptime - starttime;
-			if(rtime > MAXRUNTIMESIGTERM)  {
+			if(runtimeterm > 0 && runtimekill > 0 && rtime > runtimeterm)  {
 
-				if(rtime > MAXRUNTIMESIGKILL)  {
+				if(rtime > runtimekill)  {
 					signal = SIGKILL;
 					signame = "SIGKILL";
 				}
@@ -210,36 +298,42 @@
 			}
 
 			if(signal >= 0)  {
-				if(LOGENABLE)  {
-					char line[128];
-					struct passwd *pw;
- 					char *name, *demo;
+				char line[128];
+				struct passwd *pw;
+				char *name, *demo;
 
-					pw = getpwuid(uid);
-					if(pw) name = pw->pw_name;
-					else name = "unknown";
+				pw = getpwuid(uid);
+				if(pw) name = pw->pw_name;
+				else name = "unknown";
 
-					if(DEMOMODE) demo = "[DEMO MODE] ";
-					else demo = "";
+				if(demomode) demo = "[DEMO MODE] ";
+				else demo = "";
 
-					snprintf(line, 128, "%sSend %s to process %d, owned by %s(%d), cpu time %.2f sec, running time %.2f sec", demo, signame, pid, name, (int)uid, cputime/HERTZ, rtime/HERTZ);
-					addlogline(line);
-				}
+				snprintf(line, 128, "%sSend %s to process %ld, owned by %s(%ld), cpu time %.2f sec, running time %.2f sec", demo, signame, (long)pid, name, (long)uid, (float)cputime/(float)tickspersec, (float)rtime/(float)tickspersec);
+				if(logfile || foreground) addlogline(line, logfile);
 
-				if(!DEMOMODE) kill(pid, signal);
+				if(!demomode) kill(pid, signal);
 			}
 
 		}
 		closedir(d);
+
+		// just wait, nothing more, really, I am not kidding, you can trust me
+		// be serious, if I tell you that it is only a stupid wait inside an
+		// infinite loop it is probably true, it is not an uncommon thing
+		// as far as I know !
+		// ok... give up... and let me do my job right now, want you ?
+		if(waittime/100) sleep(waittime/100);
+		if(waittime%100) usleep((waittime%100)*10000);
 	}
 
 	return 0;
 }
 
 
-void addlogline(char *line)  {
+void addlogline(char *line, char *logfile)  {
 
-	FILE *lf;
+	FILE *lf = NULL;
 
 	struct timeval tv;
 	char date[64];
@@ -248,7 +342,10 @@
 	ctime_r(&tv.tv_sec, date);
 	date[strlen(date)-1] = '\0';
 
-	lf = fopen(LOGFILE, "a");
+	if(logfile)  {
+		lf = fopen(logfile, "a");
+	}
+
 	if(lf)  {
 		fprintf(lf, "%s: %s\n", date, line);
 		fclose(lf);
@@ -258,3 +355,25 @@
 		fprintf(stdout, "%s: %s\n", date, line);
 	}
 }
+
+
+static void usage_exit(int ret_code, char *progname)  {
+	printf ("Usage: %s [OPTION]...\n"
+		"A program to kill all process running during a certain period of time or using too much cpu\n\n"
+		"  -f, --foreground\t\tDo not daemonise, default is to daemonise\n"
+		"  -l, --logfile=LOGFILE\t\tPath to logfile, default is to log on stdout\n"
+		"      --minuid=UID\t\tDo not kill process owned by UID below MINUID, default is 10000\n"
+		"      --maxuid=UID\t\tDo not kill process owner by UID above MAXUID, default is -1 (unlimited)\n"
+		"      --runtimeterm=SECONDS\tMaximum allowed running time before sending SIGTERM signals, default to 300s\n"
+		"      --runtimekill=SECONDS\tMaximum allowed running time before sending SIGKILL signals, default to 302s\n"
+		"\t\t\t\tSetting -1 to either runtime* options disable running time check\n"
+		"      --cputimeterm=SECONDS\tMaximum allowed cpu time before sending SIGTERM signals, default to 30s\n"
+		"      --cputimekill=SECONDS\tMaximum allowed cpu time before sending SIGKILL signals, default to 32s\n"
+		"\t\t\t\tSetting -1 to either cputime* options disable cpu time check\n"
+		"  -i, --interval=SECONDS\tDelay between each probe, default to 1s\n"
+		"  -d, --demo\t\t\tDo not kill any process, default is to kill them\n"
+		"  -h, --help\t\t\tDisplay this help and exit\n"
+		"  -v, --version\t\t\tOutput version information and exit\n",
+		progname);
+	exit(ret_code);
+}


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/