[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);
+}