/*
* killall.c - kill processes by name or list PIDs
*
* Copyright (C) 1993-2002 Werner Almesberger
* Copyright (C) 2002-2012 Craig Small
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <getopt.h>
#include <pwd.h>
#include <regex.h>
#include <ctype.h>
#include <assert.h>
#ifdef WITH_SELINUX
#include <selinux/selinux.h>
#endif /*WITH_SELINUX*/
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif /* HAVE_LOCALE_H */
#include "i18n.h"
#include "comm.h"
#include "signals.h"
#define PROC_BASE "/proc"
#define MAX_NAMES (int)(sizeof(unsigned long)*8)
#define TSECOND "s"
#define TMINUTE "m"
#define THOUR "h"
#define TDAY "d"
#define TWEEK "w"
#define TMONTH "M"
#define TYEAR "y"
#define TMAX_SECOND 31536000
#define TMAX_MINUTE 525600
#define TMAX_HOUR 8760
#define TMAX_DAY 365
#define TMAX_WEEK 48
#define TMAX_MONTH 12
#define TMAX_YEAR 1
#define ER_REGFAIL -1
#define ER_NOMEM -2
#define ER_UNKWN -3
#define ER_OOFRA -4
static int verbose = 0, exact = 0, interactive = 0, reg = 0,
quiet = 0, wait_until_dead = 0, process_group = 0,
ignore_case = 0;
static long younger_than = 0, older_than = 0;
typedef struct NAMEINFO {
const char *name;
int name_length;
struct stat st;
} NAMEINFO;
static int
ask (char *name, pid_t pid, const int signal)
{
int res;
size_t len;
char *line;
line = NULL;
len = 0;
do {
if (signal == SIGTERM)
printf (_("Kill %s(%s%d) ? (y/N) "), name, process_group ? "pgid " : "",
pid);
else
printf (_("Signal %s(%s%d) ? (y/N) "), name, process_group ? "pgid " : "",
pid);
fflush (stdout);
if (getline (&line, &len, stdin) < 0)
return 0;
/* Check for default */
if (line[0] == '\n') {
free(line);
return 0;
}
res = rpmatch(line);
if (res >= 0) {
free(line);
return res;
}
} while(1);
/* Never should get here */
}
static double
uptime()
{
char * savelocale;
char buf[2048];
FILE* file;
if (!(file=fopen( PROC_BASE "/uptime", "r"))) {
fprintf(stderr, "killall: error opening uptime file\n");
exit(1);
}
savelocale = setlocale(LC_NUMERIC,"C");
if (fscanf(file, "%2047s", buf) == EOF) perror("uptime");
fclose(file);
setlocale(LC_NUMERIC,savelocale);
return atof(buf);
}
/* process age from jiffies to seconds via uptime */
static double process_age(const unsigned long long jf)
{
double age;
double sc_clk_tck = sysconf(_SC_CLK_TCK);
assert(sc_clk_tck > 0);
age = uptime() - jf / sc_clk_tck;
if (age < 0L)
return 0L;
return age;
}
/* returns requested time interval in seconds,
negative indicates error has occurred
*/
static long
parse_time_units(const char* age)
{
char *unit;
long num;
num = strtol(age,&unit,10);
if (age == unit) /* no digits found */
return -1;
if (unit[0] == '\0') /* no units found */
return -1;
switch(unit[0]) {
case 's':
return num;
case 'm':
return (num * 60);
case 'h':
return (num * 60 * 60);
case 'd':
return (num * 60 * 60 * 24);
case 'w':
return (num * 60 * 60 * 24 * 7);
case 'M':
return (num * 60 * 60 * 24 * 7 * 4);
case 'y':
return (num * 60 * 60 * 24 * 7 * 4 * 12);
}
return -1;
}
static int
match_process_uid(pid_t pid, uid_t uid)
{
char buf[128];
uid_t puid;
FILE *f;
int re = -1;
snprintf