skill: use library for process scanning
skill is one of the older and more unloved programs. It was still scanning readdir /proc. It now will use the procps library like the rest of the programs. Signed-off-by: Craig Small <csmall@enc.com.au>
This commit is contained in:
parent
1b6e5ae11e
commit
0a0e4c603e
256
skill.c
256
skill.c
@ -34,15 +34,15 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <proc/namespace.h>
|
||||||
|
#include <proc/pids.h>
|
||||||
|
|
||||||
#include "c.h"
|
#include "c.h"
|
||||||
#include "fileutils.h"
|
#include "fileutils.h"
|
||||||
#include "signals.h"
|
#include "signals.h"
|
||||||
#include "strutils.h"
|
#include "strutils.h"
|
||||||
#include "nls.h"
|
#include "nls.h"
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
#include "proc/pwcache.h"
|
|
||||||
#include "proc/devname.h"
|
|
||||||
#include <proc/namespace.h>
|
|
||||||
#include "rpmatch.h"
|
#include "rpmatch.h"
|
||||||
|
|
||||||
#define DEFAULT_NICE 4
|
#define DEFAULT_NICE 4
|
||||||
@ -62,13 +62,24 @@ static const char **cmds;
|
|||||||
static int *pids;
|
static int *pids;
|
||||||
static char **namespaces;
|
static char **namespaces;
|
||||||
static int ns_pid;
|
static int ns_pid;
|
||||||
static struct procps_namespaces ns;
|
static struct procps_namespaces match_namespaces;
|
||||||
|
static int ns_flags = 0x3f;
|
||||||
|
|
||||||
#define ENLIST(thing,addme) do{ \
|
#define ENLIST(thing,addme) do{ \
|
||||||
if(!thing##s) thing##s = xmalloc(sizeof(*thing##s)*saved_argc); \
|
if(!thing##s) thing##s = xmalloc(sizeof(*thing##s)*saved_argc); \
|
||||||
thing##s[thing##_count++] = addme; \
|
thing##s[thing##_count++] = addme; \
|
||||||
}while(0)
|
}while(0)
|
||||||
|
|
||||||
|
enum pids_item items[] = {
|
||||||
|
PROCPS_PIDS_ID_PID,
|
||||||
|
PROCPS_PIDS_ID_EUID,
|
||||||
|
PROCPS_PIDS_ID_EUSER,
|
||||||
|
PROCPS_PIDS_TTY,
|
||||||
|
PROCPS_PIDS_TTY_NAME,
|
||||||
|
PROCPS_PIDS_CMD};
|
||||||
|
enum rel_items {
|
||||||
|
EU_PID, EU_EUID, EU_EUSER, EU_TTY, EU_TTYNAME, EU_CMD};
|
||||||
|
|
||||||
static int my_pid;
|
static int my_pid;
|
||||||
static int saved_argc;
|
static int saved_argc;
|
||||||
|
|
||||||
@ -81,7 +92,6 @@ enum {
|
|||||||
};
|
};
|
||||||
static int program = PROG_UNKNOWN;
|
static int program = PROG_UNKNOWN;
|
||||||
|
|
||||||
static int ns_flags = 0x3f;
|
|
||||||
static int parse_namespaces(char *optarg)
|
static int parse_namespaces(char *optarg)
|
||||||
{
|
{
|
||||||
char *ptr = optarg, *tmp;
|
char *ptr = optarg, *tmp;
|
||||||
@ -114,126 +124,100 @@ static int parse_namespaces(char *optarg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* kill or nice a process */
|
static int match_intlist(const int value, const int len, int *list)
|
||||||
static void hurt_proc(int tty, int uid, int pid, const char *restrict const cmd,
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<len; i++)
|
||||||
|
if (list[i] == value)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int match_strlist(const char *value, const int len, const char **list)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<len; i++)
|
||||||
|
if (strcmp(list[i], value) == 0)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int match_ns(const int pid)
|
||||||
|
{
|
||||||
|
struct procps_namespaces proc_ns;
|
||||||
|
int found = 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (procps_ns_read_pid(pid, &proc_ns) < 0)
|
||||||
|
xerrx(EXIT_FAILURE,
|
||||||
|
_("Unable to read process namespace information"));
|
||||||
|
for (i = 0; i < PROCPS_NS_COUNT; i++) {
|
||||||
|
if (ns_flags & (1 << i)) {
|
||||||
|
if (proc_ns.ns[i] != match_namespaces.ns[i])
|
||||||
|
found = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ask_user(struct pids_stack *stack)
|
||||||
|
{
|
||||||
|
#define PIDS_GETINT(e) PROCPS_PIDS_VAL(EU_ ## e, s_int, stack)
|
||||||
|
#define PIDS_GETSTR(e) PROCPS_PIDS_VAL(EU_ ## e, str, stack)
|
||||||
|
char *buf=NULL;
|
||||||
|
size_t len=0;
|
||||||
|
|
||||||
|
fprintf(stderr, "%-8s %-8s %5d %-16.16s ? ",
|
||||||
|
PIDS_GETSTR(TTYNAME),
|
||||||
|
PIDS_GETSTR(EUSER),
|
||||||
|
PIDS_GETINT(PID),
|
||||||
|
PIDS_GETSTR(CMD));
|
||||||
|
fflush(stdout);
|
||||||
|
if (getline(&buf, &len, stdin) == -1)
|
||||||
|
return 0;
|
||||||
|
if (rpmatch(buf) < 1) {
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nice_or_kill(struct pids_stack *stack,
|
||||||
struct run_time_conf_t *run_time)
|
struct run_time_conf_t *run_time)
|
||||||
{
|
{
|
||||||
int failed;
|
int failed;
|
||||||
char dn_buf[1000];
|
|
||||||
dev_to_tty(dn_buf, 999, tty, pid, ABBREV_DEV);
|
if (run_time->interactive && !ask_user(stack))
|
||||||
if (run_time->interactive) {
|
|
||||||
char *buf;
|
|
||||||
size_t len = 0;
|
|
||||||
fprintf(stderr, "%-8s %-8s %5d %-16.16s ? ",
|
|
||||||
(char *)dn_buf, user_from_uid(uid), pid, cmd);
|
|
||||||
fflush (stdout);
|
|
||||||
if (getline(&buf, &len, stdin) == -1)
|
|
||||||
return;
|
return;
|
||||||
if (rpmatch(buf) < 1) {
|
|
||||||
free(buf);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
free(buf);
|
|
||||||
}
|
|
||||||
/* do the actual work */
|
/* do the actual work */
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if (program == PROG_SKILL)
|
if (program == PROG_SKILL)
|
||||||
failed = kill(pid, sig_or_pri);
|
failed = kill(PIDS_GETINT(PID), sig_or_pri);
|
||||||
else
|
else
|
||||||
failed = setpriority(PRIO_PROCESS, pid, sig_or_pri);
|
failed = setpriority(PRIO_PROCESS, PIDS_GETINT(PID), sig_or_pri);
|
||||||
if ((run_time->warnings && failed) || run_time->debugging || run_time->verbose) {
|
if ((run_time->warnings && failed) || run_time->debugging || run_time->verbose) {
|
||||||
fprintf(stderr, "%-8s %-8s %5d %-16.16s ",
|
fprintf(stderr, "%-8s %-8s %5d %-16.16s ",
|
||||||
(char *)dn_buf, user_from_uid(uid), pid, cmd);
|
PIDS_GETSTR(TTYNAME),
|
||||||
|
PIDS_GETSTR(EUSER),
|
||||||
|
PIDS_GETINT(PID),
|
||||||
|
PIDS_GETSTR(CMD));
|
||||||
perror("");
|
perror("");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (run_time->interactive)
|
if (run_time->interactive)
|
||||||
return;
|
return;
|
||||||
if (run_time->noaction) {
|
if (run_time->noaction) {
|
||||||
printf("%d\n", pid);
|
printf("%d\n", PIDS_GETINT(PID));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#undef PIDS_GETINT
|
||||||
/* check one process */
|
#undef PIDS_GETSTR
|
||||||
static void check_proc(int pid, struct run_time_conf_t *run_time)
|
|
||||||
{
|
|
||||||
char buf[128];
|
|
||||||
struct stat statbuf;
|
|
||||||
struct procps_namespaces pid_ns;
|
|
||||||
char *tmp;
|
|
||||||
int tty;
|
|
||||||
int fd;
|
|
||||||
int i;
|
|
||||||
if (pid == my_pid || pid == 0)
|
|
||||||
return;
|
|
||||||
/* pid (cmd) state ppid pgrp session tty */
|
|
||||||
sprintf(buf, "/proc/%d/stat", pid);
|
|
||||||
fd = open(buf, O_RDONLY);
|
|
||||||
if (fd == -1) {
|
|
||||||
/* process exited maybe */
|
|
||||||
if (run_time->warnings)
|
|
||||||
xwarn(_("cannot open file %s"), buf);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fstat(fd, &statbuf);
|
|
||||||
if (uids) {
|
|
||||||
/* check the EUID */
|
|
||||||
i = uid_count;
|
|
||||||
while (i--)
|
|
||||||
if (uids[i] == statbuf.st_uid)
|
|
||||||
break;
|
|
||||||
if (i == -1)
|
|
||||||
goto closure;
|
|
||||||
}
|
|
||||||
if (read(fd, buf, 128) <= 0)
|
|
||||||
goto closure;
|
|
||||||
buf[127] = '\0';
|
|
||||||
tmp = strrchr(buf, ')');
|
|
||||||
*tmp++ = '\0';
|
|
||||||
i = 5;
|
|
||||||
while (i--)
|
|
||||||
while (*tmp++ != ' ')
|
|
||||||
/* scan to find tty */ ;
|
|
||||||
tty = atoi(tmp);
|
|
||||||
if (ttys) {
|
|
||||||
i = tty_count;
|
|
||||||
while (i--)
|
|
||||||
if (ttys[i] == tty)
|
|
||||||
break;
|
|
||||||
if (i == -1)
|
|
||||||
goto closure;
|
|
||||||
}
|
|
||||||
tmp = strchr(buf, '(') + 1;
|
|
||||||
if (cmds) {
|
|
||||||
i = cmd_count;
|
|
||||||
/* fast comparison trick -- useful? */
|
|
||||||
while (i--)
|
|
||||||
if (cmds[i][0] == *tmp && !strcmp(cmds[i], tmp))
|
|
||||||
break;
|
|
||||||
if (i == -1)
|
|
||||||
goto closure;
|
|
||||||
}
|
|
||||||
if (ns_pid) {
|
|
||||||
if (procps_ns_read_pid(pid, &pid_ns) < 0)
|
|
||||||
goto closure;
|
|
||||||
for (i = 0; i < PROCPS_NS_COUNT; i++) {
|
|
||||||
if (ns_flags & (1 << i)) {
|
|
||||||
if (pid_ns.ns[i] != ns.ns[i])
|
|
||||||
goto closure;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* This is where we kill/nice something. */
|
|
||||||
/* for debugging purposes?
|
|
||||||
fprintf(stderr, "PID %d, UID %d, TTY %d,%d, COMM %s\n",
|
|
||||||
pid, statbuf.st_uid, tty >> 8, tty & 0xf, tmp);
|
|
||||||
*/
|
|
||||||
hurt_proc(tty, statbuf.st_uid, pid, tmp, run_time);
|
|
||||||
closure:
|
|
||||||
/* kill/nice _first_ to avoid PID reuse */
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* debug function */
|
/* debug function */
|
||||||
static void show_lists(void)
|
static void show_lists(void)
|
||||||
@ -277,36 +261,36 @@ static void show_lists(void)
|
|||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* iterate over all PIDs */
|
static void scan_procs(struct run_time_conf_t *run_time)
|
||||||
static void iterate(struct run_time_conf_t *run_time)
|
|
||||||
{
|
{
|
||||||
int pid;
|
#define PIDS_GETINT(e) PROCPS_PIDS_VAL(EU_ ## e, s_int, reap->stacks[i])
|
||||||
DIR *d;
|
#define PIDS_GETSTR(e) PROCPS_PIDS_VAL(EU_ ## e, str, reap->stacks[i])
|
||||||
struct dirent *de;
|
struct procps_pidsinfo *info=NULL;
|
||||||
if (pids) {
|
struct pids_reap *reap;
|
||||||
pid = pid_count;
|
int i, total_procs;
|
||||||
while (pid--)
|
|
||||||
check_proc(pids[pid], run_time);
|
if (procps_pids_new(&info, 6, items) < 0)
|
||||||
return;
|
xerrx(EXIT_FAILURE,
|
||||||
}
|
_("Unable to create pid info structure"));
|
||||||
#if 0
|
if ((reap = procps_pids_reap(info, PROCPS_REAP_TASKS_ONLY)) == NULL)
|
||||||
/* could setuid() and kill -1 to have the kernel wipe out a user */
|
xerrx(EXIT_FAILURE,
|
||||||
if (!ttys && !cmds && !pids && !run_time->interactive) {
|
_("Unable to load process information"));
|
||||||
}
|
|
||||||
#endif
|
total_procs = reap->counts.total;
|
||||||
d = opendir("/proc");
|
for (i=0; i < total_procs; i++) {
|
||||||
if (!d)
|
if (PIDS_GETINT(PID) == my_pid || PIDS_GETINT(PID) == 0)
|
||||||
xerr(EXIT_FAILURE, "/proc");
|
|
||||||
while ((de = readdir(d))) {
|
|
||||||
if (de->d_name[0] > '9')
|
|
||||||
continue;
|
continue;
|
||||||
if (de->d_name[0] < '1')
|
if (uids && !match_intlist(PIDS_GETINT(EUID), uid_count, uids))
|
||||||
continue;
|
continue;
|
||||||
pid = atoi(de->d_name);
|
if (ttys && !match_intlist(PIDS_GETINT(TTY), tty_count, ttys))
|
||||||
if (pid)
|
continue;
|
||||||
check_proc(pid, run_time);
|
if (cmds && !match_strlist(PIDS_GETSTR(CMD), cmd_count, cmds))
|
||||||
|
continue;
|
||||||
|
if (namespaces && !match_ns(PIDS_GETINT(PID)))
|
||||||
|
continue;
|
||||||
|
nice_or_kill(reap->stacks[i], run_time);
|
||||||
}
|
}
|
||||||
closedir(d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* skill and snice help */
|
/* skill and snice help */
|
||||||
@ -393,7 +377,7 @@ static int snice_prio_option(int *argc, char **argv)
|
|||||||
return (int)prio;
|
return (int)prio;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void skillsnice_parse(int argc,
|
static void parse_options(int argc,
|
||||||
char **argv, struct run_time_conf_t *run_time)
|
char **argv, struct run_time_conf_t *run_time)
|
||||||
{
|
{
|
||||||
int signo = -1;
|
int signo = -1;
|
||||||
@ -499,7 +483,7 @@ static void skillsnice_parse(int argc,
|
|||||||
xwarnx(_("invalid pid number %s"), optarg);
|
xwarnx(_("invalid pid number %s"), optarg);
|
||||||
skillsnice_usage(stderr);
|
skillsnice_usage(stderr);
|
||||||
}
|
}
|
||||||
if (procps_ns_read_pid(ns_pid, &ns) < 0) {
|
if (procps_ns_read_pid(ns_pid, &match_namespaces) < 0) {
|
||||||
xwarnx(_("error reading reference namespace "
|
xwarnx(_("error reading reference namespace "
|
||||||
"information"));
|
"information"));
|
||||||
skillsnice_usage(stderr);
|
skillsnice_usage(stderr);
|
||||||
@ -587,10 +571,10 @@ int main(int argc, char ** argv)
|
|||||||
case PROG_SNICE:
|
case PROG_SNICE:
|
||||||
case PROG_SKILL:
|
case PROG_SKILL:
|
||||||
setpriority(PRIO_PROCESS, my_pid, -20);
|
setpriority(PRIO_PROCESS, my_pid, -20);
|
||||||
skillsnice_parse(argc, argv, &run_time);
|
parse_options(argc, argv, &run_time);
|
||||||
if (run_time.debugging)
|
if (run_time.debugging)
|
||||||
show_lists();
|
show_lists();
|
||||||
iterate(&run_time);
|
scan_procs(&run_time);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, _("skill: \"%s\" is not supported\n"),
|
fprintf(stderr, _("skill: \"%s\" is not supported\n"),
|
||||||
|
Loading…
Reference in New Issue
Block a user